summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-07-08 00:53:00 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-07-08 00:53:00 +0000
commitb8553086288629b4efb77e97f5582e08bc50ad65 (patch)
tree0a19bd1c21e148f35c7a0f76baa4f7a056b966b0 /drivers
parent75b6d92f2dd5112b02f4e78cf9f35f9825946ef0 (diff)
Merge with 2.4.0-test3-pre4.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile13
-rw-r--r--drivers/acorn/block/fd1772.c20
-rw-r--r--drivers/acpi/.cvsignore2
-rw-r--r--drivers/acpi/Makefile27
-rw-r--r--drivers/acpi/common/cmalloc.c166
-rw-r--r--drivers/acpi/common/cmcopy.c711
-rw-r--r--drivers/acpi/common/cmdebug.c570
-rw-r--r--drivers/acpi/common/cmdelete.c584
-rw-r--r--drivers/acpi/common/cmeval.c310
-rw-r--r--drivers/acpi/common/cmglobal.c441
-rw-r--r--drivers/acpi/common/cminit.c362
-rw-r--r--drivers/acpi/common/cmobject.c648
-rw-r--r--drivers/acpi/common/cmutils.c726
-rw-r--r--drivers/acpi/common/cmxface.c268
-rw-r--r--drivers/acpi/dispatcher/dsfield.c414
-rw-r--r--drivers/acpi/dispatcher/dsmethod.c506
-rw-r--r--drivers/acpi/dispatcher/dsmthdat.c682
-rw-r--r--drivers/acpi/dispatcher/dsobject.c598
-rw-r--r--drivers/acpi/dispatcher/dsopcode.c464
-rw-r--r--drivers/acpi/dispatcher/dsutils.c694
-rw-r--r--drivers/acpi/dispatcher/dswexec.c572
-rw-r--r--drivers/acpi/dispatcher/dswload.c600
-rw-r--r--drivers/acpi/dispatcher/dswscope.c161
-rw-r--r--drivers/acpi/dispatcher/dswstate.c648
-rw-r--r--drivers/acpi/events/evevent.c679
-rw-r--r--drivers/acpi/events/evmisc.c357
-rw-r--r--drivers/acpi/events/evregion.c690
-rw-r--r--drivers/acpi/events/evrgnini.c425
-rw-r--r--drivers/acpi/events/evsci.c302
-rw-r--r--drivers/acpi/events/evxface.c604
-rw-r--r--drivers/acpi/events/evxfevnt.c513
-rw-r--r--drivers/acpi/events/evxfregn.c389
-rw-r--r--drivers/acpi/hardware/hwacpi.c207
-rw-r--r--drivers/acpi/hardware/hwcpu32.c716
-rw-r--r--drivers/acpi/hardware/hwgpe.c208
-rw-r--r--drivers/acpi/hardware/hwregs.c608
-rw-r--r--drivers/acpi/hardware/hwxface.c576
-rw-r--r--drivers/acpi/include/acenv.h302
-rw-r--r--drivers/acpi/include/acexcep.h162
-rw-r--r--drivers/acpi/include/acobject.h508
-rw-r--r--drivers/acpi/include/acpi.h50
-rw-r--r--drivers/acpi/include/acpiosxf.h296
-rw-r--r--drivers/acpi/include/acpixf.h299
-rw-r--r--drivers/acpi/include/actables.h188
-rw-r--r--drivers/acpi/include/actbl32.h114
-rw-r--r--drivers/acpi/include/actbl64.h115
-rw-r--r--drivers/acpi/include/actypes.h970
-rw-r--r--drivers/acpi/include/amlcode.h452
-rw-r--r--drivers/acpi/include/common.h650
-rw-r--r--drivers/acpi/include/config.h185
-rw-r--r--drivers/acpi/include/debugger.h394
-rw-r--r--drivers/acpi/include/dispatch.h383
-rw-r--r--drivers/acpi/include/events.h209
-rw-r--r--drivers/acpi/include/globals.h311
-rw-r--r--drivers/acpi/include/hardware.h169
-rw-r--r--drivers/acpi/include/internal.h850
-rw-r--r--drivers/acpi/include/interp.h660
-rw-r--r--drivers/acpi/include/macros.h423
-rw-r--r--drivers/acpi/include/namesp.h424
-rw-r--r--drivers/acpi/include/output.h124
-rw-r--r--drivers/acpi/include/parser.h327
-rw-r--r--drivers/acpi/include/resource.h300
-rw-r--r--drivers/acpi/include/tables.h168
-rw-r--r--drivers/acpi/interpreter/amconfig.c303
-rw-r--r--drivers/acpi/interpreter/amcreate.c871
-rw-r--r--drivers/acpi/interpreter/amdyadic.c750
-rw-r--r--drivers/acpi/interpreter/amfield.c327
-rw-r--r--drivers/acpi/interpreter/amfldio.c654
-rw-r--r--drivers/acpi/interpreter/ammisc.c533
-rw-r--r--drivers/acpi/interpreter/ammonad.c954
-rw-r--r--drivers/acpi/interpreter/amnames.c440
-rw-r--r--drivers/acpi/interpreter/amprep.c392
-rw-r--r--drivers/acpi/interpreter/amregion.c406
-rw-r--r--drivers/acpi/interpreter/amresnte.c555
-rw-r--r--drivers/acpi/interpreter/amresolv.c452
-rw-r--r--drivers/acpi/interpreter/amresop.c429
-rw-r--r--drivers/acpi/interpreter/amstore.c374
-rw-r--r--drivers/acpi/interpreter/amstoren.c518
-rw-r--r--drivers/acpi/interpreter/amstorob.c314
-rw-r--r--drivers/acpi/interpreter/amsystem.c343
-rw-r--r--drivers/acpi/interpreter/amutils.c522
-rw-r--r--drivers/acpi/interpreter/amxface.c94
-rw-r--r--drivers/acpi/namespace/nsaccess.c647
-rw-r--r--drivers/acpi/namespace/nsalloc.c411
-rw-r--r--drivers/acpi/namespace/nseval.c507
-rw-r--r--drivers/acpi/namespace/nsload.c488
-rw-r--r--drivers/acpi/namespace/nsnames.c503
-rw-r--r--drivers/acpi/namespace/nsobject.c556
-rw-r--r--drivers/acpi/namespace/nssearch.c646
-rw-r--r--drivers/acpi/namespace/nsutils.c886
-rw-r--r--drivers/acpi/namespace/nswalk.c279
-rw-r--r--drivers/acpi/namespace/nsxfname.c372
-rw-r--r--drivers/acpi/namespace/nsxfobj.c554
-rw-r--r--drivers/acpi/osd.c1319
-rw-r--r--drivers/acpi/parser/psargs.c735
-rw-r--r--drivers/acpi/parser/psopcode.c554
-rw-r--r--drivers/acpi/parser/psparse.c726
-rw-r--r--drivers/acpi/parser/psscope.c271
-rw-r--r--drivers/acpi/parser/pstree.c399
-rw-r--r--drivers/acpi/parser/psutils.c498
-rw-r--r--drivers/acpi/parser/pswalk.c581
-rw-r--r--drivers/acpi/parser/psxface.c132
-rw-r--r--drivers/acpi/resources/rsaddr.c810
-rw-r--r--drivers/acpi/resources/rscalc.c754
-rw-r--r--drivers/acpi/resources/rscreate.c505
-rw-r--r--drivers/acpi/resources/rsdump.c938
-rw-r--r--drivers/acpi/resources/rsio.c544
-rw-r--r--drivers/acpi/resources/rsirq.c568
-rw-r--r--drivers/acpi/resources/rslist.c506
-rw-r--r--drivers/acpi/resources/rsmemory.c570
-rw-r--r--drivers/acpi/resources/rsmisc.c612
-rw-r--r--drivers/acpi/resources/rsutils.c430
-rw-r--r--drivers/acpi/resources/rsxface.c177
-rw-r--r--drivers/acpi/tables/tbget.c324
-rw-r--r--drivers/acpi/tables/tbinstal.c533
-rw-r--r--drivers/acpi/tables/tbtable.c388
-rw-r--r--drivers/acpi/tables/tbutils.c352
-rw-r--r--drivers/acpi/tables/tbxface.c352
-rw-r--r--drivers/block/acsi_slm.c2
-rw-r--r--drivers/block/ataflop.c29
-rw-r--r--drivers/block/cpqarray.c1
-rw-r--r--drivers/block/elevator.c74
-rw-r--r--drivers/block/floppy.c5
-rw-r--r--drivers/block/ll_rw_blk.c109
-rw-r--r--drivers/block/loop.c2
-rw-r--r--drivers/block/md.c3
-rw-r--r--drivers/block/nbd.c3
-rw-r--r--drivers/block/paride/pg.c2
-rw-r--r--drivers/block/paride/pt.c2
-rw-r--r--drivers/block/ps2esdi.c1
-rw-r--r--drivers/block/rd.c4
-rw-r--r--drivers/block/xd.c2
-rw-r--r--drivers/block/xd.h4
-rw-r--r--drivers/block/z2ram.c2
-rw-r--r--drivers/cdrom/aztcd.c3
-rw-r--r--drivers/cdrom/cdrom.c8
-rw-r--r--drivers/cdrom/cdu31a.c3
-rw-r--r--drivers/cdrom/cm206.c1
-rw-r--r--drivers/cdrom/gscd.c19
-rw-r--r--drivers/cdrom/gscd.h7
-rw-r--r--drivers/cdrom/mcd.c22
-rw-r--r--drivers/cdrom/mcd.h11
-rw-r--r--drivers/cdrom/mcdx.c3
-rw-r--r--drivers/cdrom/optcd.c3
-rw-r--r--drivers/cdrom/sbpcd.c6
-rw-r--r--drivers/cdrom/sjcd.c7
-rw-r--r--drivers/cdrom/sonycd535.c9
-rw-r--r--drivers/char/console.c63
-rw-r--r--drivers/char/epca.c16
-rw-r--r--drivers/char/ftape/zftape/zftape-init.c12
-rw-r--r--drivers/char/ip2/i2ellis.c2
-rw-r--r--drivers/char/ip2/i2ellis.h10
-rw-r--r--drivers/char/ip2/i2lib.c2
-rw-r--r--drivers/char/ip2/i2lib.h8
-rw-r--r--drivers/char/ip2/i2os.h3
-rw-r--r--drivers/char/ip2main.c12
-rw-r--r--drivers/char/istallion.c2
-rw-r--r--drivers/char/lp.c2
-rw-r--r--drivers/char/misc.c9
-rw-r--r--drivers/char/msp3400.c2
-rw-r--r--drivers/char/nwbutton.h2
-rw-r--r--drivers/char/pcxx.c20
-rw-r--r--drivers/char/ppdev.c4
-rw-r--r--drivers/char/pty.c2
-rw-r--r--drivers/char/rocket.c32
-rw-r--r--drivers/char/serial.c35
-rw-r--r--drivers/char/specialix.c1
-rw-r--r--drivers/char/stallion.c2
-rw-r--r--drivers/char/stradis.c2
-rw-r--r--drivers/char/synclink.c6
-rw-r--r--drivers/char/tpqic02.c25
-rw-r--r--drivers/char/tty_io.c3
-rw-r--r--drivers/char/vc_screen.c6
-rw-r--r--drivers/char/videodev.c4
-rw-r--r--drivers/char/zr36120.c2
-rw-r--r--drivers/i2o/i2o_block.c6
-rw-r--r--drivers/ide/hd.c27
-rw-r--r--drivers/ide/ide-cd.c11
-rw-r--r--drivers/ide/ide-probe.c23
-rw-r--r--drivers/ide/ide.c4
-rw-r--r--drivers/ieee1394/Config.in4
-rw-r--r--drivers/ieee1394/Makefile11
-rw-r--r--drivers/ieee1394/aic5800.c2
-rw-r--r--drivers/ieee1394/csr.c3
-rw-r--r--drivers/ieee1394/guid.c3
-rw-r--r--drivers/ieee1394/highlevel.c3
-rw-r--r--drivers/ieee1394/hosts.c3
-rw-r--r--drivers/ieee1394/ieee1394_core.c16
-rw-r--r--drivers/ieee1394/ieee1394_core.h10
-rw-r--r--drivers/ieee1394/ieee1394_syms.c3
-rw-r--r--drivers/ieee1394/ieee1394_transactions.c79
-rw-r--r--drivers/ieee1394/ieee1394_types.h156
-rw-r--r--drivers/ieee1394/ohci1394.c1552
-rw-r--r--drivers/ieee1394/ohci1394.h133
-rw-r--r--drivers/ieee1394/pcilynx.c185
-rw-r--r--drivers/ieee1394/pcilynx.h31
-rw-r--r--drivers/ieee1394/raw1394.c57
-rw-r--r--drivers/ieee1394/raw1394.h28
-rw-r--r--drivers/ieee1394/video1394.c1266
-rw-r--r--drivers/ieee1394/video1394.h15
-rw-r--r--drivers/isdn/avmb1/capi.c10
-rw-r--r--drivers/isdn/isdn_common.c2
-rw-r--r--drivers/mtd/.cvsignore2
-rw-r--r--drivers/mtd/Config.in43
-rw-r--r--drivers/mtd/Makefile190
-rw-r--r--drivers/mtd/cfi_cmdset_0001.c871
-rw-r--r--drivers/mtd/cfi_probe.c501
-rw-r--r--drivers/mtd/doc1000.c601
-rw-r--r--drivers/mtd/doc2000.c837
-rw-r--r--drivers/mtd/doc2001.c844
-rw-r--r--drivers/mtd/docprobe.c269
-rw-r--r--drivers/mtd/ftl.c1458
-rw-r--r--drivers/mtd/jedec.c773
-rw-r--r--drivers/mtd/map_ram.c110
-rw-r--r--drivers/mtd/map_rom.c60
-rw-r--r--drivers/mtd/mapped.c674
-rw-r--r--drivers/mtd/mixmem.c151
-rw-r--r--drivers/mtd/mtdblock.c318
-rw-r--r--drivers/mtd/mtdchar.c402
-rw-r--r--drivers/mtd/mtdcore.c398
-rw-r--r--drivers/mtd/mtdram.c147
-rw-r--r--drivers/mtd/nftl.c1317
-rw-r--r--drivers/mtd/nora.c208
-rw-r--r--drivers/mtd/octagon-5066.c290
-rw-r--r--drivers/mtd/physmap.c114
-rw-r--r--drivers/mtd/pmc551.c689
-rw-r--r--drivers/mtd/rpxlite.c160
-rw-r--r--drivers/mtd/slram.c226
-rw-r--r--drivers/mtd/vmax301.c243
-rw-r--r--drivers/net/Space.c4
-rw-r--r--drivers/net/appletalk/ltpc.c19
-rw-r--r--drivers/net/atp.c2
-rw-r--r--drivers/net/bonding.c4
-rw-r--r--drivers/net/cs89x0.c3
-rw-r--r--drivers/net/defxx.c198
-rw-r--r--drivers/net/hamradio/baycom_par.c8
-rw-r--r--drivers/net/hamradio/baycom_ser_fdx.c8
-rw-r--r--drivers/net/hamradio/baycom_ser_hdx.c8
-rw-r--r--drivers/net/hamradio/soundmodem/sm.c8
-rw-r--r--drivers/net/irda/nsc-ircc.c1
-rw-r--r--drivers/net/irda/smc-ircc.c8
-rw-r--r--drivers/net/ncr885e.c60
-rw-r--r--drivers/net/pcmcia/aironet4500_cs.c6
-rw-r--r--drivers/net/sk98lin/skvpd.c2
-rw-r--r--drivers/net/sk_g16.c3
-rw-r--r--drivers/net/skfp/ecm.c4
-rw-r--r--drivers/net/skfp/ess.c4
-rw-r--r--drivers/net/skfp/fplustm.c6
-rw-r--r--drivers/net/skfp/smt.c2
-rw-r--r--drivers/net/skfp/srf.c2
-rw-r--r--drivers/net/smc9194.c3
-rw-r--r--drivers/net/sunlance.c1
-rw-r--r--drivers/net/tokenring/ibmtr.c2
-rw-r--r--drivers/net/wan/comx-proto-lapb.c14
-rw-r--r--drivers/net/wan/cosa.c2
-rw-r--r--drivers/net/wan/hostess_sv11.c4
-rw-r--r--drivers/net/wan/lmc/lmc_main.c1
-rw-r--r--drivers/parport/ChangeLog27
-rw-r--r--drivers/parport/parport_pc.c33
-rw-r--r--drivers/parport/procfs.c2
-rw-r--r--drivers/pcmcia/cs.c214
-rw-r--r--drivers/pcmcia/cs_internal.h1
-rw-r--r--drivers/pcmcia/pci_socket.c92
-rw-r--r--drivers/pcmcia/pci_socket.h2
-rw-r--r--drivers/sbus/audio/audio.c4
-rw-r--r--drivers/sbus/char/bpp.c2
-rw-r--r--drivers/sbus/char/jsflash.c1
-rw-r--r--drivers/sbus/char/sab82532.c3
-rw-r--r--drivers/sbus/char/vfc_dev.c2
-rw-r--r--drivers/sbus/char/zs.c10
-rw-r--r--drivers/scsi/gdth_proc.c13
-rw-r--r--drivers/scsi/scsi.c4
-rw-r--r--drivers/scsi/scsi_lib.c1
-rw-r--r--drivers/scsi/scsi_scan.c9
-rw-r--r--drivers/sgi/char/sgiserial.c23
-rw-r--r--drivers/sound/cmpci.c3
-rw-r--r--drivers/sound/esssolo1.c2
-rw-r--r--drivers/sound/sb_common.c1
-rw-r--r--drivers/sound/sonicvibes.c2
-rw-r--r--drivers/sound/sound_core.c4
-rw-r--r--drivers/sound/sound_syms.c3
-rw-r--r--drivers/sound/soundcard.c4
-rw-r--r--drivers/sound/sscape.c2
-rw-r--r--drivers/tc/zs.c6
-rw-r--r--drivers/usb/devio.c29
-rw-r--r--drivers/usb/ibmcam.c22
-rw-r--r--drivers/usb/input.c2
-rw-r--r--drivers/usb/serial/usbserial.c5
-rw-r--r--drivers/usb/serial/visor.c83
-rw-r--r--drivers/usb/serial/whiteheat.c175
-rw-r--r--drivers/usb/usb-ohci.c67
-rw-r--r--drivers/usb/usb-ohci.h27
-rw-r--r--drivers/usb/usb-uhci.c12
-rw-r--r--drivers/video/Config.in7
-rw-r--r--drivers/video/atyfb.c2
-rw-r--r--drivers/video/clgenfb.c3
-rw-r--r--drivers/video/fbmem.c2
-rw-r--r--drivers/video/matrox/matroxfb_DAC1064.c19
-rw-r--r--drivers/video/matrox/matroxfb_DAC1064.h8
-rw-r--r--drivers/video/matrox/matroxfb_Ti3026.c3
-rw-r--r--drivers/video/matrox/matroxfb_base.c73
-rw-r--r--drivers/video/matrox/matroxfb_base.h4
-rw-r--r--drivers/video/matrox/matroxfb_crtc2.c14
-rw-r--r--drivers/video/offb.c9
-rw-r--r--drivers/video/riva/fbdev.c6
-rw-r--r--drivers/video/riva/riva_hw.c2
-rw-r--r--drivers/video/riva/riva_tbl.h4
-rw-r--r--drivers/video/tdfxfb.c230
308 files changed, 69757 insertions, 2235 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 9d42ab23d..a91c3355e 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -11,7 +11,8 @@ SUB_DIRS := block char net parport sound misc
MOD_SUB_DIRS := $(SUB_DIRS)
ALL_SUB_DIRS := $(SUB_DIRS) pci sgi ide scsi sbus cdrom isdn pnp i2o \
ieee1394 macintosh video dio zorro fc4 \
- usb nubus tc atm pcmcia i2c telephony
+ usb nubus tc atm pcmcia i2c telephony \
+ acpi mtd
ifdef CONFIG_DIO
SUB_DIRS += dio
@@ -30,6 +31,11 @@ else
endif
endif
+ifdef CONFIG_MTD
+SUB_DIRS += mtd
+MOD_SUB_DIRS += mtd
+endif
+
ifdef CONFIG_SBUS
SUB_DIRS += sbus
MOD_SUB_DIRS += sbus
@@ -180,4 +186,9 @@ else
endif
endif
+ifeq ($(CONFIG_ACPI),y)
+SUB_DIRS += acpi
+MOD_SUB_DIRS += acpi
+endif
+
include $(TOPDIR)/Rules.make
diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c
index e2e7d96df..980add976 100644
--- a/drivers/acorn/block/fd1772.c
+++ b/drivers/acorn/block/fd1772.c
@@ -289,6 +289,7 @@ static unsigned int changed_floppies = 0xff, fake_change = 0;
#define MAX_ERRORS 8 /* After this many errors the driver
* will give up. */
+static struct timer_list fd_timer;
#define START_MOTOR_OFF_TIMER(delay) \
do { \
@@ -299,8 +300,7 @@ static unsigned int changed_floppies = 0xff, fake_change = 0;
#define START_CHECK_CHANGE_TIMER(delay) \
do { \
- timer_table[FLOPPY_TIMER].expires = jiffies + (delay); \
- timer_active |= (1 << FLOPPY_TIMER); \
+ mod_timer(&fd_timer, jiffies + (delay)); \
} while(0)
#define START_TIMEOUT() \
@@ -340,7 +340,7 @@ static void fd_select_side(int side);
static void fd_select_drive(int drive);
static void fd_deselect(void);
static void fd_motor_off_timer(unsigned long dummy);
-static void check_change(void);
+static void check_change(unsigned long dummy);
static __inline__ void set_head_settle_flag(void);
static __inline__ int get_head_settle_flag(void);
static void floppy_irqconsequencehandler(void);
@@ -501,7 +501,7 @@ static void fd_motor_off_timer(unsigned long dummy)
* as possible) and keep track of the current state of the write protection.
*/
-static void check_change(void)
+static void check_change(unsigned long dummy)
{
static int drive = 0;
@@ -1093,12 +1093,12 @@ static void finish_fdc_done(int dummy)
STOP_TIMEOUT();
NeedSeek = 0;
- if ((timer_active & (1 << FLOPPY_TIMER)) &&
- time_after(jiffies + 5, timer_table[FLOPPY_TIMER].expires))
+ if (timer_pending(&fd_timer) &&
+ time_after(jiffies + 5, fd_timer.expires))
/* If the check for a disk change is done too early after this
* last seek command, the WP bit still reads wrong :-((
*/
- timer_table[FLOPPY_TIMER].expires = jiffies + 5;
+ mod_timer(&fd_timer, jiffies + 5);
else {
/* START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */
};
@@ -1602,9 +1602,9 @@ int fd1772_init(void)
#endif
/* initialize check_change timer */
- timer_table[FLOPPY_TIMER].fn = check_change;
- timer_active &= ~(1 << FLOPPY_TIMER);
-
+ init_timer(&fd_timer);
+ fd_timer.function = check_change;
+}
#ifdef TRACKBUFFER
DMABuffer = (char *)kmalloc((MAX_SECTORS+1)*512,GFP_KERNEL); /* Atari uses 512 - I want to eventually cope with 1K sectors */
diff --git a/drivers/acpi/.cvsignore b/drivers/acpi/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/drivers/acpi/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
new file mode 100644
index 000000000..c8b888ff1
--- /dev/null
+++ b/drivers/acpi/Makefile
@@ -0,0 +1,27 @@
+#
+# Makefile for the Linux ACPI interpreter
+#
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+MOD_IN_SUB_DIRS :=
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+O_TARGET := acpi.o
+O_OBJS :=
+M_OBJS :=
+
+ACPI_OBJS := osd.o
+ACPI_OBJS += $(patsubst %.c,%.o,$(wildcard */*.c))
+
+EXTRA_CFLAGS += -I./include -D_LINUX
+
+# if the interpreter is used, it overrides arch/i386/kernel/acpi.c
+ifeq ($(CONFIG_ACPI_INTERPRETER),y)
+ O_OBJS += $(ACPI_OBJS)
+endif
+
+include $(TOPDIR)/Rules.make
+
+clean:
+ $(RM) *.o */*.o
diff --git a/drivers/acpi/common/cmalloc.c b/drivers/acpi/common/cmalloc.c
new file mode 100644
index 000000000..3cea827da
--- /dev/null
+++ b/drivers/acpi/common/cmalloc.c
@@ -0,0 +1,166 @@
+/******************************************************************************
+ *
+ * Module Name: cmalloc - local memory allocation routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "interp.h"
+#include "namesp.h"
+#include "globals.h"
+
+#define _COMPONENT MISCELLANEOUS
+ MODULE_NAME ("cmalloc");
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: _Cm_allocate
+ *
+ * PARAMETERS: Size - Size of the allocation
+ * Component - Component type of caller
+ * Module - Source file name of caller
+ * Line - Line number of caller
+ *
+ * RETURN: Address of the allocated memory on success, NULL on failure.
+ *
+ * DESCRIPTION: The subsystem's equivalent of malloc.
+ *
+ ****************************************************************************/
+
+void *
+_cm_allocate (
+ u32 size,
+ u32 component,
+ ACPI_STRING module,
+ s32 line)
+{
+ void *address = NULL;
+
+ /* Check for an inadvertent size of zero bytes */
+
+ if (!size) {
+ REPORT_ERROR ("Cm_allocate: Attempt to allocate zero bytes");
+ size = 1;
+ }
+
+ address = acpi_os_allocate (size);
+ if (!address) {
+ /* Report allocation error */
+
+ _REPORT_ERROR (module, line, component,
+ "Cm_allocate: Memory allocation failure");
+
+ return (NULL);
+ }
+
+
+ return (address);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: _Cm_callocate
+ *
+ * PARAMETERS: Size - Size of the allocation
+ * Component - Component type of caller
+ * Module - Source file name of caller
+ * Line - Line number of caller
+ *
+ * RETURN: Address of the allocated memory on success, NULL on failure.
+ *
+ * DESCRIPTION: Subsystem equivalent of calloc.
+ *
+ ****************************************************************************/
+
+void *
+_cm_callocate (
+ u32 size,
+ u32 component,
+ ACPI_STRING module,
+ s32 line)
+{
+ void *address = NULL;
+
+ /* Check for an inadvertent size of zero bytes */
+
+ if (!size) {
+ REPORT_ERROR ("Cm_callocate: Attempt to allocate zero bytes");
+ return (NULL);
+ }
+
+
+ address = acpi_os_callocate (size);
+
+ if (!address) {
+ /* Report allocation error */
+
+ _REPORT_ERROR (module, line, component,
+ "Cm_callocate: Memory allocation failure");
+
+ return (NULL);
+ }
+
+
+ return (address);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: _Cm_free
+ *
+ * PARAMETERS: Address - Address of the memory to deallocate
+ * Component - Component type of caller
+ * Module - Source file name of caller
+ * Line - Line number of caller
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Frees the memory at Address
+ *
+ ****************************************************************************/
+
+void
+_cm_free (
+ void *address,
+ u32 component,
+ ACPI_STRING module,
+ s32 line)
+{
+
+ if (NULL == address) {
+ _REPORT_ERROR (module, line, component,
+ "_Cm_free: Trying to delete a NULL address.");
+
+ return;
+ }
+
+
+ acpi_os_free (address);
+
+ return;
+}
+
+
diff --git a/drivers/acpi/common/cmcopy.c b/drivers/acpi/common/cmcopy.c
new file mode 100644
index 000000000..c5a828c62
--- /dev/null
+++ b/drivers/acpi/common/cmcopy.c
@@ -0,0 +1,711 @@
+/******************************************************************************
+ *
+ * Module Name: cmcopy - Internal to external object translation utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "interp.h"
+#include "namesp.h"
+
+
+#define _COMPONENT MISCELLANEOUS
+ MODULE_NAME ("cmcopy");
+
+
+typedef struct search_st
+{
+ ACPI_OBJECT_INTERNAL *internal_obj;
+ u32 index;
+ ACPI_OBJECT *external_obj;
+
+} PKG_SEARCH_INFO;
+
+
+/* Used to traverse nested packages */
+
+PKG_SEARCH_INFO level[MAX_PACKAGE_DEPTH];
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_build_external_simple_object
+ *
+ * PARAMETERS: *Internal_obj - Pointer to the object we are examining
+ * *Buffer - Where the object is returned
+ * *Space_used - Where the data length is returned
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to place a simple object in a user
+ * buffer.
+ *
+ * The buffer is assumed to have sufficient space for the object.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_cm_build_external_simple_object (
+ ACPI_OBJECT_INTERNAL *internal_obj,
+ ACPI_OBJECT *external_obj,
+ u8 *data_space,
+ u32 *buffer_space_used)
+{
+ u32 length = 0;
+ char *source_ptr = NULL;
+
+
+ /*
+ * Check for NULL object case (could be an uninitialized
+ * package element
+ */
+
+ if (!internal_obj) {
+ *buffer_space_used = 0;
+ return (AE_OK);
+ }
+
+ /* Always clear the external object */
+
+ MEMSET (external_obj, 0, sizeof (ACPI_OBJECT));
+
+ /*
+ * In general, the external object will be the same type as
+ * the internal object
+ */
+
+ external_obj->type = internal_obj->common.type;
+
+ /* However, only a limited number of external types are supported */
+
+ switch (external_obj->type)
+ {
+
+ case ACPI_TYPE_STRING:
+
+ length = internal_obj->string.length;
+ external_obj->string.length = internal_obj->string.length;
+ external_obj->string.pointer = (char *) data_space;
+ source_ptr = internal_obj->string.pointer;
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ length = internal_obj->buffer.length;
+ external_obj->buffer.length = internal_obj->buffer.length;
+ external_obj->buffer.pointer = data_space;
+ source_ptr = (char *) internal_obj->buffer.pointer;
+ break;
+
+
+ case ACPI_TYPE_NUMBER:
+
+ external_obj->number.value= internal_obj->number.value;
+ break;
+
+
+ case INTERNAL_TYPE_REFERENCE:
+
+ /*
+ * This is an object reference. We use the object type of "Any"
+ * to indicate a reference object containing a handle to an ACPI
+ * named object.
+ */
+
+ external_obj->type = ACPI_TYPE_ANY;
+ external_obj->reference.handle = internal_obj->reference.nte;
+ break;
+
+
+ case ACPI_TYPE_PROCESSOR:
+
+ external_obj->processor.proc_id =
+ internal_obj->processor.proc_id;
+
+ external_obj->processor.pblk_address =
+ internal_obj->processor.pblk_address;
+
+ external_obj->processor.pblk_length =
+ internal_obj->processor.pblk_length;
+ break;
+
+ case ACPI_TYPE_POWER:
+
+ external_obj->power_resource.system_level =
+ internal_obj->power_resource.system_level;
+
+ external_obj->power_resource.resource_order =
+ internal_obj->power_resource.resource_order;
+ break;
+
+ default:
+ return (AE_CTRL_RETURN_VALUE);
+ break;
+ }
+
+
+ /* Copy data if necessary (strings or buffers) */
+
+ if (length) {
+ /*
+ * Copy the return data to the caller's buffer
+ */
+ MEMCPY ((void *) data_space, (void *) source_ptr, length);
+ }
+
+
+ *buffer_space_used = (u32) ROUND_UP_TO_NATIVE_WORD (length);
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_build_external_package_object
+ *
+ * PARAMETERS: *Internal_obj - Pointer to the object we are returning
+ * *Buffer - Where the object is returned
+ * *Space_used - Where the object length is returned
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to place a package object in a user
+ * buffer. A package object by definition contains other objects.
+ *
+ * The buffer is assumed to have sufficient space for the object.
+ * The caller must have verified the buffer length needed using the
+ * Acpi_cm_get_object_size function before calling this function.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_cm_build_external_package_object (
+ ACPI_OBJECT_INTERNAL *internal_obj,
+ u8 *buffer,
+ u32 *space_used)
+{
+ u8 *free_space;
+ ACPI_OBJECT *external_obj;
+ u32 current_depth = 0;
+ ACPI_STATUS status;
+ u32 length = 0;
+ u32 this_index;
+ u32 object_space;
+ ACPI_OBJECT_INTERNAL *this_internal_obj;
+ ACPI_OBJECT *this_external_obj;
+ PKG_SEARCH_INFO *level_ptr;
+
+
+ /*
+ * First package at head of the buffer
+ */
+ external_obj = (ACPI_OBJECT *) buffer;
+
+ /*
+ * Free space begins right after the first package
+ */
+ free_space = buffer + ROUND_UP_TO_NATIVE_WORD (sizeof (ACPI_OBJECT));
+
+
+ /*
+ * Initialize the working variables
+ */
+
+ MEMSET ((void *) level, 0, sizeof (level));
+
+ level[0].internal_obj = internal_obj;
+ level[0].external_obj = external_obj;
+ level[0].index = 0;
+ level_ptr = &level[0];
+ current_depth = 0;
+
+ external_obj->type = internal_obj->common.type;
+ external_obj->package.count = internal_obj->package.count;
+ external_obj->package.elements = (ACPI_OBJECT *) free_space;
+
+
+ /*
+ * Build an array of ACPI_OBJECTS in the buffer
+ * and move the free space past it
+ */
+
+ free_space += external_obj->package.count *
+ ROUND_UP_TO_NATIVE_WORD (sizeof (ACPI_OBJECT));
+
+
+ while (1) {
+ this_index = level_ptr->index;
+ this_internal_obj =
+ (ACPI_OBJECT_INTERNAL *)
+ level_ptr->internal_obj->package.elements[this_index];
+ this_external_obj =
+ (ACPI_OBJECT *)
+ &level_ptr->external_obj->package.elements[this_index];
+
+
+ /*
+ * Check for 1) Null object -- OK, this can happen if package
+ * element is never initialized
+ * 2) Not an internal object - can be an NTE instead
+ * 3) Any internal object other than a package.
+ *
+ * The more complex package case is handled later
+ */
+
+ if ((!this_internal_obj) ||
+ (!VALID_DESCRIPTOR_TYPE (
+ this_internal_obj, ACPI_DESC_TYPE_INTERNAL)) ||
+ (!IS_THIS_OBJECT_TYPE (
+ this_internal_obj, ACPI_TYPE_PACKAGE)))
+ {
+ /*
+ * This is a simple or null object -- get the size
+ */
+
+ status =
+ acpi_cm_build_external_simple_object (this_internal_obj,
+ this_external_obj,
+ free_space,
+ &object_space);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ free_space += object_space;
+ length += object_space;
+
+ level_ptr->index++;
+ while (level_ptr->index >=
+ level_ptr->internal_obj->package.count)
+ {
+ /*
+ * We've handled all of the objects at this
+ * level. This means that we have just
+ * completed a package. That package may
+ * have contained one or more packages
+ * itself
+ */
+ if (current_depth == 0) {
+ /*
+ * We have handled all of the objects
+ * in the top level package just add
+ * the length of the package objects
+ * and get out
+ */
+ *space_used = length;
+ return (AE_OK);
+ }
+
+ /*
+ * go back up a level and move the index
+ * past the just completed package object.
+ */
+ current_depth--;
+ level_ptr = &level[current_depth];
+ level_ptr->index++;
+ }
+ }
+
+
+ else {
+ /*
+ * This object is a package
+ * -- we must go one level deeper
+ */
+ if (current_depth >= MAX_PACKAGE_DEPTH-1) {
+ /*
+ * Too many nested levels of packages
+ * for us to handle
+ */
+ return (AE_LIMIT);
+ }
+
+ /*
+ * Build the package object
+ */
+ this_external_obj->type = ACPI_TYPE_PACKAGE;
+ this_external_obj->package.count =
+ this_internal_obj->package.count;
+ this_external_obj->package.elements =
+ (ACPI_OBJECT *) free_space;
+
+ /*
+ * Save space for the array of objects (Package elements)
+ * update the buffer length counter
+ */
+ object_space = (u32) ROUND_UP_TO_NATIVE_WORD (
+ this_external_obj->package.count *
+ sizeof (ACPI_OBJECT));
+
+ free_space += object_space;
+ length += object_space;
+
+ current_depth++;
+ level_ptr = &level[current_depth];
+ level_ptr->internal_obj = this_internal_obj;
+ level_ptr->external_obj = this_external_obj;
+ level_ptr->index = 0;
+ }
+ }
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_build_external_object
+ *
+ * PARAMETERS: *Internal_obj - The internal object to be converted
+ * *Buffer_ptr - Where the object is returned
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to build an API object to be returned to
+ * the caller.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_cm_build_external_object (
+ ACPI_OBJECT_INTERNAL *internal_obj,
+ ACPI_BUFFER *ret_buffer)
+{
+ ACPI_STATUS status;
+
+
+ if (IS_THIS_OBJECT_TYPE (internal_obj, ACPI_TYPE_PACKAGE)) {
+ /*
+ * Package objects contain other objects (which can be objects)
+ * buildpackage does it all
+ */
+ status =
+ acpi_cm_build_external_package_object (internal_obj,
+ ret_buffer->pointer,
+ &ret_buffer->length);
+ }
+
+ else {
+ /*
+ * Build a simple object (no nested objects)
+ */
+ status =
+ acpi_cm_build_external_simple_object (internal_obj,
+ (ACPI_OBJECT *) ret_buffer->pointer,
+ ((u8 *) ret_buffer->pointer +
+ ROUND_UP_TO_NATIVE_WORD (
+ sizeof (ACPI_OBJECT))),
+ &ret_buffer->length);
+ /*
+ * build simple does not include the object size in the length
+ * so we add it in here
+ */
+ ret_buffer->length += sizeof (ACPI_OBJECT);
+ }
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_build_internal_simple_object
+ *
+ * PARAMETERS: *External_obj - The external object to be converted
+ * *Internal_obj - Where the internal object is returned
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function copies an external object to an internal one.
+ * NOTE: Pointers can be copied, we don't need to copy data.
+ * (The pointers have to be valid in our address space no matter
+ * what we do with them!)
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_cm_build_internal_simple_object (
+ ACPI_OBJECT *external_obj,
+ ACPI_OBJECT_INTERNAL *internal_obj)
+{
+
+
+ internal_obj->common.type = (u8) external_obj->type;
+
+ switch (external_obj->type)
+ {
+
+ case ACPI_TYPE_STRING:
+
+ internal_obj->string.length = external_obj->string.length;
+ internal_obj->string.pointer = external_obj->string.pointer;
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ internal_obj->buffer.length = external_obj->buffer.length;
+ internal_obj->buffer.pointer = external_obj->buffer.pointer;
+ break;
+
+
+ case ACPI_TYPE_NUMBER:
+ /*
+ * Number is included in the object itself
+ */
+ internal_obj->number.value = external_obj->number.value;
+ break;
+
+
+ default:
+ return (AE_CTRL_RETURN_VALUE);
+ break;
+ }
+
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_build_internal_package_object
+ *
+ * PARAMETERS: *Internal_obj - Pointer to the object we are returning
+ * *Buffer - Where the object is returned
+ * *Space_used - Where the length of the object is returned
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to place a package object in a user
+ * buffer. A package object by definition contains other objects.
+ *
+ * The buffer is assumed to have sufficient space for the object.
+ * The caller must have verified the buffer length needed using the
+ * Acpi_cm_get_object_size function before calling this function.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_cm_build_internal_package_object (
+ ACPI_OBJECT_INTERNAL *internal_obj,
+ u8 *buffer,
+ u32 *space_used)
+{
+ u8 *free_space;
+ ACPI_OBJECT *external_obj;
+ u32 current_depth = 0;
+ ACPI_STATUS status = AE_OK;
+ u32 length = 0;
+ u32 this_index;
+ u32 object_space = 0;
+ ACPI_OBJECT_INTERNAL *this_internal_obj;
+ ACPI_OBJECT *this_external_obj;
+ PKG_SEARCH_INFO *level_ptr;
+
+
+ /*
+ * First package at head of the buffer
+ */
+ external_obj = (ACPI_OBJECT *)buffer;
+
+ /*
+ * Free space begins right after the first package
+ */
+ free_space = buffer + sizeof(ACPI_OBJECT);
+
+
+ /*
+ * Initialize the working variables
+ */
+
+ MEMSET ((void *) level, 0, sizeof(level));
+
+ level[0].internal_obj = internal_obj;
+ level[0].external_obj = external_obj;
+ level_ptr = &level[0];
+ current_depth = 0;
+
+ external_obj->type = internal_obj->common.type;
+ external_obj->package.count = internal_obj->package.count;
+ external_obj->package.elements = (ACPI_OBJECT *)free_space;
+
+
+ /*
+ * Build an array of ACPI_OBJECTS in the buffer
+ * and move the free space past it
+ */
+
+ free_space += external_obj->package.count * sizeof(ACPI_OBJECT);
+
+
+ while (1) {
+ this_index = level_ptr->index;
+
+ this_internal_obj = (ACPI_OBJECT_INTERNAL *)
+ &level_ptr->internal_obj->package.elements[this_index];
+
+ this_external_obj = (ACPI_OBJECT *)
+ &level_ptr->external_obj->package.elements[this_index];
+
+ if (IS_THIS_OBJECT_TYPE (this_internal_obj, ACPI_TYPE_PACKAGE)) {
+ /*
+ * If this object is a package then we go one deeper
+ */
+ if (current_depth >= MAX_PACKAGE_DEPTH-1) {
+ /*
+ * Too many nested levels of packages for us to handle
+ */
+ return (AE_LIMIT);
+ }
+
+ /*
+ * Build the package object
+ */
+ this_external_obj->type = ACPI_TYPE_PACKAGE;
+ this_external_obj->package.count = this_internal_obj->package.count;
+ this_external_obj->package.elements = (ACPI_OBJECT *) free_space;
+
+ /*
+ * Save space for the array of objects (Package elements)
+ * update the buffer length counter
+ */
+ object_space = this_external_obj->package.count *
+ sizeof (ACPI_OBJECT);
+
+ free_space += object_space;
+ length += object_space;
+
+ current_depth++;
+ level_ptr = &level[current_depth];
+ level_ptr->internal_obj = this_internal_obj;
+ level_ptr->external_obj = this_external_obj;
+ level_ptr->index = 0;
+
+ } /* if object is a package */
+
+ else {
+/* Status = Acpi_cm_build_simple_object(This_internal_obj,
+ This_external_obj, Free_space,
+ &Object_space);
+*/
+ if (status != AE_OK) {
+ /*
+ * Failure get out
+ */
+ return (status);
+ }
+
+ free_space += object_space;
+ length += object_space;
+
+ level_ptr->index++;
+ while (level_ptr->index >=
+ level_ptr->internal_obj->package.count)
+ {
+ /*
+ * We've handled all of the objects at
+ * this level, This means that we have
+ * just completed a package. That package
+ * may have contained one or more packages
+ * itself
+ */
+ if (current_depth == 0) {
+ /*
+ * We have handled all of the objects
+ * in the top level package just add
+ * the length of the package objects
+ * and get out
+ */
+ *space_used = length;
+ return (AE_OK);
+ }
+
+ /*
+ * go back up a level and move the index
+ * past the just completed package object.
+ */
+ current_depth--;
+ level_ptr = &level[current_depth];
+ level_ptr->index++;
+ }
+ } /* else object is NOT a package */
+ } /* while (1) */
+
+
+ /*
+ * We'll never get here, but the compiler whines about
+ * return value
+ */
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_build_internal_object
+ *
+ * PARAMETERS: *Internal_obj - The external object to be converted
+ * *Buffer_ptr - Where the internal object is returned
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: Converts an external object to an internal object.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_cm_build_internal_object (
+ ACPI_OBJECT *external_obj,
+ ACPI_OBJECT_INTERNAL *internal_obj)
+{
+ ACPI_STATUS status;
+
+
+ if (external_obj->type == ACPI_TYPE_PACKAGE) {
+ /*
+ * Package objects contain other objects (which can be objects)
+ * buildpackage does it all
+ */
+/*
+ Status = Acpi_cm_build_internal_package_object(Internal_obj,
+ Ret_buffer->Pointer,
+ &Ret_buffer->Length);
+*/
+ return (AE_NOT_IMPLEMENTED);
+ }
+
+ else {
+ /*
+ * Build a simple object (no nested objects)
+ */
+ status = acpi_cm_build_internal_simple_object (external_obj, internal_obj);
+ /*
+ * build simple does not include the object size in the length
+ * so we add it in here
+ */
+ }
+
+ return (status);
+}
+
diff --git a/drivers/acpi/common/cmdebug.c b/drivers/acpi/common/cmdebug.c
new file mode 100644
index 000000000..5c0d31c45
--- /dev/null
+++ b/drivers/acpi/common/cmdebug.c
@@ -0,0 +1,570 @@
+
+/******************************************************************************
+ *
+ * Module Name: cmdebug - Debug print routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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"
+
+#define _COMPONENT MISCELLANEOUS
+ MODULE_NAME ("cmdebug");
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Get/Set debug level
+ *
+ * DESCRIPTION: Get or set value of the debug flag
+ *
+ * These are used to allow user's to get/set the debug level
+ *
+ ****************************************************************************/
+
+
+s32
+get_debug_level (void)
+{
+
+ return acpi_dbg_level;
+}
+
+void
+set_debug_level (
+ s32 new_debug_level)
+{
+
+ acpi_dbg_level = new_debug_level;
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Function_trace
+ *
+ * PARAMETERS: Module_name - Caller's module name (for error output)
+ * Line_number - Caller's line number (for error output)
+ * Component_id - Caller's component ID (for error output)
+ * Function_name - Name of Caller's function
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is
+ * set in Debug_level
+ *
+ ****************************************************************************/
+
+void
+function_trace (
+ char *module_name,
+ s32 line_number,
+ s32 component_id,
+ char *function_name)
+{
+
+ acpi_gbl_nesting_level++;
+
+ debug_print (module_name, line_number, component_id,
+ TRACE_FUNCTIONS,
+ " %2.2ld Entered Function: %s\n",
+ acpi_gbl_nesting_level, function_name);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Function_trace_ptr
+ *
+ * PARAMETERS: Module_name - Caller's module name (for error output)
+ * Line_number - Caller's line number (for error output)
+ * Component_id - Caller's component ID (for error output)
+ * Function_name - Name of Caller's function
+ * Pointer - Pointer to display
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is
+ * set in Debug_level
+ *
+ ****************************************************************************/
+
+void
+function_trace_ptr (
+ char *module_name,
+ s32 line_number,
+ s32 component_id,
+ char *function_name,
+ void *pointer)
+{
+
+ acpi_gbl_nesting_level++;
+ debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS,
+ " %2.2ld Entered Function: %s, 0x%p\n",
+ acpi_gbl_nesting_level, function_name, pointer);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Function_trace_str
+ *
+ * PARAMETERS: Module_name - Caller's module name (for error output)
+ * Line_number - Caller's line number (for error output)
+ * Component_id - Caller's component ID (for error output)
+ * Function_name - Name of Caller's function
+ * String - Additional string to display
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is
+ * set in Debug_level
+ *
+ ****************************************************************************/
+
+void
+function_trace_str (
+ char *module_name,
+ s32 line_number,
+ s32 component_id,
+ char *function_name,
+ char *string)
+{
+
+ acpi_gbl_nesting_level++;
+ debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS,
+ " %2.2ld Entered Function: %s, %s\n",
+ acpi_gbl_nesting_level, function_name, string);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Function_trace_u32
+ *
+ * PARAMETERS: Module_name - Caller's module name (for error output)
+ * Line_number - Caller's line number (for error output)
+ * Component_id - Caller's component ID (for error output)
+ * Function_name - Name of Caller's function
+ * Integer - Integer to display
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is
+ * set in Debug_level
+ *
+ ****************************************************************************/
+
+void
+function_trace_u32 (
+ char *module_name,
+ s32 line_number,
+ s32 component_id,
+ char *function_name,
+ u32 integer)
+{
+
+ acpi_gbl_nesting_level++;
+ debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS,
+ " %2.2ld Entered Function: %s, 0x%l_x\n",
+ acpi_gbl_nesting_level, function_name, integer);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Function_exit
+ *
+ * PARAMETERS: Module_name - Caller's module name (for error output)
+ * Line_number - Caller's line number (for error output)
+ * Component_id - Caller's component ID (for error output)
+ * Function_name - Name of Caller's function
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is
+ * set in Debug_level
+ *
+ ****************************************************************************/
+
+void
+function_exit (
+ char *module_name,
+ s32 line_number,
+ s32 component_id,
+ char *function_name)
+{
+
+ debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS,
+ " %2.2ld Exiting Function: %s\n",
+ acpi_gbl_nesting_level, function_name);
+
+ acpi_gbl_nesting_level--;
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Function_status_exit
+ *
+ * PARAMETERS: Module_name - Caller's module name (for error output)
+ * Line_number - Caller's line number (for error output)
+ * Component_id - Caller's component ID (for error output)
+ * Function_name - Name of Caller's function
+ * Status - Exit status code
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is
+ * set in Debug_level. Prints exit status also.
+ *
+ ****************************************************************************/
+
+void
+function_status_exit (
+ char *module_name,
+ s32 line_number,
+ s32 component_id,
+ char *function_name,
+ ACPI_STATUS status)
+{
+
+ if (status > ACPI_MAX_STATUS) {
+ debug_print (module_name, line_number, component_id,
+ TRACE_FUNCTIONS,
+ " %2.2ld Exiting Function: %s, [Unknown Status] 0x%X\n",
+ acpi_gbl_nesting_level,
+ function_name,
+ status);
+ }
+
+ else {
+ debug_print (module_name, line_number, component_id,
+ TRACE_FUNCTIONS,
+ " %2.2ld Exiting Function: %s, %s\n",
+ acpi_gbl_nesting_level,
+ function_name,
+ acpi_cm_format_exception (status));
+ }
+
+ acpi_gbl_nesting_level--;
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Function_value_exit
+ *
+ * PARAMETERS: Module_name - Caller's module name (for error output)
+ * Line_number - Caller's line number (for error output)
+ * Component_id - Caller's component ID (for error output)
+ * Function_name - Name of Caller's function
+ * Value - Value to be printed with exit msg
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is
+ * set in Debug_level. Prints exit value also.
+ *
+ ****************************************************************************/
+
+void
+function_value_exit (
+ char *module_name,
+ s32 line_number,
+ s32 component_id,
+ char *function_name,
+ NATIVE_UINT value)
+{
+
+ debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS,
+ " %2.2ld Exiting Function: %s, 0x%X\n",
+ acpi_gbl_nesting_level, function_name, value);
+
+ acpi_gbl_nesting_level--;
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Function_ptr_exit
+ *
+ * PARAMETERS: Module_name - Caller's module name (for error output)
+ * Line_number - Caller's line number (for error output)
+ * Component_id - Caller's component ID (for error output)
+ * Function_name - Name of Caller's function
+ * Value - Value to be printed with exit msg
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is
+ * set in Debug_level. Prints exit value also.
+ *
+ ****************************************************************************/
+
+void
+function_ptr_exit (
+ char *module_name,
+ s32 line_number,
+ s32 component_id,
+ char *function_name,
+ char *ptr)
+{
+
+ debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS,
+ " %2.2ld Exiting Function: %s, 0x%p\n",
+ acpi_gbl_nesting_level, function_name, ptr);
+
+ acpi_gbl_nesting_level--;
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Debug_print
+ *
+ * PARAMETERS: Module_name - Caller's module name (for error output)
+ * Line_number - Caller's line number (for error output)
+ * Component_id - Caller's component ID (for error output)
+ * Print_level - Requested debug print level
+ * Format - Printf format field
+ * ... - Optional printf arguments
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print error message with prefix consisting of the module name,
+ * line number, and component ID.
+ *
+ ****************************************************************************/
+
+void
+debug_print (
+ char *module_name,
+ s32 line_number,
+ s32 component_id,
+ s32 print_level,
+ char *format,
+ ...)
+{
+ va_list args;
+
+
+ /* Both the level and the component must be enabled */
+
+ if ((print_level & acpi_dbg_level) &&
+ (component_id & acpi_dbg_layer))
+ {
+ va_start (args, format);
+
+ acpi_os_printf ("%8s-%04d: ", module_name, line_number);
+ acpi_os_vprintf (format, args);
+ }
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Debug_print_prefix
+ *
+ * PARAMETERS: Module_name - Caller's module name (for error output)
+ * Line_number - Caller's line number (for error output)
+ * Component_id - Caller's component ID (for error output)
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print the prefix part of an error message, consisting of the
+ * module name, and line number
+ *
+ ****************************************************************************/
+
+void
+debug_print_prefix (
+ char *module_name,
+ s32 line_number)
+{
+
+
+ acpi_os_printf ("%8s-%04d: ", module_name, line_number);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Debug_print_raw
+ *
+ * PARAMETERS: Format - Printf format field
+ * ... - Optional printf arguments
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print error message -- without module/line indentifiers
+ *
+ ****************************************************************************/
+
+void
+debug_print_raw (
+ char *format,
+ ...)
+{
+ va_list args;
+
+
+ va_start (args, format);
+
+ acpi_os_vprintf (format, args);
+
+ va_end (args);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_dump_buffer
+ *
+ * PARAMETERS: Buffer - Buffer to dump
+ * Count - Amount to dump, in bytes
+ * Component_iD - Caller's component ID
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Generic dump buffer in both hex and ascii.
+ *
+ ****************************************************************************/
+
+void
+acpi_cm_dump_buffer (
+ char *buffer,
+ u32 count,
+ u32 display,
+ s32 component_id)
+{
+ u32 i = 0;
+ u32 j;
+ u32 temp32;
+ u8 buf_char;
+
+
+ /* Only dump the buffer if tracing is enabled */
+
+ if (!((TRACE_TABLES & acpi_dbg_level) &&
+ (component_id & acpi_dbg_layer)))
+ {
+ return;
+ }
+
+
+ /*
+ * Nasty little dump buffer routine!
+ */
+ while (i < count) {
+ /* Print current offset */
+
+ acpi_os_printf ("%05_x ", i);
+
+
+ /* Print 16 hex chars */
+
+ for (j = 0; j < 16;) {
+ if (i + j >= count) {
+ acpi_os_printf ("\n");
+ return;
+ }
+
+ /* Make sure that the char doesn't get sign-extended! */
+
+ switch (display)
+ {
+ /* Default is BYTE display */
+
+ default:
+
+ acpi_os_printf ("%02_x ",
+ *((u8 *) &buffer[i + j]));
+ j += 1;
+ break;
+
+
+ case DB_WORD_DISPLAY:
+
+ MOVE_UNALIGNED16_TO_32 (&temp32,
+ &buffer[i + j]);
+ acpi_os_printf ("%04_x ", temp32);
+ j += 2;
+ break;
+
+
+ case DB_DWORD_DISPLAY:
+
+ MOVE_UNALIGNED32_TO_32 (&temp32,
+ &buffer[i + j]);
+ acpi_os_printf ("%08_x ", temp32);
+ j += 4;
+ break;
+
+
+ case DB_QWORD_DISPLAY:
+
+ MOVE_UNALIGNED32_TO_32 (&temp32,
+ &buffer[i + j]);
+ acpi_os_printf ("%08_x", temp32);
+
+ MOVE_UNALIGNED32_TO_32 (&temp32,
+ &buffer[i + j + 4]);
+ acpi_os_printf ("%08_x ", temp32);
+ j += 8;
+ break;
+ }
+ }
+
+
+ /*
+ * Print the ASCII equivalent characters
+ * But watch out for the bad unprintable ones...
+ */
+
+ for (j = 0; j < 16; j++) {
+ if (i + j >= count) {
+ acpi_os_printf ("\n");
+ return;
+ }
+
+ buf_char = buffer[i + j];
+ if ((buf_char > 0x1F && buf_char < 0x2E) ||
+ (buf_char > 0x2F && buf_char < 0x61) ||
+ (buf_char > 0x60 && buf_char < 0x7F))
+ {
+ acpi_os_printf ("%c", buf_char);
+ }
+ else {
+ acpi_os_printf (".");
+ }
+ }
+
+ /* Done with that line. */
+
+ acpi_os_printf ("\n");
+ i += 16;
+ }
+
+ return;
+}
+
+
diff --git a/drivers/acpi/common/cmdelete.c b/drivers/acpi/common/cmdelete.c
new file mode 100644
index 000000000..fc32e3cec
--- /dev/null
+++ b/drivers/acpi/common/cmdelete.c
@@ -0,0 +1,584 @@
+
+/******************************************************************************
+ *
+ * Module Name: cmdelete - object deletion and reference count utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "interp.h"
+#include "namesp.h"
+#include "tables.h"
+#include "parser.h"
+
+#define _COMPONENT MISCELLANEOUS
+ MODULE_NAME ("cmdelete");
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_delete_internal_obj
+ *
+ * PARAMETERS: *Object - Pointer to the list to be deleted
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Low level object deletion, after reference counts have been
+ * updated (All reference counts, including sub-objects!)
+ *
+ ******************************************************************************/
+
+void
+acpi_cm_delete_internal_obj (
+ ACPI_OBJECT_INTERNAL *object)
+{
+ void *obj_pointer = NULL;
+
+
+ if (!object) {
+ return;
+ }
+
+ /*
+ * Must delete or free any pointers within the object that are not
+ * actual ACPI objects (for example, a raw buffer pointer).
+ */
+
+ switch (object->common.type)
+ {
+
+ case ACPI_TYPE_STRING:
+
+ /* Free the actual string buffer */
+
+ obj_pointer = object->string.pointer;
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ /* Free the actual buffer */
+
+ obj_pointer = object->buffer.pointer;
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+
+ /*
+ * Elements of the package are not handled here, they are deleted
+ * separately
+ */
+
+ /* Free the (variable length) element pointer array */
+
+ obj_pointer = object->package.elements;
+ break;
+
+
+ case ACPI_TYPE_MUTEX:
+
+ acpi_os_delete_semaphore (object->mutex.semaphore);
+ break;
+
+
+ case ACPI_TYPE_EVENT:
+
+ acpi_os_delete_semaphore (object->event.semaphore);
+ object->event.semaphore = NULL;
+ break;
+
+
+ case ACPI_TYPE_METHOD:
+
+ /* Delete parse tree if it exists */
+
+ if (object->method.parser_op) {
+ acpi_ps_delete_parse_tree (object->method.parser_op);
+ object->method.parser_op = NULL;
+ }
+
+ /* Delete semaphore if it exists */
+
+ if (object->method.semaphore) {
+ acpi_os_delete_semaphore (object->method.semaphore);
+ object->method.semaphore = NULL;
+ }
+
+ break;
+
+
+ default:
+ break;
+ }
+
+
+ /*
+ * Delete any allocated memory found above
+ */
+
+ if (obj_pointer) {
+ if (!acpi_tb_system_table_pointer (obj_pointer)) {
+ acpi_cm_free (obj_pointer);
+ }
+ }
+
+
+ /* Only delete the object if it was dynamically allocated */
+
+
+ if (!(object->common.flags & AO_STATIC_ALLOCATION)) {
+ acpi_cm_delete_object_desc (object);
+
+ }
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_delete_internal_object_list
+ *
+ * PARAMETERS: *Obj_list - Pointer to the list to be deleted
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function deletes an internal object list, including both
+ * simple objects and package objects
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_cm_delete_internal_object_list (
+ ACPI_OBJECT_INTERNAL **obj_list)
+{
+ ACPI_OBJECT_INTERNAL **internal_obj;
+
+
+ /* Walk the null-terminated internal list */
+
+ for (internal_obj = obj_list; *internal_obj; internal_obj++) {
+ /*
+ * Check for a package
+ * Simple objects are simply stored in the array and do not
+ * need to be deleted separately.
+ */
+
+ if (IS_THIS_OBJECT_TYPE ((*internal_obj), ACPI_TYPE_PACKAGE)) {
+ /* Delete the package */
+
+ /*
+ * TBD: [Investigate] This might not be the right thing to do,
+ * depending on how the internal package object was allocated!!!
+ */
+ acpi_cm_delete_internal_obj (*internal_obj);
+ }
+
+ }
+
+ /* Free the combined parameter pointer list and object array */
+
+ acpi_cm_free (obj_list);
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_update_ref_count
+ *
+ * PARAMETERS: *Object - Object whose ref count is to be updated
+ * Count - Current ref count
+ * Action - What to do
+ *
+ * RETURN: New ref count
+ *
+ * DESCRIPTION: Modify the ref count and return it.
+ *
+ ******************************************************************************/
+
+void
+acpi_cm_update_ref_count (
+ ACPI_OBJECT_INTERNAL *object,
+ s32 action)
+{
+ u16 count;
+ u16 new_count;
+
+
+ if (!object) {
+ return;
+ }
+
+
+ count = object->common.reference_count;
+ new_count = count;
+
+ /*
+ * Reference count action (increment, decrement, or force delete)
+ */
+
+ switch (action)
+ {
+
+ case REF_INCREMENT:
+
+ new_count++;
+ object->common.reference_count = new_count;
+
+ break;
+
+
+ case REF_DECREMENT:
+
+ if (count < 1) {
+ new_count = 0;
+ }
+
+ else {
+ new_count--;
+
+ }
+
+
+ object->common.reference_count = new_count;
+ if (new_count == 0) {
+ acpi_cm_delete_internal_obj (object);
+ }
+
+ break;
+
+
+ case REF_FORCE_DELETE:
+
+ new_count = 0;
+ object->common.reference_count = new_count;
+ acpi_cm_delete_internal_obj (object);
+ break;
+
+
+ default:
+
+ break;
+ }
+
+
+ /*
+ * Sanity check the reference count, for debug purposes only.
+ * (A deleted object will have a huge reference count)
+ */
+
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_update_object_reference
+ *
+ * PARAMETERS: *Object - Increment ref count for this object
+ * and all sub-objects
+ * Action - Either REF_INCREMENT or REF_DECREMENT or
+ * REF_FORCE_DELETE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Increment the object reference count
+ *
+ * Object references are incremented when:
+ * 1) An object is added as a value in an Name Table Entry (NTE)
+ * 2) An object is copied (all subobjects must be incremented)
+ *
+ * Object references are decremented when:
+ * 1) An object is removed from an NTE
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_cm_update_object_reference (
+ ACPI_OBJECT_INTERNAL *object,
+ u16 action)
+{
+ ACPI_STATUS status;
+ u32 i;
+ ACPI_OBJECT_INTERNAL *next;
+ ACPI_OBJECT_INTERNAL *new;
+ ACPI_GENERIC_STATE *state_list = NULL;
+ ACPI_GENERIC_STATE *state;
+
+
+ /* Ignore a null object ptr */
+
+ if (!object) {
+ return (AE_OK);
+ }
+
+
+ /*
+ * Make sure that this isn't a namespace handle or an AML pointer
+ */
+
+ if (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_NAMED)) {
+ return (AE_OK);
+ }
+
+ if (acpi_tb_system_table_pointer (object)) {
+ return (AE_OK);
+ }
+
+
+ state = acpi_cm_create_update_state (object, action);
+
+ while (state) {
+
+ object = state->update.object;
+ action = state->update.value;
+ acpi_cm_delete_generic_state (state);
+
+ /*
+ * All sub-objects must have their reference count incremented also.
+ * Different object types have different subobjects.
+ */
+ switch (object->common.type)
+ {
+
+ case ACPI_TYPE_DEVICE:
+
+ status = acpi_cm_create_update_state_and_push (object->device.addr_handler,
+ action, &state_list);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ acpi_cm_update_ref_count (object->device.sys_handler, action);
+ acpi_cm_update_ref_count (object->device.drv_handler, action);
+ break;
+
+
+ case INTERNAL_TYPE_ADDRESS_HANDLER:
+
+ /* Must walk list of address handlers */
+
+ next = object->addr_handler.link;
+ while (next) {
+ new = next->addr_handler.link;
+ acpi_cm_update_ref_count (next, action);
+
+ next = new;
+ }
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+
+ /*
+ * We must update all the sub-objects of the package
+ * (Each of whom may have their own sub-objects, etc.
+ */
+ for (i = 0; i < object->package.count; i++) {
+ /*
+ * Push each element onto the stack for later processing.
+ * Note: There can be null elements within the package,
+ * these are simply ignored
+ */
+
+ status =
+ acpi_cm_create_update_state_and_push (object->package.elements[i],
+ action, &state_list);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+ break;
+
+
+ case ACPI_TYPE_FIELD_UNIT:
+
+ status =
+ acpi_cm_create_update_state_and_push (object->field_unit.container,
+ action, &state_list);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ break;
+
+
+ case INTERNAL_TYPE_DEF_FIELD:
+
+ status =
+ acpi_cm_create_update_state_and_push (object->field.container,
+ action, &state_list);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ break;
+
+
+ case INTERNAL_TYPE_BANK_FIELD:
+
+ status =
+ acpi_cm_create_update_state_and_push (object->bank_field.bank_select,
+ action, &state_list);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ status =
+ acpi_cm_create_update_state_and_push (object->bank_field.container,
+ action, &state_list);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ break;
+
+
+ case ACPI_TYPE_REGION:
+
+ acpi_cm_update_ref_count (object->region.method, action);
+
+ /* TBD: [Investigate]
+ Acpi_cm_update_ref_count (Object->Region.Addr_handler, Action);
+ */
+/*
+ Status =
+ Acpi_cm_create_update_state_and_push (Object->Region.Addr_handler,
+ Action, &State_list);
+ if (ACPI_FAILURE (Status)) {
+ return (Status);
+ }
+*/
+ break;
+
+
+ case INTERNAL_TYPE_REFERENCE:
+
+ break;
+ }
+
+
+ /*
+ * Now we can update the count in the main object. This can only
+ * happen after we update the sub-objects in case this causes the
+ * main object to be deleted.
+ */
+
+ acpi_cm_update_ref_count (object, action);
+
+
+ /* Move on to the next object to be updated */
+
+ state = acpi_cm_pop_generic_state (&state_list);
+ }
+
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_add_reference
+ *
+ * PARAMETERS: *Object - Object whose reference count is to be
+ * incremented
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Add one reference to an ACPI object
+ *
+ ******************************************************************************/
+
+void
+acpi_cm_add_reference (
+ ACPI_OBJECT_INTERNAL *object)
+{
+
+
+ /*
+ * Ensure that we have a valid object
+ */
+
+ if (!acpi_cm_valid_internal_object (object)) {
+ return;
+ }
+
+
+ /*
+ * We have a valid ACPI internal object, now increment the reference count
+ */
+
+ acpi_cm_update_object_reference (object, REF_INCREMENT);
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_remove_reference
+ *
+ * PARAMETERS: *Object - Object whose ref count will be decremented
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Decrement the reference count of an ACPI internal object
+ *
+ ******************************************************************************/
+
+void
+acpi_cm_remove_reference (
+ ACPI_OBJECT_INTERNAL *object)
+{
+
+
+ /*
+ * Ensure that we have a valid object
+ */
+
+ if (!acpi_cm_valid_internal_object (object)) {
+ return;
+ }
+
+ /*
+ * Decrement the reference count, and only actually delete the object
+ * if the reference count becomes 0. (Must also decrement the ref count
+ * of all subobjects!)
+ */
+
+ acpi_cm_update_object_reference (object, REF_DECREMENT);
+
+ /*
+ * If the reference count has reached zero,
+ * delete the object and all sub-objects contained within it
+ */
+/*
+ if (Object->Common.Reference_count == 0) {
+ Acpi_cm_delete_internal_obj (Object);
+ }
+*/
+ return;
+}
+
+
diff --git a/drivers/acpi/common/cmeval.c b/drivers/acpi/common/cmeval.c
new file mode 100644
index 000000000..4692eced9
--- /dev/null
+++ b/drivers/acpi/common/cmeval.c
@@ -0,0 +1,310 @@
+
+/******************************************************************************
+ *
+ * Module Name: cmeval - Object evaluation
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "namesp.h"
+#include "interp.h"
+
+
+#define _COMPONENT MISCELLANEOUS
+ MODULE_NAME ("cmeval");
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_evaluate_numeric_object
+ *
+ * PARAMETERS: Acpi_device - NTE for the device
+ * *Address - Where the value is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: evaluates a numeric namespace object for a selected device
+ * and stores results in *Address.
+ *
+ * NOTE: Internal function, no parameter validation
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_cm_evaluate_numeric_object (
+ char *object_name,
+ ACPI_NAMED_OBJECT *acpi_device,
+ u32 *address)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_STATUS status;
+
+
+ /* Execute the method */
+
+ status = acpi_ns_evaluate_relative (acpi_device, object_name, NULL, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+
+ return (status);
+ }
+
+
+ /* Did we get a return object? */
+
+ if (!obj_desc) {
+ return (AE_TYPE);
+ }
+
+ /* Is the return object of the correct type? */
+
+ if (obj_desc->common.type != ACPI_TYPE_NUMBER) {
+ status = AE_TYPE;
+ }
+ else {
+ /*
+ * Since the structure is a union, setting any field will set all
+ * of the variables in the union
+ */
+ *address = obj_desc->number.value;
+ }
+
+ /* On exit, we must delete the return object */
+
+ acpi_cm_remove_reference (obj_desc);
+
+ return (status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_execute_HID
+ *
+ * PARAMETERS: Acpi_device - NTE for the device
+ * *Hid - Where the HID is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Executes the _HID control method that returns the hardware
+ * ID of the device.
+ *
+ * NOTE: Internal function, no parameter validation
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_cm_execute_HID (
+ ACPI_NAMED_OBJECT *acpi_device,
+ DEVICE_ID *hid)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_STATUS status;
+
+
+ /* Execute the method */
+
+ status = acpi_ns_evaluate_relative (acpi_device,
+ METHOD_NAME__HID, NULL, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+
+
+ return (status);
+ }
+
+ /* Did we get a return object? */
+
+ if (!obj_desc) {
+ return (AE_TYPE);
+ }
+
+ /*
+ * A _HID can return either a Number (32 bit compressed EISA ID) or
+ * a string
+ */
+
+ if ((obj_desc->common.type != ACPI_TYPE_NUMBER) &&
+ (obj_desc->common.type != ACPI_TYPE_STRING))
+ {
+ status = AE_TYPE;
+ }
+
+ else {
+ if (obj_desc->common.type == ACPI_TYPE_NUMBER) {
+ /* Convert the Numeric HID to string */
+
+ acpi_aml_eisa_id_to_string (obj_desc->number.value, hid->data.buffer);
+ hid->type = STRING_DEVICE_ID;
+ }
+
+ else {
+ /* Copy the String HID from the returned object */
+
+ hid->data.string_ptr = obj_desc->string.pointer;
+ hid->type = STRING_PTR_DEVICE_ID;
+ }
+ }
+
+
+ /* On exit, we must delete the return object */
+
+ acpi_cm_remove_reference (obj_desc);
+
+ return (status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_execute_UID
+ *
+ * PARAMETERS: Acpi_device - NTE for the device
+ * *Uid - Where the UID is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Executes the _UID control method that returns the hardware
+ * ID of the device.
+ *
+ * NOTE: Internal function, no parameter validation
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_cm_execute_UID (
+ ACPI_NAMED_OBJECT *acpi_device,
+ DEVICE_ID *uid)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_STATUS status;
+
+
+ /* Execute the method */
+
+ status = acpi_ns_evaluate_relative (acpi_device,
+ METHOD_NAME__UID, NULL, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+
+
+ return (status);
+ }
+
+ /* Did we get a return object? */
+
+ if (!obj_desc) {
+ return (AE_TYPE);
+ }
+
+ /*
+ * A _UID can return either a Number (32 bit compressed EISA ID) or
+ * a string
+ */
+
+ if ((obj_desc->common.type != ACPI_TYPE_NUMBER) &&
+ (obj_desc->common.type != ACPI_TYPE_STRING))
+ {
+ status = AE_TYPE;
+ }
+
+ else {
+ if (obj_desc->common.type == ACPI_TYPE_NUMBER) {
+ /* Convert the Numeric HID to string */
+
+ uid->data.number = obj_desc->number.value;
+ }
+
+ else {
+ /* Copy the String HID from the returned object */
+
+ uid->data.string_ptr = obj_desc->string.pointer;
+ uid->type = STRING_PTR_DEVICE_ID;
+ }
+ }
+
+
+ /* On exit, we must delete the return object */
+
+ acpi_cm_remove_reference (obj_desc);
+
+ return (status);
+}
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_execute_STA
+ *
+ * PARAMETERS: Acpi_device - NTE for the device
+ * *Flags - Where the status flags are returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Executes _STA for selected device and stores results in
+ * *Flags.
+ *
+ * NOTE: Internal function, no parameter validation
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_cm_execute_STA (
+ ACPI_NAMED_OBJECT *acpi_device,
+ u32 *flags)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_STATUS status;
+
+
+ /* Execute the method */
+
+ status = acpi_ns_evaluate_relative (acpi_device,
+ METHOD_NAME__STA, NULL, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+
+
+ return (status);
+ }
+
+
+ /* Did we get a return object? */
+
+ if (!obj_desc) {
+ return (AE_TYPE);
+ }
+
+ /* Is the return object of the correct type? */
+
+ if (obj_desc->common.type != ACPI_TYPE_NUMBER) {
+ status = AE_TYPE;
+ }
+
+ else {
+ /* Extract the status flags */
+
+ *flags = obj_desc->number.value;
+ }
+
+
+ /* On exit, we must delete the return object */
+
+ acpi_cm_remove_reference (obj_desc);
+
+ return (status);
+}
diff --git a/drivers/acpi/common/cmglobal.c b/drivers/acpi/common/cmglobal.c
new file mode 100644
index 000000000..a23061cae
--- /dev/null
+++ b/drivers/acpi/common/cmglobal.c
@@ -0,0 +1,441 @@
+
+/******************************************************************************
+ *
+ * Module Name: cmglobal - Global variables for the ACPI subsystem
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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
+ */
+
+#define DEFINE_ACPI_GLOBALS
+
+#include "acpi.h"
+#include "events.h"
+#include "namesp.h"
+#include "interp.h"
+
+
+#define _COMPONENT MISCELLANEOUS
+ MODULE_NAME ("cmglobal");
+
+
+/******************************************************************************
+ *
+ * Static global variable initialization.
+ *
+ ******************************************************************************/
+
+/*
+ * We want the debug switches statically initialized so they
+ * are already set when the debugger is entered.
+ */
+
+/* Debug switch - level and trace mask */
+
+u32 acpi_dbg_level = NORMAL_DEFAULT;
+
+/* Debug switch - layer (component) mask */
+
+u32 acpi_dbg_layer = ALL_COMPONENTS;
+u32 acpi_gbl_nesting_level = 0;
+
+
+/* Debugger globals */
+
+u8 acpi_gbl_db_terminate_threads = FALSE;
+u8 acpi_gbl_method_executing = FALSE;
+
+/* System flags */
+
+u32 acpi_gbl_system_flags = 0;
+u32 acpi_gbl_startup_flags = 0;
+
+/* System starts unitialized! */
+u8 acpi_gbl_shutdown = TRUE;
+
+
+/******************************************************************************
+ *
+ * Namespace globals
+ *
+ ******************************************************************************/
+
+
+/*
+ * Names built-in to the interpreter
+ *
+ * Initial values are currently supported only for types String and Number.
+ * To avoid type punning, both are specified as strings in this table.
+ */
+
+PREDEFINED_NAMES acpi_gbl_pre_defined_names[] =
+{
+ {"_GPE", INTERNAL_TYPE_DEF_ANY},
+ {"_PR_", INTERNAL_TYPE_DEF_ANY},
+ {"_SB_", INTERNAL_TYPE_DEF_ANY},
+ {"_SI_", INTERNAL_TYPE_DEF_ANY},
+ {"_TZ_", INTERNAL_TYPE_DEF_ANY},
+ {"_REV", ACPI_TYPE_NUMBER, "2"},
+ {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME},
+ {"_GL_", ACPI_TYPE_MUTEX, "0"},
+
+ /* Table terminator */
+
+ {NULL, ACPI_TYPE_ANY}
+};
+
+
+/*
+ * Properties of the ACPI Object Types, both internal and external.
+ *
+ * Elements of Acpi_ns_properties are bit significant
+ * and the table is indexed by values of ACPI_OBJECT_TYPE
+ */
+
+u8 acpi_gbl_ns_properties[] =
+{
+ NSP_NORMAL, /* 00 Any */
+ NSP_NORMAL, /* 01 Number */
+ NSP_NORMAL, /* 02 String */
+ NSP_NORMAL, /* 03 Buffer */
+ NSP_LOCAL, /* 04 Package */
+ NSP_NORMAL, /* 05 Field_unit */
+ NSP_NEWSCOPE | NSP_LOCAL, /* 06 Device */
+ NSP_LOCAL, /* 07 Acpi_event */
+ NSP_NEWSCOPE | NSP_LOCAL, /* 08 Method */
+ NSP_LOCAL, /* 09 Mutex */
+ NSP_LOCAL, /* 10 Region */
+ NSP_NEWSCOPE | NSP_LOCAL, /* 11 Power */
+ NSP_NEWSCOPE | NSP_LOCAL, /* 12 Processor */
+ NSP_NEWSCOPE | NSP_LOCAL, /* 13 Thermal */
+ NSP_NORMAL, /* 14 Buffer_field */
+ NSP_NORMAL, /* 15 Ddb_handle */
+ NSP_NORMAL, /* 16 reserved */
+ NSP_NORMAL, /* 17 reserved */
+ NSP_NORMAL, /* 18 reserved */
+ NSP_NORMAL, /* 19 reserved */
+ NSP_NORMAL, /* 20 reserved */
+ NSP_NORMAL, /* 21 reserved */
+ NSP_NORMAL, /* 22 reserved */
+ NSP_NORMAL, /* 23 reserved */
+ NSP_NORMAL, /* 24 reserved */
+ NSP_NORMAL, /* 25 Def_field */
+ NSP_NORMAL, /* 26 Bank_field */
+ NSP_NORMAL, /* 27 Index_field */
+ NSP_NORMAL, /* 28 Def_field_defn */
+ NSP_NORMAL, /* 29 Bank_field_defn */
+ NSP_NORMAL, /* 30 Index_field_defn */
+ NSP_NORMAL, /* 31 If */
+ NSP_NORMAL, /* 32 Else */
+ NSP_NORMAL, /* 33 While */
+ NSP_NEWSCOPE, /* 34 Scope */
+ NSP_LOCAL, /* 35 Def_any */
+ NSP_NORMAL, /* 36 Reference */
+ NSP_NORMAL, /* 37 Alias */
+ NSP_NORMAL, /* 38 Notify */
+ NSP_NORMAL, /* 39 Address Handler */
+ NSP_NORMAL /* 40 Invalid */
+};
+
+
+/******************************************************************************
+ *
+ * Table globals
+ *
+ ******************************************************************************/
+
+
+ACPI_TABLE_DESC acpi_gbl_acpi_tables[NUM_ACPI_TABLES];
+
+
+ACPI_TABLE_SUPPORT acpi_gbl_acpi_table_data[NUM_ACPI_TABLES] =
+{
+ /* Name, Signature, Signature size, How many allowed?, Supported? Global typed pointer */
+
+ /* RSDP 0 */ {"RSDP", RSDP_SIG, sizeof (RSDP_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, NULL},
+ /* APIC 1 */ {APIC_SIG, APIC_SIG, sizeof (APIC_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, (void **) &acpi_gbl_APIC},
+ /* DSDT 2 */ {DSDT_SIG, DSDT_SIG, sizeof (DSDT_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, (void **) &acpi_gbl_DSDT},
+ /* FACP 3 */ {FACP_SIG, FACP_SIG, sizeof (FACP_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, (void **) &acpi_gbl_FACP},
+ /* FACS 4 */ {FACS_SIG, FACS_SIG, sizeof (FACS_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, (void **) &acpi_gbl_FACS},
+ /* PSDT 5 */ {PSDT_SIG, PSDT_SIG, sizeof (PSDT_SIG)-1, ACPI_TABLE_MULTIPLE, AE_OK, NULL},
+ /* RSDT 6 */ {RSDT_SIG, RSDT_SIG, sizeof (RSDT_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, NULL},
+ /* SSDT 7 */ {SSDT_SIG, SSDT_SIG, sizeof (SSDT_SIG)-1, ACPI_TABLE_MULTIPLE, AE_OK, NULL},
+ /* SBST 8 */ {SBST_SIG, SBST_SIG, sizeof (SBST_SIG)-1, ACPI_TABLE_SINGLE, AE_OK, (void **) &acpi_gbl_SBST},
+ /* BOOT 9 */ {BOOT_SIG, BOOT_SIG, sizeof (BOOT_SIG)-1, ACPI_TABLE_SINGLE, AE_SUPPORT, NULL}
+};
+
+ACPI_INIT_DATA acpi_gbl_acpi_init_data;
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_valid_object_type
+ *
+ * PARAMETERS: None.
+ *
+ * RETURN: TRUE if valid object type
+ *
+ * DESCRIPTION: Validate an object type
+ *
+ ****************************************************************************/
+
+u8
+acpi_cm_valid_object_type (
+ u32 type)
+{
+
+ if (type > ACPI_TYPE_MAX) {
+ if ((type < INTERNAL_TYPE_BEGIN) ||
+ (type > INTERNAL_TYPE_MAX))
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_format_exception
+ *
+ * PARAMETERS: Status - Acpi status to be formatted
+ *
+ * RETURN: Formatted status string
+ *
+ * DESCRIPTION: Convert an ACPI exception to a string
+ *
+ ****************************************************************************/
+
+char *
+acpi_cm_format_exception (
+ ACPI_STATUS status)
+{
+
+ if (status > ACPI_MAX_STATUS) {
+ return "UNKNOWN_STATUS";
+ }
+
+ return (acpi_gbl_exception_names [status]);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_allocate_owner_id
+ *
+ * PARAMETERS: Id_type - Type of ID (method or table)
+ *
+ * DESCRIPTION: Allocate a table or method owner id
+ *
+ ***************************************************************************/
+
+ACPI_OWNER_ID
+acpi_cm_allocate_owner_id (
+ u32 id_type)
+{
+ ACPI_OWNER_ID owner_id = 0xFFFF;
+
+
+ acpi_cm_acquire_mutex (ACPI_MTX_CACHES);
+
+ switch (id_type)
+ {
+ case OWNER_TYPE_TABLE:
+
+ owner_id = acpi_gbl_next_table_owner_id;
+ acpi_gbl_next_table_owner_id++;
+
+ if (acpi_gbl_next_table_owner_id == FIRST_METHOD_ID) {
+ acpi_gbl_next_table_owner_id = FIRST_TABLE_ID;
+ }
+ break;
+
+
+ case OWNER_TYPE_METHOD:
+
+ owner_id = acpi_gbl_next_method_owner_id;
+ acpi_gbl_next_method_owner_id++;
+
+ if (acpi_gbl_next_method_owner_id == FIRST_TABLE_ID) {
+ acpi_gbl_next_method_owner_id = FIRST_METHOD_ID;
+ }
+ break;
+ }
+
+
+ acpi_cm_release_mutex (ACPI_MTX_CACHES);
+
+ return (owner_id);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_init_globals
+ *
+ * PARAMETERS: none
+ *
+ * DESCRIPTION: Init library globals. All globals that require specific
+ * initialization should be initialized here!
+ *
+ ***************************************************************************/
+
+void
+acpi_cm_init_globals (ACPI_INIT_DATA *init_data)
+{
+ u32 i;
+
+
+ if (init_data) {
+ MEMCPY (&acpi_gbl_acpi_init_data, init_data, sizeof (ACPI_INIT_DATA));
+ }
+
+ else {
+ MEMSET (&acpi_gbl_acpi_init_data, 0, sizeof (ACPI_INIT_DATA));
+ }
+
+ /* ACPI table structure */
+
+ for (i = 0; i < ACPI_TABLE_MAX; i++) {
+ acpi_gbl_acpi_tables[i].prev = &acpi_gbl_acpi_tables[i];
+ acpi_gbl_acpi_tables[i].next = &acpi_gbl_acpi_tables[i];
+ acpi_gbl_acpi_tables[i].pointer = NULL;
+ acpi_gbl_acpi_tables[i].length = 0;
+ acpi_gbl_acpi_tables[i].allocation = ACPI_MEM_NOT_ALLOCATED;
+ acpi_gbl_acpi_tables[i].count = 0;
+ }
+
+
+ /* Address Space handler array */
+
+ for (i = 0; i < ACPI_MAX_ADDRESS_SPACE; i++) {
+ acpi_gbl_address_spaces[i].handler = NULL;
+ acpi_gbl_address_spaces[i].context = NULL;
+ }
+
+ /* Mutex locked flags */
+
+ for (i = 0; i < NUM_MTX; i++) {
+ acpi_gbl_acpi_mutex_info[i].mutex = NULL;
+ acpi_gbl_acpi_mutex_info[i].locked = FALSE;
+ acpi_gbl_acpi_mutex_info[i].use_count = 0;
+ }
+
+ /* Global notify handlers */
+
+ acpi_gbl_sys_notify.handler = NULL;
+ acpi_gbl_drv_notify.handler = NULL;
+
+ /* Global "typed" ACPI table pointers */
+
+ acpi_gbl_RSDP = NULL;
+ acpi_gbl_RSDT = NULL;
+ acpi_gbl_FACS = NULL;
+ acpi_gbl_FACP = NULL;
+ acpi_gbl_APIC = NULL;
+ acpi_gbl_DSDT = NULL;
+ acpi_gbl_SBST = NULL;
+
+
+ /* Global Lock support */
+
+ acpi_gbl_global_lock_acquired = FALSE;
+ acpi_gbl_global_lock_thread_count = 0;
+
+ /* Miscellaneous variables */
+
+ acpi_gbl_system_flags = 0;
+ acpi_gbl_startup_flags = 0;
+ acpi_gbl_global_lock_set = FALSE;
+ acpi_gbl_rsdp_original_location = 0;
+ acpi_gbl_when_to_parse_methods = METHOD_PARSE_CONFIGURATION;
+ acpi_gbl_cm_single_step = FALSE;
+ acpi_gbl_db_terminate_threads = FALSE;
+ acpi_gbl_shutdown = FALSE;
+ acpi_gbl_ns_lookup_count = 0;
+ acpi_gbl_ps_find_count = 0;
+ acpi_gbl_acpi_hardware_present = TRUE;
+ acpi_gbl_next_table_owner_id = FIRST_TABLE_ID;
+ acpi_gbl_next_method_owner_id = FIRST_METHOD_ID;
+ acpi_gbl_debugger_configuration = DEBUGGER_THREADING;
+
+ /* Cache of small "state" objects */
+
+ acpi_gbl_generic_state_cache = NULL;
+ acpi_gbl_generic_state_cache_depth = 0;
+ acpi_gbl_state_cache_requests = 0;
+ acpi_gbl_state_cache_hits = 0;
+
+ acpi_gbl_parse_cache = NULL;
+ acpi_gbl_parse_cache_depth = 0;
+ acpi_gbl_parse_cache_requests = 0;
+ acpi_gbl_parse_cache_hits = 0;
+
+ acpi_gbl_object_cache = NULL;
+ acpi_gbl_object_cache_depth = 0;
+ acpi_gbl_object_cache_requests = 0;
+ acpi_gbl_object_cache_hits = 0;
+
+ acpi_gbl_walk_state_cache = NULL;
+ acpi_gbl_walk_state_cache_depth = 0;
+ acpi_gbl_walk_state_cache_requests = 0;
+ acpi_gbl_walk_state_cache_hits = 0;
+
+ /* Interpreter */
+
+ acpi_gbl_buf_seq = 0;
+ acpi_gbl_named_object_err = FALSE;
+
+ /* Parser */
+
+ acpi_gbl_parsed_namespace_root = NULL;
+
+ /* Hardware oriented */
+
+ acpi_gbl_gpe0enable_register_save = NULL;
+ acpi_gbl_gpe1_enable_register_save = NULL;
+ acpi_gbl_original_mode = SYS_MODE_UNKNOWN; /* original ACPI/legacy mode */
+ acpi_gbl_gpe_registers = NULL;
+ acpi_gbl_gpe_info = NULL;
+
+ /* Namespace */
+
+ acpi_gbl_root_name_table.next_table = NULL;
+ acpi_gbl_root_name_table.parent_entry = NULL;
+ acpi_gbl_root_name_table.parent_table = NULL;
+
+ acpi_gbl_root_object = acpi_gbl_root_name_table.entries;
+
+ acpi_gbl_root_object->name = ACPI_ROOT_NAME;
+ acpi_gbl_root_object->data_type = ACPI_DESC_TYPE_NAMED;
+ acpi_gbl_root_object->type = ACPI_TYPE_ANY;
+ acpi_gbl_root_object->this_index = 0;
+ acpi_gbl_root_object->child_table = NULL;
+ acpi_gbl_root_object->object = NULL;
+
+ /* Memory allocation metrics - compiled out in non-debug mode. */
+
+ INITIALIZE_ALLOCATION_METRICS();
+
+ return;
+}
+
+
diff --git a/drivers/acpi/common/cminit.c b/drivers/acpi/common/cminit.c
new file mode 100644
index 000000000..a4a7c4c0f
--- /dev/null
+++ b/drivers/acpi/common/cminit.c
@@ -0,0 +1,362 @@
+
+/******************************************************************************
+ *
+ * Module Name: cminit - Common ACPI subsystem initialization
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "hardware.h"
+#include "namesp.h"
+#include "events.h"
+#include "parser.h"
+#include "dispatch.h"
+
+#define _COMPONENT MISCELLANEOUS
+ MODULE_NAME ("cminit");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_facp_register_error
+ *
+ * PARAMETERS: *Register_name - Pointer to string identifying register
+ * Value - Actual register contents value
+ * Acpi_test_spec_section - TDS section containing assertion
+ * Acpi_assertion - Assertion number being tested
+ *
+ * RETURN: none
+ *
+ * DESCRIPTION: Display failure message and link failure to TDS assertion
+ *
+ ******************************************************************************/
+
+void
+acpi_cm_facp_register_error (
+ char *register_name,
+ u32 value)
+{
+
+ REPORT_ERROR ("Invalid FACP register value");
+
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_hardware_initialize
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize and validate various ACPI registers
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_cm_hardware_initialize (void)
+{
+ ACPI_STATUS status = AE_OK;
+ s32 index;
+
+
+ /* Are we running on the actual hardware */
+
+ if (!acpi_gbl_acpi_hardware_present) {
+ /* No, just return */
+
+ return (AE_OK);
+ }
+
+ /* We must have the ACPI tables by the time we get here */
+
+ if (!acpi_gbl_FACP) {
+ acpi_gbl_restore_acpi_chipset = FALSE;
+
+ return (AE_NO_ACPI_TABLES);
+ }
+
+ /* Must support *some* mode! */
+/*
+ if (!(System_flags & SYS_MODES_MASK)) {
+ Restore_acpi_chipset = FALSE;
+
+ return (AE_ERROR);
+ }
+
+*/
+
+
+ switch (acpi_gbl_system_flags & SYS_MODES_MASK)
+ {
+ /* Identify current ACPI/legacy mode */
+
+ case (SYS_MODE_ACPI):
+
+ acpi_gbl_original_mode = SYS_MODE_ACPI;
+ break;
+
+
+ case (SYS_MODE_LEGACY):
+
+ acpi_gbl_original_mode = SYS_MODE_LEGACY;
+ break;
+
+
+ case (SYS_MODE_ACPI | SYS_MODE_LEGACY):
+
+ if (acpi_hw_get_mode () == SYS_MODE_ACPI) {
+ acpi_gbl_original_mode = SYS_MODE_ACPI;
+ }
+ else {
+ acpi_gbl_original_mode = SYS_MODE_LEGACY;
+ }
+
+ break;
+ }
+
+
+ if (acpi_gbl_system_flags & SYS_MODE_ACPI) {
+ /* Target system supports ACPI mode */
+
+ /*
+ * The purpose of this block of code is to save the initial state
+ * of the ACPI event enable registers. An exit function will be
+ * registered which will restore this state when the application
+ * exits. The exit function will also clear all of the ACPI event
+ * status bits prior to restoring the original mode.
+ *
+ * The location of the PM1a_evt_blk enable registers is defined as the
+ * base of PM1a_evt_blk + PM1a_evt_blk_length / 2. Since the spec further
+ * fully defines the PM1a_evt_blk to be a total of 4 bytes, the offset
+ * for the enable registers is always 2 from the base. It is hard
+ * coded here. If this changes in the spec, this code will need to
+ * be modified. The PM1b_evt_blk behaves as expected.
+ */
+
+ acpi_gbl_pm1_enable_register_save =
+ acpi_os_in16 ((acpi_gbl_FACP->pm1a_evt_blk + 2));
+ if (acpi_gbl_FACP->pm1b_evt_blk) {
+ acpi_gbl_pm1_enable_register_save |=
+ acpi_os_in16 ((acpi_gbl_FACP->pm1b_evt_blk + 2));
+ }
+
+
+ /*
+ * The GPEs behave similarly, except that the length of the register
+ * block is not fixed, so the buffer must be allocated with malloc
+ */
+
+ if (acpi_gbl_FACP->gpe0blk && acpi_gbl_FACP->gpe0blk_len) {
+ /* GPE0 specified in FACP */
+
+ acpi_gbl_gpe0enable_register_save =
+ acpi_cm_allocate (DIV_2 (acpi_gbl_FACP->gpe0blk_len));
+ if (!acpi_gbl_gpe0enable_register_save) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Save state of GPE0 enable bits */
+
+ for (index = 0; index < DIV_2 (acpi_gbl_FACP->gpe0blk_len); index++) {
+ acpi_gbl_gpe0enable_register_save[index] =
+ acpi_os_in8 (acpi_gbl_FACP->gpe0blk +
+ DIV_2 (acpi_gbl_FACP->gpe0blk_len));
+ }
+ }
+
+ else {
+ acpi_gbl_gpe0enable_register_save = NULL;
+ }
+
+ if (acpi_gbl_FACP->gpe1_blk && acpi_gbl_FACP->gpe1_blk_len) {
+ /* GPE1 defined */
+
+ acpi_gbl_gpe1_enable_register_save =
+ acpi_cm_allocate (DIV_2 (acpi_gbl_FACP->gpe1_blk_len));
+ if (!acpi_gbl_gpe1_enable_register_save) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* save state of GPE1 enable bits */
+
+ for (index = 0; index < DIV_2 (acpi_gbl_FACP->gpe1_blk_len); index++) {
+ acpi_gbl_gpe1_enable_register_save[index] =
+ acpi_os_in8 (acpi_gbl_FACP->gpe1_blk +
+ DIV_2 (acpi_gbl_FACP->gpe1_blk_len));
+ }
+ }
+
+ else {
+ acpi_gbl_gpe1_enable_register_save = NULL;
+ }
+
+
+ /*
+ * Verify Fixed ACPI Description Table fields,
+ * but don't abort on any problems, just display error
+ */
+
+ if (acpi_gbl_FACP->pm1_evt_len < 4) {
+ acpi_cm_facp_register_error ("PM1_EVT_LEN",
+ (u32) acpi_gbl_FACP->pm1_evt_len);
+ }
+
+ if (!acpi_gbl_FACP->pm1_cnt_len) {
+ acpi_cm_facp_register_error ("PM1_CNT_LEN",
+ (u32) acpi_gbl_FACP->pm1_cnt_len);
+ }
+
+ if (!acpi_gbl_FACP->pm1a_evt_blk) {
+ acpi_cm_facp_register_error ("PM1a_EVT_BLK", acpi_gbl_FACP->pm1a_evt_blk);
+ }
+
+ if (!acpi_gbl_FACP->pm1a_cnt_blk) {
+ acpi_cm_facp_register_error ("PM1a_CNT_BLK", acpi_gbl_FACP->pm1a_cnt_blk);
+ }
+
+ if (!acpi_gbl_FACP->pm_tmr_blk) {
+ acpi_cm_facp_register_error ("PM_TMR_BLK", acpi_gbl_FACP->pm_tmr_blk);
+ }
+
+ if (acpi_gbl_FACP->pm2_cnt_blk && !acpi_gbl_FACP->pm2_cnt_len) {
+ acpi_cm_facp_register_error ("PM2_CNT_LEN",
+ (u32) acpi_gbl_FACP->pm2_cnt_len);
+ }
+
+ if (acpi_gbl_FACP->pm_tm_len < 4) {
+ acpi_cm_facp_register_error ("PM_TM_LEN",
+ (u32) acpi_gbl_FACP->pm_tm_len);
+ }
+
+ /* length not multiple of 2 */
+ if (acpi_gbl_FACP->gpe0blk && (acpi_gbl_FACP->gpe0blk_len & 1)) {
+ acpi_cm_facp_register_error ("GPE0_BLK_LEN",
+ (u32) acpi_gbl_FACP->gpe0blk_len);
+ }
+
+ /* length not multiple of 2 */
+ if (acpi_gbl_FACP->gpe1_blk && (acpi_gbl_FACP->gpe1_blk_len & 1)) {
+ acpi_cm_facp_register_error ("GPE1_BLK_LEN",
+ (u32) acpi_gbl_FACP->gpe1_blk_len);
+ }
+ }
+
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_terminate
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: none
+ *
+ * DESCRIPTION: free memory allocated for table storage.
+ *
+ ******************************************************************************/
+
+void
+acpi_cm_terminate (void)
+{
+
+
+ /* Free global tables, etc. */
+
+ if (acpi_gbl_gpe0enable_register_save) {
+ acpi_cm_free (acpi_gbl_gpe0enable_register_save);
+ }
+
+ if (acpi_gbl_gpe1_enable_register_save) {
+ acpi_cm_free (acpi_gbl_gpe1_enable_register_save);
+ }
+
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_subsystem_shutdown
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: none
+ *
+ * DESCRIPTION: Shutdown the various subsystems. Don't delete the mutex
+ * objects here -- because the AML debugger may be still running.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_cm_subsystem_shutdown (void)
+{
+
+ /* Just exit if subsystem is already shutdown */
+
+ if (acpi_gbl_shutdown) {
+ return (AE_OK);
+ }
+
+ /* Subsystem appears active, go ahead and shut it down */
+
+ acpi_gbl_shutdown = TRUE;
+
+ /* Close the Namespace */
+
+ acpi_ns_terminate ();
+
+ /* Close the Acpi_event Handling */
+
+ acpi_ev_terminate ();
+
+ /* Close the globals */
+
+ acpi_cm_terminate ();
+
+ /* Flush the local cache(s) */
+
+ acpi_cm_delete_generic_state_cache ();
+ acpi_cm_delete_object_cache ();
+ acpi_ds_delete_walk_state_cache ();
+
+ /* Close the Parser */
+
+ /* TBD: [Restructure] Acpi_ps_terminate () */
+
+ acpi_ps_delete_parse_cache ();
+
+ /* Debug only - display leftover memory allocation, if any */
+
+ acpi_cm_dump_current_allocations (ACPI_UINT32_MAX, NULL);
+
+ BREAKPOINT3;
+
+ return (AE_OK);
+}
+
+
diff --git a/drivers/acpi/common/cmobject.c b/drivers/acpi/common/cmobject.c
new file mode 100644
index 000000000..f22c15cca
--- /dev/null
+++ b/drivers/acpi/common/cmobject.c
@@ -0,0 +1,648 @@
+
+/******************************************************************************
+ *
+ * Module Name: cmobject - ACPI object create/delete/size/cache routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "interp.h"
+#include "namesp.h"
+#include "tables.h"
+#include "amlcode.h"
+
+
+#define _COMPONENT MISCELLANEOUS
+ MODULE_NAME ("cmobject");
+
+
+/******************************************************************************
+ *
+ * FUNCTION: _Cm_create_internal_object
+ *
+ * PARAMETERS: Address - Address of the memory to deallocate
+ * Component - Component type of caller
+ * Module - Source file name of caller
+ * Line - Line number of caller
+ * Type - ACPI Type of the new object
+ *
+ * RETURN: Object - The new object. Null on failure
+ *
+ * DESCRIPTION: Create and initialize a new internal object.
+ *
+ * NOTE:
+ * We always allocate the worst-case object descriptor because these
+ * objects are cached, and we want them to be one-size-satisifies-any-request.
+ * This in itself may not be the most memory efficient, but the efficiency
+ * of the object cache should more than make up for this!
+ *
+ ******************************************************************************/
+
+ACPI_OBJECT_INTERNAL *
+_cm_create_internal_object (
+ char *module_name,
+ s32 line_number,
+ s32 component_id,
+ OBJECT_TYPE_INTERNAL type)
+{
+ ACPI_OBJECT_INTERNAL *object;
+
+
+ /* Allocate the raw object descriptor */
+
+ object = _cm_allocate_object_desc (module_name, line_number, component_id);
+ if (!object) {
+ /* Allocation failure */
+
+ return (NULL);
+ }
+
+ /* Save the object type in the object descriptor */
+
+ object->common.type = type;
+ object->common.size = (u8) sizeof (ACPI_OBJECT_INTERNAL);
+
+ /* Init the reference count */
+
+ object->common.reference_count = 1;
+
+ /* Any per-type initialization should go here */
+
+
+ /* Memory allocation metrics - compiled out in non debug mode. */
+
+ INCREMENT_OBJECT_METRICS (sizeof (ACPI_OBJECT_INTERNAL));
+
+ return (object);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_valid_internal_object
+ *
+ * PARAMETERS: Operand - Object to be validated
+ *
+ * RETURN: Validate a pointer to be an ACPI_OBJECT_INTERNAL
+ *
+ *****************************************************************************/
+
+u8
+acpi_cm_valid_internal_object (
+ void *object)
+{
+
+ /* Check for a null pointer */
+
+ if (!object) {
+ return FALSE;
+ }
+
+ /* Check for a pointer within one of the ACPI tables */
+
+ if (acpi_tb_system_table_pointer (object)) {
+ return FALSE;
+ }
+
+ /* Check the descriptor type field */
+
+ if (!VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_INTERNAL)) {
+ /* Not an ACPI internal object, do some further checking */
+
+
+
+
+ return FALSE;
+ }
+
+
+ /* The object appears to be a valid ACPI_OBJECT_INTERNAL */
+
+ return TRUE;
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: _Cm_allocate_object_desc
+ *
+ * PARAMETERS: Module_name - Caller's module name (for error output)
+ * Line_number - Caller's line number (for error output)
+ * Component_id - Caller's component ID (for error output)
+ * Message - Error message to use on failure
+ *
+ * RETURN: Pointer to newly allocated object descriptor. Null on error
+ *
+ * DESCRIPTION: Allocate a new object descriptor. Gracefully handle
+ * error conditions.
+ *
+ ****************************************************************************/
+
+void *
+_cm_allocate_object_desc (
+ char *module_name,
+ s32 line_number,
+ s32 component_id)
+{
+ ACPI_OBJECT_INTERNAL *object;
+
+
+ acpi_cm_acquire_mutex (ACPI_MTX_CACHES);
+
+ acpi_gbl_object_cache_requests++;
+
+ /* Check the cache first */
+
+ if (acpi_gbl_object_cache) {
+ /* There is an object available, use it */
+
+ object = acpi_gbl_object_cache;
+ acpi_gbl_object_cache = object->common.next;
+ object->common.next = NULL;
+
+ acpi_gbl_object_cache_hits++;
+ acpi_gbl_object_cache_depth--;
+
+ acpi_cm_release_mutex (ACPI_MTX_CACHES);
+ }
+
+ else {
+ /* The cache is empty, create a new object */
+
+ acpi_cm_release_mutex (ACPI_MTX_CACHES);
+
+ /* Attempt to allocate new descriptor */
+
+ object = _cm_callocate (sizeof (ACPI_OBJECT_INTERNAL), component_id,
+ module_name, line_number);
+
+ if (!object) {
+ /* Allocation failed */
+
+ _REPORT_ERROR (module_name, line_number, component_id,
+ "Could not allocate Object Descriptor");
+
+ return (NULL);
+ }
+ }
+
+ /* Mark the descriptor type */
+
+ object->common.data_type = ACPI_DESC_TYPE_INTERNAL;
+
+ return (object);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_delete_object_desc
+ *
+ * PARAMETERS: Object - Acpi internal object to be deleted
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Free an ACPI object descriptor or add it to the object cache
+ *
+ ****************************************************************************/
+
+void
+acpi_cm_delete_object_desc (
+ ACPI_OBJECT_INTERNAL *object)
+{
+
+
+ /* Object must be an ACPI_OBJECT_INTERNAL */
+
+ if (object->common.data_type != ACPI_DESC_TYPE_INTERNAL) {
+ return;
+ }
+
+ /* Make sure that the object isn't already in the cache */
+
+ if (object->common.next) {
+ return;
+ }
+
+
+ /* If cache is full, just free this object */
+
+ if (acpi_gbl_object_cache_depth >= MAX_OBJECT_CACHE_DEPTH) {
+ /*
+ * Memory allocation metrics. Call the macro here since we only
+ * care about dynamically allocated objects.
+ */
+ DECREMENT_OBJECT_METRICS (acpi_gbl_object_cache->common.size);
+
+ acpi_cm_free (object);
+ return;
+ }
+
+ acpi_cm_acquire_mutex (ACPI_MTX_CACHES);
+
+ /* Clear the entire object. This is important! */
+
+ MEMSET (object, 0, sizeof (ACPI_OBJECT_INTERNAL));
+ object->common.data_type = ACPI_DESC_TYPE_INTERNAL;
+
+ /* Put the object at the head of the global cache list */
+
+ object->common.next = acpi_gbl_object_cache;
+ acpi_gbl_object_cache = object;
+ acpi_gbl_object_cache_depth++;
+
+
+ acpi_cm_release_mutex (ACPI_MTX_CACHES);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_delete_object_cache
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Purge the global state object cache. Used during subsystem
+ * termination.
+ *
+ ******************************************************************************/
+
+void
+acpi_cm_delete_object_cache (
+ void)
+{
+ ACPI_OBJECT_INTERNAL *next;
+
+
+ /* Traverse the global cache list */
+
+ while (acpi_gbl_object_cache) {
+ /* Delete one cached state object */
+
+ next = acpi_gbl_object_cache->common.next;
+ acpi_gbl_object_cache->common.next = NULL;
+
+ /*
+ * Memory allocation metrics. Call the macro here since we only
+ * care about dynamically allocated objects.
+ */
+ DECREMENT_OBJECT_METRICS (acpi_gbl_object_cache->common.size);
+
+ acpi_cm_free (acpi_gbl_object_cache);
+ acpi_gbl_object_cache = next;
+ }
+
+ return;
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_init_static_object
+ *
+ * PARAMETERS: Obj_desc - Pointer to a "static" object - on stack
+ * or in the data segment.
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Initialize a static object. Sets flags to disallow dynamic
+ * deletion of the object.
+ *
+ ****************************************************************************/
+
+void
+acpi_cm_init_static_object (
+ ACPI_OBJECT_INTERNAL *obj_desc)
+{
+
+
+ if (!obj_desc) {
+ return;
+ }
+
+
+ /*
+ * Clear the entire descriptor
+ */
+ MEMSET ((void *) obj_desc, 0, sizeof (ACPI_OBJECT_INTERNAL));
+
+
+ /*
+ * Initialize the header fields
+ * 1) This is an ACPI_OBJECT_INTERNAL descriptor
+ * 2) The size is the full object (worst case)
+ * 3) The flags field indicates static allocation
+ * 4) Reference count starts at one (not really necessary since the
+ * object can't be deleted, but keeps everything sane)
+ */
+
+ obj_desc->common.data_type = ACPI_DESC_TYPE_INTERNAL;
+ obj_desc->common.size = sizeof (ACPI_OBJECT_INTERNAL);
+ obj_desc->common.flags = AO_STATIC_ALLOCATION;
+ obj_desc->common.reference_count = 1;
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_get_simple_object_size
+ *
+ * PARAMETERS: *Internal_obj - Pointer to the object we are examining
+ * *Ret_length - Where the length is returned
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to determine the space required to
+ * contain a simple object for return to an API user.
+ *
+ * The length includes the object structure plus any additional
+ * needed space.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_cm_get_simple_object_size (
+ ACPI_OBJECT_INTERNAL *internal_obj,
+ u32 *obj_length)
+{
+ u32 length;
+ ACPI_STATUS status = AE_OK;
+
+
+ /* Handle a null object (Could be a uninitialized package element -- which is legal) */
+
+ if (!internal_obj) {
+ *obj_length = 0;
+ return (AE_OK);
+ }
+
+
+ /* Start with the length of the Acpi object */
+
+ length = sizeof (ACPI_OBJECT);
+
+ if (VALID_DESCRIPTOR_TYPE (internal_obj, ACPI_DESC_TYPE_NAMED)) {
+ /* Object is an NTE (reference), just return the length */
+
+ *obj_length = (u32) ROUND_UP_TO_NATIVE_WORD (length);
+ return (status);
+ }
+
+
+ /*
+ * The final length depends on the object type
+ * Strings and Buffers are packed right up against the parent object and
+ * must be accessed bytewise or there may be alignment problems.
+ *
+ * TBD:[Investigate] do strings and buffers require alignment also?
+ */
+
+ switch (internal_obj->common.type)
+ {
+
+ case ACPI_TYPE_STRING:
+
+ length += internal_obj->string.length;
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ length += internal_obj->buffer.length;
+ break;
+
+
+ case ACPI_TYPE_NUMBER:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_POWER:
+
+ /*
+ * No extra data for these types
+ */
+ break;
+
+
+ case INTERNAL_TYPE_REFERENCE:
+
+ /*
+ * The only type that should be here is opcode AML_NAMEPATH_OP -- since
+ * this means an object reference
+ */
+ if (internal_obj->reference.op_code != AML_NAMEPATH_OP) {
+ status = AE_TYPE;
+ }
+ break;
+
+
+ default:
+
+ status = AE_TYPE;
+ break;
+ }
+
+
+ /*
+ * Account for the space required by the object rounded up to the next
+ * multiple of the machine word size. This keeps each object aligned
+ * on a machine word boundary. (preventing alignment faults on some
+ * machines.)
+ */
+ *obj_length = (u32) ROUND_UP_TO_NATIVE_WORD (length);
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_get_package_object_size
+ *
+ * PARAMETERS: *Internal_obj - Pointer to the object we are examining
+ * *Ret_length - Where the length is returned
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to determine the space required to contain
+ * a package object for return to an API user.
+ *
+ * This is moderately complex since a package contains other objects
+ * including packages.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_cm_get_package_object_size (
+ ACPI_OBJECT_INTERNAL *internal_obj,
+ u32 *obj_length)
+{
+
+ ACPI_OBJECT_INTERNAL *this_internal_obj;
+ ACPI_OBJECT_INTERNAL *parent_obj[MAX_PACKAGE_DEPTH] = { 0,0,0,0,0 };
+ ACPI_OBJECT_INTERNAL *this_parent;
+ u32 this_index;
+ u32 index[MAX_PACKAGE_DEPTH] = { 0,0,0,0,0 };
+ u32 length = 0;
+ u32 object_space;
+ u32 current_depth = 0;
+ u32 package_count = 1;
+ ACPI_STATUS status;
+
+
+ parent_obj[0] = internal_obj;
+
+ while (1) {
+ this_parent = parent_obj[current_depth];
+ this_index = index[current_depth];
+ this_internal_obj = this_parent->package.elements[this_index];
+
+
+ /*
+ * Check for 1) An unitialized package element. It is completely
+ * legal to declare a package and leave it uninitialized
+ * 2) Any type other than a package. Packages are handled
+ * below.
+ */
+
+ if ((!this_internal_obj) ||
+ (!IS_THIS_OBJECT_TYPE (this_internal_obj, ACPI_TYPE_PACKAGE)))
+ {
+ /*
+ * Simple object - just get the size (Null object/entry handled
+ * also)
+ */
+
+ status =
+ acpi_cm_get_simple_object_size (this_internal_obj, &object_space);
+
+ if (status != AE_OK) {
+ return (status);
+ }
+
+ length += object_space;
+
+ index[current_depth]++;
+ while (index[current_depth] >=
+ parent_obj[current_depth]->package.count)
+ {
+ /*
+ * We've handled all of the objects at
+ * this level, This means that we have
+ * just completed a package. That package
+ * may have contained one or more packages
+ * itself.
+ */
+ if (current_depth == 0) {
+ /*
+ * We have handled all of the objects
+ * in the top level package just add the
+ * length of the package objects and
+ * get out. Round up to the next machine
+ * word.
+ */
+ length +=
+ ROUND_UP_TO_NATIVE_WORD (
+ sizeof (ACPI_OBJECT)) *
+ package_count;
+
+ *obj_length = length;
+
+ return (AE_OK);
+ }
+
+ /*
+ * Go back up a level and move the index
+ * past the just completed package object.
+ */
+ current_depth--;
+ index[current_depth]++;
+ }
+ }
+
+ else {
+ /*
+ * This object is a package
+ * -- go one level deeper
+ */
+ package_count++;
+ if (current_depth < MAX_PACKAGE_DEPTH-1) {
+ current_depth++;
+ parent_obj[current_depth] = this_internal_obj;
+ index[current_depth] = 0;
+ }
+
+ else {
+ /*
+ * Too many nested levels of packages for us
+ * to handle
+ */
+
+ return (AE_LIMIT);
+ }
+ }
+ }
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_get_object_size
+ *
+ * PARAMETERS: *Internal_obj - Pointer to the object we are examining
+ * *Ret_length - Where the length will be returned
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to determine the space required to
+ * contain an object for return to an API user.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_cm_get_object_size(
+ ACPI_OBJECT_INTERNAL *internal_obj,
+ u32 *obj_length)
+{
+ ACPI_STATUS status;
+
+
+ if ((VALID_DESCRIPTOR_TYPE (internal_obj, ACPI_DESC_TYPE_INTERNAL)) &&
+ (IS_THIS_OBJECT_TYPE (internal_obj, ACPI_TYPE_PACKAGE)))
+ {
+ status =
+ acpi_cm_get_package_object_size (internal_obj, obj_length);
+ }
+
+ else {
+ status =
+ acpi_cm_get_simple_object_size (internal_obj, obj_length);
+ }
+
+ return status;
+}
+
+
diff --git a/drivers/acpi/common/cmutils.c b/drivers/acpi/common/cmutils.c
new file mode 100644
index 000000000..bec5d4ccb
--- /dev/null
+++ b/drivers/acpi/common/cmutils.c
@@ -0,0 +1,726 @@
+/******************************************************************************
+ *
+ * Module Name: cmutils - common utility procedures
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "events.h"
+#include "hardware.h"
+#include "namesp.h"
+#include "interp.h"
+#include "amlcode.h"
+#include "debugger.h"
+
+
+#define _COMPONENT MISCELLANEOUS
+ MODULE_NAME ("cmutils");
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_valid_acpi_name
+ *
+ * PARAMETERS: Character - The character to be examined
+ *
+ * RETURN: 1 if Character may appear in a name, else 0
+ *
+ * DESCRIPTION: Check for a valid ACPI name. Each character must be one of:
+ * 1) Upper case alpha
+ * 2) numeric
+ * 3) underscore
+ *
+ ****************************************************************************/
+
+u8
+acpi_cm_valid_acpi_name (
+ u32 name)
+{
+ char *name_ptr = (char *) &name;
+ u32 i;
+
+
+ for (i = 0; i < ACPI_NAME_SIZE; i++) {
+ if (!((name_ptr[i] == '_') ||
+ (name_ptr[i] >= 'A' && name_ptr[i] <= 'Z') ||
+ (name_ptr[i] >= '0' && name_ptr[i] <= '9')))
+ {
+ return FALSE;
+ }
+ }
+
+
+ return TRUE;
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_valid_acpi_character
+ *
+ * PARAMETERS: Character - The character to be examined
+ *
+ * RETURN: 1 if Character may appear in a name, else 0
+ *
+ * DESCRIPTION: Check for a printable character
+ *
+ ****************************************************************************/
+
+u8
+acpi_cm_valid_acpi_character (
+ char character)
+{
+
+ return ((u8) ((character == '_') ||
+ (character >= 'A' && character <= 'Z') ||
+ (character >= '0' && character <= '9')));
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_mutex_initialize
+ *
+ * PARAMETERS: None.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create the system mutex objects.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_cm_mutex_initialize (
+ void)
+{
+ u32 i;
+ ACPI_STATUS status;
+
+
+ /*
+ * Create each of the predefined mutex objects
+ */
+ for (i = 0; i < NUM_MTX; i++) {
+ status = acpi_cm_create_mutex (i);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_mutex_terminate
+ *
+ * PARAMETERS: None.
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Delete all of the system mutex objects.
+ *
+ ****************************************************************************/
+
+void
+acpi_cm_mutex_terminate (
+ void)
+{
+ u32 i;
+
+
+ /*
+ * Delete each predefined mutex object
+ */
+ for (i = 0; i < NUM_MTX; i++) {
+ acpi_cm_delete_mutex (i);
+ }
+
+ return;
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_create_mutex
+ *
+ * PARAMETERS: Mutex_iD - ID of the mutex to be created
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a mutex object.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_cm_create_mutex (
+ ACPI_MUTEX_HANDLE mutex_id)
+{
+ ACPI_STATUS status = AE_OK;
+
+
+ if (mutex_id > MAX_MTX) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ if (!acpi_gbl_acpi_mutex_info[mutex_id].mutex) {
+ status = acpi_os_create_semaphore (1, 1,
+ &acpi_gbl_acpi_mutex_info[mutex_id].mutex);
+ acpi_gbl_acpi_mutex_info[mutex_id].locked = FALSE;
+ acpi_gbl_acpi_mutex_info[mutex_id].use_count = 0;
+ }
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_delete_mutex
+ *
+ * PARAMETERS: Mutex_iD - ID of the mutex to be deleted
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Delete a mutex object.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_cm_delete_mutex (
+ ACPI_MUTEX_HANDLE mutex_id)
+{
+ ACPI_STATUS status;
+
+
+ if (mutex_id > MAX_MTX) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ status = acpi_os_delete_semaphore (acpi_gbl_acpi_mutex_info[mutex_id].mutex);
+
+ acpi_gbl_acpi_mutex_info[mutex_id].mutex = NULL;
+ acpi_gbl_acpi_mutex_info[mutex_id].locked = FALSE;
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_acquire_mutex
+ *
+ * PARAMETERS: Mutex_iD - ID of the mutex to be acquired
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Acquire a mutex object.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_cm_acquire_mutex (
+ ACPI_MUTEX_HANDLE mutex_id)
+{
+ ACPI_STATUS status;
+
+
+ if (mutex_id > MAX_MTX) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ status =
+ acpi_os_wait_semaphore (acpi_gbl_acpi_mutex_info[mutex_id].mutex,
+ 1, WAIT_FOREVER);
+
+ if (ACPI_SUCCESS (status)) {
+ acpi_gbl_acpi_mutex_info[mutex_id].locked = TRUE;
+ acpi_gbl_acpi_mutex_info[mutex_id].use_count++;
+ }
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_cm_release_mutex
+ *
+ * PARAMETERS: Mutex_iD - ID of the mutex to be released
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Release a mutex object.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_cm_release_mutex (
+ ACPI_MUTEX_HANDLE mutex_id)
+{
+ ACPI_STATUS status;
+
+
+ if (mutex_id > MAX_MTX) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ acpi_gbl_acpi_mutex_info[mutex_id].locked = FALSE; /* Mark before unlocking */
+
+ status =
+ acpi_os_signal_semaphore (acpi_gbl_acpi_mutex_info[mutex_id].mutex, 1);
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_create_update_state_and_push
+ *
+ * PARAMETERS: *Object - Object to be added to the new state
+ * Action - Increment/Decrement
+ * State_list - List the state will be added to
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Create a new state and push it
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_cm_create_update_state_and_push (
+ ACPI_OBJECT_INTERNAL *object,
+ u16 action,
+ ACPI_GENERIC_STATE **state_list)
+{
+ ACPI_GENERIC_STATE *state;
+
+
+ /* Ignore null objects; these are expected */
+
+ if (!object) {
+ return AE_OK;
+ }
+
+ state = acpi_cm_create_update_state (object, action);
+ if (!state) {
+ return AE_NO_MEMORY;
+ }
+
+
+ acpi_cm_push_generic_state (state_list, state);
+ return AE_OK;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_push_generic_state
+ *
+ * PARAMETERS: List_head - Head of the state stack
+ * State - State object to push
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Push a state object onto a state stack
+ *
+ ******************************************************************************/
+
+void
+acpi_cm_push_generic_state (
+ ACPI_GENERIC_STATE **list_head,
+ ACPI_GENERIC_STATE *state)
+{
+ /* Push the state object onto the front of the list (stack) */
+
+ state->common.next = *list_head;
+ *list_head = state;
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_pop_generic_state
+ *
+ * PARAMETERS: List_head - Head of the state stack
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop a state object from a state stack
+ *
+ ******************************************************************************/
+
+ACPI_GENERIC_STATE *
+acpi_cm_pop_generic_state (
+ ACPI_GENERIC_STATE **list_head)
+{
+ ACPI_GENERIC_STATE *state;
+
+
+ /* Remove the state object at the head of the list (stack) */
+
+ state = *list_head;
+ if (state) {
+ /* Update the list head */
+
+ *list_head = state->common.next;
+ }
+
+ return (state);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_create_generic_state
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a generic state object. Attempt to obtain one from
+ * the global state cache; If none available, create a new one.
+ *
+ ******************************************************************************/
+
+ACPI_GENERIC_STATE *
+acpi_cm_create_generic_state (void)
+{
+ ACPI_GENERIC_STATE *state;
+
+
+ acpi_cm_acquire_mutex (ACPI_MTX_CACHES);
+
+ acpi_gbl_state_cache_requests++;
+
+ /* Check the cache first */
+
+ if (acpi_gbl_generic_state_cache) {
+ /* There is an object available, use it */
+
+ state = acpi_gbl_generic_state_cache;
+ acpi_gbl_generic_state_cache = state->common.next;
+ state->common.next = NULL;
+
+ acpi_gbl_state_cache_hits++;
+ acpi_gbl_generic_state_cache_depth--;
+
+ acpi_cm_release_mutex (ACPI_MTX_CACHES);
+ }
+
+ else {
+ /* The cache is empty, create a new object */
+
+ acpi_cm_release_mutex (ACPI_MTX_CACHES);
+
+ state = acpi_cm_callocate (sizeof (ACPI_GENERIC_STATE));
+ }
+
+ /* Initialize */
+
+ if (state) {
+ state->common.data_type = ACPI_DESC_TYPE_STATE;
+ }
+
+ return state;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_create_update_state
+ *
+ * PARAMETERS: Object - Initial Object to be installed in the state
+ * Action - Update action to be performed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create an "Update State" - a flavor of the generic state used
+ * to update reference counts and delete complex objects such
+ * as packages.
+ *
+ ******************************************************************************/
+
+ACPI_GENERIC_STATE *
+acpi_cm_create_update_state (
+ ACPI_OBJECT_INTERNAL *object,
+ u16 action)
+{
+ ACPI_GENERIC_STATE *state;
+
+
+ /* Create the generic state object */
+
+ state = acpi_cm_create_generic_state ();
+ if (!state) {
+ return NULL;
+ }
+
+ /* Init fields specific to the update struct */
+
+ state->update.object = object;
+ state->update.value = action;
+
+ return (state);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_create_control_state
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a "Control State" - a flavor of the generic state used
+ * to support nested IF/WHILE constructs in the AML.
+ *
+ ******************************************************************************/
+
+ACPI_GENERIC_STATE *
+acpi_cm_create_control_state (
+ void)
+{
+ ACPI_GENERIC_STATE *state;
+
+
+ /* Create the generic state object */
+
+ state = acpi_cm_create_generic_state ();
+ if (!state) {
+ return NULL;
+ }
+
+
+ /* Init fields specific to the control struct */
+
+ state->common.state = CONTROL_CONDITIONAL_EXECUTING;
+
+ return (state);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_delete_generic_state
+ *
+ * PARAMETERS: State - The state object to be deleted
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Put a state object back into the global state cache. The object
+ * is not actually freed at this time.
+ *
+ ******************************************************************************/
+
+void
+acpi_cm_delete_generic_state (
+ ACPI_GENERIC_STATE *state)
+{
+
+ /* If cache is full, just free this state object */
+
+ if (acpi_gbl_generic_state_cache_depth >= MAX_STATE_CACHE_DEPTH) {
+ acpi_cm_free (state);
+ }
+
+ /* Otherwise put this object back into the cache */
+
+ else {
+ acpi_cm_acquire_mutex (ACPI_MTX_CACHES);
+
+ /* Clear the state */
+
+ MEMSET (state, 0, sizeof (ACPI_GENERIC_STATE));
+ state->common.data_type = ACPI_DESC_TYPE_STATE;
+
+ /* Put the object at the head of the global cache list */
+
+ state->common.next = acpi_gbl_generic_state_cache;
+ acpi_gbl_generic_state_cache = state;
+ acpi_gbl_generic_state_cache_depth++;
+
+
+ acpi_cm_release_mutex (ACPI_MTX_CACHES);
+ }
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_cm_delete_generic_state_cache
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Purge the global state object cache. Used during subsystem
+ * termination.
+ *
+ ******************************************************************************/
+
+void
+acpi_cm_delete_generic_state_cache (
+ void)
+{
+ ACPI_GENERIC_STATE *next;
+
+
+ /* Traverse the global cache list */
+
+ while (acpi_gbl_generic_state_cache) {
+ /* Delete one cached state object */
+
+ next = acpi_gbl_generic_state_cache->common.next;
+ acpi_cm_free (acpi_gbl_generic_state_cache);
+ acpi_gbl_generic_state_cache = next;
+ }
+
+ return;
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: _Report_error
+ *
+ * PARAMETERS: Module_name - Caller's module name (for error output)
+ * Line_number - Caller's line number (for error output)
+ * Component_id - Caller's component ID (for error output)
+ * Message - Error message to use on failure
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print error message from KD table
+ *
+ ****************************************************************************/
+
+void
+_report_error (
+ char *module_name,
+ s32 line_number,
+ s32 component_id,
+ char *message)
+{
+
+ debug_print (module_name, line_number, component_id, ACPI_ERROR,
+ "*** Error: %s\n", message);
+
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: _Report_warning
+ *
+ * PARAMETERS: Module_name - Caller's module name (for error output)
+ * Line_number - Caller's line number (for error output)
+ * Component_id - Caller's component ID (for error output)
+ * Message - Error message to use on failure
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print warning message from KD table
+ *
+ ****************************************************************************/
+
+void
+_report_warning (
+ char *module_name,
+ s32 line_number,
+ s32 component_id,
+ char *message)
+{
+
+ debug_print (module_name, line_number, component_id, ACPI_WARN,
+ "*** Warning: %s\n", message);
+
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: _Report_success
+ *
+ * PARAMETERS: Module_name - Caller's module name (for error output)
+ * Line_number - Caller's line number (for error output)
+ * Component_id - Caller's component ID (for error output)
+ * Message - Error message to use on failure
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print warning message from KD table
+ *
+ ****************************************************************************/
+
+void
+_report_success (
+ char *module_name,
+ s32 line_number,
+ s32 component_id,
+ char *message)
+{
+
+ debug_print (module_name, line_number, component_id, ACPI_OK,
+ "*** Success: %s\n", message);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: _Report_info
+ *
+ * PARAMETERS: Module_name - Caller's module name (for error output)
+ * Line_number - Caller's line number (for error output)
+ * Component_id - Caller's component ID (for error output)
+ * Message - Error message to use on failure
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print information message from KD table
+ *
+ ****************************************************************************/
+
+void
+_report_info (
+ char *module_name,
+ s32 line_number,
+ s32 component_id,
+ char *message)
+{
+
+ debug_print (module_name, line_number, component_id, ACPI_INFO,
+ "*** Info: %s\n", message);
+
+}
+
+
diff --git a/drivers/acpi/common/cmxface.c b/drivers/acpi/common/cmxface.c
new file mode 100644
index 000000000..adb0f4e72
--- /dev/null
+++ b/drivers/acpi/common/cmxface.c
@@ -0,0 +1,268 @@
+/******************************************************************************
+ *
+ * Module Name: cmxface - External interfaces for "global" ACPI functions
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "events.h"
+#include "hardware.h"
+#include "namesp.h"
+#include "interp.h"
+#include "amlcode.h"
+#include "debugger.h"
+
+
+#define _COMPONENT MISCELLANEOUS
+ MODULE_NAME ("cmxface");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_initialize
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initializes all global variables. This is the first function
+ * called, so any early initialization belongs here.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_initialize (ACPI_INIT_DATA *init_data)
+{
+ ACPI_STATUS status;
+
+
+ /* Initialize all globals used by the subsystem */
+
+ acpi_cm_init_globals (init_data);
+
+ /* Initialize the OS-Dependent layer */
+
+ status = acpi_os_initialize ();
+ if (ACPI_FAILURE (status)) {
+ REPORT_ERROR ("OSD Initialization Failure");
+ return (status);
+ }
+
+ /* Create the default mutex objects */
+
+ status = acpi_cm_mutex_initialize ();
+ if (ACPI_FAILURE (status)) {
+ REPORT_ERROR ("Global Mutex Initialization Failure");
+ return (status);
+ }
+
+ /* If configured, initialize the AML debugger */
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_terminate
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Shutdown the ACPI subsystem. Release all resources.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_terminate (void)
+{
+
+ /* Terminate the AML Debuger if present */
+
+ acpi_gbl_db_terminate_threads = TRUE;
+ acpi_cm_release_mutex (ACPI_MTX_DEBUG_CMD_READY);
+
+
+ /* Shutdown and free all resources */
+
+ acpi_cm_subsystem_shutdown ();
+
+
+ /* Free the mutex objects */
+
+ acpi_cm_mutex_terminate ();
+
+
+ /* Now we can shutdown the OS-dependent layer */
+
+ acpi_os_terminate ();
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_get_system_info
+ *
+ * PARAMETERS: Out_buffer - a pointer to a buffer to receive the
+ * resources for the device
+ * Buffer_length - the number of bytes available in the buffer
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to get information about the current
+ * state of the ACPI subsystem. It will return system information
+ * in the Out_buffer.
+ *
+ * If the function fails an appropriate status will be returned
+ * and the value of Out_buffer is undefined.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_get_system_info (
+ ACPI_BUFFER *out_buffer)
+{
+ ACPI_SYSTEM_INFO *info_ptr;
+ u32 i;
+
+
+ /*
+ * Must have a valid buffer
+ */
+ if ((!out_buffer) ||
+ (!out_buffer->pointer))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+ if (out_buffer->length < sizeof (ACPI_SYSTEM_INFO)) {
+ /*
+ * Caller's buffer is too small
+ */
+ out_buffer->length = sizeof (ACPI_SYSTEM_INFO);
+
+ return (AE_BUFFER_OVERFLOW);
+ }
+
+
+ /*
+ * Set return length and get data
+ */
+ out_buffer->length = sizeof (ACPI_SYSTEM_INFO);
+ info_ptr = (ACPI_SYSTEM_INFO *) out_buffer->pointer;
+
+ /* TBD [Future]: need a version number, or use the version string */
+ info_ptr->acpi_ca_version = 0x1234;
+
+ /* System flags (ACPI capabilities) */
+
+ info_ptr->flags = acpi_gbl_system_flags;
+
+ /* Timer resolution - 24 or 32 bits */
+
+ info_ptr->timer_resolution = acpi_hw_pmt_resolution ();
+
+ /* Clear the reserved fields */
+
+ info_ptr->reserved1 = 0;
+ info_ptr->reserved2 = 0;
+
+ /* Current debug levels */
+
+ info_ptr->debug_layer = acpi_dbg_layer;
+ info_ptr->debug_level = acpi_dbg_level;
+
+ /* Current status of the ACPI tables, per table type */
+
+ info_ptr->num_table_types = NUM_ACPI_TABLES;
+ for (i = 0; i < NUM_ACPI_TABLES; i++); {
+ info_ptr->table_info[i].count = acpi_gbl_acpi_tables[i].count;
+ }
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_format_exception
+ *
+ * PARAMETERS: Out_buffer - a pointer to a buffer to receive the
+ * exception name
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function translates an ACPI exception into an ASCII string.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_format_exception (
+ ACPI_STATUS exception,
+ ACPI_BUFFER *out_buffer)
+{
+ u32 length;
+ char *formatted_exception;
+
+
+ /*
+ * Must have a valid buffer
+ */
+ if ((!out_buffer) ||
+ (!out_buffer->pointer))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /* Exception must be within range */
+
+ if (exception > ACPI_MAX_STATUS) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /* Convert the exception code */
+
+ formatted_exception = acpi_cm_format_exception (exception);
+
+ /*
+ * Get length of string and check if it will fit in caller's buffer
+ */
+
+ length = STRLEN (formatted_exception);
+ if (out_buffer->length < length) {
+ out_buffer->length = length;
+ return (AE_BUFFER_OVERFLOW);
+ }
+
+
+ /* Copy the string, all done */
+
+ STRCPY (out_buffer->pointer, formatted_exception);
+
+ return (AE_OK);
+}
+
diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c
new file mode 100644
index 000000000..a0ca0cb63
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsfield.c
@@ -0,0 +1,414 @@
+
+/******************************************************************************
+ *
+ * Module Name: dsfield - Dispatcher field routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "amlcode.h"
+#include "dispatch.h"
+#include "interp.h"
+#include "namesp.h"
+
+
+#define _COMPONENT DISPATCHER
+ MODULE_NAME ("dsfield");
+
+
+/*
+ * Field flags: Bits 00 - 03 : Access_type (Any_acc, Byte_acc, etc.)
+ * 04 : Lock_rule (1 == Lock)
+ * 05 - 06 : Update_rule
+ */
+
+#define FIELD_ACCESS_TYPE_MASK 0x0F
+#define FIELD_LOCK_RULE_MASK 0x10
+#define FIELD_UPDATE_RULE_MASK 0x60
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_create_field
+ *
+ * PARAMETERS: Op - Op containing the Field definition and args
+ * Region - NTE for the containing Operation Region
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new field in the specified operation region
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_create_field (
+ ACPI_GENERIC_OP *op,
+ ACPI_HANDLE region,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_STATUS status = AE_AML_ERROR;
+ ACPI_GENERIC_OP *arg;
+ ACPI_NAMED_OBJECT *entry;
+ u8 field_flags;
+ u8 access_attribute = 0;
+ u32 field_bit_position = 0;
+
+
+ /* First arg is the name of the parent Op_region */
+
+ arg = op->value.arg;
+
+ /* Second arg is the field flags */
+
+ arg = arg->next;
+ field_flags = (u8) arg->value.integer;
+
+ /* Each remaining arg is a Named Field */
+
+ arg = arg->next;
+ while (arg) {
+ switch (arg->opcode)
+ {
+ case AML_RESERVEDFIELD_OP:
+
+ field_bit_position += arg->value.size;
+ break;
+
+
+ case AML_ACCESSFIELD_OP:
+
+ /*
+ * Get a new Access_type and Access_attribute for all
+ * entries (until end or another Access_as keyword)
+ */
+
+ access_attribute = (u8) arg->value.integer;
+ field_flags = (u8)
+ ((field_flags & FIELD_ACCESS_TYPE_MASK) ||
+ ((u8) (arg->value.integer >> 8)));
+ break;
+
+
+ case AML_NAMEDFIELD_OP:
+
+ status = acpi_ns_lookup (walk_state->scope_info,
+ (char *) &((ACPI_NAMED_OP *)arg)->name,
+ INTERNAL_TYPE_DEF_FIELD,
+ IMODE_LOAD_PASS1,
+ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE,
+ NULL, &entry);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /*
+ * Initialize an object for the new NTE that is on
+ * the object stack
+ */
+
+ status = acpi_aml_prep_def_field_value (entry, region,
+ field_flags,
+ access_attribute,
+ field_bit_position,
+ arg->value.size);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Keep track of bit position for the *next* field */
+
+ field_bit_position += arg->value.size;
+ break;
+ }
+
+ arg = arg->next;
+ }
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_create_bank_field
+ *
+ * PARAMETERS: Op - Op containing the Field definition and args
+ * Region - NTE for the containing Operation Region
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new bank field in the specified operation region
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_create_bank_field (
+ ACPI_GENERIC_OP *op,
+ ACPI_HANDLE region,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_STATUS status = AE_AML_ERROR;
+ ACPI_GENERIC_OP *arg;
+ ACPI_NAMED_OBJECT *bank_reg;
+ ACPI_NAMED_OBJECT *entry;
+ u32 bank_value;
+ u8 field_flags;
+ u8 access_attribute = 0;
+ u32 field_bit_position = 0;
+
+
+ /* First arg is the name of the parent Op_region */
+
+ arg = op->value.arg;
+
+ /* Socond arg is the Bank Register */
+
+ arg = arg->next;
+
+ status = acpi_ns_lookup (walk_state->scope_info, arg->value.string,
+ INTERNAL_TYPE_BANK_FIELD_DEFN,
+ IMODE_LOAD_PASS1,
+ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE,
+ NULL, &bank_reg);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Third arg is the Bank_value */
+
+ arg = arg->next;
+ bank_value = arg->value.integer;
+
+
+ /* Next arg is the field flags */
+
+ arg = arg->next;
+ field_flags = (u8) arg->value.integer;
+
+ /* Each remaining arg is a Named Field */
+
+ arg = arg->next;
+ while (arg) {
+ switch (arg->opcode)
+ {
+ case AML_RESERVEDFIELD_OP:
+
+ field_bit_position += arg->value.size;
+ break;
+
+
+ case AML_ACCESSFIELD_OP:
+
+ /*
+ * Get a new Access_type and Access_attribute for
+ * all entries (until end or another Access_as keyword)
+ */
+
+ access_attribute = (u8) arg->value.integer;
+ field_flags = (u8)
+ ((field_flags & FIELD_ACCESS_TYPE_MASK) ||
+ ((u8) (arg->value.integer >> 8)));
+ break;
+
+
+ case AML_NAMEDFIELD_OP:
+
+ status = acpi_ns_lookup (walk_state->scope_info,
+ (char *) &((ACPI_NAMED_OP *)arg)->name,
+ INTERNAL_TYPE_DEF_FIELD,
+ IMODE_LOAD_PASS1,
+ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE,
+ NULL, &entry);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /*
+ * Initialize an object for the new NTE that is on
+ * the object stack
+ */
+
+ status = acpi_aml_prep_bank_field_value (entry, region,
+ bank_reg, bank_value,
+ field_flags,
+ access_attribute,
+ field_bit_position,
+ arg->value.size);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Keep track of bit position for the *next* field */
+
+ field_bit_position += arg->value.size;
+ break;
+
+ }
+
+ arg = arg->next;
+ }
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_create_index_field
+ *
+ * PARAMETERS: Op - Op containing the Field definition and args
+ * Region - NTE for the containing Operation Region
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new index field in the specified operation region
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_create_index_field (
+ ACPI_GENERIC_OP *op,
+ ACPI_HANDLE region,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_STATUS status;
+ ACPI_GENERIC_OP *arg;
+ ACPI_NAMED_OBJECT *entry;
+ ACPI_NAMED_OBJECT *index_reg;
+ ACPI_NAMED_OBJECT *data_reg;
+ u8 field_flags;
+ u8 access_attribute = 0;
+ u32 field_bit_position = 0;
+
+
+ arg = op->value.arg;
+
+ /* First arg is the name of the Index register */
+
+ status = acpi_ns_lookup (walk_state->scope_info, arg->value.string,
+ ACPI_TYPE_ANY, IMODE_LOAD_PASS1,
+ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE,
+ NULL, &index_reg);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Second arg is the data register */
+
+ arg = arg->next;
+
+ status = acpi_ns_lookup (walk_state->scope_info, arg->value.string,
+ INTERNAL_TYPE_INDEX_FIELD_DEFN,
+ IMODE_LOAD_PASS1,
+ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE,
+ NULL, &data_reg);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+
+ /* Next arg is the field flags */
+
+ arg = arg->next;
+ field_flags = (u8) arg->value.integer;
+
+
+ /* Each remaining arg is a Named Field */
+
+ arg = arg->next;
+ while (arg) {
+ switch (arg->opcode)
+ {
+ case AML_RESERVEDFIELD_OP:
+
+ field_bit_position += arg->value.size;
+ break;
+
+
+ case AML_ACCESSFIELD_OP:
+
+ /*
+ * Get a new Access_type and Access_attribute for all
+ * entries (until end or another Access_as keyword)
+ */
+
+ access_attribute = (u8) arg->value.integer;
+ field_flags = (u8)
+ ((field_flags & FIELD_ACCESS_TYPE_MASK) ||
+ ((u8) (arg->value.integer >> 8)));
+ break;
+
+
+ case AML_NAMEDFIELD_OP:
+
+ status = acpi_ns_lookup (walk_state->scope_info,
+ (char *) &((ACPI_NAMED_OP *)arg)->name,
+ INTERNAL_TYPE_INDEX_FIELD,
+ IMODE_LOAD_PASS1,
+ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE,
+ NULL, &entry);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /*
+ * Initialize an object for the new NTE that is on
+ * the object stack
+ */
+
+ status = acpi_aml_prep_index_field_value (entry, index_reg,
+ data_reg, field_flags,
+ access_attribute,
+ field_bit_position,
+ arg->value.size);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Keep track of bit position for the *next* field */
+
+ field_bit_position += arg->value.size;
+ break;
+
+
+ default:
+
+ status = AE_AML_ERROR;
+ break;
+ }
+
+ arg = arg->next;
+ }
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
new file mode 100644
index 000000000..af55b770b
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -0,0 +1,506 @@
+
+/******************************************************************************
+ *
+ * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "amlcode.h"
+#include "dispatch.h"
+#include "interp.h"
+#include "namesp.h"
+#include "tables.h"
+#include "debugger.h"
+
+
+#define _COMPONENT DISPATCHER
+ MODULE_NAME ("dsmethod");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_parse_method
+ *
+ * PARAMETERS: Obj_handle - NTE of the method
+ * Level - Current nesting level
+ * Context - Points to a method counter
+ * Return_value - Not used
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Call the parser and parse the AML that is
+ * associated with the method.
+ *
+ * MUTEX: Assumes parser is locked
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_parse_method (
+ ACPI_HANDLE obj_handle)
+{
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_GENERIC_OP *op;
+ ACPI_NAMED_OBJECT *entry;
+ ACPI_OWNER_ID owner_id;
+
+
+ /* Parameter Validation */
+
+ if (!obj_handle) {
+ return (AE_NULL_ENTRY);
+ }
+
+
+ /* Extract the method object from the method NTE */
+
+ entry = (ACPI_NAMED_OBJECT*) obj_handle;
+ obj_desc = entry->object;
+ if (!obj_desc) {
+ return (AE_NULL_OBJECT);
+ }
+
+ /* Create a mutex for the method if there is a concurrency limit */
+
+ if ((obj_desc->method.concurrency != INFINITE_CONCURRENCY) &&
+ (!obj_desc->method.semaphore))
+ {
+ status = acpi_os_create_semaphore (1,
+ obj_desc->method.concurrency,
+ &obj_desc->method.semaphore);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+ /*
+ * Allocate a new parser op to be the root of the parsed
+ * method tree
+ */
+
+ op = acpi_ps_alloc_op (AML_METHOD_OP);
+ if (!op) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Init new op with the method name and pointer back to the NTE */
+
+ acpi_ps_set_name (op, entry->name);
+ op->acpi_named_object = entry;
+
+
+ /*
+ * Parse the method, creating a parse tree.
+ *
+ * The parse also includes a first pass load of the
+ * namespace where newly declared named objects are
+ * added into the namespace. Actual evaluation of
+ * the named objects (what would be called a "second
+ * pass") happens during the actual execution of the
+ * method so that operands to the named objects can
+ * take on dynamic run-time values.
+ */
+
+ status = acpi_ps_parse_aml (op, obj_desc->method.pcode,
+ obj_desc->method.pcode_length, 0);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Get a new Owner_id for objects created by this method */
+
+ owner_id = acpi_cm_allocate_owner_id (OWNER_TYPE_METHOD);
+
+ /* Install the parsed tree in the method object */
+
+ obj_desc->method.parser_op = op;
+ obj_desc->method.owning_id = owner_id;
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_begin_method_execution
+ *
+ * PARAMETERS: Method_entry - NTE of the method
+ * Obj_desc - The method object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
+ * increments the thread count, and waits at the method semaphore
+ * for clearance to execute.
+ *
+ * MUTEX: Locks/unlocks parser.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_begin_method_execution (
+ ACPI_NAMED_OBJECT *method_entry,
+ ACPI_OBJECT_INTERNAL *obj_desc)
+{
+ ACPI_STATUS status = AE_OK;
+
+
+ if (!method_entry) {
+ return (AE_NULL_ENTRY);
+ }
+
+ obj_desc = acpi_ns_get_attached_object (method_entry);
+ if (!obj_desc) {
+ return (AE_NULL_OBJECT);
+ }
+
+ /*
+ * Lock the parser while we check for and possibly parse the
+ * control method
+ */
+
+ acpi_cm_acquire_mutex (ACPI_MTX_PARSER);
+
+
+ /* If method is not parsed at this time, we must parse it first */
+
+ if (!obj_desc->method.parser_op) {
+
+ status = acpi_ds_parse_method (method_entry);
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_release_mutex (ACPI_MTX_PARSER);
+ return (status);
+ }
+ }
+
+
+ /*
+ * Increment the method parse tree thread count since there
+ * is one additional thread executing in it. If configured
+ * for deletion-on-exit, the parse tree will be deleted when
+ * the last thread completes execution of the method
+ */
+
+ ((ACPI_DEFERRED_OP *) obj_desc->method.parser_op)->thread_count++;
+
+ /*
+ * Parsing is complete, we can unlock the parser. Parse tree
+ * cannot be deleted at least until this thread completes.
+ */
+
+ acpi_cm_release_mutex (ACPI_MTX_PARSER);
+
+ /*
+ * If there is a concurrency limit on this method, we need to
+ * obtain a unit from the method semaphore. This releases the
+ * interpreter if we block
+ */
+
+ if (obj_desc->method.semaphore) {
+ status = acpi_aml_system_wait_semaphore (obj_desc->method.semaphore,
+ WAIT_FOREVER);
+ }
+
+
+ return (status);
+
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_call_control_method
+ *
+ * PARAMETERS: Walk_state - Current state of the walk
+ * Op - Current Op to be walked
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Transfer execution to a called control method
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_call_control_method (
+ ACPI_WALK_LIST *walk_list,
+ ACPI_WALK_STATE *this_walk_state,
+ ACPI_GENERIC_OP *op)
+{
+ ACPI_STATUS status;
+ ACPI_DEFERRED_OP *method;
+ ACPI_NAMED_OBJECT *method_entry;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_WALK_STATE *next_walk_state;
+ u32 i;
+
+
+ /*
+ * Prev_op points to the METHOD_CALL Op.
+ * Get the NTE entry (in the METHOD_CALL->NAME Op) and the
+ * corresponding METHOD Op
+ */
+
+ method_entry = (this_walk_state->prev_op->value.arg)->acpi_named_object;
+ if (!method_entry) {
+ return (AE_NULL_ENTRY);
+ }
+
+ obj_desc = acpi_ns_get_attached_object (method_entry);
+ if (!obj_desc) {
+ return (AE_NULL_OBJECT);
+ }
+
+ /* Parse method if necessary, wait on concurrency semaphore */
+
+ status = acpi_ds_begin_method_execution (method_entry, obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Save the (current) Op for when this walk is restarted */
+
+ this_walk_state->method_call_op = this_walk_state->prev_op;
+ this_walk_state->prev_op = op;
+ method = obj_desc->method.parser_op;
+
+ /* Create a new state for the preempting walk */
+
+ next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id,
+ (ACPI_GENERIC_OP *) method,
+ obj_desc, walk_list);
+ if (!next_walk_state) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* The Next_op of the Next_walk will be the beginning of the method */
+
+ next_walk_state->next_op = (ACPI_GENERIC_OP *) method;
+
+ /* Open a new scope */
+
+ status = acpi_ds_scope_stack_push (method_entry->child_table,
+ ACPI_TYPE_METHOD, next_walk_state);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+
+ /*
+ * Initialize the arguments for the method. The resolved
+ * arguments were put on the previous walk state's operand
+ * stack. Operands on the previous walk state stack always
+ * start at index 0.
+ */
+
+ status = acpi_ds_method_data_init_args (&this_walk_state->operands[0],
+ this_walk_state->num_operands);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /*
+ * Delete the operands on the previous walkstate operand stack
+ * (they were copied to new objects)
+ */
+
+ for (i = 0; i < obj_desc->method.param_count; i++) {
+ acpi_cm_remove_reference (this_walk_state->operands [i]);
+ }
+
+ /* Clear the operand stack */
+
+ this_walk_state->num_operands = 0;
+
+
+ return (AE_OK);
+
+
+ /* On error, we must delete the new walk state */
+
+cleanup:
+ acpi_ds_terminate_control_method (next_walk_state);
+ acpi_ds_delete_walk_state (next_walk_state);
+ return (status);
+
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_restart_control_method
+ *
+ * PARAMETERS: Walk_state - State of the method when it was preempted
+ * Op - Pointer to new current op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Restart a method that was preempted
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_restart_control_method (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OBJECT_INTERNAL *return_desc)
+{
+ ACPI_STATUS status;
+
+
+ if (return_desc) {
+ /*
+ * Get the return value (if any) from the previous method.
+ * NULL if no return value
+ */
+
+ status = acpi_ds_result_stack_push (return_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_remove_reference (return_desc);
+ return (status);
+ }
+
+ /*
+ * Delete the return value if it will not be used by the
+ * calling method
+ */
+
+ acpi_ds_delete_result_if_not_used (walk_state->method_call_op,
+ return_desc, walk_state);
+ }
+
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_terminate_control_method
+ *
+ * PARAMETERS: Walk_state - State of the method
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Terminate a control method. Delete everything that the method
+ * created, delete all locals and arguments, and delete the parse
+ * tree if requested.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_terminate_control_method (
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_DEFERRED_OP *op;
+ ACPI_NAMED_OBJECT *method_entry;
+
+
+ /* The method object should be stored in the walk state */
+
+ obj_desc = walk_state->method_desc;
+ if (!obj_desc) {
+ return (AE_OK);
+ }
+
+ /* Delete all arguments and locals */
+
+ acpi_ds_method_data_delete_all (walk_state);
+
+ /*
+ * Lock the parser while we terminate this method.
+ * If this is the last thread executing the method,
+ * we have additional cleanup to perform
+ */
+
+ acpi_cm_acquire_mutex (ACPI_MTX_PARSER);
+
+ /*
+ * The root of the method parse tree should be stored
+ * in the method object
+ */
+
+ op = obj_desc->method.parser_op;
+ if (!op) {
+ goto unlock_and_exit;
+ }
+
+ /* Signal completion of the execution of this method if necessary */
+
+ if (walk_state->method_desc->method.semaphore) {
+ status = acpi_os_signal_semaphore (
+ walk_state->method_desc->method.semaphore, 1);
+ }
+
+ /* Decrement the thread count on the method parse tree */
+
+ op->thread_count--;
+ if (!op->thread_count) {
+ /*
+ * There are no more threads executing this method. Perform
+ * additional cleanup.
+ *
+ * The method NTE is stored in the method Op
+ */
+ method_entry = op->acpi_named_object;
+
+ /*
+ * Delete any namespace entries created immediately underneath
+ * the method
+ */
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (method_entry->child_table) {
+ acpi_ns_delete_namespace_subtree (method_entry);
+ }
+
+ /*
+ * Delete any namespace entries created anywhere else within
+ * the namespace
+ */
+
+ acpi_ns_delete_namespace_by_owner (
+ walk_state->method_desc->method.owning_id);
+
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+
+ /*
+ * Delete the method's parse tree if asked to
+ */
+ if (acpi_gbl_when_to_parse_methods & METHOD_DELETE_AT_COMPLETION) {
+ acpi_ps_delete_parse_tree (
+ walk_state->method_desc->method.parser_op);
+
+ walk_state->method_desc->method.parser_op = NULL;
+ }
+ }
+
+unlock_and_exit:
+
+ acpi_cm_release_mutex (ACPI_MTX_PARSER);
+ return (AE_OK);
+}
+
+
diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c
new file mode 100644
index 000000000..a988b8911
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsmthdat.c
@@ -0,0 +1,682 @@
+
+/******************************************************************************
+ *
+ * Module Name: dsmthdat - control method arguments and local variables
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "dispatch.h"
+#include "interp.h"
+#include "amlcode.h"
+#include "namesp.h"
+
+
+#define _COMPONENT DISPATCHER
+ MODULE_NAME ("dsmthdat");
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_method_data_init
+ *
+ * PARAMETERS: *Obj_desc
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize the data structures that hold the method's arguments
+ * and locals. The data struct is an array of NTEs for each.
+ * This allows Ref_of and De_ref_of to work properly for these
+ * special data types.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_method_data_init (
+ ACPI_WALK_STATE *walk_state)
+{
+ u32 i;
+
+
+ /*
+ * Walk_state fields are initialized to zero by the
+ * Acpi_cm_callocate().
+ *
+ * An NTE is assigned to each argument and local so
+ * that Ref_of() can return a pointer to the NTE.
+ */
+
+ /* Init the method arguments */
+
+ for (i = 0; i < MTH_NUM_ARGS; i++) {
+ MOVE_UNALIGNED32_TO_32 (&walk_state->arguments[i].name,
+ NAMEOF_ARG_NTE);
+
+ walk_state->arguments[i].name |= (i << 24);
+ walk_state->arguments[i].data_type = ACPI_DESC_TYPE_NAMED;
+ walk_state->arguments[i].type =
+ INTERNAL_TYPE_METHOD_ARGUMENT;
+ }
+
+ /* Init the method locals */
+
+ for (i = 0; i < MTH_NUM_LOCALS; i++) {
+ MOVE_UNALIGNED32_TO_32 (&walk_state->local_variables[i].name,
+ NAMEOF_LOCAL_NTE);
+
+ walk_state->local_variables[i].name |= (i << 24);
+ walk_state->local_variables[i].data_type = ACPI_DESC_TYPE_NAMED;
+ walk_state->local_variables[i].type =
+ INTERNAL_TYPE_METHOD_LOCAL_VAR;
+ }
+
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_method_data_delete_all
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Delete method locals and arguments. Arguments are only
+ * deleted if this method was called from another method.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_method_data_delete_all (
+ ACPI_WALK_STATE *walk_state)
+{
+ u32 index;
+ ACPI_OBJECT_INTERNAL *object;
+
+
+ /* Delete the locals */
+
+ for (index = 0; index < MTH_NUM_LOCALS; index++) {
+ object = walk_state->local_variables[index].object;
+ if (object) {
+ /* Remove first */
+ walk_state->local_variables[index].object = NULL;
+ /* Was given a ref when stored */
+ acpi_cm_remove_reference (object);
+ }
+ }
+
+
+ /* Delete the arguments */
+
+ for (index = 0; index < MTH_NUM_ARGS; index++) {
+ object = walk_state->arguments[index].object;
+ if (object) {
+ /* Remove first */
+ walk_state->arguments[index].object = NULL;
+ /* Was given a ref when stored */
+ acpi_cm_remove_reference (object);
+ }
+ }
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_method_data_init_args
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize arguments for a method
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_method_data_init_args (
+ ACPI_OBJECT_INTERNAL **params,
+ u32 max_param_count)
+{
+ ACPI_STATUS status;
+ u32 mindex;
+ u32 pindex;
+
+
+ if (!params) {
+ return (AE_OK);
+ }
+
+ /* Copy passed parameters into the new method stack frame */
+
+ for (pindex = mindex = 0;
+ (mindex < MTH_NUM_ARGS) && (pindex < max_param_count);
+ mindex++)
+ {
+ if (params[pindex]) {
+ /*
+ * A valid parameter.
+ * Set the current method argument to the
+ * Params[Pindex++] argument object descriptor
+ */
+ status = acpi_ds_method_data_set_value (MTH_TYPE_ARG,
+ mindex,
+ params[pindex]);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ pindex++;
+ }
+
+ else {
+ break;
+ }
+ }
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_method_data_get_entry
+ *
+ * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG
+ * Index - Which local_var or argument to get
+ * Entry - Pointer to where a pointer to the stack
+ * entry is returned.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get the address of the stack entry given by Type:Index
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_method_data_get_entry (
+ u32 type,
+ u32 index,
+ ACPI_OBJECT_INTERNAL ***entry)
+{
+ ACPI_WALK_STATE *walk_state;
+
+
+ walk_state = acpi_ds_get_current_walk_state (acpi_gbl_current_walk_list);
+
+ /*
+ * Get the requested object.
+ * The stack "Type" is either a Local_variable or an Argument
+ */
+
+ switch (type)
+ {
+
+ case MTH_TYPE_LOCAL:
+
+ if (index > MTH_MAX_LOCAL) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ *entry =
+ (ACPI_OBJECT_INTERNAL **) &walk_state->local_variables[index].object;
+ break;
+
+
+ case MTH_TYPE_ARG:
+
+ if (index > MTH_MAX_ARG) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ *entry =
+ (ACPI_OBJECT_INTERNAL **) &walk_state->arguments[index].object;
+ break;
+
+
+ default:
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_method_data_set_entry
+ *
+ * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG
+ * Index - Which local_var or argument to get
+ * Object - Object to be inserted into the stack entry
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Insert an object onto the method stack at entry Type:Index.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_method_data_set_entry (
+ u32 type,
+ u32 index,
+ ACPI_OBJECT_INTERNAL *object)
+{
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL **entry;
+
+
+ /* Get a pointer to the stack entry to set */
+
+ status = acpi_ds_method_data_get_entry (type, index, &entry);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Increment ref count so object can't be deleted while installed */
+
+ acpi_cm_add_reference (object);
+
+ /* Install the object into the stack entry */
+
+ *entry = object;
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_method_data_get_type
+ *
+ * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG
+ * Index - Which local_var or argument whose type
+ * to get
+ *
+ * RETURN: Data type of selected Arg or Local
+ * Used only in Exec_monadic2()/Type_op.
+ *
+ ****************************************************************************/
+
+OBJECT_TYPE_INTERNAL
+acpi_ds_method_data_get_type (
+ u32 type,
+ u32 index)
+{
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL **entry;
+ ACPI_OBJECT_INTERNAL *object;
+
+
+ /* Get a pointer to the requested stack entry */
+
+ status = acpi_ds_method_data_get_entry (type, index, &entry);
+ if (ACPI_FAILURE (status)) {
+ return ((ACPI_TYPE_NOT_FOUND));
+ }
+
+ /* Get the object from the method stack */
+
+ object = *entry;
+
+ /* Get the object type */
+
+ if (!object) {
+ /* Any == 0 => "uninitialized" -- see spec 15.2.3.5.2.28 */
+ return (ACPI_TYPE_ANY);
+ }
+
+ return (object->common.type);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_method_data_get_nte
+ *
+ * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG
+ * Index - Which local_var or argument whose type
+ * to get
+ *
+ * RETURN: Get the NTE associated with a local or arg.
+ *
+ ****************************************************************************/
+
+ACPI_NAMED_OBJECT*
+acpi_ds_method_data_get_nte (
+ u32 type,
+ u32 index)
+{
+ ACPI_NAMED_OBJECT *entry = NULL;
+ ACPI_WALK_STATE *walk_state;
+
+
+ walk_state = acpi_ds_get_current_walk_state (acpi_gbl_current_walk_list);
+
+
+ switch (type)
+ {
+
+ case MTH_TYPE_LOCAL:
+
+ if (index > MTH_MAX_LOCAL) {
+ return (entry);
+ }
+
+ entry = &walk_state->local_variables[index];
+ break;
+
+
+ case MTH_TYPE_ARG:
+
+ if (index > MTH_MAX_ARG) {
+ return (entry);
+ }
+
+ entry = &walk_state->arguments[index];
+ break;
+
+
+ default:
+ break;
+ }
+
+
+ return (entry);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_method_data_get_value
+ *
+ * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG
+ * Index - Which local_var or argument to get
+ * *Dest_desc - Descriptor into which selected Arg
+ * or Local value should be copied
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieve value of selected Arg or Local from the method frame
+ * at the current top of the method stack.
+ * Used only in Acpi_aml_resolve_to_value().
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_method_data_get_value (
+ u32 type,
+ u32 index,
+ ACPI_OBJECT_INTERNAL **dest_desc)
+{
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL **entry;
+ ACPI_OBJECT_INTERNAL *object;
+
+
+ /* Validate the object descriptor */
+
+ if (!dest_desc) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /* Get a pointer to the requested method stack entry */
+
+ status = acpi_ds_method_data_get_entry (type, index, &entry);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Get the object from the method stack */
+
+ object = *entry;
+
+
+ /* Examine the returned object, it must be valid. */
+
+ if (!object) {
+ /*
+ * Index points to uninitialized object stack value.
+ * This means that either 1) The expected argument was
+ * not passed to the method, or 2) A local variable
+ * was referenced by the method (via the ASL)
+ * before it was initialized. Either case is an error.
+ */
+
+ switch (type)
+ {
+ case MTH_TYPE_ARG:
+ return (AE_AML_UNINITIALIZED_ARG);
+ break;
+
+ case MTH_TYPE_LOCAL:
+ return (AE_AML_UNINITIALIZED_LOCAL);
+ break;
+ }
+ }
+
+
+ /*
+ * Index points to initialized and valid object stack value.
+ * Return an additional reference to the object
+ */
+
+ *dest_desc = object;
+ acpi_cm_add_reference (object);
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_method_data_delete_value
+ *
+ * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG
+ * Index - Which local_var or argument to delete
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Delete the entry at Type:Index on the method stack. Inserts
+ * a null into the stack slot after the object is deleted.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_method_data_delete_value (
+ u32 type,
+ u32 index)
+{
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL **entry;
+ ACPI_OBJECT_INTERNAL *object;
+
+
+ /* Get a pointer to the requested entry */
+
+ status = acpi_ds_method_data_get_entry (type, index, &entry);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Get the current entry in this slot k */
+
+ object = *entry;
+
+ /*
+ * Undefine the Arg or Local by setting its descriptor
+ * pointer to NULL. Locals/Args can contain both
+ * ACPI_OBJECT_INTERNALS and ACPI_NAMED_OBJECTs
+ */
+ *entry = NULL;
+
+
+ if ((object) &&
+ (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_INTERNAL)))
+ {
+ /*
+ * There is a valid object in this slot
+ * Decrement the reference count by one to balance the
+ * increment when the object was stored in the slot.
+ */
+
+ acpi_cm_remove_reference (object);
+ }
+
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_method_data_set_value
+ *
+ * PARAMETERS: Type - Either MTH_TYPE_LOCAL or MTH_TYPE_ARG
+ * Index - Which local_var or argument to set
+ * *Src_desc - Value to be stored
+ * *Dest_desc - Descriptor into which *Src_desc
+ * can be copied, or NULL if one must
+ * be allocated for the purpose. If
+ * provided, this descriptor will be
+ * used for the new value.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Store a value in an Arg or Local. The Src_desc is installed
+ * as the new value for the Arg or Local and the reference count
+ * is incremented.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_method_data_set_value (
+ u32 type,
+ u32 index,
+ ACPI_OBJECT_INTERNAL *src_desc)
+{
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL **entry;
+
+
+ /* Parameter validation */
+
+ if (!src_desc) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /* Get a pointer to the requested method stack entry */
+
+ status = acpi_ds_method_data_get_entry (type, index, &entry);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ if (*entry == src_desc) {
+ goto cleanup;
+ }
+
+
+ /*
+ * If there is an object already in this slot, we either
+ * have to delete it, or if this is an argument and there
+ * is an object reference stored there, we have to do
+ * an indirect store!
+ */
+
+ if (*entry) {
+ /*
+ * Check for an indirect store if an argument
+ * contains an object reference (stored as an NTE).
+ * We don't allow this automatic dereferencing for
+ * locals, since a store to a local should overwrite
+ * anything there, including an object reference.
+ *
+ * If both Arg0 and Local0 contain Ref_of (Local4):
+ *
+ * Store (1, Arg0) - Causes indirect store to local4
+ * Store (1, Local0) - Stores 1 in local0, overwriting
+ * the reference to local4
+ * Store (1, De_refof (Local0)) - Causes indirect store to local4
+ *
+ * Weird, but true.
+ */
+
+ if ((type == MTH_TYPE_ARG) &&
+ (VALID_DESCRIPTOR_TYPE (*entry, ACPI_DESC_TYPE_NAMED)))
+ {
+ /* Detach an existing object from the NTE */
+
+ acpi_ns_detach_object (*entry);
+
+ /*
+ * Store this object into the NTE
+ * (do the indirect store)
+ */
+
+ status = acpi_ns_attach_object (*entry, src_desc,
+ src_desc->common.type);
+ return (status);
+ }
+
+
+ /*
+ * Otherwise, just delete the existing object
+ * before storing the new one
+ */
+
+ acpi_ds_method_data_delete_value (type, index);
+ }
+
+
+ /*
+ * Install the Obj_stack descriptor (*Src_desc) into
+ * the descriptor for the Arg or Local.
+ * Install the new object in the stack entry
+ * (increments the object reference count by one)
+ */
+
+ status = acpi_ds_method_data_set_entry (type, index, src_desc);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Normal exit */
+
+ return (AE_OK);
+
+
+ /* Error exit */
+
+cleanup:
+
+ return (status);
+}
+
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
new file mode 100644
index 000000000..c366eb153
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsobject.c
@@ -0,0 +1,598 @@
+
+/******************************************************************************
+ *
+ * Module Name: dsobject - Dispatcher object management routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "amlcode.h"
+#include "dispatch.h"
+#include "interp.h"
+#include "namesp.h"
+
+#define _COMPONENT DISPATCHER
+ MODULE_NAME ("dsobject");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_init_one_object
+ *
+ * PARAMETERS: Obj_handle - NTE of the object
+ * Level - Current nesting level
+ * Context - Points to a init info struct
+ * Return_value - Not used
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Callback from Acpi_walk_namespace. Invoked for every object
+ * within the namespace.
+ *
+ * Currently, the only objects that require initialization are:
+ * 1) Methods
+ * 2) Op Regions
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_init_one_object (
+ ACPI_HANDLE obj_handle,
+ u32 level,
+ void *context,
+ void **return_value)
+{
+ OBJECT_TYPE_INTERNAL type;
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ INIT_WALK_INFO *info = (INIT_WALK_INFO *) context;
+
+
+ /*
+ * We are only interested in objects owned by the table that
+ * was just loaded
+ */
+
+ if (((ACPI_NAMED_OBJECT*) obj_handle)->owner_id !=
+ info->table_desc->table_id)
+ {
+ return AE_OK;
+ }
+
+
+ /* And even then, we are only interested in a few object types */
+
+ type = acpi_ns_get_type (obj_handle);
+
+ switch (type)
+ {
+
+ case ACPI_TYPE_REGION:
+
+ acpi_ds_initialize_region (obj_handle);
+
+ info->op_region_count++;
+ break;
+
+
+ case ACPI_TYPE_METHOD:
+
+ info->method_count++;
+
+
+ /*
+ * Always parse methods to detect errors, we may delete
+ * the parse tree below
+ */
+
+ status = acpi_ds_parse_method (obj_handle);
+
+ /* TBD: [Errors] what do we do with an error? */
+
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ /*
+ * Keep the parse tree only if we are parsing all methods
+ * at init time (versus just-in-time)
+ */
+
+ if (acpi_gbl_when_to_parse_methods != METHOD_PARSE_AT_INIT) {
+
+ acpi_ns_delete_namespace_subtree (obj_handle);
+
+ obj_desc = ((ACPI_NAMED_OBJECT*)obj_handle)->object;
+ acpi_ps_delete_parse_tree (obj_desc->method.parser_op);
+ obj_desc->method.parser_op = NULL;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * We ignore errors from above, and always return OK, since
+ * we don't want to abort the walk on a single error.
+ */
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_initialize_objects
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Walk the entire namespace and perform any necessary initialization
+ * on the objects found therein
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_initialize_objects (
+ ACPI_TABLE_DESC *table_desc,
+ ACPI_NAMED_OBJECT *start_entry)
+{
+ ACPI_STATUS status;
+ INIT_WALK_INFO info;
+
+
+ info.method_count = 0;
+ info.op_region_count = 0;
+ info.table_desc = table_desc;
+
+
+ /* Walk entire namespace from the supplied root */
+
+ status = acpi_walk_namespace (ACPI_TYPE_ANY, start_entry,
+ ACPI_INT32_MAX, acpi_ds_init_one_object,
+ &info, NULL);
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_init_object_from_op
+ *
+ * PARAMETERS: Op - Parser op used to init the internal object
+ * Opcode - AML opcode associated with the object
+ * 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_GENERIC_OP *op,
+ u16 opcode,
+ ACPI_OBJECT_INTERNAL *obj_desc)
+{
+ ACPI_STATUS status;
+ ACPI_GENERIC_OP *arg;
+ ACPI_BYTELIST_OP *byte_list;
+ ACPI_OBJECT_INTERNAL *arg_desc;
+ ACPI_OP_INFO *op_info;
+
+
+ op_info = acpi_ps_get_opcode_info (opcode);
+ if (!op_info) {
+ /* Unknown opcode */
+
+ return AE_TYPE;
+ }
+
+
+ /* Get and prepare the first argument */
+
+ switch (obj_desc->common.type)
+ {
+ case ACPI_TYPE_BUFFER:
+
+ /* First arg is a number */
+
+ acpi_ds_create_operand (walk_state, op->value.arg);
+ arg_desc = walk_state->operands [walk_state->num_operands - 1];
+ acpi_ds_obj_stack_pop (1, walk_state);
+
+ /* Resolve the object (could be an arg or local) */
+
+ status = acpi_aml_resolve_to_value (&arg_desc);
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_remove_reference (arg_desc);
+ return status;
+ }
+
+ /* We are expecting a number */
+
+ if (arg_desc->common.type != ACPI_TYPE_NUMBER) {
+ acpi_cm_remove_reference (arg_desc);
+ return AE_TYPE;
+ }
+
+ /* Get the value, delete the internal object */
+
+ obj_desc->buffer.length = arg_desc->number.value;
+ acpi_cm_remove_reference (arg_desc);
+
+ /* Allocate the buffer */
+
+ obj_desc->buffer.pointer =
+ acpi_cm_callocate (obj_desc->buffer.length);
+
+ if (!obj_desc->buffer.pointer) {
+ return AE_NO_MEMORY;
+ }
+
+ /*
+ * Second arg is the buffer data (optional)
+ * Byte_list can be either individual bytes or a
+ * string initializer!
+ */
+
+ /* skip first arg */
+ arg = op->value.arg;
+ byte_list = (ACPI_BYTELIST_OP *) arg->next;
+ if (byte_list) {
+ if (byte_list->opcode != AML_BYTELIST_OP) {
+ return AE_TYPE;
+ }
+
+ MEMCPY (obj_desc->buffer.pointer, byte_list->data,
+ obj_desc->buffer.length);
+ }
+
+ break;
+
+
+ case ACPI_TYPE_NUMBER:
+ obj_desc->number.value = op->value.integer;
+ break;
+
+
+ case ACPI_TYPE_STRING:
+ obj_desc->string.pointer = op->value.string;
+ obj_desc->string.length = STRLEN (op->value.string);
+ break;
+
+
+ case ACPI_TYPE_METHOD:
+ break;
+
+
+ case INTERNAL_TYPE_REFERENCE:
+
+ switch (op_info->flags & OP_INFO_TYPE)
+ {
+ case OPTYPE_LOCAL_VARIABLE:
+
+ /* Split the opcode into a base opcode + offset */
+
+ obj_desc->reference.op_code = AML_LOCAL_OP;
+ obj_desc->reference.offset = opcode - AML_LOCAL_OP;
+ break;
+
+ case OPTYPE_METHOD_ARGUMENT:
+
+ /* Split the opcode into a base opcode + offset */
+
+ obj_desc->reference.op_code = AML_ARG_OP;
+ obj_desc->reference.offset = opcode - AML_ARG_OP;
+ break;
+
+ default: /* Constants, Literals, etc.. */
+
+ if (op->opcode == AML_NAMEPATH_OP) {
+ /* Nte was saved in Op */
+
+ obj_desc->reference.nte = op->acpi_named_object;
+ }
+
+ obj_desc->reference.op_code = opcode;
+ break;
+ }
+
+ break;
+
+
+ default:
+
+ break;
+ }
+
+ return AE_OK;
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_build_internal_simple_obj
+ *
+ * PARAMETERS: Op - Parser object to be translated
+ * Obj_desc_ptr - Where the ACPI internal object is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate a parser Op object to the equivalent namespace object
+ * Simple objects are any objects other than a package object!
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_build_internal_simple_obj (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op,
+ ACPI_OBJECT_INTERNAL **obj_desc_ptr)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ OBJECT_TYPE_INTERNAL type;
+ ACPI_STATUS status;
+
+
+ if (op->opcode == AML_NAMEPATH_OP) {
+ /*
+ * This is an object reference. If The name was
+ * previously looked up in the NS, it is stored in this op.
+ * Otherwise, go ahead and look it up now
+ */
+
+ if (!op->acpi_named_object) {
+ status = acpi_ns_lookup (walk_state->scope_info,
+ op->value.string, ACPI_TYPE_ANY,
+ IMODE_EXECUTE,
+ NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE,
+ NULL,
+ (ACPI_NAMED_OBJECT**)&(op->acpi_named_object));
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+ /*
+ * The reference will be a Reference
+ * TBD: [Restructure] unless we really need a separate
+ * type of INTERNAL_TYPE_REFERENCE change
+ * Acpi_ds_map_opcode_to_data_type to handle this case
+ */
+ type = INTERNAL_TYPE_REFERENCE;
+ }
+ else {
+ type = acpi_ds_map_opcode_to_data_type (op->opcode, NULL);
+ }
+
+
+ /* Create and init the internal ACPI object */
+
+ obj_desc = acpi_cm_create_internal_object (type);
+ if (!obj_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+ status = acpi_ds_init_object_from_op (walk_state, op,
+ op->opcode, obj_desc);
+
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_remove_reference (obj_desc);
+ return (status);
+ }
+
+ *obj_desc_ptr = obj_desc;
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_build_internal_package_obj
+ *
+ * PARAMETERS: Op - Parser object to be translated
+ * Obj_desc_ptr - Where the ACPI internal object is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate a parser Op package object to the equivalent
+ * namespace object
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_build_internal_package_obj (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op,
+ ACPI_OBJECT_INTERNAL **obj_desc_ptr)
+{
+ ACPI_GENERIC_OP *arg;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_STATUS status = AE_OK;
+
+
+ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_PACKAGE);
+ if (!obj_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* The first argument must be the package length */
+
+ arg = op->value.arg;
+ obj_desc->package.count = arg->value.integer;
+
+ /*
+ * Allocate the array of pointers (ptrs to the
+ * individual objects) Add an extra pointer slot so
+ * that the list is always null terminated.
+ */
+
+ obj_desc->package.elements =
+ acpi_cm_callocate ((obj_desc->package.count + 1) *
+ sizeof (void *));
+
+ if (!obj_desc->package.elements) {
+ /* Package vector allocation failure */
+
+ REPORT_ERROR ("Ds_build_internal_package_obj: Package vector allocation failure");
+
+ acpi_cm_free (obj_desc);
+ return (AE_NO_MEMORY);
+ }
+
+ obj_desc->package.next_element = obj_desc->package.elements;
+
+ /*
+ * Now init the elements of the package
+ */
+
+ arg = arg->next;
+ while (arg) {
+ if (arg->opcode == AML_PACKAGE_OP) {
+ status = acpi_ds_build_internal_package_obj (walk_state, arg,
+ obj_desc->package.next_element);
+ }
+
+ else {
+ status = acpi_ds_build_internal_simple_obj (walk_state, arg,
+ obj_desc->package.next_element);
+ }
+
+ obj_desc->package.next_element++;
+ arg = arg->next;
+ }
+
+ *obj_desc_ptr = obj_desc;
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_build_internal_object
+ *
+ * PARAMETERS: Op - Parser object to be translated
+ * Obj_desc_ptr - Where the ACPI internal object is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate a parser Op object to the equivalent namespace
+ * object
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_build_internal_object (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op,
+ ACPI_OBJECT_INTERNAL **obj_desc_ptr)
+{
+ ACPI_STATUS status;
+
+
+ if (op->opcode == AML_PACKAGE_OP) {
+ status = acpi_ds_build_internal_package_obj (walk_state, op,
+ obj_desc_ptr);
+ }
+
+ else {
+ status = acpi_ds_build_internal_simple_obj (walk_state, op,
+ obj_desc_ptr);
+ }
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_create_named_object
+ *
+ * PARAMETERS: Op - Parser object to be translated
+ * Obj_desc_ptr - Where the ACPI internal object is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION:
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_create_named_object (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_NAMED_OBJECT *entry,
+ ACPI_GENERIC_OP *op)
+{
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+
+
+ if (!op->value.arg) {
+ /* No arguments, there is nothing to do */
+
+ return (AE_OK);
+ }
+
+
+ /* Build an internal object for the argument(s) */
+
+ status = acpi_ds_build_internal_object (walk_state,
+ op->value.arg, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+
+ /* Re-type the object according to it's argument */
+
+ entry->type = obj_desc->common.type;
+
+ /* Init obj */
+
+ status = acpi_ns_attach_object ((ACPI_HANDLE) entry, obj_desc,
+ (u8) entry->type);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ return (status);
+
+
+cleanup:
+
+ acpi_cm_remove_reference (obj_desc);
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
new file mode 100644
index 000000000..c2020574f
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -0,0 +1,464 @@
+
+/******************************************************************************
+ *
+ * Module Name: dsopcode - Dispatcher Op Region support
+ * and handling of "control" opcodes
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "amlcode.h"
+#include "dispatch.h"
+#include "interp.h"
+#include "namesp.h"
+#include "events.h"
+#include "tables.h"
+
+#define _COMPONENT DISPATCHER
+ MODULE_NAME ("dsopcode");
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_get_region_arguments
+ *
+ * PARAMETERS: Rgn_desc - A valid region object
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Get region address and length. This implements the late
+ * evaluation of these region attributes.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_get_region_arguments (
+ ACPI_OBJECT_INTERNAL *rgn_desc)
+{
+ ACPI_OBJECT_INTERNAL *method_desc;
+ ACPI_NAMED_OBJECT *entry;
+ ACPI_GENERIC_OP *op;
+ ACPI_GENERIC_OP *region_op;
+ ACPI_STATUS status;
+ ACPI_TABLE_DESC *table_desc;
+
+
+ if (rgn_desc->region.region_flags & REGION_AGRUMENT_DATA_VALID) {
+ return (AE_OK);
+ }
+
+
+ method_desc = rgn_desc->region.method;
+ entry = rgn_desc->region.nte;
+
+
+ /*
+ * Allocate a new parser op to be the root of the parsed
+ * Op_region tree
+ */
+
+ op = acpi_ps_alloc_op (AML_REGION_OP);
+ if (!op) {
+ return AE_NO_MEMORY;
+ }
+
+ /* Save the NTE for use in Acpi_ps_parse_aml */
+
+ op->acpi_named_object = acpi_ns_get_parent_entry (entry);
+
+ /* Get a handle to the parent ACPI table */
+
+ status = acpi_tb_handle_to_object (entry->owner_id, &table_desc);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Parse the entire Op_region declaration, creating a parse tree */
+
+ status = acpi_ps_parse_aml (op, method_desc->method.pcode,
+ method_desc->method.pcode_length, 0);
+ if (ACPI_SUCCESS (status)) {
+ /* Get and init the actual Region_op created above */
+
+ region_op = op->value.arg;
+ region_op->acpi_named_object = entry;
+
+ /* Acpi_evaluate the address and length arguments for the Op_region */
+
+ acpi_ps_walk_parsed_aml (region_op, region_op, NULL, NULL, NULL,
+ NULL, table_desc->table_id,
+ acpi_ds_exec_begin_op, acpi_ds_exec_end_op);
+ }
+
+ /* All done with the parse tree, delete it */
+
+ acpi_ps_delete_parse_tree (op);
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_initialize_region
+ *
+ * PARAMETERS: Op - A valid region Op object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION:
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_initialize_region (
+ ACPI_HANDLE obj_handle)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_STATUS status;
+
+
+ obj_desc = acpi_ns_get_attached_object (obj_handle);
+
+ /* Namespace is NOT locked */
+
+ status = acpi_ev_initialize_region (obj_desc, FALSE);
+
+ return status;
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_eval_region_operands
+ *
+ * PARAMETERS: Op - A valid region Op object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get region address and length
+ * Called from Acpi_ds_exec_end_op during Op_region parse tree walk
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_eval_region_operands (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op)
+{
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_OBJECT_INTERNAL *region_desc;
+ ACPI_NAMED_OBJECT *entry;
+ ACPI_GENERIC_OP *next_op;
+
+
+ /*
+ * This is where we evaluate the address and length fields of the Op_region declaration
+ */
+
+ entry = op->acpi_named_object;
+
+ /* Next_op points to the op that holds the Space_iD */
+ next_op = op->value.arg;
+
+ /* Next_op points to address op */
+ next_op = next_op->next;
+
+ /* Acpi_evaluate/create the address and length operands */
+
+ status = acpi_ds_create_operands (walk_state, next_op);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ region_desc = acpi_ns_get_attached_object (entry);
+ if (!region_desc) {
+ return (AE_NOT_EXIST);
+ }
+
+ /* Get the length and save it */
+
+ /* Top of stack */
+ obj_desc = walk_state->operands[walk_state->num_operands - 1];
+
+ region_desc->region.length = obj_desc->number.value;
+ acpi_cm_remove_reference (obj_desc);
+
+ /* Get the address and save it */
+
+ /* Top of stack - 1 */
+ obj_desc = walk_state->operands[walk_state->num_operands - 2];
+
+ region_desc->region.address = obj_desc->number.value;
+ acpi_cm_remove_reference (obj_desc);
+
+
+ /* Now the address and length are valid for this opregion */
+
+ region_desc->region.region_flags |= REGION_AGRUMENT_DATA_VALID;
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_exec_begin_control_op
+ *
+ * PARAMETERS: Walk_list - The list that owns the walk stack
+ * Op - The control Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Handles all control ops encountered during control method
+ * execution.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_exec_begin_control_op (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_GENERIC_STATE *control_state;
+
+
+ switch (op->opcode)
+ {
+ case AML_IF_OP:
+ case AML_WHILE_OP:
+
+ /*
+ * IF/WHILE: Create a new control state to manage these
+ * constructs. We need to manage these as a stack, in order
+ * to handle nesting.
+ */
+
+ control_state = acpi_cm_create_control_state ();
+ if (!control_state) {
+ status = AE_NO_MEMORY;
+ break;
+ }
+
+ acpi_cm_push_generic_state (&walk_state->control_state, control_state);
+ break;
+
+
+ case AML_ELSE_OP:
+
+ /* Predicate is in the state object */
+ /* If predicate is true, the IF was executed, ignore ELSE part */
+
+ if (walk_state->last_predicate) {
+ status = AE_CTRL_TRUE;
+ }
+
+ break;
+
+
+ case AML_RETURN_OP:
+
+ break;
+
+
+ default:
+ break;
+ }
+
+ return status;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_exec_end_control_op
+ *
+ * PARAMETERS: Walk_list - The list that owns the walk stack
+ * Op - The control Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Handles all control ops encountered during control method
+ * execution.
+ *
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_exec_end_control_op (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_GENERIC_STATE *control_state;
+
+
+ switch (op->opcode)
+ {
+ case AML_IF_OP:
+
+ /*
+ * Save the result of the predicate in case there is an
+ * ELSE to come
+ */
+
+ walk_state->last_predicate =
+ (u8) walk_state->control_state->common.value;
+
+ /*
+ * Pop the control state that was created at the start
+ * of the IF and free it
+ */
+
+ control_state =
+ acpi_cm_pop_generic_state (&walk_state->control_state);
+
+ acpi_cm_delete_generic_state (control_state);
+
+ break;
+
+
+ case AML_ELSE_OP:
+
+ break;
+
+
+ case AML_WHILE_OP:
+
+ if (walk_state->control_state->common.value) {
+ /* Predicate was true, go back and evaluate it again! */
+
+ status = AE_CTRL_TRUE;
+ }
+
+ else {
+ /* Pop this control state and free it */
+
+ control_state =
+ acpi_cm_pop_generic_state (&walk_state->control_state);
+ acpi_cm_delete_generic_state (control_state);
+ }
+
+ break;
+
+
+ case AML_RETURN_OP:
+
+
+ /* One optional operand -- the return value */
+
+ if (op->value.arg) {
+ status = acpi_ds_create_operands (walk_state, op->value.arg);
+ if (ACPI_FAILURE (status)) {
+ return status;
+ }
+
+ /*
+ * TBD: [Restructure] Just check for NULL arg
+ * to signify no return value???
+ */
+
+ /*
+ * If value being returned is a Reference (such as
+ * an arg or local), resolve it now because it may
+ * cease to exist at the end of the method.
+ */
+
+ status = acpi_aml_resolve_to_value (&walk_state->operands [0]);
+ if (ACPI_FAILURE (status)) {
+ return status;
+ }
+
+ /*
+ * Get the return value and save as the last result
+ * value
+ * This is the only place where Walk_state->Return_desc
+ * is set to anything other than zero!
+ */
+
+ walk_state->return_desc = walk_state->operands[0];
+ }
+
+ else {
+ /* No return operand */
+
+ acpi_cm_remove_reference (walk_state->operands [0]);
+
+ walk_state->operands [0] = NULL;
+ walk_state->num_operands = 0;
+ walk_state->return_desc = NULL;
+ }
+
+
+ /* End the control method execution right now */
+ status = AE_CTRL_TERMINATE;
+ break;
+
+
+ case AML_NOOP_CODE:
+
+ /* Just do nothing! */
+ break;
+
+
+ case AML_BREAK_POINT_OP:
+
+ /* Call up to the OS dependent layer to handle this */
+
+ acpi_os_breakpoint (NULL);
+
+ /* If it returns, we are done! */
+
+ break;
+
+
+ case AML_BREAK_OP:
+
+ /*
+ * As per the ACPI specification:
+ * "The break operation causes the current package
+ * execution to complete"
+ * "Break -- Stop executing the current code package
+ * at this point"
+ *
+ * Returning AE_FALSE here will cause termination of
+ * the current package, and execution will continue one
+ * level up, starting with the completion of the parent Op.
+ */
+
+ status = AE_CTRL_FALSE;
+ break;
+
+
+ default:
+
+ status = AE_AML_BAD_OPCODE;
+ break;
+ }
+
+
+ return status;
+}
+
diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c
new file mode 100644
index 000000000..a5f79c96e
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsutils.c
@@ -0,0 +1,694 @@
+
+/******************************************************************************
+ *
+ * Module Name: dsutils - Dispatcher utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "amlcode.h"
+#include "dispatch.h"
+#include "interp.h"
+#include "namesp.h"
+#include "debugger.h"
+
+#define _COMPONENT PARSER
+ MODULE_NAME ("dsutils");
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_delete_result_if_not_used
+ *
+ * PARAMETERS: Op
+ * Result_obj
+ * Walk_state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Used after interpretation of an opcode. If there is an internal
+ * result descriptor, check if the parent opcode will actually use
+ * this result. If not, delete the result now so that it will
+ * not become orphaned.
+ *
+ ****************************************************************************/
+
+void
+acpi_ds_delete_result_if_not_used (
+ ACPI_GENERIC_OP *op,
+ ACPI_OBJECT_INTERNAL *result_obj,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_OP_INFO *parent_info;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_STATUS status;
+
+
+ if (!op) {
+ return;
+ }
+
+ if (!result_obj) {
+ return;
+ }
+
+ if (!op->parent) {
+ /*
+ * If there is no parent, the result can't possibly be used!
+ * (An executing method typically has no parent, since each
+ * method is parsed separately
+ */
+
+ /*
+ * Must pop the result stack (Obj_desc should be equal
+ * to Result_obj)
+ */
+
+ status = acpi_ds_result_stack_pop (&obj_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return;
+ }
+
+ acpi_cm_remove_reference (result_obj);
+
+ return;
+ }
+
+
+ /*
+ * Get info on the parent. The root Op is AML_SCOPE
+ */
+
+ parent_info = acpi_ps_get_opcode_info (op->parent->opcode);
+ if (!parent_info) {
+ return;
+ }
+
+
+ /* Never delete the return value associated with a return opcode */
+
+ if (op->parent->opcode == AML_RETURN_OP) {
+ return;
+ }
+
+
+ /*
+ * Decide what to do with the result based on the parent. If
+ * the parent opcode will not use the result, delete the object.
+ * Otherwise leave it as is, it will be deleted when it is used
+ * as an operand later.
+ */
+
+ switch (parent_info->flags & OP_INFO_TYPE)
+ {
+ /*
+ * In these cases, the parent will never use the return object,
+ * so delete it here and now.
+ */
+ case OPTYPE_CONTROL: /* IF, ELSE, WHILE only */
+ case OPTYPE_NAMED_OBJECT: /* Scope, method, etc. */
+
+ /*
+ * Must pop the result stack (Obj_desc should be equal
+ * to Result_obj)
+ */
+
+ status = acpi_ds_result_stack_pop (&obj_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return;
+ }
+
+ acpi_cm_remove_reference (result_obj);
+ break;
+
+ /*
+ * In all other cases. the parent will actually use the return
+ * object, so keep it.
+ */
+ default:
+ break;
+ }
+
+ return;
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_create_operand
+ *
+ * PARAMETERS: Walk_state
+ * Arg
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate a parse tree object that is an argument to an AML
+ * opcode to the equivalent interpreter object. This may include
+ * looking up a name or entering a new name into the internal
+ * namespace.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_create_operand (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *arg)
+{
+ ACPI_STATUS status = AE_OK;
+ char *name_string;
+ u32 name_length;
+ OBJECT_TYPE_INTERNAL data_type;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_GENERIC_OP *parent_op;
+ u16 opcode;
+ u32 flags;
+ OPERATING_MODE interpreter_mode;
+
+
+ /* A valid name must be looked up in the namespace */
+
+ if ((arg->opcode == AML_NAMEPATH_OP) &&
+ (arg->value.string))
+ {
+ /* Get the entire name string from the AML stream */
+
+ status = acpi_aml_get_name_string (ACPI_TYPE_ANY,
+ arg->value.buffer,
+ &name_string,
+ &name_length);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /*
+ * All prefixes have been handled, and the name is
+ * in Name_string
+ */
+
+ /*
+ * Differentiate between a namespace "create" operation
+ * versus a "lookup" operation (IMODE_LOAD_PASS2 vs.
+ * IMODE_EXECUTE) in order to support the creation of
+ * namespace objects during the execution of control methods.
+ */
+
+ parent_op = arg->parent;
+ if ((acpi_ps_is_named_object_op (parent_op->opcode)) &&
+ (parent_op->opcode != AML_METHODCALL_OP) &&
+ (parent_op->opcode != AML_NAMEPATH_OP))
+ {
+ /* Enter name into namespace if not found */
+
+ interpreter_mode = IMODE_LOAD_PASS2;
+ }
+
+ else {
+ /* Return a failure if name not found */
+
+ interpreter_mode = IMODE_EXECUTE;
+ }
+
+ status = acpi_ns_lookup (walk_state->scope_info, name_string,
+ ACPI_TYPE_ANY, interpreter_mode,
+ NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE,
+ walk_state,
+ (ACPI_NAMED_OBJECT**) &obj_desc);
+
+ /* Free the namestring created above */
+
+ acpi_cm_free (name_string);
+
+ /*
+ * The only case where we pass through (ignore) a NOT_FOUND
+ * error is for the Cond_ref_of opcode.
+ */
+
+ if (status == AE_NOT_FOUND) {
+ if (parent_op->opcode == AML_COND_REF_OF_OP) {
+ /*
+ * For the Conditional Reference op, it's OK if
+ * the name is not found; We just need a way to
+ * indicate this to the interpreter, set the
+ * object to the root
+ */
+ obj_desc = (ACPI_OBJECT_INTERNAL *) acpi_gbl_root_object;
+ status = AE_OK;
+ }
+
+ else {
+ /*
+ * We just plain didn't find it -- which is a
+ * very serious error at this point
+ */
+ status = AE_AML_NAME_NOT_FOUND;
+ }
+ }
+
+ /* Check status from the lookup */
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Put the resulting object onto the current object stack */
+
+ status = acpi_ds_obj_stack_push (obj_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+
+ else {
+ /* Check for null name case */
+
+ if (arg->opcode == AML_NAMEPATH_OP) {
+ /*
+ * If the name is null, this means that this is an
+ * optional result parameter that was not specified
+ * in the original ASL. Create an Reference for a
+ * placeholder
+ */
+ opcode = AML_ZERO_OP; /* Has no arguments! */
+
+ /*
+ * TBD: [Investigate] anything else needed for the
+ * zero op lvalue?
+ */
+ }
+
+ else {
+ opcode = arg->opcode;
+ }
+
+
+ /* Get the data type of the argument */
+
+ data_type = acpi_ds_map_opcode_to_data_type (opcode, &flags);
+ if (data_type == INTERNAL_TYPE_INVALID) {
+ return (AE_NOT_IMPLEMENTED);
+ }
+
+ if (flags & OP_HAS_RETURN_VALUE) {
+ /*
+ * Use value that was already previously returned
+ * by the evaluation of this argument
+ */
+
+ status = acpi_ds_result_stack_pop (&obj_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ /*
+ * Only error is underflow, and this indicates
+ * a missing or null operand!
+ */
+ return (status);
+ }
+
+ }
+
+ else {
+ /* Create an ACPI_INTERNAL_OBJECT for the argument */
+
+ obj_desc = acpi_cm_create_internal_object (data_type);
+ if (!obj_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Initialize the new object */
+
+ status = acpi_ds_init_object_from_op (walk_state, arg,
+ opcode, obj_desc);
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_free (obj_desc);
+ return (status);
+ }
+ }
+
+ /* Put the operand object on the object stack */
+
+ status = acpi_ds_obj_stack_push (obj_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ }
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_create_operands
+ *
+ * PARAMETERS: First_arg - First argument of a parser argument tree
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Convert an operator's arguments from a parse tree format to
+ * namespace objects and place those argument object on the object
+ * stack in preparation for evaluation by the interpreter.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_create_operands (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *first_arg)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_GENERIC_OP *arg;
+ u32 args_pushed = 0;
+
+
+ arg = first_arg;
+
+
+ /* For all arguments in the list... */
+
+ while (arg) {
+
+ status = acpi_ds_create_operand (walk_state, arg);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Move on to next argument, if any */
+
+ arg = arg->next;
+ args_pushed++;
+ }
+
+ return (status);
+
+
+cleanup:
+ /*
+ * We must undo everything done above; meaning that we must
+ * pop everything off of the operand stack and delete those
+ * objects
+ */
+
+ acpi_ds_obj_stack_pop_and_delete (args_pushed, walk_state);
+
+ return (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;
+
+
+ /*
+ * Attempt to resolve each of the valid operands
+ * Method arguments are passed by value, not by reference
+ */
+
+ /*
+ * TBD: [Investigate] Note from previous parser:
+ * Ref_of problem with Acpi_aml_resolve_to_value() conversion.
+ */
+
+ for (i = 0; i < walk_state->num_operands; i++) {
+ status = acpi_aml_resolve_to_value (&walk_state->operands[i]);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+ }
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_map_opcode_to_data_type
+ *
+ * PARAMETERS: Opcode - AML opcode to map
+ * Out_flags - Additional info about the opcode
+ *
+ * RETURN: The ACPI type associated with the opcode
+ *
+ * DESCRIPTION: Convert a raw AML opcode to the associated ACPI data type,
+ * if any. If the opcode returns a value as part of the
+ * intepreter execution, a flag is returned in Out_flags.
+ *
+ ****************************************************************************/
+
+OBJECT_TYPE_INTERNAL
+acpi_ds_map_opcode_to_data_type (
+ u16 opcode,
+ u32 *out_flags)
+{
+ OBJECT_TYPE_INTERNAL data_type = INTERNAL_TYPE_INVALID;
+ ACPI_OP_INFO *op_info;
+ u32 flags = 0;
+
+
+ op_info = acpi_ps_get_opcode_info (opcode);
+ if (!op_info) {
+ /* Unknown opcode */
+
+ return data_type;
+ }
+
+ switch (op_info->flags & OP_INFO_TYPE)
+ {
+
+ case OPTYPE_LITERAL:
+
+ switch (opcode)
+ {
+ case AML_BYTE_OP:
+ case AML_WORD_OP:
+ case AML_DWORD_OP:
+
+ data_type = ACPI_TYPE_NUMBER;
+ break;
+
+
+ case AML_STRING_OP:
+
+ data_type = ACPI_TYPE_STRING;
+ break;
+
+ case AML_NAMEPATH_OP:
+ data_type = INTERNAL_TYPE_REFERENCE;
+ break;
+ }
+
+ break;
+
+
+ case OPTYPE_DATA_TERM:
+
+ switch (opcode)
+ {
+ case AML_BUFFER_OP:
+
+ data_type = ACPI_TYPE_BUFFER;
+ break;
+
+ case AML_PACKAGE_OP:
+
+ data_type = ACPI_TYPE_PACKAGE;
+ break;
+ }
+
+ break;
+
+
+ case OPTYPE_CONSTANT:
+ case OPTYPE_METHOD_ARGUMENT:
+ case OPTYPE_LOCAL_VARIABLE:
+
+ data_type = INTERNAL_TYPE_REFERENCE;
+ break;
+
+
+ case OPTYPE_MONADIC2:
+ case OPTYPE_MONADIC2_r:
+ case OPTYPE_DYADIC2:
+ case OPTYPE_DYADIC2_r:
+ case OPTYPE_DYADIC2_s:
+ case OPTYPE_INDEX:
+ case OPTYPE_MATCH:
+
+ flags = OP_HAS_RETURN_VALUE;
+ data_type = ACPI_TYPE_ANY;
+
+ break;
+
+ case OPTYPE_METHOD_CALL:
+
+ flags = OP_HAS_RETURN_VALUE;
+ data_type = ACPI_TYPE_METHOD;
+
+ break;
+
+
+ case OPTYPE_NAMED_OBJECT:
+
+ data_type = acpi_ds_map_named_opcode_to_data_type (opcode);
+
+ break;
+
+
+ case OPTYPE_DYADIC1:
+ case OPTYPE_CONTROL:
+
+ /* No mapping needed at this time */
+
+ break;
+
+
+ default:
+
+ break;
+ }
+
+ /* Return flags to caller if requested */
+
+ if (out_flags) {
+ *out_flags = flags;
+ }
+
+ return data_type;
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_map_named_opcode_to_data_type
+ *
+ * PARAMETERS: Opcode - The Named AML opcode to map
+ *
+ * RETURN: The ACPI type associated with the named opcode
+ *
+ * DESCRIPTION: Convert a raw Named AML opcode to the associated data type.
+ * Named opcodes are a subsystem of the AML opcodes.
+ *
+ ****************************************************************************/
+
+OBJECT_TYPE_INTERNAL
+acpi_ds_map_named_opcode_to_data_type (
+ u16 opcode)
+{
+ OBJECT_TYPE_INTERNAL data_type;
+
+
+ /* Decode Opcode */
+
+ switch (opcode)
+ {
+ case AML_SCOPE_OP:
+ data_type = INTERNAL_TYPE_SCOPE;
+ break;
+
+ case AML_DEVICE_OP:
+ data_type = ACPI_TYPE_DEVICE;
+ break;
+
+ case AML_THERMAL_ZONE_OP:
+ data_type = ACPI_TYPE_THERMAL;
+ break;
+
+ case AML_METHOD_OP:
+ data_type = ACPI_TYPE_METHOD;
+ break;
+
+ case AML_POWER_RES_OP:
+ data_type = ACPI_TYPE_POWER;
+ break;
+
+ case AML_PROCESSOR_OP:
+ data_type = ACPI_TYPE_PROCESSOR;
+ break;
+
+ case AML_DEF_FIELD_OP: /* Def_field_op */
+ data_type = INTERNAL_TYPE_DEF_FIELD_DEFN;
+ break;
+
+ case AML_INDEX_FIELD_OP: /* Index_field_op */
+ data_type = INTERNAL_TYPE_INDEX_FIELD_DEFN;
+ break;
+
+ case AML_BANK_FIELD_OP: /* Bank_field_op */
+ data_type = INTERNAL_TYPE_BANK_FIELD_DEFN;
+ break;
+
+ case AML_NAMEDFIELD_OP: /* NO CASE IN ORIGINAL */
+ data_type = ACPI_TYPE_ANY;
+ break;
+
+ case AML_NAME_OP: /* Name_op - special code in original */
+ case AML_NAMEPATH_OP:
+ data_type = ACPI_TYPE_ANY;
+ break;
+
+ case AML_ALIAS_OP:
+ data_type = INTERNAL_TYPE_ALIAS;
+ break;
+
+ case AML_MUTEX_OP:
+ data_type = ACPI_TYPE_MUTEX;
+ break;
+
+ case AML_EVENT_OP:
+ data_type = ACPI_TYPE_EVENT;
+ break;
+
+ case AML_REGION_OP:
+ data_type = ACPI_TYPE_REGION;
+ break;
+
+
+ default:
+ data_type = ACPI_TYPE_ANY;
+ break;
+
+ }
+
+ return data_type;
+}
+
+
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
new file mode 100644
index 000000000..707b30031
--- /dev/null
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -0,0 +1,572 @@
+/******************************************************************************
+ *
+ * Module Name: dswexec - Dispatcher method execution callbacks;
+ * Dispatch to interpreter.
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "amlcode.h"
+#include "dispatch.h"
+#include "interp.h"
+#include "namesp.h"
+#include "debugger.h"
+
+
+#define _COMPONENT DISPATCHER
+ MODULE_NAME ("dswexec");
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_exec_begin_op
+ *
+ * PARAMETERS: Walk_state - Current state of the parse tree walk
+ * Op - Op that has been just been reached in the
+ * walk; Arguments have not been evaluated yet.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Descending callback used during the execution of control
+ * methods. This is where most operators and operands are
+ * dispatched to the interpreter.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_exec_begin_op (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op)
+{
+ ACPI_OP_INFO *op_info;
+ ACPI_STATUS status = AE_OK;
+
+
+ if (op == walk_state->origin) {
+ return (AE_OK);
+ }
+
+ /*
+ * If the previous opcode was a conditional, this opcode
+ * must be the beginning of the associated predicate.
+ * Save this knowledge in the current scope descriptor
+ */
+
+ if ((walk_state->control_state) &&
+ (walk_state->control_state->common.state ==
+ CONTROL_CONDITIONAL_EXECUTING))
+ {
+ walk_state->control_state->common.state = CONTROL_PREDICATE_EXECUTING;
+
+ /* Save start of predicate */
+
+ walk_state->control_state->control.predicate_op = op;
+ }
+
+
+ op_info = acpi_ps_get_opcode_info (op->opcode);
+
+ /* We want to send namepaths to the load code */
+
+ if (op->opcode == AML_NAMEPATH_OP) {
+ op_info->flags = OPTYPE_NAMED_OBJECT;
+ }
+
+
+ /*
+ * Handle the opcode based upon the opcode type
+ */
+
+ switch (op_info->flags & OP_INFO_TYPE)
+ {
+ case OPTYPE_CONTROL:
+
+ status = acpi_ds_exec_begin_control_op (walk_state, op);
+ break;
+
+
+ case OPTYPE_NAMED_OBJECT:
+
+ if (walk_state->origin->opcode == AML_METHOD_OP) {
+ /*
+ * Found a named object declaration during method
+ * execution; we must enter this object into the
+ * namespace. The created object is temporary and
+ * will be deleted upon completion of the execution
+ * of this method.
+ */
+
+ status = acpi_ds_load2_begin_op (walk_state, op);
+ }
+ break;
+
+
+ default:
+ break;
+ }
+
+ /* Nothing to do here during method execution */
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_exec_end_op
+ *
+ * PARAMETERS: Walk_state - Current state of the parse tree walk
+ * Op - Op that has been just been completed in the
+ * walk; Arguments have now been evaluated.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Ascending callback used during the execution of control
+ * methods. The only thing we really need to do here is to
+ * notice the beginning of IF, ELSE, and WHILE blocks.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_exec_end_op (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op)
+{
+ ACPI_STATUS status = AE_OK;
+ u16 opcode;
+ u8 optype;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_GENERIC_OP *next_op;
+ ACPI_NAMED_OBJECT *entry;
+ ACPI_GENERIC_OP *first_arg;
+ ACPI_OBJECT_INTERNAL *result_obj = NULL;
+ ACPI_OP_INFO *op_info;
+ u32 operand_index;
+
+
+ opcode = (u16) op->opcode;
+
+
+ op_info = acpi_ps_get_opcode_info (op->opcode);
+ if (!op_info) {
+ return (AE_NOT_IMPLEMENTED);
+ }
+
+ optype = (u8) (op_info->flags & OP_INFO_TYPE);
+ first_arg = op->value.arg;
+
+ /* Init the walk state */
+
+ walk_state->num_operands = 0;
+ walk_state->return_desc = NULL;
+
+
+ /* Call debugger for single step support (DEBUG build only) */
+
+
+ /* Decode the opcode */
+
+ switch (optype)
+ {
+ case OPTYPE_UNDEFINED:
+
+ return (AE_NOT_IMPLEMENTED);
+ break;
+
+
+ case OPTYPE_BOGUS:
+ break;
+
+ case OPTYPE_CONSTANT: /* argument type only */
+ case OPTYPE_LITERAL: /* argument type only */
+ case OPTYPE_DATA_TERM: /* argument type only */
+ case OPTYPE_LOCAL_VARIABLE: /* argument type only */
+ case OPTYPE_METHOD_ARGUMENT: /* argument type only */
+ break;
+
+
+ /* most operators with arguments */
+
+ case OPTYPE_MONADIC1:
+ case OPTYPE_DYADIC1:
+ case OPTYPE_MONADIC2:
+ case OPTYPE_MONADIC2_r:
+ case OPTYPE_DYADIC2:
+ case OPTYPE_DYADIC2_r:
+ case OPTYPE_DYADIC2_s:
+ case OPTYPE_RECONFIGURATION:
+ case OPTYPE_INDEX:
+ case OPTYPE_MATCH:
+ case OPTYPE_CREATE_FIELD:
+ case OPTYPE_FATAL:
+
+ status = acpi_ds_create_operands (walk_state, first_arg);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ operand_index = walk_state->num_operands - 1;
+
+ switch (optype)
+ {
+
+ case OPTYPE_MONADIC1:
+
+ /* 1 Operand, 0 External_result, 0 Internal_result */
+
+ status = acpi_aml_exec_monadic1 (opcode, walk_state);
+ break;
+
+
+ case OPTYPE_MONADIC2:
+
+ /* 1 Operand, 0 External_result, 1 Internal_result */
+
+ status = acpi_aml_exec_monadic2 (opcode, walk_state, &result_obj);
+ if (ACPI_SUCCESS (status)) {
+ status = acpi_ds_result_stack_push (result_obj, walk_state);
+ }
+
+ break;
+
+
+ case OPTYPE_MONADIC2_r:
+
+ /* 1 Operand, 1 External_result, 1 Internal_result */
+
+ status = acpi_aml_exec_monadic2_r (opcode, walk_state, &result_obj);
+ if (ACPI_SUCCESS (status)) {
+ status = acpi_ds_result_stack_push (result_obj, walk_state);
+ }
+
+ break;
+
+
+ case OPTYPE_DYADIC1:
+
+ /* 2 Operands, 0 External_result, 0 Internal_result */
+
+ status = acpi_aml_exec_dyadic1 (opcode, walk_state);
+
+ break;
+
+
+ case OPTYPE_DYADIC2:
+
+ /* 2 Operands, 0 External_result, 1 Internal_result */
+
+ status = acpi_aml_exec_dyadic2 (opcode, walk_state, &result_obj);
+ if (ACPI_SUCCESS (status)) {
+ status = acpi_ds_result_stack_push (result_obj, walk_state);
+ }
+
+ break;
+
+
+ case OPTYPE_DYADIC2_r:
+
+ /* 2 Operands, 1 or 2 External_results, 1 Internal_result */
+
+
+ /* NEW INTERFACE:
+ * Pass in Walk_state, keep result obj but let interpreter
+ * push the result
+ */
+
+ status = acpi_aml_exec_dyadic2_r (opcode, walk_state, &result_obj);
+ if (ACPI_SUCCESS (status)) {
+ status = acpi_ds_result_stack_push (result_obj, walk_state);
+ }
+
+ break;
+
+
+ case OPTYPE_DYADIC2_s: /* Synchronization Operator */
+
+ /* 2 Operands, 0 External_result, 1 Internal_result */
+
+ status = acpi_aml_exec_dyadic2_s (opcode, walk_state, &result_obj);
+ if (ACPI_SUCCESS (status)) {
+ status = acpi_ds_result_stack_push (result_obj, walk_state);
+ }
+
+ break;
+
+
+ case OPTYPE_RECONFIGURATION:
+
+ /* 1 or 2 operands, 0 Internal Result */
+
+ status = acpi_aml_exec_reconfiguration (opcode, walk_state);
+ break;
+
+
+ case OPTYPE_CREATE_FIELD:
+
+ /* 3 or 4 Operands, 0 External_result, 0 Internal_result */
+
+ status = acpi_aml_exec_create_field (opcode, walk_state);
+ break;
+
+
+ case OPTYPE_FATAL:
+
+ /* 3 Operands, 0 External_result, 0 Internal_result */
+
+ status = acpi_aml_exec_fatal (walk_state);
+ break;
+
+
+ case OPTYPE_INDEX: /* Type 2 opcode with 3 operands */
+
+ /* 3 Operands, 1 External_result, 1 Internal_result */
+
+ status = acpi_aml_exec_index (walk_state, &result_obj);
+ if (ACPI_SUCCESS (status)) {
+ status = acpi_ds_result_stack_push (result_obj, walk_state);
+ }
+
+ break;
+
+
+ case OPTYPE_MATCH: /* Type 2 opcode with 6 operands */
+
+ /* 6 Operands, 0 External_result, 1 Internal_result */
+
+ status = acpi_aml_exec_match (walk_state, &result_obj);
+ if (ACPI_SUCCESS (status)) {
+ status = acpi_ds_result_stack_push (result_obj, walk_state);
+ }
+
+ break;
+ }
+
+ break;
+
+
+ case OPTYPE_CONTROL: /* Type 1 opcode, IF/ELSE/WHILE/NOOP */
+
+ /* 1 Operand, 0 External_result, 0 Internal_result */
+
+ status = acpi_ds_exec_end_control_op (walk_state, op);
+
+ break;
+
+
+ case OPTYPE_METHOD_CALL:
+
+ /*
+ * (AML_METHODCALL) Op->Value->Arg->Acpi_named_object contains
+ * the method NTE pointer
+ */
+ /* Next_op points to the op that holds the method name */
+ next_op = first_arg;
+ entry = next_op->acpi_named_object;
+
+ /* Next_op points to first argument op */
+ next_op = next_op->next;
+
+
+ /*
+ * Get the method's arguments and put them on the operand stack
+ */
+
+ status = acpi_ds_create_operands (walk_state, next_op);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ /*
+ * Since the operands will be passed to another
+ * control method, we must resolve all local
+ * references here (Local variables, arguments
+ * to *this* method, etc.)
+ */
+
+ status = acpi_ds_resolve_operands (walk_state);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ /* Open new scope on the scope stack */
+/*
+ Status = Acpi_ns_scope_stack_push_entry (Entry);
+ if (ACPI_FAILURE (Status)) {
+ break;
+ }
+*/
+
+ /* Tell the walk loop to preempt this running method and
+ execute the new method */
+
+ status = AE_CTRL_PENDING;
+
+ /* Return now; we don't want to disturb anything,
+ especially the operand count! */
+
+ return (status);
+ break;
+
+
+ case OPTYPE_NAMED_OBJECT:
+
+
+ if ((walk_state->origin->opcode == AML_METHOD_OP) &&
+ (walk_state->origin != op))
+ {
+ status = acpi_ds_load2_end_op (walk_state, op);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+ }
+
+ switch (op->opcode)
+ {
+ case AML_REGION_OP:
+
+ status = acpi_ds_eval_region_operands (walk_state, op);
+
+ break;
+
+
+ case AML_METHOD_OP:
+
+ break;
+
+
+ case AML_ALIAS_OP:
+
+ /* Alias creation was already handled by call
+ to psxload above */
+ break;
+
+
+ default:
+ /* Nothing needs to be done */
+
+ status = AE_OK;
+ break;
+ }
+
+ break;
+
+ default:
+
+ status = AE_NOT_IMPLEMENTED;
+ break;
+ }
+
+
+ /*
+ * Check if we just completed the evaluation of a
+ * conditional predicate
+ */
+
+ if ((walk_state->control_state) &&
+ (walk_state->control_state->common.state ==
+ CONTROL_PREDICATE_EXECUTING) &&
+ (walk_state->control_state->control.predicate_op == op))
+ {
+ /* Completed the predicate, the result must be a number */
+
+ walk_state->control_state->common.state = 0;
+
+ if (result_obj) {
+ status = acpi_ds_result_stack_pop (&obj_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+ }
+
+ else {
+ status = acpi_ds_create_operand (walk_state, op);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ status = acpi_aml_resolve_to_value (&walk_state->operands [0]);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ obj_desc = walk_state->operands [0];
+ }
+
+ if (!obj_desc) {
+ status = AE_AML_NO_OPERAND;
+ goto cleanup;
+ }
+
+ if (obj_desc->common.type != ACPI_TYPE_NUMBER) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+ /* Save the result of the predicate evaluation on
+ the control stack */
+
+ if (obj_desc->number.value) {
+ walk_state->control_state->common.value = TRUE;
+ }
+ else {
+ /* Predicate is FALSE, we will just toss the
+ rest of the package */
+
+ walk_state->control_state->common.value = FALSE;
+ status = AE_CTRL_FALSE;
+ }
+
+ /* Break to debugger to display result */
+
+ /* Delete the predicate result object (we know that
+ we don't need it anymore) and cleanup the stack */
+
+ acpi_cm_remove_reference (obj_desc);
+ result_obj = NULL;
+
+ walk_state->control_state->common.state = CONTROL_NORMAL;
+ }
+
+
+cleanup:
+
+ if (result_obj) {
+ /* Break to debugger to display result */
+
+ /*
+ * Delete the result op if and only if:
+ * Parent will not use the result -- such as any
+ * non-nested type2 op in a method (parent will be method)
+ */
+ acpi_ds_delete_result_if_not_used (op, result_obj, walk_state);
+ }
+
+ /* Always clear the object stack */
+
+ /* TBD: [Investigate] Clear stack of return value,
+ but don't delete it */
+ walk_state->num_operands = 0;
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
new file mode 100644
index 000000000..bfb54593f
--- /dev/null
+++ b/drivers/acpi/dispatcher/dswload.c
@@ -0,0 +1,600 @@
+
+/******************************************************************************
+ *
+ * Module Name: dswload - Dispatcher namespace load callbacks
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "amlcode.h"
+#include "dispatch.h"
+#include "interp.h"
+#include "namesp.h"
+#include "events.h"
+
+
+#define _COMPONENT DISPATCHER
+ MODULE_NAME ("dswload");
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_load1_begin_op
+ *
+ * PARAMETERS: Walk_state - Current state of the parse tree walk
+ * Op - Op that has been just been reached in the
+ * walk; Arguments have not been evaluated yet.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Descending callback used during the loading of ACPI tables.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_load1_begin_op (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op)
+{
+ ACPI_NAMED_OBJECT *new_entry;
+ ACPI_STATUS status;
+ OBJECT_TYPE_INTERNAL data_type;
+
+
+ /* We are only interested in opcodes that have an associated name */
+
+ if (!acpi_ps_is_named_op (op->opcode)) {
+ return AE_OK;
+ }
+
+
+ /* Check if this object has already been installed in the namespace */
+
+ if (op->acpi_named_object) {
+ return AE_OK;
+ }
+
+ /* Map the raw opcode into an internal object type */
+
+ data_type = acpi_ds_map_named_opcode_to_data_type (op->opcode);
+
+ /* Attempt to type a NAME opcode by examining the argument */
+
+ /* TBD: [Investigate] is this the right place to do this? */
+
+ if (op->opcode == AML_NAME_OP) {
+ if (op->value.arg) {
+
+ data_type = acpi_ds_map_opcode_to_data_type ((op->value.arg)->opcode,
+ NULL);
+ }
+ }
+
+
+ /*
+ * Enter the named type into the internal namespace. We enter the name
+ * as we go downward in the parse tree. Any necessary subobjects that involve
+ * arguments to the opcode must be created as we go back up the parse tree later.
+ */
+ status = acpi_ns_lookup (walk_state->scope_info,
+ (char *) &((ACPI_NAMED_OP *)op)->name,
+ data_type, IMODE_LOAD_PASS1,
+ NS_NO_UPSEARCH, walk_state, &(new_entry));
+
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * Put the NTE in the "op" object that the parser uses, so we
+ * can get it again quickly when this scope is closed
+ */
+ op->acpi_named_object = new_entry;
+ }
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_load1_end_op
+ *
+ * PARAMETERS: Walk_state - Current state of the parse tree walk
+ * Op - Op that has been just been completed in the
+ * walk; Arguments have now been evaluated.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Ascending callback used during the loading of the namespace,
+ * both control methods and everything else.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_load1_end_op (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op)
+{
+ OBJECT_TYPE_INTERNAL data_type;
+
+
+ /* We are only interested in opcodes that have an associated name */
+
+ if (!acpi_ps_is_named_op (op->opcode)) {
+ return AE_OK;
+ }
+
+ /* TBD: [Investigate] can this be removed? */
+
+ if (op->opcode == AML_SCOPE_OP) {
+ if (((ACPI_NAMED_OP *)op)->name == -1) {
+ return AE_OK;
+ }
+ }
+
+
+ data_type = acpi_ds_map_named_opcode_to_data_type (op->opcode);
+
+ /* Pop the scope stack */
+
+ if (acpi_ns_opens_scope (data_type)) {
+
+ acpi_ds_scope_stack_pop (walk_state);
+ }
+
+ return AE_OK;
+
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_load2_begin_op
+ *
+ * PARAMETERS: Walk_state - Current state of the parse tree walk
+ * Op - Op that has been just been reached in the
+ * walk; Arguments have not been evaluated yet.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Descending callback used during the loading of ACPI tables.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_load2_begin_op (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op)
+{
+ ACPI_NAMED_OBJECT *new_entry;
+ ACPI_STATUS status;
+ OBJECT_TYPE_INTERNAL data_type;
+ char *buffer_ptr;
+ void *original = NULL;
+
+
+ /* We only care about Namespace opcodes here */
+
+ if (!acpi_ps_is_namespace_op (op->opcode) &&
+ op->opcode != AML_NAMEPATH_OP)
+ {
+ return AE_OK;
+ }
+
+
+ /*
+ * Get the name we are going to enter or lookup in the namespace
+ */
+ if (op->opcode == AML_NAMEPATH_OP) {
+ /* For Namepath op , get the path string */
+
+ buffer_ptr = op->value.string;
+ if (!buffer_ptr) {
+ /* No name, just exit */
+
+ return AE_OK;
+ }
+ }
+
+ else {
+ /* Get name from the op */
+
+ buffer_ptr = (char *) &((ACPI_NAMED_OP *)op)->name;
+ }
+
+
+ /* Map the raw opcode into an internal object type */
+
+ data_type = acpi_ds_map_named_opcode_to_data_type (op->opcode);
+
+
+ if (op->opcode == AML_DEF_FIELD_OP ||
+ op->opcode == AML_BANK_FIELD_OP ||
+ op->opcode == AML_INDEX_FIELD_OP)
+ {
+ new_entry = NULL;
+ status = AE_OK;
+ }
+
+ else if (op->opcode == AML_NAMEPATH_OP) {
+ /*
+ * The Name_path is an object reference to an existing object. Don't enter the
+ * name into the namespace, but look it up for use later
+ */
+ status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr,
+ data_type, IMODE_EXECUTE,
+ NS_SEARCH_PARENT, walk_state,
+ &(new_entry));
+ }
+
+ else {
+ if (op->acpi_named_object) {
+ original = op->acpi_named_object;
+ new_entry = op->acpi_named_object;
+
+ if (acpi_ns_opens_scope (data_type)) {
+ status = acpi_ds_scope_stack_push (new_entry->child_table,
+ data_type,
+ walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ }
+ return AE_OK;
+ }
+
+ /*
+ * Enter the named type into the internal namespace. We enter the name
+ * as we go downward in the parse tree. Any necessary subobjects that involve
+ * arguments to the opcode must be created as we go back up the parse tree later.
+ */
+ status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr,
+ data_type, IMODE_EXECUTE,
+ NS_NO_UPSEARCH, walk_state,
+ &(new_entry));
+ }
+
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * Put the NTE in the "op" object that the parser uses, so we
+ * can get it again quickly when this scope is closed
+ */
+ op->acpi_named_object = new_entry;
+
+ }
+
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_load2_end_op
+ *
+ * PARAMETERS: Walk_state - Current state of the parse tree walk
+ * Op - Op that has been just been completed in the
+ * walk; Arguments have now been evaluated.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Ascending callback used during the loading of the namespace,
+ * both control methods and everything else.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_load2_end_op (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op)
+{
+ ACPI_STATUS status = AE_OK;
+ OBJECT_TYPE_INTERNAL data_type;
+ ACPI_NAMED_OBJECT *entry;
+ ACPI_GENERIC_OP *arg;
+ ACPI_NAMED_OBJECT *new_entry;
+
+
+ if (!acpi_ps_is_namespace_object_op (op->opcode)) {
+ return AE_OK;
+ }
+
+ if (op->opcode == AML_SCOPE_OP) {
+ if (((ACPI_NAMED_OP *)op)->name == -1) {
+ return AE_OK;
+ }
+ }
+
+
+ data_type = acpi_ds_map_named_opcode_to_data_type (op->opcode);
+
+ /*
+ * Get the NTE/name from the earlier lookup
+ * (It was saved in the *op structure)
+ */
+ entry = op->acpi_named_object;
+
+ /*
+ * Put the NTE on the object stack (Contains the ACPI Name of
+ * this object)
+ */
+
+ walk_state->operands[0] = (void *) entry;
+ walk_state->num_operands = 1;
+
+ /* Pop the scope stack */
+
+ if (acpi_ns_opens_scope (data_type)) {
+
+ acpi_ds_scope_stack_pop (walk_state);
+ }
+
+
+ /*
+ * Named operations are as follows:
+ *
+ * AML_SCOPE
+ * AML_DEVICE
+ * AML_THERMALZONE
+ * AML_METHOD
+ * AML_POWERRES
+ * AML_PROCESSOR
+ * AML_FIELD
+ * AML_INDEXFIELD
+ * AML_BANKFIELD
+ * AML_NAMEDFIELD
+ * AML_NAME
+ * AML_ALIAS
+ * AML_MUTEX
+ * AML_EVENT
+ * AML_OPREGION
+ * AML_CREATEFIELD
+ * AML_CREATEBITFIELD
+ * AML_CREATEBYTEFIELD
+ * AML_CREATEWORDFIELD
+ * AML_CREATEDWORDFIELD
+ * AML_METHODCALL
+ */
+
+
+ /* Decode the opcode */
+
+ arg = op->value.arg;
+
+ switch (op->opcode)
+ {
+
+ case AML_CREATE_FIELD_OP:
+ case AML_BIT_FIELD_OP:
+ case AML_BYTE_FIELD_OP:
+ case AML_WORD_FIELD_OP:
+ case AML_DWORD_FIELD_OP:
+
+ /* Get the Name_string argument */
+
+ if (op->opcode == AML_CREATE_FIELD_OP) {
+ arg = acpi_ps_get_arg (op, 3);
+ }
+ else {
+ /* Create Bit/Byte/Word/Dword field */
+
+ arg = acpi_ps_get_arg (op, 2);
+ }
+
+ /*
+ * Enter the Name_string into the namespace
+ */
+
+ status = acpi_ns_lookup (walk_state->scope_info,
+ arg->value.string,
+ INTERNAL_TYPE_DEF_ANY,
+ IMODE_LOAD_PASS1,
+ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE,
+ walk_state, &(new_entry));
+
+ if (ACPI_SUCCESS (status)) {
+ /* We could put the returned object (NTE) on the object stack for later, but
+ * for now, we will put it in the "op" object that the parser uses, so we
+ * can get it again at the end of this scope
+ */
+ op->acpi_named_object = new_entry;
+ }
+
+ break;
+
+
+ case AML_METHODCALL_OP:
+
+ /*
+ * Lookup the method name and save the NTE
+ */
+
+ status = acpi_ns_lookup (walk_state->scope_info, arg->value.string,
+ ACPI_TYPE_ANY, IMODE_LOAD_PASS2,
+ NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE,
+ walk_state, &(new_entry));
+
+ if (ACPI_SUCCESS (status)) {
+
+/* has name already been resolved by here ??*/
+
+ /* TBD: [Restructure] Make sure that what we found is indeed a method! */
+ /* We didn't search for a method on purpose, to see if the name would resolve! */
+
+ /* We could put the returned object (NTE) on the object stack for later, but
+ * for now, we will put it in the "op" object that the parser uses, so we
+ * can get it again at the end of this scope
+ */
+ op->acpi_named_object = new_entry;
+ }
+
+
+ break;
+
+
+ case AML_PROCESSOR_OP:
+
+ /* Nothing to do other than enter object into namespace */
+
+ status = acpi_aml_exec_create_processor (op, (ACPI_HANDLE) entry);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ break;
+
+
+ case AML_POWER_RES_OP:
+
+ /* Nothing to do other than enter object into namespace */
+
+ status = acpi_aml_exec_create_power_resource (op, (ACPI_HANDLE) entry);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ break;
+
+
+ case AML_THERMAL_ZONE_OP:
+
+ /* Nothing to do other than enter object into namespace */
+
+ break;
+
+
+ case AML_DEF_FIELD_OP:
+
+ arg = op->value.arg;
+
+ status = acpi_ds_create_field (op,
+ (ACPI_HANDLE) arg->acpi_named_object,
+ walk_state);
+ break;
+
+
+ case AML_INDEX_FIELD_OP:
+
+ arg = op->value.arg;
+
+ status = acpi_ds_create_index_field (op,
+ (ACPI_HANDLE) arg->acpi_named_object,
+ walk_state);
+ break;
+
+
+ case AML_BANK_FIELD_OP:
+
+ arg = op->value.arg;
+ status = acpi_ds_create_bank_field (op,
+ (ACPI_HANDLE) arg->acpi_named_object,
+ walk_state);
+ break;
+
+
+ /*
+ * Method_op Pkg_length Names_string Method_flags Term_list
+ */
+ case AML_METHOD_OP:
+
+ if (!entry->object) {
+ status = acpi_aml_exec_create_method (((ACPI_DEFERRED_OP *) op)->body,
+ ((ACPI_DEFERRED_OP *) op)->body_length,
+ arg->value.integer, (ACPI_HANDLE) entry);
+ }
+
+ break;
+
+
+ case AML_MUTEX_OP:
+
+ status = acpi_ds_create_operands (walk_state, arg);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ status = acpi_aml_exec_create_mutex (walk_state);
+ break;
+
+
+ case AML_EVENT_OP:
+
+ status = acpi_ds_create_operands (walk_state, arg);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ status = acpi_aml_exec_create_event (walk_state);
+ break;
+
+
+ case AML_REGION_OP:
+
+
+ /*
+ * The Op_region is not fully parsed at this time. Only valid argument is the Space_id.
+ * (We must save the address of the AML of the address and length operands)
+ */
+
+ status = acpi_aml_exec_create_region (((ACPI_DEFERRED_OP *) op)->body,
+ ((ACPI_DEFERRED_OP *) op)->body_length,
+ arg->value.integer, walk_state);
+
+ break;
+
+
+ /* Namespace Modifier Opcodes */
+
+ case AML_ALIAS_OP:
+
+ status = acpi_ds_create_operands (walk_state, arg);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ status = acpi_aml_exec_create_alias (walk_state);
+ break;
+
+
+ case AML_NAME_OP:
+
+ status = acpi_ds_create_named_object (walk_state, entry, op);
+
+ break;
+
+
+ case AML_NAMEPATH_OP:
+
+ break;
+
+
+ default:
+ break;
+ }
+
+
+cleanup:
+ /* Remove the NTE pushed at the very beginning */
+ acpi_ds_obj_stack_pop (1, walk_state);
+ return (status);
+}
+
diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c
new file mode 100644
index 000000000..9deb499f2
--- /dev/null
+++ b/drivers/acpi/dispatcher/dswscope.c
@@ -0,0 +1,161 @@
+
+/******************************************************************************
+ *
+ * Module Name: dswscope - Scope stack manipulation
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "interp.h"
+#include "dispatch.h"
+
+
+#define _COMPONENT NAMESPACE
+ MODULE_NAME ("dswscope");
+
+
+#define STACK_POP(head) head
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_scope_stack_clear
+ *
+ * PARAMETERS: None
+ *
+ * DESCRIPTION: Pop (and free) everything on the scope stack except the
+ * root scope object (which remains at the stack top.)
+ *
+ ***************************************************************************/
+
+void
+acpi_ds_scope_stack_clear (
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_GENERIC_STATE *scope_info;
+
+
+ while (walk_state->scope_info) {
+ /* Pop a scope off the stack */
+
+ scope_info = walk_state->scope_info;
+ walk_state->scope_info = scope_info->scope.next;
+
+ acpi_cm_delete_generic_state (scope_info);
+ }
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_scope_stack_push
+ *
+ * PARAMETERS: *New_scope, - Name to be made current
+ * Type, - Type of frame being pushed
+ *
+ * DESCRIPTION: Push the current scope on the scope stack, and make the
+ * passed nte current.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ds_scope_stack_push (
+ ACPI_NAME_TABLE *new_scope,
+ OBJECT_TYPE_INTERNAL type,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_GENERIC_STATE *scope_info;
+
+
+ if (!new_scope) {
+ /* invalid scope */
+
+ REPORT_ERROR ("Ds_scope_stack_push: null scope passed");
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Make sure object type is valid */
+
+ if (!acpi_aml_validate_object_type (type)) {
+ REPORT_WARNING ("Ds_scope_stack_push: type code out of range");
+ }
+
+
+ /* Allocate a new scope object */
+
+ scope_info = acpi_cm_create_generic_state ();
+ if (!scope_info) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Init new scope object */
+
+ scope_info->scope.name_table = new_scope;
+ scope_info->common.value = (u16) type;
+
+ /* Push new scope object onto stack */
+
+ acpi_cm_push_generic_state (&walk_state->scope_info, scope_info);
+
+ return (AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_scope_stack_pop
+ *
+ * PARAMETERS: Type - The type of frame to be found
+ *
+ * DESCRIPTION: Pop the scope stack until a frame of the requested type
+ * is found.
+ *
+ * RETURN: Count of frames popped. If no frame of the requested type
+ * was found, the count is returned as a negative number and
+ * the scope stack is emptied (which sets the current scope
+ * to the root). If the scope stack was empty at entry, the
+ * function is a no-op and returns 0.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ds_scope_stack_pop (
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_GENERIC_STATE *scope_info;
+
+
+ /*
+ * Pop scope info object off the stack.
+ */
+
+ scope_info = acpi_cm_pop_generic_state (&walk_state->scope_info);
+ if (!scope_info) {
+ return (AE_STACK_UNDERFLOW);
+ }
+
+ acpi_cm_delete_generic_state (scope_info);
+
+ return (AE_OK);
+}
+
+
diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c
new file mode 100644
index 000000000..e98f4e36c
--- /dev/null
+++ b/drivers/acpi/dispatcher/dswstate.c
@@ -0,0 +1,648 @@
+/******************************************************************************
+ *
+ * Module Name: dswstate - Dispatcher parse tree walk management routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "amlcode.h"
+#include "parser.h"
+#include "dispatch.h"
+#include "namesp.h"
+#include "interp.h"
+
+#define _COMPONENT DISPATCHER
+ MODULE_NAME ("dswstate");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_result_stack_clear
+ *
+ * PARAMETERS: Walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Reset this walk's result stack pointers to zero, thus setting
+ * the stack to zero.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_result_stack_clear (
+ ACPI_WALK_STATE *walk_state)
+{
+
+ walk_state->num_results = 0;
+ walk_state->current_result = 0;
+
+ return AE_OK;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_result_stack_push
+ *
+ * PARAMETERS: Object - Object to push
+ * Walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Push an object onto this walk's result stack
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_result_stack_push (
+ void *object,
+ ACPI_WALK_STATE *walk_state)
+{
+
+
+ if (walk_state->num_results >= OBJ_NUM_OPERANDS) {
+ return AE_STACK_OVERFLOW;
+ }
+
+ walk_state->results [walk_state->num_results] = object;
+ walk_state->num_results++;
+
+ return AE_OK;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_result_stack_pop
+ *
+ * PARAMETERS: Object - Where to return the popped object
+ * Walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In
+ * other words, this is a FIFO.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_result_stack_pop (
+ ACPI_OBJECT_INTERNAL **object,
+ ACPI_WALK_STATE *walk_state)
+{
+
+
+ /* Check for stack underflow */
+
+ if (walk_state->num_results == 0) {
+ return AE_AML_NO_OPERAND;
+ }
+
+
+ /* Pop the stack */
+
+ walk_state->num_results--;
+
+ /* Check for a valid result object */
+
+ if (!walk_state->results [walk_state->num_results]) {
+ return AE_AML_NO_OPERAND;
+ }
+
+ *object = walk_state->results [walk_state->num_results];
+ walk_state->results [walk_state->num_results] = NULL;
+
+ return AE_OK;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_obj_stack_delete_all
+ *
+ * PARAMETERS: Walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Clear the object stack by deleting all objects that are on it.
+ * Should be used with great care, if at all!
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_obj_stack_delete_all (
+ ACPI_WALK_STATE *walk_state)
+{
+ u32 i;
+
+
+ /* The stack size is configurable, but fixed */
+
+ for (i = 0; i < OBJ_NUM_OPERANDS; i++) {
+ if (walk_state->operands[i]) {
+ acpi_cm_remove_reference (walk_state->operands[i]);
+ walk_state->operands[i] = NULL;
+ }
+ }
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_obj_stack_push
+ *
+ * PARAMETERS: Object - Object to push
+ * Walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Push an object onto this walk's object/operand stack
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_obj_stack_push (
+ void *object,
+ ACPI_WALK_STATE *walk_state)
+{
+
+
+ /* Check for stack overflow */
+
+ if (walk_state->num_operands >= OBJ_NUM_OPERANDS) {
+ return AE_STACK_OVERFLOW;
+ }
+
+ /* Put the object onto the stack */
+
+ walk_state->operands [walk_state->num_operands] = object;
+ walk_state->num_operands++;
+
+ return AE_OK;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_obj_stack_pop_object
+ *
+ * PARAMETERS: Pop_count - Number of objects/entries to pop
+ * Walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT
+ * deleted by this routine.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_obj_stack_pop_object (
+ ACPI_OBJECT_INTERNAL **object,
+ ACPI_WALK_STATE *walk_state)
+{
+
+
+ /* Check for stack underflow */
+
+ if (walk_state->num_operands == 0) {
+ return AE_AML_NO_OPERAND;
+ }
+
+
+ /* Pop the stack */
+
+ walk_state->num_operands--;
+
+ /* Check for a valid operand */
+
+ if (!walk_state->operands [walk_state->num_operands]) {
+ return AE_AML_NO_OPERAND;
+ }
+
+ /* Get operand and set stack entry to null */
+
+ *object = walk_state->operands [walk_state->num_operands];
+ walk_state->operands [walk_state->num_operands] = NULL;
+
+ return AE_OK;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_obj_stack_pop
+ *
+ * PARAMETERS: Pop_count - Number of objects/entries to pop
+ * Walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT
+ * deleted by this routine.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_obj_stack_pop (
+ u32 pop_count,
+ ACPI_WALK_STATE *walk_state)
+{
+ u32 i;
+
+
+ for (i = 0; i < pop_count; i++) {
+ /* Check for stack underflow */
+
+ if (walk_state->num_operands == 0) {
+ return AE_STACK_UNDERFLOW;
+ }
+
+ /* Just set the stack entry to null */
+
+ walk_state->num_operands--;
+ walk_state->operands [walk_state->num_operands] = NULL;
+ }
+
+ return AE_OK;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_obj_stack_pop_and_delete
+ *
+ * PARAMETERS: Pop_count - Number of objects/entries to pop
+ * Walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop this walk's object stack and delete each object that is
+ * popped off.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_obj_stack_pop_and_delete (
+ u32 pop_count,
+ ACPI_WALK_STATE *walk_state)
+{
+ u32 i;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+
+
+ for (i = 0; i < pop_count; i++) {
+ /* Check for stack underflow */
+
+ if (walk_state->num_operands == 0) {
+ return AE_STACK_UNDERFLOW;
+ }
+
+ /* Pop the stack and delete an object if present in this stack entry */
+
+ walk_state->num_operands--;
+ obj_desc = walk_state->operands [walk_state->num_operands];
+ if (obj_desc) {
+ acpi_cm_remove_reference (walk_state->operands [walk_state->num_operands]);
+ walk_state->operands [walk_state->num_operands] = NULL;
+ }
+ }
+
+ return AE_OK;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_obj_stack_get_value
+ *
+ * PARAMETERS: Index - Stack index whose value is desired. Based
+ * on the top of the stack (index=0 == top)
+ * Walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieve an object from this walk's object stack. Index must
+ * be within the range of the current stack pointer.
+ *
+ ******************************************************************************/
+
+void *
+acpi_ds_obj_stack_get_value (
+ u32 index,
+ ACPI_WALK_STATE *walk_state)
+{
+
+
+ /* Can't do it if the stack is empty */
+
+ if (walk_state->num_operands == 0) {
+ return (NULL);
+ }
+
+ /* or if the index is past the top of the stack */
+
+ if (index > (walk_state->num_operands - (u32) 1)) {
+ return (NULL);
+ }
+
+
+ return (walk_state->operands[(NATIVE_UINT)(walk_state->num_operands - 1) -
+ index]);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_get_current_walk_state
+ *
+ * PARAMETERS: Walk_list - Get current active state for this walk list
+ *
+ * RETURN: Pointer to the current walk state
+ *
+ * DESCRIPTION: Get the walk state that is at the head of the list (the "current"
+ * walk state.
+ *
+ ******************************************************************************/
+
+ACPI_WALK_STATE *
+acpi_ds_get_current_walk_state (
+ ACPI_WALK_LIST *walk_list)
+
+{
+
+ if (!walk_list) {
+ return NULL;
+ }
+
+ return walk_list->walk_state;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_push_walk_state
+ *
+ * PARAMETERS: Walk_state - State to push
+ * Walk_list - The list that owns the walk stack
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Place the Walk_state at the head of the state list.
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_push_walk_state (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_WALK_LIST *walk_list)
+{
+
+
+ walk_state->next = walk_list->walk_state;
+ walk_list->walk_state = walk_state;
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_pop_walk_state
+ *
+ * PARAMETERS: Walk_list - The list that owns the walk stack
+ *
+ * RETURN: A Walk_state object popped from the stack
+ *
+ * DESCRIPTION: Remove and return the walkstate object that is at the head of
+ * the walk stack for the given walk list. NULL indicates that
+ * the list is empty.
+ *
+ ******************************************************************************/
+
+ACPI_WALK_STATE *
+acpi_ds_pop_walk_state (
+ ACPI_WALK_LIST *walk_list)
+{
+ ACPI_WALK_STATE *walk_state;
+
+
+ walk_state = walk_list->walk_state;
+
+ if (walk_state) {
+ /* Next walk state becomes the current walk state */
+
+ walk_list->walk_state = walk_state->next;
+
+ /*
+ * Don't clear the NEXT field, this serves as an indicator
+ * that there is a parent WALK STATE
+ * Walk_state->Next = NULL;
+ */
+ }
+
+ return (walk_state);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_create_walk_state
+ *
+ * PARAMETERS: Origin - Starting point for this walk
+ * Walk_list - Owning walk list
+ *
+ * RETURN: Pointer to the new walk state.
+ *
+ * DESCRIPTION: Allocate and initialize a new walk state. The current walk state
+ * is set to this new state.
+ *
+ ******************************************************************************/
+
+ACPI_WALK_STATE *
+acpi_ds_create_walk_state (
+ ACPI_OWNER_ID owner_id,
+ ACPI_GENERIC_OP *origin,
+ ACPI_OBJECT_INTERNAL *mth_desc,
+ ACPI_WALK_LIST *walk_list)
+{
+ ACPI_WALK_STATE *walk_state;
+
+
+ acpi_cm_acquire_mutex (ACPI_MTX_CACHES);
+ acpi_gbl_walk_state_cache_requests++;
+
+ /* Check the cache first */
+
+ if (acpi_gbl_walk_state_cache) {
+ /* There is an object available, use it */
+
+ walk_state = acpi_gbl_walk_state_cache;
+ acpi_gbl_walk_state_cache = walk_state->next;
+
+ acpi_gbl_walk_state_cache_hits++;
+ acpi_gbl_walk_state_cache_depth--;
+
+ acpi_cm_release_mutex (ACPI_MTX_CACHES);
+ }
+
+ else {
+ /* The cache is empty, create a new object */
+
+ /* Avoid deadlock with Acpi_cm_callocate */
+ acpi_cm_release_mutex (ACPI_MTX_CACHES);
+
+ walk_state = acpi_cm_callocate (sizeof (ACPI_WALK_STATE));
+ if (!walk_state) {
+ return (NULL);
+ }
+ }
+
+ walk_state->data_type = ACPI_DESC_TYPE_WALK;
+ walk_state->owner_id = owner_id;
+ walk_state->origin = origin;
+ walk_state->method_desc = mth_desc;
+
+ /* Init the method args/local */
+
+ acpi_ds_method_data_init (walk_state);
+
+ /* Put the new state at the head of the walk list */
+
+ acpi_ds_push_walk_state (walk_state, walk_list);
+
+ return (walk_state);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_delete_walk_state
+ *
+ * PARAMETERS: Walk_state - State to delete
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Delete a walk state including all internal data structures
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_delete_walk_state (
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_GENERIC_STATE *state;
+
+
+ if (!walk_state) {
+ return;
+ }
+
+ if (walk_state->data_type != ACPI_DESC_TYPE_WALK) {
+ return;
+ }
+
+ /* Always must free any linked control states */
+
+ while (walk_state->control_state) {
+ state = walk_state->control_state;
+ walk_state->control_state = state->common.next;
+
+ acpi_cm_delete_generic_state (state);
+ }
+
+
+ /* Always must free any linked parse states */
+
+ while (walk_state->scope_info) {
+ state = walk_state->scope_info;
+ walk_state->scope_info = state->common.next;
+
+ acpi_cm_delete_generic_state (state);
+ }
+
+ /* If walk cache is full, just free this wallkstate object */
+
+ if (acpi_gbl_walk_state_cache_depth >= MAX_WALK_CACHE_DEPTH) {
+ acpi_cm_free (walk_state);
+ }
+
+ /* Otherwise put this object back into the cache */
+
+ else {
+ acpi_cm_acquire_mutex (ACPI_MTX_CACHES);
+
+ /* Clear the state */
+
+ MEMSET (walk_state, 0, sizeof (ACPI_WALK_STATE));
+ walk_state->data_type = ACPI_DESC_TYPE_WALK;
+
+ /* Put the object at the head of the global cache list */
+
+ walk_state->next = acpi_gbl_walk_state_cache;
+ acpi_gbl_walk_state_cache = walk_state;
+ acpi_gbl_walk_state_cache_depth++;
+
+
+ acpi_cm_release_mutex (ACPI_MTX_CACHES);
+ }
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_delete_walk_state_cache
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Purge the global state object cache. Used during subsystem
+ * termination.
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_delete_walk_state_cache (
+ void)
+{
+ ACPI_WALK_STATE *next;
+
+
+ /* Traverse the global cache list */
+
+ while (acpi_gbl_walk_state_cache) {
+ /* Delete one cached state object */
+
+ next = acpi_gbl_walk_state_cache->next;
+ acpi_cm_free (acpi_gbl_walk_state_cache);
+ acpi_gbl_walk_state_cache = next;
+ }
+
+ return;
+}
+
+
diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
new file mode 100644
index 000000000..d3ad64408
--- /dev/null
+++ b/drivers/acpi/events/evevent.c
@@ -0,0 +1,679 @@
+/******************************************************************************
+ *
+ * Module Name: evevent - Fixed and General Purpose Acpi_event
+ * handling and dispatch
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "hardware.h"
+#include "events.h"
+#include "namesp.h"
+#include "common.h"
+
+#define _COMPONENT EVENT_HANDLING
+ MODULE_NAME ("evevent");
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_fixed_event_initialize
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize the Fixed Acpi_event data structures
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ev_fixed_event_initialize(void)
+{
+ int i = 0;
+
+ /* Initialize the structure that keeps track of fixed event handlers */
+
+ for (i = 0; i < NUM_FIXED_EVENTS; i++) {
+ acpi_gbl_fixed_event_handlers[i].handler = NULL;
+ acpi_gbl_fixed_event_handlers[i].context = NULL;
+ }
+
+ acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_LOCK, ACPI_EVENT_PMTIMER +
+ TMR_EN, 0);
+ acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_LOCK, ACPI_EVENT_GLOBAL +
+ TMR_EN, 0);
+ acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_LOCK, ACPI_EVENT_POWER_BUTTON +
+ TMR_EN, 0);
+ acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_LOCK, ACPI_EVENT_SLEEP_BUTTON +
+ TMR_EN, 0);
+ acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_LOCK, ACPI_EVENT_RTC +
+ TMR_EN, 0);
+
+ return AE_OK;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_fixed_event_detect
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
+ *
+ * DESCRIPTION: Checks the PM status register for fixed events
+ *
+ ******************************************************************************/
+
+u32
+acpi_ev_fixed_event_detect(void)
+{
+ u32 int_status = INTERRUPT_NOT_HANDLED;
+ u32 status_register = 0;
+ u32 enable_register = 0;
+
+ /*
+ * Read the fixed feature status and enable registers, as all the cases
+ * depend on their values.
+ */
+
+ status_register = (u32) acpi_os_in16 (acpi_gbl_FACP->pm1a_evt_blk);
+ if (acpi_gbl_FACP->pm1b_evt_blk) {
+ status_register |= (u32) acpi_os_in16 (acpi_gbl_FACP->pm1b_evt_blk);
+ }
+
+ enable_register = (u32) acpi_os_in16 (acpi_gbl_FACP->pm1a_evt_blk +
+ DIV_2 (acpi_gbl_FACP->pm1_evt_len));
+ if (acpi_gbl_FACP->pm1b_evt_blk) {
+ enable_register |= (u32) acpi_os_in16 (acpi_gbl_FACP->pm1b_evt_blk +
+ DIV_2 (acpi_gbl_FACP->pm1_evt_len));
+ }
+
+ /* power management timer roll over */
+
+ if ((status_register & ACPI_STATUS_PMTIMER) &&
+ (enable_register & ACPI_ENABLE_PMTIMER))
+ {
+ int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_PMTIMER);
+ }
+
+ /* global event (BIOS want's the global lock) */
+
+ if ((status_register & ACPI_STATUS_GLOBAL) &&
+ (enable_register & ACPI_ENABLE_GLOBAL))
+ {
+ int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_GLOBAL);
+ }
+
+ /* power button event */
+
+ if ((status_register & ACPI_STATUS_POWER_BUTTON) &&
+ (enable_register & ACPI_ENABLE_POWER_BUTTON))
+ {
+ int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_POWER_BUTTON);
+ }
+
+ /* sleep button event */
+
+ if ((status_register & ACPI_STATUS_SLEEP_BUTTON) &&
+ (enable_register & ACPI_ENABLE_SLEEP_BUTTON))
+ {
+ int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_SLEEP_BUTTON);
+ }
+
+ return int_status;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_fixed_event_dispatch
+ *
+ * PARAMETERS: Event - Event type
+ *
+ * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
+ *
+ * DESCRIPTION: Clears the status bit for the requested event, calls the
+ * handler that previously registered for the event.
+ *
+ ******************************************************************************/
+
+u32
+acpi_ev_fixed_event_dispatch (
+ u32 event)
+{
+ /* Clear the status bit */
+
+ acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, (s32)TMR_STS +
+ event, 1);
+
+ /*
+ * Make sure we've got a handler. If not, report an error.
+ * The event is disabled to prevent further interrupts.
+ */
+ if (NULL == acpi_gbl_fixed_event_handlers[event].handler) {
+ acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK,
+ TMR_EN + event, 0);
+
+ REPORT_ERROR("No installed handler for fixed event.");
+ return INTERRUPT_NOT_HANDLED;
+ }
+
+ /* Invoke the handler */
+
+ return (acpi_gbl_fixed_event_handlers[event].handler)(
+ acpi_gbl_fixed_event_handlers[event].context);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_gpe_initialize
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize the GPE data structures
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ev_gpe_initialize (void)
+{
+ u32 i;
+ u32 j;
+ u32 register_index;
+ u32 gpe_number;
+ u16 gpe0register_count;
+ u16 gpe1_register_count;
+
+
+ /*
+ * Setup various GPE counts
+ */
+
+ gpe0register_count = (u16) DIV_2 (acpi_gbl_FACP->gpe0blk_len);
+ gpe1_register_count = (u16) DIV_2 (acpi_gbl_FACP->gpe1_blk_len);
+ acpi_gbl_gpe_register_count = gpe0register_count + gpe1_register_count;
+
+ /*
+ * Allocate the Gpe information block
+ */
+
+ acpi_gbl_gpe_registers = acpi_cm_callocate (acpi_gbl_gpe_register_count *
+ sizeof (ACPI_GPE_REGISTERS));
+ if (!acpi_gbl_gpe_registers) {
+ return (AE_NO_MEMORY);
+ }
+
+ /*
+ * Allocate the Gpe dispatch handler block
+ * There are eight distinct GP events per register.
+ * Initialization to zeros is sufficient
+ */
+
+ acpi_gbl_gpe_info = acpi_cm_callocate (MUL_8 (acpi_gbl_gpe_register_count) *
+ sizeof (ACPI_GPE_LEVEL_INFO));
+ if (!acpi_gbl_gpe_info) {
+ acpi_cm_free (acpi_gbl_gpe_registers);
+ return (AE_NO_MEMORY);
+ }
+
+ /* Set the Gpe validation table to GPE_INVALID */
+
+ MEMSET (acpi_gbl_gpe_valid, (int) ACPI_GPE_INVALID, NUM_GPE);
+
+ /*
+ * Initialize the Gpe information and validation blocks. A goal of these
+ * blocks is to hide the fact that there are two separate GPE register sets
+ * In a given block, the status registers occupy the first half, and
+ * the enable registers occupy the second half.
+ */
+
+ /* GPE Block 0 */
+
+ register_index = 0;
+
+ for (i = 0; i < gpe0register_count; i++) {
+ acpi_gbl_gpe_registers[register_index].status_addr =
+ (u16) (acpi_gbl_FACP->gpe0blk + i);
+
+ acpi_gbl_gpe_registers[register_index].enable_addr =
+ (u16) (acpi_gbl_FACP->gpe0blk + i + gpe0register_count);
+
+ acpi_gbl_gpe_registers[register_index].gpe_base = (u8) MUL_8 (i);
+
+ for (j = 0; j < 8; j++) {
+ gpe_number = acpi_gbl_gpe_registers[register_index].gpe_base + j;
+ acpi_gbl_gpe_valid[gpe_number] = (u8) register_index;
+ }
+
+ /*
+ * Clear the status/enable registers. Note that status registers
+ * are cleared by writing a '1', while enable registers are cleared
+ * by writing a '0'.
+ */
+ acpi_os_out8 (acpi_gbl_gpe_registers[register_index].enable_addr, 0x00);
+ acpi_os_out8 (acpi_gbl_gpe_registers[register_index].status_addr, 0xFF);
+
+ register_index++;
+ }
+
+ /* GPE Block 1 */
+
+ for (i = 0; i < gpe1_register_count; i++) {
+ acpi_gbl_gpe_registers[register_index].status_addr =
+ (u16) (acpi_gbl_FACP->gpe1_blk + i);
+
+ acpi_gbl_gpe_registers[register_index].enable_addr =
+ (u16) (acpi_gbl_FACP->gpe1_blk + i + gpe1_register_count);
+
+ acpi_gbl_gpe_registers[register_index].gpe_base =
+ (u8) (acpi_gbl_FACP->gpe1_base + MUL_8 (i));
+
+ for (j = 0; j < 8; j++) {
+ gpe_number = acpi_gbl_gpe_registers[register_index].gpe_base + j;
+ acpi_gbl_gpe_valid[gpe_number] = (u8) register_index;
+ }
+
+ /*
+ * Clear the status/enable registers. Note that status registers
+ * are cleared by writing a '1', while enable registers are cleared
+ * by writing a '0'.
+ */
+ acpi_os_out8 (acpi_gbl_gpe_registers[register_index].enable_addr, 0x00);
+ acpi_os_out8 (acpi_gbl_gpe_registers[register_index].status_addr, 0xFF);
+
+ register_index++;
+ }
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_save_method_info
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Called from Acpi_walk_namespace. Expects each object to be a
+ * control method under the _GPE portion of the namespace.
+ * Extract the name and GPE type from the object, saving this
+ * information for quick lookup during GPE dispatch
+ *
+ * The name of each GPE control method is of the form:
+ * "_Lnn" or "_Enn"
+ * Where:
+ * L - means that the GPE is level triggered
+ * E - means that the GPE is edge triggered
+ * nn - is the GPE number
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ev_save_method_info (
+ ACPI_HANDLE obj_handle,
+ u32 level,
+ void *obj_desc,
+ void **return_value)
+{
+ u32 gpe_number;
+ char name[ACPI_NAME_SIZE + 1];
+ u8 type;
+
+
+ /* Extract the name from the object and convert to a string */
+
+ MOVE_UNALIGNED32_TO_32 (name, &((ACPI_NAMED_OBJECT*) obj_handle)->name);
+ name[ACPI_NAME_SIZE] = 0;
+
+ /*
+ * Edge/Level determination is based on the 2nd char of the method name
+ */
+ if (name[1] == 'L') {
+ type = ACPI_EVENT_LEVEL_TRIGGERED;
+ }
+ else if (name[1] == 'E') {
+ type = ACPI_EVENT_EDGE_TRIGGERED;
+ }
+ else {
+ /* Unknown method type, just ignore it! */
+
+ return AE_OK;
+ }
+
+ /* Convert the last two characters of the name to the Gpe Number */
+
+ gpe_number = STRTOUL (&name[2], NULL, 16);
+ if (gpe_number == ACPI_UINT32_MAX) {
+ /* Conversion failed; invalid method, just ignore it */
+
+ return AE_OK;
+ }
+
+ /* Ensure that we have a valid GPE number */
+
+ if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) {
+ /* Not valid, all we can do here is ignore it */
+
+ return AE_OK;
+ }
+
+ /*
+ * Now we can add this information to the Gpe_info block
+ * for use during dispatch of this GPE.
+ */
+
+ acpi_gbl_gpe_info [gpe_number].type = type;
+ acpi_gbl_gpe_info [gpe_number].method_handle = obj_handle;
+
+
+ /*
+ * Enable the GPE (SCIs should be disabled at this point)
+ */
+
+ acpi_hw_enable_gpe (gpe_number);
+
+ return AE_OK;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_init_gpe_control_methods
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Obtain the control methods associated with the GPEs.
+ *
+ * NOTE: Must be called AFTER namespace initialization!
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ev_init_gpe_control_methods (void)
+{
+ ACPI_STATUS status;
+
+
+ /* Get a permanent handle to the _GPE object */
+
+ status = acpi_get_handle (NULL, "\\_GPE", &acpi_gbl_gpe_obj_handle);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Traverse the namespace under \_GPE to find all methods there */
+
+ status = acpi_walk_namespace (ACPI_TYPE_METHOD, acpi_gbl_gpe_obj_handle,
+ ACPI_INT32_MAX, acpi_ev_save_method_info,
+ NULL, NULL);
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_gpe_cleanup
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Cleanup in preparation for unload.
+ *
+ ******************************************************************************/
+
+void
+acpi_ev_gpe_cleanup (void)
+{
+
+ acpi_cm_free (acpi_gbl_gpe_registers);
+ acpi_cm_free (acpi_gbl_gpe_info);
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_gpe_detect
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
+ *
+ * DESCRIPTION: Detect if any GP events have occurred
+ *
+ ******************************************************************************/
+
+u32
+acpi_ev_gpe_detect (void)
+{
+ u32 int_status = INTERRUPT_NOT_HANDLED;
+ u32 i;
+ u32 j;
+ u8 enabled_status_byte;
+ u8 bit_mask;
+
+
+ /*
+ * Read all of the 8-bit GPE status and enable registers
+ * in both of the register blocks, saving all of it.
+ * Find all currently active GP events.
+ */
+
+ for (i = 0; i < acpi_gbl_gpe_register_count; i++) {
+ acpi_gbl_gpe_registers[i].status =
+ acpi_os_in8 (acpi_gbl_gpe_registers[i].status_addr);
+
+ acpi_gbl_gpe_registers[i].enable =
+ acpi_os_in8 (acpi_gbl_gpe_registers[i].enable_addr);
+
+ /* First check if there is anything active at all in this register */
+
+ enabled_status_byte = (u8) (acpi_gbl_gpe_registers[i].status &
+ acpi_gbl_gpe_registers[i].enable);
+
+ if (!enabled_status_byte) {
+ /* No active GPEs in this register, move on */
+
+ continue;
+ }
+
+ /* Now look at the individual GPEs in this byte register */
+
+ for (j = 0, bit_mask = 1; j < 8; j++, bit_mask <<= 1) {
+ /* Examine one GPE bit */
+
+ if (enabled_status_byte & bit_mask) {
+ /*
+ * Found an active GPE. Dispatch the event to a handler
+ * or method.
+ */
+ int_status |=
+ acpi_ev_gpe_dispatch (acpi_gbl_gpe_registers[i].gpe_base + j);
+ }
+ }
+ }
+
+ return int_status;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_asynch_execute_gpe_method
+ *
+ * PARAMETERS: Gpe_number - The 0-based Gpe number
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Perform the actual execution of a GPE control method. This
+ * function is called from an invocation of Acpi_os_queue_for_execution
+ * (and therefore does NOT execute at interrupt level) so that
+ * the control method itself is not executed in the context of
+ * the SCI interrupt handler.
+ *
+ ******************************************************************************/
+
+void
+acpi_ev_asynch_execute_gpe_method (
+ void *context)
+{
+ u32 gpe_number = (u32) context;
+ ACPI_GPE_LEVEL_INFO gpe_info;
+
+
+ /* Take a snapshot of the GPE info for this level */
+
+ acpi_cm_acquire_mutex (ACPI_MTX_EVENTS);
+ gpe_info = acpi_gbl_gpe_info [gpe_number];
+ acpi_cm_release_mutex (ACPI_MTX_EVENTS);
+
+ /*
+ * Function Handler (e.g. EC):
+ * ---------------------------
+ * Execute the installed function handler to handle this event.
+ */
+ if (gpe_info.handler) {
+ gpe_info.handler (gpe_info.context);
+ }
+
+ /*
+ * Method Handler (_Lxx, _Exx):
+ * ----------------------------
+ * Acpi_evaluate the _Lxx/_Exx control method that corresponds to this GPE.
+ */
+ else if (gpe_info.method_handle) {
+ acpi_ns_evaluate_by_handle (gpe_info.method_handle, NULL, NULL);
+ }
+
+ /*
+ * Level-Triggered?
+ * ----------------
+ * If level-triggered, clear the GPE status bit after execution. Note
+ * that edge-triggered events are cleared prior to calling (via DPC)
+ * this function.
+ */
+ if (gpe_info.type | ACPI_EVENT_LEVEL_TRIGGERED) {
+ acpi_hw_clear_gpe (gpe_number);
+ }
+
+ /*
+ * Enable the GPE.
+ */
+ acpi_hw_enable_gpe (gpe_number);
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_gpe_dispatch
+ *
+ * PARAMETERS: Gpe_number - The 0-based Gpe number
+ *
+ * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
+ *
+ * DESCRIPTION: Handle and dispatch a General Purpose Acpi_event.
+ * Clears the status bit for the requested event.
+ *
+ * TBD: [Investigate] is this still valid or necessary:
+ * The Gpe handler differs from the fixed events in that it clears the enable
+ * bit rather than the status bit to clear the interrupt. This allows
+ * software outside of interrupt context to determine what caused the SCI and
+ * dispatch the correct AML.
+ *
+ ******************************************************************************/
+
+u32
+acpi_ev_gpe_dispatch (
+ u32 gpe_number)
+{
+
+ /*DEBUG_INCREMENT_EVENT_COUNT (EVENT_GENERAL);*/
+
+ /* Ensure that we have a valid GPE number */
+
+ if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) {
+ return (INTERRUPT_NOT_HANDLED);
+ }
+
+ /*
+ * Disable the GPE.
+ */
+ acpi_hw_disable_gpe (gpe_number);
+
+ /*
+ * Edge-Triggered?
+ * ---------------
+ * If edge-triggered, clear the GPE status bit now. Note that
+ * level-triggered events are cleared after the GPE is serviced
+ * (see Acpi_ev_asynch_execute_gpe_method).
+ */
+ if (acpi_gbl_gpe_info [gpe_number].type | ACPI_EVENT_EDGE_TRIGGERED) {
+ acpi_hw_clear_gpe (gpe_number);
+ }
+
+ /*
+ * Queue-up the Handler:
+ * ---------------------
+ * Queue the handler, which is either an installable function handler
+ * (e.g. EC) or a control method (e.g. _Lxx/_Exx) for later execution.
+ */
+ if (acpi_gbl_gpe_info [gpe_number].handler ||
+ acpi_gbl_gpe_info [gpe_number].method_handle)
+ {
+ if (ACPI_FAILURE (acpi_os_queue_for_execution (OSD_PRIORITY_GPE,
+ acpi_ev_asynch_execute_gpe_method,
+ (void*)(NATIVE_UINT)gpe_number)))
+ {
+ /*
+ * Shoudn't occur, but if it does report an error. Note that
+ * the GPE will remain disabled until the ACPI Core Subsystem
+ * is restarted, or the handler is removed/reinstalled.
+ */
+ REPORT_ERROR ("Unable to queue-up handler for GPE.");
+ }
+ }
+
+ /*
+ * Non Handled GPEs:
+ * -----------------
+ * GPEs without handlers are disabled and kept that way until a handler
+ * is registered for them.
+ */
+ else {
+ REPORT_ERROR ("No installed handler for GPE.");
+ }
+
+ return (INTERRUPT_HANDLED);
+}
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
new file mode 100644
index 000000000..5164d3f27
--- /dev/null
+++ b/drivers/acpi/events/evmisc.c
@@ -0,0 +1,357 @@
+/******************************************************************************
+ *
+ * Module Name: evmisc - ACPI device notification handler dispatch
+ * and ACPI Global Lock support
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "events.h"
+#include "namesp.h"
+#include "interp.h"
+#include "hardware.h"
+
+#define _COMPONENT EVENT_HANDLING
+ MODULE_NAME ("evmisc");
+
+
+/**************************************************************************
+ *
+ * FUNCTION: Acpi_ev_notify_dispatch
+ *
+ * PARAMETERS:
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Dispatch a device notification event to a previously
+ * installed handler.
+ *
+ *************************************************************************/
+
+void
+acpi_ev_notify_dispatch (
+ ACPI_HANDLE device,
+ u32 notify_value)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_OBJECT_INTERNAL *handler_obj;
+ NOTIFY_HANDLER handler;
+
+
+ /*
+ * For value 1 (Ejection Request), some device method may need to be run.
+ * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need to be run.
+ * For value 0x80 (Status Change) on the power button or sleep button,
+ * initiate soft-off or sleep operation?
+ */
+
+
+ switch (notify_value)
+ {
+ case 0:
+ break;
+
+ case 1:
+ break;
+
+ case 2:
+ break;
+
+ case 0x80:
+ break;
+
+ default:
+ break;
+ }
+
+
+ /*
+ * Invoke a global notify handler if installed.
+ * This is done _before_ we invoke the per-device handler attached to the device.
+ */
+
+ if (notify_value <= MAX_SYS_NOTIFY) {
+ /* Global system notification handler */
+
+ if (acpi_gbl_sys_notify.handler) {
+ acpi_gbl_sys_notify.handler (device, notify_value,
+ acpi_gbl_sys_notify.context);
+ }
+ }
+
+ else {
+ /* Global driver notification handler */
+
+ if (acpi_gbl_drv_notify.handler) {
+ acpi_gbl_drv_notify.handler (device, notify_value,
+ acpi_gbl_drv_notify.context);
+ }
+ }
+
+
+ /*
+ * Get the notify object which must be attached to the device NTE
+ */
+
+ obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) device);
+ if (!obj_desc) {
+ /* There can be no notify handler for this device */
+
+ return;
+ }
+
+
+ /* We have the notify object, Get the right handler */
+
+ if (notify_value <= MAX_SYS_NOTIFY) {
+ handler_obj = obj_desc->device.sys_handler;
+ }
+ else {
+ handler_obj = obj_desc->device.drv_handler;
+ }
+
+ /* Validate the handler */
+
+ if (!handler_obj) {
+ /* There is no notify handler for this device */
+
+ return;
+ }
+
+ /* There is a handler, invoke it */
+
+ handler = handler_obj->notify_handler.handler;
+ handler (device, notify_value, handler_obj->notify_handler.context);
+
+}
+
+
+/***************************************************************************
+ *
+ * FUNCTION: Acpi_ev_global_lock_thread
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Invoked by SCI interrupt handler upon acquisition of the
+ * Global Lock. Simply signal all threads that are waiting
+ * for the lock.
+ *
+ **************************************************************************/
+
+void
+acpi_ev_global_lock_thread (
+ void *context)
+{
+
+ /* Signal threads that are waiting for the lock */
+
+ if (acpi_gbl_global_lock_thread_count) {
+ /* Send sufficient units to the semaphore */
+
+ acpi_os_signal_semaphore (acpi_gbl_global_lock_semaphore,
+ acpi_gbl_global_lock_thread_count);
+ }
+}
+
+
+/***************************************************************************
+ *
+ * FUNCTION: Acpi_ev_global_lock_handler
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Invoked directly from the SCI handler when a global lock
+ * release interrupt occurs. Grab the global lock and queue
+ * the global lock thread for execution
+ *
+ **************************************************************************/
+
+u32
+acpi_ev_global_lock_handler (
+ void *context)
+{
+ u8 acquired = FALSE;
+ void *global_lock;
+
+
+ /*
+ * Attempt to get the lock
+ * If we don't get it now, it will be marked pending and we will
+ * take another interrupt when it becomes free.
+ */
+
+ global_lock = &acpi_gbl_FACS->global_lock;
+ ACPI_ACQUIRE_GLOBAL_LOCK (global_lock, acquired);
+ if (acquired) {
+ /* Got the lock, now wake all threads waiting for it */
+
+ acpi_gbl_global_lock_acquired = TRUE;
+
+ /* Run the Global Lock thread which will signal all waiting threads */
+
+ acpi_os_queue_for_execution (OSD_PRIORITY_HIGH, acpi_ev_global_lock_thread,
+ context);
+ }
+
+ return INTERRUPT_HANDLED;
+}
+
+
+/***************************************************************************
+ *
+ * FUNCTION: Acpi_ev_init_global_lock_handler
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install a handler for the global lock release event
+ *
+ **************************************************************************/
+
+ACPI_STATUS
+acpi_ev_init_global_lock_handler (void)
+{
+ ACPI_STATUS status;
+
+
+ status = acpi_install_fixed_event_handler (ACPI_EVENT_GLOBAL,
+ acpi_ev_global_lock_handler, NULL);
+
+ return (status);
+}
+
+
+/***************************************************************************
+ *
+ * FUNCTION: Acpi_ev_acquire_global_lock
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Attempt to gain ownership of the Global Lock.
+ *
+ **************************************************************************/
+
+ACPI_STATUS
+acpi_ev_acquire_global_lock(void)
+{
+ ACPI_STATUS status = AE_OK;
+ u8 acquired = FALSE;
+ void *global_lock;
+
+
+ /* One more thread wants the global lock */
+
+ acpi_gbl_global_lock_thread_count++;
+
+
+ /* If we (OS side) have the hardware lock already, we are done */
+
+ if (acpi_gbl_global_lock_acquired) {
+ return (AE_OK);
+ }
+
+ /* Only if the FACS is valid */
+
+ if (!acpi_gbl_FACS) {
+ return (AE_OK);
+ }
+
+
+ /* We must acquire the actualy hardware lock */
+
+ global_lock = &acpi_gbl_FACS->global_lock;
+ ACPI_ACQUIRE_GLOBAL_LOCK (global_lock, acquired);
+ if (acquired) {
+ /* We got the lock */
+
+ acpi_gbl_global_lock_acquired = TRUE;
+
+ return (AE_OK);
+ }
+
+
+ /*
+ * Did not get the lock. The pending bit was set above, and we must now
+ * wait until we get the global lock released interrupt.
+ */
+
+ /*
+ * Acquire the global lock semaphore first.
+ * Since this wait will block, we must release the interpreter
+ */
+
+ acpi_aml_exit_interpreter ();
+ status = acpi_aml_system_wait_semaphore (acpi_gbl_global_lock_semaphore,
+ ACPI_UINT32_MAX);
+ acpi_aml_enter_interpreter ();
+
+
+ return (status);
+}
+
+
+/***************************************************************************
+ *
+ * FUNCTION: Acpi_ev_release_global_lock
+ *
+ * DESCRIPTION: Releases ownership of the Global Lock.
+ *
+ **************************************************************************/
+
+void
+acpi_ev_release_global_lock (void)
+{
+ u8 pending = FALSE;
+ void *global_lock;
+
+
+ if (!acpi_gbl_FACS) {
+ return;
+ }
+
+ /* One fewer thread has the global lock */
+
+ acpi_gbl_global_lock_thread_count--;
+
+
+ /* Have all threads released the lock? */
+
+ if (!acpi_gbl_global_lock_thread_count) {
+ /*
+ * No more threads holding lock, we can do the actual hardware
+ * release
+ */
+
+ global_lock = &acpi_gbl_FACS->global_lock;
+ ACPI_RELEASE_GLOBAL_LOCK (global_lock, pending);
+ acpi_gbl_global_lock_acquired = FALSE;
+
+ /*
+ * If the pending bit was set, we must write GBL_RLS to the control
+ * register
+ */
+ if (pending) {
+ acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_LOCK,
+ (s32)PM1_CONTROL | GBL_RLS, 1);
+ }
+ }
+
+ return;
+}
diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c
new file mode 100644
index 000000000..3e2a91d32
--- /dev/null
+++ b/drivers/acpi/events/evregion.c
@@ -0,0 +1,690 @@
+/******************************************************************************
+ *
+ * Module Name: evregion - ACPI Address_space / Op_region handler dispatch
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "events.h"
+#include "namesp.h"
+#include "interp.h"
+#include "amlcode.h"
+
+#define _COMPONENT EVENT_HANDLING
+ MODULE_NAME ("evregion");
+
+
+#define PCI_ROOT_HID_STRING "PNP0A03"
+#define PCI_ROOT_HID_VALUE 0x030AD041 /* EISAID("PNP0A03") */
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_find_one_pci_root_bus
+ *
+ * PARAMETERS:
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION:
+ *
+ *****************************************************************************/
+
+ACPI_STATUS
+acpi_ev_find_one_pci_root_bus (
+ ACPI_HANDLE obj_handle,
+ u32 nesting_level,
+ void *context,
+ void **return_value)
+{
+ ACPI_NAMED_OBJECT *entry;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_STATUS status;
+
+
+ entry = (ACPI_NAMED_OBJECT*) obj_handle;
+ obj_desc = ((ACPI_NAMED_OBJECT*)obj_handle)->object;
+
+
+ /*
+ * We are looking for all valid _HID objects.
+ */
+
+ if (STRNCMP ((char *)&entry->name, METHOD_NAME__HID, ACPI_NAME_SIZE) ||
+ (!obj_desc))
+ {
+ return AE_OK;
+ }
+
+
+ /*
+ * Found an _HID object.
+ * Now we need a HID with the value EISAID("PNP0A03")
+ * HID can be either a number or a string.
+ */
+
+ switch (obj_desc->common.type)
+ {
+ case ACPI_TYPE_NUMBER:
+
+ if (obj_desc->number.value != PCI_ROOT_HID_VALUE) {
+ return AE_OK;
+ }
+
+ break;
+
+ case ACPI_TYPE_STRING:
+
+ if (STRNCMP (obj_desc->string.pointer, PCI_ROOT_HID_STRING,
+ sizeof (PCI_ROOT_HID_STRING)))
+ {
+ return AE_OK;
+ }
+
+ break;
+
+ default:
+
+ return AE_OK;
+ }
+
+
+ /*
+ * We found a valid PCI_ROOT_HID.
+ * The parent of the HID entry is the PCI device; Install the default PCI
+ * handler for this PCI device.
+ */
+
+ status = acpi_install_address_space_handler (acpi_ns_get_parent_entry (entry),
+ ADDRESS_SPACE_PCI_CONFIG,
+ ACPI_DEFAULT_HANDLER, NULL, NULL);
+
+ return AE_OK;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_find_pci_root_buses
+ *
+ * PARAMETERS:
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION:
+ *
+ *****************************************************************************/
+
+ACPI_STATUS
+acpi_ev_find_pci_root_buses (
+ void)
+{
+
+ acpi_ns_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
+ FALSE, acpi_ev_find_one_pci_root_bus, NULL, NULL);
+
+ return AE_OK;
+}
+
+
+/**************************************************************************
+ *
+ * FUNCTION: Acpi_ev_install_default_address_space_handlers
+ *
+ * PARAMETERS:
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Installs the core subsystem address space handlers.
+ *
+ *************************************************************************/
+
+ACPI_STATUS
+acpi_ev_install_default_address_space_handlers (
+ void)
+{
+ ACPI_STATUS status;
+
+
+ /*
+ * NOTE: All address spaces (PCI Config, EC, SMBus) are scope dependent
+ * and registration must occur for a specific device. In the case
+ * system memory and IO address spaces there is currently no device
+ * associated with the address space. For these we use the root.
+ */
+
+ status = acpi_install_address_space_handler (acpi_gbl_root_object,
+ ADDRESS_SPACE_SYSTEM_MEMORY,
+ ACPI_DEFAULT_HANDLER, NULL, NULL);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ status = acpi_install_address_space_handler (acpi_gbl_root_object,
+ ADDRESS_SPACE_SYSTEM_IO,
+ ACPI_DEFAULT_HANDLER, NULL, NULL);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /*
+ * Install PCI config space handler for all PCI root bridges. A PCI root
+ * bridge is found by searching for devices containing a HID with the value
+ * EISAID("PNP0A03")
+ */
+
+ acpi_ev_find_pci_root_buses ();
+
+
+ return (AE_OK);
+}
+
+
+/* TBD: [Restructure] Move to the methods directory */
+
+/**************************************************************************
+ *
+ * FUNCTION: Acpi_ev_execute_reg_method
+ *
+ * PARAMETERS: Region_obj - Object structure
+ * Function - On (1) or Off (0)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute _REG method for a region
+ *
+ *************************************************************************/
+
+ACPI_STATUS
+acpi_ev_execute_reg_method (
+ ACPI_OBJECT_INTERNAL *region_obj,
+ u32 function)
+{
+ ACPI_OBJECT_INTERNAL *params[3];
+ ACPI_OBJECT_INTERNAL space_iD_obj;
+ ACPI_OBJECT_INTERNAL function_obj;
+ ACPI_STATUS status;
+
+
+ if (region_obj->region.REGmethod == NULL) {
+ return (AE_OK);
+ }
+
+ /*
+ * _REG method has two arguments
+ * Arg0: Integer: Operation region space ID
+ * Same value as Region_obj->Region.Space_id
+ * Arg1: Integer: connection status
+ * 1 for connecting the handler,
+ * 0 for disconnecting the handler
+ * Passed as a parameter
+ */
+
+ acpi_cm_init_static_object (&space_iD_obj);
+ acpi_cm_init_static_object (&function_obj);
+
+ /*
+ * Method requires two parameters.
+ */
+ params [0] = &space_iD_obj;
+ params [1] = &function_obj;
+ params [2] = NULL;
+
+ /*
+ * Set up the parameter objects
+ */
+ space_iD_obj.common.type = ACPI_TYPE_NUMBER;
+ space_iD_obj.number.value = region_obj->region.space_id;
+
+ function_obj.common.type = ACPI_TYPE_NUMBER;
+ function_obj.number.value = function;
+
+ /*
+ * Execute the method, no return value
+ */
+ status = acpi_ns_evaluate_by_handle (region_obj->region.REGmethod, params, NULL);
+ return (status);
+}
+
+
+/**************************************************************************
+ *
+ * FUNCTION: Acpi_ev_address_space_dispatch
+ *
+ * PARAMETERS: Region_obj - internal region object
+ * Space_id - ID of the address space (0-255)
+ * Function - Read or Write operation
+ * Address - Where in the space to read or write
+ * Bit_width - Field width in bits (8, 16, or 32)
+ * Value - Pointer to in or out value
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Dispatch an address space or operation region access to
+ * a previously installed handler.
+ *
+ *************************************************************************/
+
+ACPI_STATUS
+acpi_ev_address_space_dispatch (
+ ACPI_OBJECT_INTERNAL *region_obj,
+ u32 function,
+ u32 address,
+ u32 bit_width,
+ u32 *value)
+{
+ ACPI_STATUS status;
+ ADDRESS_SPACE_HANDLER handler;
+ ADDRESS_SPACE_SETUP region_setup;
+ ACPI_OBJECT_INTERNAL *handler_desc;
+ void *region_context;
+
+
+ /*
+ * Check for an installed handler
+ */
+ handler_desc = region_obj->region.addr_handler;
+
+ if (!handler_desc) {
+ return(AE_EXIST);
+ }
+
+ /*
+ * It may be the case that the region has never been initialized
+ * Some types of regions require special init code
+ */
+ if (!(region_obj->region.region_flags & REGION_INITIALIZED)) {
+ /*
+ * This region has not been initialized yet, do it
+ */
+ region_setup = handler_desc->addr_handler.setup;
+ if (!region_setup) {
+ /*
+ * Bad news, no init routine and not init'd
+ */
+ return (AE_UNKNOWN_STATUS);
+ }
+
+ /*
+ * We must exit the interpreter because the region setup will potentially
+ * execute control methods
+ */
+ acpi_aml_exit_interpreter ();
+
+ status = region_setup (region_obj, ACPI_REGION_ACTIVATE,
+ handler_desc->addr_handler.context,
+ &region_context);
+
+ /* Re-enter the interpreter */
+
+ acpi_aml_enter_interpreter ();
+
+ /*
+ * Init routine may fail
+ */
+ if (ACPI_FAILURE (status)) {
+ return(status);
+ }
+
+ /*
+ * Save the returned context for use in all accesses to the region
+ */
+ handler_desc->addr_handler.context = region_context;
+ }
+
+ /*
+ * We have everything we need, begin the process
+ */
+ handler = handler_desc->addr_handler.handler;
+
+ if (!(handler_desc->addr_handler.flags & ADDR_HANDLER_DEFAULT_INSTALLED)) {
+ /*
+ * For handlers other than the default (supplied) handlers, we must
+ * exit the interpreter because the handler *might* block -- we don't
+ * know what it will do, so we can't hold the lock on the intepreter.
+ */
+ acpi_aml_exit_interpreter();
+ }
+
+ /*
+ * Invoke the handler.
+ */
+ status = handler (function, address, bit_width, value,
+ handler_desc->addr_handler.context);
+
+
+ if (!(handler_desc->addr_handler.flags & ADDR_HANDLER_DEFAULT_INSTALLED)) {
+ /* We just returned from a non-default handler, we must re-enter the
+ interpreter */
+
+ acpi_aml_enter_interpreter ();
+ }
+
+ return (status);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_disassociate_region_and_handler
+ *
+ * PARAMETERS: Handler_obj - Handler Object
+ * Region_obj - Region Object
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Break the association between the handler and the region
+ * this is a two way association.
+ *
+ ******************************************************************************/
+
+void
+acpi_ev_disassociate_region_from_handler(
+ ACPI_OBJECT_INTERNAL *region_obj)
+{
+ ACPI_OBJECT_INTERNAL *handler_obj;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_OBJECT_INTERNAL **last_obj_ptr;
+ ADDRESS_SPACE_SETUP region_setup;
+ void *region_context;
+ ACPI_STATUS status;
+
+
+ /*
+ * Get the address handler from the region object
+ */
+
+ handler_obj = region_obj->region.addr_handler;
+ if (!handler_obj) {
+ /*
+ * This region has no handler, all done
+ */
+ return;
+ }
+
+
+ /*
+ * Find this region in the handler's list
+ */
+
+ obj_desc = handler_obj->addr_handler.region_list;
+ last_obj_ptr = &handler_obj->addr_handler.region_list;
+
+ while (obj_desc) {
+ /*
+ * See if this is the one
+ */
+ if (obj_desc == region_obj) {
+ /*
+ * This is it, remove it from the handler's list
+ */
+ *last_obj_ptr = obj_desc->region.link;
+
+ /*
+ * Now stop region accesses by executing the _REG method
+ */
+ acpi_ev_execute_reg_method (region_obj, 0);
+
+ /*
+ * Call the setup handler with the deactivate notification
+ */
+ region_setup = handler_obj->addr_handler.setup;
+ status = region_setup (region_obj, ACPI_REGION_DEACTIVATE,
+ handler_obj->addr_handler.context,
+ &region_context);
+
+ /*
+ * Save the returned context (It is the original context
+ * passed into Install)
+ */
+ handler_obj->addr_handler.context = region_context;
+
+ /*
+ * Init routine may fail, Just ignore errors
+ */
+
+ /*
+ * Remove handler reference in the region
+ *
+ * NOTE: this doesn't mean that the region goes away
+ * The region is just inaccessible as indicated to
+ * the _REG method
+ *
+ * If the region is on the handler's list
+ * this better be the region's handler
+ */
+ ACPI_ASSERT (region_obj->region.addr_handler == handler_obj);
+
+ region_obj->region.addr_handler = NULL;
+
+ return;
+
+ } /* found the right handler */
+
+ /*
+ * Move through the linked list of handlers
+ */
+ last_obj_ptr = &obj_desc->region.link;
+ obj_desc = obj_desc->region.link;
+ }
+
+ /*
+ * If we get here, the region was not in the handler's region list
+ */
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_associate_region_and_handler
+ *
+ * PARAMETERS: Handler_obj - Handler Object
+ * Region_obj - Region Object
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Create the association between the handler and the region
+ * this is a two way association.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ev_associate_region_and_handler(
+ ACPI_OBJECT_INTERNAL *handler_obj,
+ ACPI_OBJECT_INTERNAL *region_obj)
+{
+ ACPI_STATUS status;
+
+
+ ACPI_ASSERT (region_obj->region.space_id == handler_obj->addr_handler.space_id);
+ ACPI_ASSERT (region_obj->region.addr_handler == 0);
+
+ /*
+ * Link this region to the front of the handler's list
+ */
+
+ region_obj->region.link = handler_obj->addr_handler.region_list;
+ handler_obj->addr_handler.region_list = region_obj;
+
+ /*
+ * set the region's handler
+ */
+
+/*
+ Handler_obj->Common.Reference_count =
+ (u16) (Handler_obj->Common.Reference_count +
+ Region_obj->Common.Reference_count - 1);
+*/
+ region_obj->region.addr_handler = handler_obj;
+
+ /*
+ * Last thing, tell all users that this region is usable
+ */
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ status = acpi_ev_execute_reg_method (region_obj, 1);
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+ return (status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ev_addr_handler_helper
+ *
+ * PARAMETERS: Handle - Entry to be dumped
+ * Level - Nesting level of the handle
+ * Context - Passed into Acpi_ns_walk_namespace
+ *
+ * DESCRIPTION: This routine checks to see if the object is a Region if it
+ * is then the address handler is installed in it.
+ *
+ * If the Object is a Device, and the device has a handler of
+ * the same type then the search is terminated in that branch.
+ *
+ * This is because the existing handler is closer in proximity
+ * to any more regions than the one we are trying to install.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ev_addr_handler_helper (
+ ACPI_HANDLE obj_handle,
+ u32 level,
+ void *context,
+ void **return_value)
+{
+ ACPI_OBJECT_INTERNAL *handler_obj;
+ ACPI_OBJECT_INTERNAL *tmp_obj;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_NAMED_OBJECT *obj_entry;
+ ACPI_STATUS status;
+
+
+ handler_obj = (ACPI_OBJECT_INTERNAL *) context;
+
+ /* Parameter validation */
+
+ if (!handler_obj) {
+ return (AE_OK);
+ }
+
+ /* Convert and validate the device handle */
+
+ obj_entry = acpi_ns_convert_handle_to_entry (obj_handle);
+ if (!obj_entry) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * We only care about regions.and objects
+ * that can have address handlers
+ */
+
+ if ((obj_entry->type != ACPI_TYPE_DEVICE) &&
+ (obj_entry->type != ACPI_TYPE_REGION) &&
+ (obj_entry != acpi_gbl_root_object))
+ {
+ return (AE_OK);
+ }
+
+ /* Check for an existing internal object */
+
+ obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) obj_entry);
+ if (!obj_desc) {
+ /*
+ * The object DNE, we don't care about it
+ */
+ return (AE_OK);
+ }
+
+ /*
+ * Devices are handled different than regions
+ */
+ if (IS_THIS_OBJECT_TYPE (obj_desc, ACPI_TYPE_DEVICE)) {
+ /*
+ * See if this guy has any handlers
+ */
+ tmp_obj = obj_desc->device.addr_handler;
+ while (tmp_obj) {
+ /*
+ * Now let's see if it's for the same address space.
+ */
+ if (tmp_obj->addr_handler.space_id == handler_obj->addr_handler.space_id) {
+ /*
+ * It's for the same address space
+ */
+
+ /*
+ * Since the object we found it on was a device, then it
+ * means that someone has already installed a handler for
+ * the branch of the namespace from this device on. Just
+ * bail out telling the walk routine to not traverse this
+ * branch. This preserves the scoping rule for handlers.
+ */
+ return (AE_CTRL_DEPTH);
+ }
+
+ /*
+ * Move through the linked list of handlers
+ */
+ tmp_obj = tmp_obj->addr_handler.link;
+ }
+
+ /*
+ * As long as the device didn't have a handler for this
+ * space we don't care about it. We just ignore it and
+ * proceed.
+ */
+ return (AE_OK);
+ }
+
+ /*
+ * Only here if it was a region
+ */
+ ACPI_ASSERT (obj_desc->common.type == ACPI_TYPE_REGION);
+
+ if (obj_desc->region.space_id != handler_obj->addr_handler.space_id) {
+ /*
+ * This region is for a different address space
+ * ignore it
+ */
+ return (AE_OK);
+ }
+
+ /*
+ * Now we have a region and it is for the handler's address
+ * space type.
+ *
+ * First disconnect region for any previous handler (if any)
+ */
+ acpi_ev_disassociate_region_from_handler (obj_desc);
+
+ /*
+ * Then connect the region to the new handler
+ */
+ status = acpi_ev_associate_region_and_handler (handler_obj, obj_desc);
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
new file mode 100644
index 000000000..526bd036c
--- /dev/null
+++ b/drivers/acpi/events/evrgnini.c
@@ -0,0 +1,425 @@
+/******************************************************************************
+ *
+ * Module Name: evrgnini- ACPI Address_space / Op_region init
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "events.h"
+#include "namesp.h"
+#include "interp.h"
+#include "amlcode.h"
+
+#define _COMPONENT EVENT_HANDLING
+ MODULE_NAME ("evrgnini");
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ev_system_memory_region_setup
+ *
+ * PARAMETERS: Region_obj - region we are interested in
+ * Function - start or stop
+ * Handler_context - Address space handler context
+ * Returned context - context to be used with each call to the
+ * handler for this region
+ * RETURN: Status
+ *
+ * DESCRIPTION: Do any prep work for region handling, a nop for now
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ev_system_memory_region_setup (
+ ACPI_HANDLE handle,
+ u32 function,
+ void *handler_context,
+ void **return_context)
+{
+ MEM_HANDLER_CONTEXT *mem_context;
+ ACPI_OBJECT_INTERNAL *region_obj = (ACPI_OBJECT_INTERNAL *) handle;
+
+
+ if (function == ACPI_REGION_DEACTIVATE) {
+ region_obj->region.region_flags &= ~(REGION_INITIALIZED);
+
+ *return_context = NULL;
+ if (handler_context) {
+ mem_context = handler_context;
+ *return_context = mem_context->handler_context;
+
+ acpi_cm_free (mem_context);
+ }
+ return (AE_OK);
+ }
+
+
+ /* Activate. Create a new context */
+
+ mem_context = acpi_cm_callocate (sizeof (MEM_HANDLER_CONTEXT));
+ if (!mem_context) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Init. (Mapping fields are all set to zeros above) */
+
+ mem_context->handler_context = handler_context;
+ region_obj->region.region_flags |= REGION_INITIALIZED;
+
+ *return_context = mem_context;
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ev_io_space_region_setup
+ *
+ * PARAMETERS: Region_obj - region we are interested in
+ * Function - start or stop
+ * Handler_context - Address space handler context
+ * Returned context - context to be used with each call to the
+ * handler for this region
+ * RETURN: Status
+ *
+ * DESCRIPTION: Do any prep work for region handling
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ev_io_space_region_setup (
+ ACPI_HANDLE handle,
+ u32 function,
+ void *handler_context,
+ void **return_context)
+{
+ ACPI_OBJECT_INTERNAL *region_obj = (ACPI_OBJECT_INTERNAL *) handle;
+
+
+ if (function == ACPI_REGION_DEACTIVATE) {
+ region_obj->region.region_flags &= ~(REGION_INITIALIZED);
+ *return_context = handler_context;
+ return (AE_OK);
+ }
+
+ /* Activate the region */
+
+ region_obj->region.region_flags |= REGION_INITIALIZED;
+ *return_context = handler_context;
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ev_pci_config_region_setup
+ *
+ * PARAMETERS: Region_obj - region we are interested in
+ * Function - start or stop
+ * Handler_context - Address space handler context
+ * Returned context - context to be used with each call to the
+ * handler for this region
+ * RETURN: Status
+ *
+ * DESCRIPTION: Do any prep work for region handling
+ *
+ * MUTEX: Assumes namespace is locked
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ev_pci_config_region_setup (
+ ACPI_HANDLE handle,
+ u32 function,
+ void *handler_context,
+ void **return_context)
+{
+ ACPI_STATUS status = AE_OK;
+ u32 temp;
+ PCI_HANDLER_CONTEXT *pci_context;
+ ACPI_OBJECT_INTERNAL *handler_obj;
+ ACPI_NAMED_OBJECT *search_scope;
+ ACPI_OBJECT_INTERNAL *region_obj = (ACPI_OBJECT_INTERNAL *) handle;
+
+
+ handler_obj = region_obj->region.addr_handler;
+
+ if (!handler_obj) {
+ /*
+ * No installed handler. This shouldn't happen because the dispatch
+ * routine checks before we get here, but we check again just in case.
+ */
+ return(AE_EXIST);
+ }
+
+ if (function == ACPI_REGION_DEACTIVATE) {
+ region_obj->region.region_flags &= ~(REGION_INITIALIZED);
+
+ *return_context = NULL;
+ if (handler_context) {
+ pci_context = handler_context;
+ *return_context = pci_context->handler_context;
+
+ acpi_cm_free (pci_context);
+ }
+
+ return (status);
+ }
+
+
+ /* Create a new context */
+
+ pci_context = acpi_cm_allocate (sizeof(PCI_HANDLER_CONTEXT));
+ if (!pci_context) {
+ return (AE_NO_MEMORY);
+ }
+
+ /*
+ * For PCI Config space access, we have to pass the segment, bus,
+ * device and function numbers. This routine must acquire those.
+ */
+
+ /*
+ * First get device and function numbers from the _ADR object
+ * in the parent's scope.
+ */
+ ACPI_ASSERT(region_obj->region.nte);
+
+ search_scope = acpi_ns_get_parent_entry (region_obj->region.nte);
+
+
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+
+ /* Acpi_evaluate the _ADR object */
+
+ status = acpi_cm_evaluate_numeric_object (METHOD_NAME__ADR, search_scope, &temp);
+ /*
+ * The default is zero, since the allocation above zeroed the data, just
+ * do nothing on failures.
+ */
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * Got it..
+ */
+ pci_context->dev_func = temp;
+ }
+
+ /*
+ * Get the _SEG and _BBN values from the device upon which the handler
+ * is installed.
+ *
+ * We need to get the _SEG and _BBN objects relative to the PCI BUS device.
+ * This is the device the handler has been registered to handle.
+ */
+
+ search_scope = handler_obj->addr_handler.nte;
+
+ status = acpi_cm_evaluate_numeric_object (METHOD_NAME__SEG, search_scope, &temp);
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * Got it..
+ */
+ pci_context->seg = temp;
+ }
+
+ status = acpi_cm_evaluate_numeric_object (METHOD_NAME__BBN, search_scope, &temp);
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * Got it..
+ */
+ pci_context->bus = temp;
+ }
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+ *return_context = pci_context;
+
+ region_obj->region.region_flags |= REGION_INITIALIZED;
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ev_default_region_setup
+ *
+ * PARAMETERS: Region_obj - region we are interested in
+ * Function - start or stop
+ * Handler_context - Address space handler context
+ * Returned context - context to be used with each call to the
+ * handler for this region
+ * RETURN: Status
+ *
+ * DESCRIPTION: Do any prep work for region handling
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ev_default_region_setup (
+ ACPI_HANDLE handle,
+ u32 function,
+ void *handler_context,
+ void **return_context)
+{
+ ACPI_OBJECT_INTERNAL *region_obj = (ACPI_OBJECT_INTERNAL *) handle;
+
+
+ if (function == ACPI_REGION_DEACTIVATE) {
+ region_obj->region.region_flags &= ~(REGION_INITIALIZED);
+ *return_context = NULL;
+ }
+ else {
+ region_obj->region.region_flags |= REGION_INITIALIZED;
+ *return_context = handler_context;
+ }
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_initialize_region
+ *
+ * PARAMETERS: Region_obj - Region we are initializing
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initializes the region, finds any _REG methods and saves them
+ * for execution at a later time
+ *
+ * Get the appropriate address space handler for a newly
+ * created region.
+ *
+ * This also performs address space specific intialization. For
+ * example, PCI regions must have an _ADR object that contains
+ * a PCI address in the scope of the defintion. This address is
+ * required to perform an access to PCI config space.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ev_initialize_region (
+ ACPI_OBJECT_INTERNAL *region_obj,
+ u8 acpi_ns_locked)
+{
+ ACPI_OBJECT_INTERNAL *handler_obj;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ u32 space_id;
+ ACPI_NAMED_OBJECT *entry; /* Namespace Object */
+ ACPI_STATUS status;
+ ACPI_NAMED_OBJECT *reg_entry;
+ ACPI_NAME *reg_name_ptr = (ACPI_NAME *) METHOD_NAME__REG;
+
+
+ if (!region_obj) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ ACPI_ASSERT(region_obj->region.nte);
+
+ entry = acpi_ns_get_parent_entry (region_obj->region.nte);
+ space_id = region_obj->region.space_id;
+
+ region_obj->region.addr_handler = NULL;
+ region_obj->region.REGmethod = NULL;
+ region_obj->region.region_flags = INITIAL_REGION_FLAGS;
+
+ /*
+ * Find any "_REG" associated with this region definition
+ */
+ status = acpi_ns_search_one_scope (*reg_name_ptr, entry->child_table,
+ ACPI_TYPE_METHOD, &reg_entry, NULL);
+ if (status == AE_OK) {
+ /*
+ * The _REG method is optional and there can be only one per region
+ * definition. This will be executed when the handler is attached
+ * or removed
+ */
+ region_obj->region.REGmethod = reg_entry;
+ }
+
+ /*
+ * The following loop depends upon the root nte having no parent
+ * ie: Acpi_gbl_Root_object->Parent_entry being set to NULL
+ */
+ while (entry) {
+ /*
+ * Check to see if a handler exists
+ */
+ handler_obj = NULL;
+ obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) entry);
+ if (obj_desc) {
+ /*
+ * can only be a handler if the object exists
+ */
+ switch (entry->type)
+ {
+ case ACPI_TYPE_DEVICE:
+
+ handler_obj = obj_desc->device.addr_handler;
+ break;
+
+ case ACPI_TYPE_PROCESSOR:
+
+ handler_obj = obj_desc->processor.addr_handler;
+ break;
+
+ case ACPI_TYPE_THERMAL:
+
+ handler_obj = obj_desc->thermal_zone.addr_handler;
+ break;
+ }
+
+ while (handler_obj) {
+ /*
+ * This guy has at least one address handler
+ * see if it has the type we want
+ */
+ if (handler_obj->addr_handler.space_id == space_id) {
+ /*
+ * Found it! Now update the region and the handler
+ */
+ acpi_ev_associate_region_and_handler(handler_obj, region_obj);
+ return (AE_OK);
+ }
+
+ handler_obj = handler_obj->addr_handler.link;
+
+ } /* while handlerobj */
+ }
+
+ /*
+ * This one does not have the handler we need
+ * Pop up one level
+ */
+ entry = acpi_ns_get_parent_entry (entry);
+
+ } /* while Entry != ROOT */
+
+ /*
+ * If we get here, there is no handler for this region
+ */
+ return (AE_NOT_EXIST);
+}
+
diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c
new file mode 100644
index 000000000..6bf605d85
--- /dev/null
+++ b/drivers/acpi/events/evsci.c
@@ -0,0 +1,302 @@
+/******************************************************************************
+ *
+ * Module Name: evsci - System Control Interrupt configuration and
+ * legacy to ACPI mode state transition functions
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "namesp.h"
+#include "hardware.h"
+#include "events.h"
+
+
+#define _COMPONENT EVENT_HANDLING
+ MODULE_NAME ("evsci");
+
+
+/*
+ * Elements correspond to counts for
+ * TMR, NOT_USED, GBL, PWR_BTN, SLP_BTN, RTC,
+ * and GENERAL respectively. These counts
+ * are modified by the ACPI interrupt handler...
+ * Note that GENERAL should probably be split out
+ * into one element for each bit in the GPE
+ * registers
+ */
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_sci_handler
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: Status code indicates whether interrupt was handled.
+ *
+ * DESCRIPTION: Interrupt handler that will figure out what function or
+ * control method to call to deal with a SCI. Installed
+ * using BU interrupt support.
+ *
+ ******************************************************************************/
+
+u32
+acpi_ev_sci_handler (void *context)
+{
+ u32 interrupt_handled = INTERRUPT_NOT_HANDLED;
+
+ /*
+ * ACPI Enabled?
+ * -------------
+ * Make sure that ACPI is enabled by checking SCI_EN. Note that we are
+ * required to treat the SCI interrupt as sharable, level, active low.
+ */
+ if (!acpi_hw_register_access (ACPI_READ, ACPI_MTX_DO_NOT_LOCK, (s32)SCI_EN)) {
+ REPORT_ERROR ("Received and SCI but ACPI is not enabled.");
+ return (INTERRUPT_NOT_HANDLED);
+ }
+
+ /*
+ * Fixed Acpi_events:
+ * -------------
+ * Check for and dispatch any Fixed Acpi_events that have occurred
+ */
+ interrupt_handled |= acpi_ev_fixed_event_detect ();
+
+ /*
+ * GPEs:
+ * -----
+ * Check for and dispatch any GPEs that have occurred
+ */
+ interrupt_handled |= acpi_ev_gpe_detect ();
+
+ return (interrupt_handled);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_install_sci_handler
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Installs SCI handler.
+ *
+ ******************************************************************************/
+
+u32
+acpi_ev_install_sci_handler (void)
+{
+ u32 except = AE_OK;
+
+ except = acpi_os_install_interrupt_handler (
+ (u32) acpi_gbl_FACP->sci_int,
+ acpi_ev_sci_handler,
+ NULL);
+
+ return (except);
+}
+
+
+/******************************************************************************
+
+ *
+ * FUNCTION: Acpi_ev_remove_sci_handler
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: E_OK if handler uninstalled OK, E_ERROR if handler was not
+ * installed to begin with
+ *
+ * DESCRIPTION: Restores original status of all fixed event enable bits and
+ * removes SCI handler.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ev_remove_sci_handler (void)
+{
+#if 0
+ /* TBD:[Investigate] Figure this out!! Disable all events first ??? */
+
+ if (original_fixed_enable_bit_status ^ 1 << acpi_event_index (TMR_FIXED_EVENT)) {
+ acpi_event_disable_event (TMR_FIXED_EVENT);
+ }
+
+ if (original_fixed_enable_bit_status ^ 1 << acpi_event_index (GBL_FIXED_EVENT)) {
+ acpi_event_disable_event (GBL_FIXED_EVENT);
+ }
+
+ if (original_fixed_enable_bit_status ^ 1 << acpi_event_index (PWR_BTN_FIXED_EVENT)) {
+ acpi_event_disable_event (PWR_BTN_FIXED_EVENT);
+ }
+
+ if (original_fixed_enable_bit_status ^ 1 << acpi_event_index (SLP_BTN_FIXED_EVENT)) {
+ acpi_event_disable_event (SLP_BTN_FIXED_EVENT);
+ }
+
+ if (original_fixed_enable_bit_status ^ 1 << acpi_event_index (RTC_FIXED_EVENT)) {
+ acpi_event_disable_event (RTC_FIXED_EVENT);
+ }
+
+ original_fixed_enable_bit_status = 0;
+
+#endif
+
+ acpi_os_remove_interrupt_handler (
+ (u32) acpi_gbl_FACP->sci_int,
+ acpi_ev_sci_handler);
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_sci_count
+ *
+ * PARAMETERS: char * Event_name name (fully qualified name from namespace
+ * or one of the fixed event names defined above)
+ * of the event to check if it's generated an SCI.
+ *
+ * RETURN: Number of SCI's for requested event since last time i_sci_occured()
+ * was called for this event.
+ *
+ * DESCRIPTION: Checks to see if SCI has been generated from requested source
+ * since the last time this function was called.
+ *
+ ******************************************************************************/
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_restore_acpi_state
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: none
+ *
+ * DESCRIPTION: Restore the original ACPI state of the machine
+ *
+ ******************************************************************************/
+
+void
+acpi_ev_restore_acpi_state (void)
+{
+ s32 index;
+
+
+ /* Restore the state of the chipset enable bits. */
+
+ if (acpi_gbl_restore_acpi_chipset == TRUE) {
+ /* Restore the fixed events */
+
+ if (acpi_os_in16 (acpi_gbl_FACP->pm1a_evt_blk + 2) !=
+ acpi_gbl_pm1_enable_register_save)
+ {
+ acpi_os_out16 ((acpi_gbl_FACP->pm1a_evt_blk + 2),
+ acpi_gbl_pm1_enable_register_save);
+ }
+
+ if (acpi_gbl_FACP->pm1b_evt_blk) {
+ if (acpi_os_in16 (acpi_gbl_FACP->pm1b_evt_blk + 2) !=
+ acpi_gbl_pm1_enable_register_save)
+ {
+ acpi_os_out16 ((acpi_gbl_FACP->pm1b_evt_blk + 2),
+ acpi_gbl_pm1_enable_register_save);
+ }
+ }
+
+
+ /* Ensure that all status bits are clear */
+
+ acpi_hw_clear_acpi_status ();
+
+
+ /* Now restore the GPEs */
+
+ for (index = 0; index < DIV_2 (acpi_gbl_FACP->gpe0blk_len); index++) {
+ if (acpi_os_in8 (acpi_gbl_FACP->gpe0blk +
+ DIV_2 (acpi_gbl_FACP->gpe0blk_len)) !=
+ acpi_gbl_gpe0enable_register_save[index])
+ {
+ acpi_os_out8 ((acpi_gbl_FACP->gpe0blk +
+ DIV_2 (acpi_gbl_FACP->gpe0blk_len)),
+ acpi_gbl_gpe0enable_register_save[index]);
+ }
+ }
+
+ if (acpi_gbl_FACP->gpe1_blk && acpi_gbl_FACP->gpe1_blk_len) {
+ for (index = 0; index < DIV_2 (acpi_gbl_FACP->gpe1_blk_len); index++) {
+ if (acpi_os_in8 (acpi_gbl_FACP->gpe1_blk +
+ DIV_2 (acpi_gbl_FACP->gpe1_blk_len)) !=
+ acpi_gbl_gpe1_enable_register_save[index])
+ {
+ acpi_os_out8 ((acpi_gbl_FACP->gpe1_blk +
+ DIV_2 (acpi_gbl_FACP->gpe1_blk_len)),
+ acpi_gbl_gpe1_enable_register_save[index]);
+ }
+ }
+ }
+
+ if (acpi_hw_get_mode() != acpi_gbl_original_mode) {
+ acpi_hw_set_mode (acpi_gbl_original_mode);
+ }
+ }
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_terminate
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: none
+ *
+ * DESCRIPTION: free memory allocated for table storage.
+ *
+ ******************************************************************************/
+
+void
+acpi_ev_terminate (void)
+{
+
+ /*
+ * Free global tables, etc.
+ */
+
+ if (acpi_gbl_gpe_registers) {
+ acpi_cm_free (acpi_gbl_gpe_registers);
+ }
+
+ if (acpi_gbl_gpe_info) {
+ acpi_cm_free (acpi_gbl_gpe_info);
+ }
+
+ return;
+}
+
+
diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c
new file mode 100644
index 000000000..385365515
--- /dev/null
+++ b/drivers/acpi/events/evxface.c
@@ -0,0 +1,604 @@
+/******************************************************************************
+ *
+ * Module Name: evxface - External interfaces for ACPI events
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "hardware.h"
+#include "namesp.h"
+#include "events.h"
+#include "amlcode.h"
+#include "interp.h"
+
+#define _COMPONENT EVENT_HANDLING
+ MODULE_NAME ("evxface");
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_install_fixed_event_handler
+ *
+ * PARAMETERS: Event - Event type to enable.
+ * Handler - Pointer to the handler function for the
+ * event
+ * Context - Value passed to the handler on each GPE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Saves the pointer to the handler function and then enables the
+ * event.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_install_fixed_event_handler (
+ u32 event,
+ FIXED_EVENT_HANDLER handler,
+ void *context)
+{
+ ACPI_STATUS status = AE_OK;
+
+
+ /* Sanity check the parameters. */
+
+ if (event >= NUM_FIXED_EVENTS) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ acpi_cm_acquire_mutex (ACPI_MTX_EVENTS);
+
+ /* Don't allow two handlers. */
+
+ if (NULL != acpi_gbl_fixed_event_handlers[event].handler) {
+ status = AE_EXIST;
+ goto cleanup;
+ }
+
+
+ /* Install the handler before enabling the event - just in case... */
+
+ acpi_gbl_fixed_event_handlers[event].handler = handler;
+ acpi_gbl_fixed_event_handlers[event].context = context;
+
+ if (1 != acpi_hw_register_access (ACPI_WRITE,
+ ACPI_MTX_LOCK, event + TMR_EN, 1))
+ {
+ /* Remove the handler */
+
+ acpi_gbl_fixed_event_handlers[event].handler = NULL;
+ acpi_gbl_fixed_event_handlers[event].context = NULL;
+
+ status = AE_ERROR;
+ goto cleanup;
+ }
+
+
+cleanup:
+ acpi_cm_release_mutex (ACPI_MTX_EVENTS);
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_remove_fixed_event_handler
+ *
+ * PARAMETERS: Event - Event type to disable.
+ * Handler - Address of the handler
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Disables the event and unregisters the event handler.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_remove_fixed_event_handler (
+ u32 event,
+ FIXED_EVENT_HANDLER handler)
+{
+ ACPI_STATUS status = AE_OK;
+
+
+ /* Sanity check the parameters. */
+
+ if (event >= NUM_FIXED_EVENTS) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ acpi_cm_acquire_mutex (ACPI_MTX_EVENTS);
+
+ /* Disable the event before removing the handler - just in case... */
+
+ if (0 != acpi_hw_register_access (ACPI_WRITE,
+ ACPI_MTX_LOCK, event + TMR_EN, 0))
+ {
+ status = AE_ERROR;
+ goto cleanup;
+ }
+
+ /* Remove the handler */
+
+ acpi_gbl_fixed_event_handlers[event].handler = NULL;
+ acpi_gbl_fixed_event_handlers[event].context = NULL;
+
+cleanup:
+ acpi_cm_release_mutex (ACPI_MTX_EVENTS);
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_install_notify_handler
+ *
+ * PARAMETERS: Device - The device for which notifies will be handled
+ * Handler_type - The type of handler:
+ * ACPI_SYSTEM_NOTIFY: System_handler (00-7f)
+ * ACPI_DEVICE_NOTIFY: Driver_handler (80-ff)
+ * Handler - Address of the handler
+ * Context - Value passed to the handler on each GPE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install a handler for notifies on an ACPI device
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_install_notify_handler (
+ ACPI_HANDLE device,
+ u32 handler_type,
+ NOTIFY_HANDLER handler,
+ void *context)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_OBJECT_INTERNAL *notify_obj;
+ ACPI_NAMED_OBJECT *obj_entry;
+ ACPI_STATUS status = AE_OK;
+
+
+ /* Parameter validation */
+
+ if ((!handler) ||
+ (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Convert and validate the device handle */
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+ obj_entry = acpi_ns_convert_handle_to_entry (device);
+ if (!obj_entry) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+
+ /*
+ * Support for global notify handlers. These handlers are invoked for
+ * every notifiy of the type specifiec
+ */
+
+ if (device == ACPI_ROOT_OBJECT) {
+ /*
+ * Make sure the handler is not already installed.
+ */
+
+ if (((handler_type == ACPI_SYSTEM_NOTIFY) &&
+ acpi_gbl_sys_notify.handler) ||
+ ((handler_type == ACPI_DEVICE_NOTIFY) &&
+ acpi_gbl_drv_notify.handler))
+ {
+ status = AE_EXIST;
+ goto unlock_and_exit;
+ }
+
+ if (handler_type == ACPI_SYSTEM_NOTIFY) {
+ acpi_gbl_sys_notify.nte = obj_entry;
+ acpi_gbl_sys_notify.handler = handler;
+ acpi_gbl_sys_notify.context = context;
+ }
+
+ else {
+ acpi_gbl_drv_notify.nte = obj_entry;
+ acpi_gbl_drv_notify.handler = handler;
+ acpi_gbl_drv_notify.context = context;
+ }
+
+
+ /* Global notify handler installed */
+
+ goto unlock_and_exit;
+ }
+
+
+ /*
+ * These are the ONLY objects that can receive ACPI notifications
+ */
+
+ if ((obj_entry->type != ACPI_TYPE_DEVICE) &&
+ (obj_entry->type != ACPI_TYPE_PROCESSOR) &&
+ (obj_entry->type != ACPI_TYPE_POWER) &&
+ (obj_entry->type != ACPI_TYPE_THERMAL))
+ {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Check for an existing internal object */
+
+ obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) obj_entry);
+ if (obj_desc) {
+ /*
+ * The object exists.
+ * Make sure the handler is not already installed.
+ */
+
+ if (((handler_type == ACPI_SYSTEM_NOTIFY) &&
+ obj_desc->device.sys_handler) ||
+ ((handler_type == ACPI_DEVICE_NOTIFY) &&
+ obj_desc->device.drv_handler))
+ {
+ status = AE_EXIST;
+ goto unlock_and_exit;
+ }
+ }
+
+ else {
+ /* Create a new object */
+
+ obj_desc = acpi_cm_create_internal_object (obj_entry->type);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ /* Attach new object to the NTE */
+
+ status = acpi_ns_attach_object (device, obj_desc, (u8) obj_entry->type);
+
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+ }
+
+
+ /*
+ * If we get here, we know that there is no handler installed
+ * so let's party
+ */
+ notify_obj = acpi_cm_create_internal_object (INTERNAL_TYPE_NOTIFY);
+ if (!notify_obj) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ notify_obj->notify_handler.nte = obj_entry;
+ notify_obj->notify_handler.handler = handler;
+ notify_obj->notify_handler.context = context;
+
+
+ if (handler_type == ACPI_SYSTEM_NOTIFY) {
+ obj_desc->device.sys_handler = notify_obj;
+ }
+
+ else {
+ obj_desc->device.drv_handler = notify_obj;
+ }
+
+
+unlock_and_exit:
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_remove_notify_handler
+ *
+ * PARAMETERS: Device - The device for which notifies will be handled
+ * Handler_type - The type of handler:
+ * ACPI_SYSTEM_NOTIFY: System_handler (00-7f)
+ * ACPI_DEVICE_NOTIFY: Driver_handler (80-ff)
+ * Handler - Address of the handler
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove a handler for notifies on an ACPI device
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_remove_notify_handler (
+ ACPI_HANDLE device,
+ u32 handler_type,
+ NOTIFY_HANDLER handler)
+{
+ ACPI_OBJECT_INTERNAL *notify_obj;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_NAMED_OBJECT *obj_entry;
+ ACPI_STATUS status = AE_OK;
+
+
+ /* Parameter validation */
+
+ if ((!handler) ||
+ (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+ /* Convert and validate the device handle */
+
+ obj_entry = acpi_ns_convert_handle_to_entry (device);
+ if (!obj_entry) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /*
+ * These are the ONLY objects that can receive ACPI notifications
+ */
+
+ if ((obj_entry->type != ACPI_TYPE_DEVICE) &&
+ (obj_entry->type != ACPI_TYPE_PROCESSOR) &&
+ (obj_entry->type != ACPI_TYPE_POWER) &&
+ (obj_entry->type != ACPI_TYPE_THERMAL))
+ {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Check for an existing internal object */
+
+ obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) obj_entry);
+ if (!obj_desc) {
+ status = AE_NOT_EXIST;
+ goto unlock_and_exit;
+ }
+
+ /*
+ * The object exists.
+ *
+ * Make sure the handler is installed.
+ */
+
+ if (handler_type == ACPI_SYSTEM_NOTIFY) {
+ notify_obj = obj_desc->device.sys_handler;
+ }
+ else {
+ notify_obj = obj_desc->device.drv_handler;
+ }
+
+ if ((!notify_obj) ||
+ (notify_obj->notify_handler.handler != handler))
+ {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /*
+ * Now we can remove the handler
+ */
+ if (handler_type == ACPI_SYSTEM_NOTIFY) {
+ obj_desc->device.sys_handler = NULL;
+ }
+ else {
+ obj_desc->device.drv_handler = NULL;
+ }
+
+ acpi_cm_remove_reference (notify_obj);
+
+unlock_and_exit:
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ return (status);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_install_gpe_handler
+ *
+ * PARAMETERS: Gpe_number - The GPE number. The numbering scheme is
+ * bank 0 first, then bank 1.
+ * Trigger - Whether this GPE should be treated as an
+ * edge- or level-triggered interrupt.
+ * Handler - Address of the handler
+ * Context - Value passed to the handler on each GPE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install a handler for a General Purpose Acpi_event.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_install_gpe_handler (
+ u32 gpe_number,
+ u32 type,
+ GPE_HANDLER handler,
+ void *context)
+{
+ ACPI_STATUS status = AE_OK;
+
+ /* Parameter validation */
+
+ if (!handler || (gpe_number > NUM_GPE)) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Ensure that we have a valid GPE number */
+
+ if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ acpi_cm_acquire_mutex (ACPI_MTX_EVENTS);
+
+ /* Make sure that there isn't a handler there already */
+
+ if (acpi_gbl_gpe_info[gpe_number].handler) {
+ status = AE_EXIST;
+ goto cleanup;
+ }
+
+ /* Install the handler */
+
+ acpi_gbl_gpe_info[gpe_number].handler = handler;
+ acpi_gbl_gpe_info[gpe_number].context = context;
+ acpi_gbl_gpe_info[gpe_number].type = (u8) type;
+
+ /* Clear the GPE (of stale events), the enable it */
+
+ acpi_hw_clear_gpe (gpe_number);
+ acpi_hw_enable_gpe (gpe_number);
+
+cleanup:
+ acpi_cm_release_mutex (ACPI_MTX_EVENTS);
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_remove_gpe_handler
+ *
+ * PARAMETERS: Gpe_number - The event to remove a handler
+ * Handler - Address of the handler
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove a handler for a General Purpose Acpi_event.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_remove_gpe_handler (
+ u32 gpe_number,
+ GPE_HANDLER handler)
+{
+ ACPI_STATUS status = AE_OK;
+
+
+ /* Parameter validation */
+
+ if (!handler || (gpe_number > NUM_GPE)) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Ensure that we have a valid GPE number */
+
+ if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Disable the GPE before removing the handler */
+
+ acpi_hw_disable_gpe (gpe_number);
+
+ acpi_cm_acquire_mutex (ACPI_MTX_EVENTS);
+
+ /* Make sure that the installed handler is the same */
+
+ if (acpi_gbl_gpe_info[gpe_number].handler != handler) {
+ acpi_hw_enable_gpe (gpe_number);
+ status = AE_BAD_PARAMETER;
+ goto cleanup;
+ }
+
+ /* Remove the handler */
+
+ acpi_gbl_gpe_info[gpe_number].handler = NULL;
+ acpi_gbl_gpe_info[gpe_number].context = NULL;
+
+cleanup:
+ acpi_cm_release_mutex (ACPI_MTX_EVENTS);
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_acquire_global_lock
+ *
+ * PARAMETERS: Timeout - How long the caller is willing to wait
+ * Out_handle - A handle to the lock if acquired
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Acquire the ACPI Global Lock
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_acquire_global_lock (
+ u32 timeout,
+ u32 *out_handle)
+{
+ ACPI_STATUS status;
+
+
+ acpi_aml_enter_interpreter ();
+
+ /*
+ * TBD: [Restructure] add timeout param to internal interface, and
+ * perhaps INTERPRETER_LOCKED
+ */
+
+ status = acpi_ev_acquire_global_lock ();
+ acpi_aml_exit_interpreter ();
+
+ *out_handle = 0;
+ return status;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_release_global_lock
+ *
+ * PARAMETERS: Handle - Returned from Acpi_acquire_global_lock
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Release the ACPI Global Lock
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_release_global_lock (
+ u32 handle)
+{
+
+
+ /* TBD: [Restructure] Validate handle */
+
+ acpi_ev_release_global_lock ();
+ return AE_OK;
+}
+
+
diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c
new file mode 100644
index 000000000..01f95f0c0
--- /dev/null
+++ b/drivers/acpi/events/evxfevnt.c
@@ -0,0 +1,513 @@
+/******************************************************************************
+ *
+ * Module Name: evxfevnt - External Interfaces, ACPI event disable/enable
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "hardware.h"
+#include "namesp.h"
+#include "events.h"
+#include "amlcode.h"
+#include "interp.h"
+
+#define _COMPONENT EVENT_HANDLING
+ MODULE_NAME ("evxfevnt");
+
+
+/**************************************************************************
+ *
+ * FUNCTION: Acpi_enable
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Ensures that the system control interrupt (SCI) is properly
+ * configured, disables SCI event sources, installs the SCI
+ * handler, and transfers the system into ACPI mode.
+ *
+ *************************************************************************/
+
+ACPI_STATUS
+acpi_enable (void)
+{
+ ACPI_STATUS status;
+
+
+ /* Make sure we've got ACPI tables */
+
+ if (!acpi_gbl_DSDT) {
+ return (AE_NO_ACPI_TABLES);
+ }
+
+ /* Make sure the BIOS supports ACPI mode */
+
+ if (SYS_MODE_LEGACY == acpi_hw_get_mode_capabilities()) {
+ return (AE_ERROR);
+ }
+
+ acpi_gbl_original_mode = acpi_hw_get_mode();
+
+ /*
+ * Initialize the Fixed and General Purpose Acpi_events prior. This is
+ * done prior to enabling SCIs to prevent interrupts from occuring
+ * before handers are installed.
+ */
+
+ if (ACPI_FAILURE (acpi_ev_fixed_event_initialize ())) {
+ return (AE_ERROR);
+ }
+
+ if (ACPI_FAILURE (acpi_ev_gpe_initialize())) {
+ return (AE_ERROR);
+ }
+
+ /* Install the SCI handler */
+
+ if (ACPI_FAILURE (acpi_ev_install_sci_handler ())) {
+ return (AE_ERROR);
+ }
+
+ /* Transition to ACPI mode */
+
+ if (AE_OK != acpi_hw_set_mode (SYS_MODE_ACPI)) {
+ return (AE_ERROR);
+ }
+
+ /* Install handlers for control method GPE handlers (_Lxx, _Exx) */
+
+ acpi_ev_init_gpe_control_methods ();
+
+ status = acpi_ev_init_global_lock_handler ();
+
+ return (status);
+}
+
+
+/**************************************************************************
+ *
+ * FUNCTION: Acpi_disable
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Returns the system to original ACPI/legacy mode, and
+ * uninstalls the SCI interrupt handler.
+ *
+ *************************************************************************/
+
+ACPI_STATUS
+acpi_disable (void)
+{
+
+
+ /* Restore original mode */
+
+ if (AE_OK != acpi_hw_set_mode (acpi_gbl_original_mode)) {
+ return (AE_ERROR);
+ }
+
+ /* Unload the SCI interrupt handler */
+
+ acpi_ev_remove_sci_handler ();
+ acpi_ev_restore_acpi_state ();
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_enable_event
+ *
+ * PARAMETERS: Event - The fixed event or GPE to be enabled
+ * Type - The type of event
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Enable an ACPI event (fixed and general purpose)
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_enable_event (
+ u32 event,
+ u32 type)
+{
+ ACPI_STATUS status = AE_OK;
+ u32 register_id;
+
+
+ /* The Type must be either Fixed Acpi_event or GPE */
+
+ switch (type)
+ {
+
+ case ACPI_EVENT_FIXED:
+
+ /* Decode the Fixed Acpi_event */
+
+ switch (event)
+ {
+ case ACPI_EVENT_PMTIMER:
+ register_id = TMR_EN;
+ break;
+
+ case ACPI_EVENT_GLOBAL:
+ register_id = GBL_EN;
+ break;
+
+ case ACPI_EVENT_POWER_BUTTON:
+ register_id = PWRBTN_EN;
+ break;
+
+ case ACPI_EVENT_SLEEP_BUTTON:
+ register_id = SLPBTN_EN;
+ break;
+
+ case ACPI_EVENT_RTC:
+ register_id = RTC_EN;
+ break;
+
+ default:
+ return (AE_BAD_PARAMETER);
+ break;
+ }
+
+ /*
+ * Enable the requested fixed event (by writing a one to the
+ * enable register bit)
+ */
+
+ acpi_hw_register_access (ACPI_WRITE, TRUE, register_id, 1);
+ break;
+
+
+ case ACPI_EVENT_GPE:
+
+ /* Ensure that we have a valid GPE number */
+
+ if ((event >= NUM_GPE) ||
+ (acpi_gbl_gpe_valid[event] == ACPI_GPE_INVALID))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /* Enable the requested GPE number */
+
+ acpi_hw_enable_gpe (event);
+ break;
+
+
+ default:
+
+ status = AE_BAD_PARAMETER;
+ }
+
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_disable_event
+ *
+ * PARAMETERS: Event - The fixed event or GPE to be enabled
+ * Type - The type of event
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Disable an ACPI event (fixed and general purpose)
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_disable_event (
+ u32 event,
+ u32 type)
+{
+ ACPI_STATUS status = AE_OK;
+ u32 register_id;
+
+
+ /* The Type must be either Fixed Acpi_event or GPE */
+
+ switch (type)
+ {
+
+ case ACPI_EVENT_FIXED:
+
+ /* Decode the Fixed Acpi_event */
+
+ switch (event)
+ {
+ case ACPI_EVENT_PMTIMER:
+ register_id = TMR_EN;
+ break;
+
+ case ACPI_EVENT_GLOBAL:
+ register_id = GBL_EN;
+ break;
+
+ case ACPI_EVENT_POWER_BUTTON:
+ register_id = PWRBTN_EN;
+ break;
+
+ case ACPI_EVENT_SLEEP_BUTTON:
+ register_id = SLPBTN_EN;
+ break;
+
+ case ACPI_EVENT_RTC:
+ register_id = RTC_EN;
+ break;
+
+ default:
+ return (AE_BAD_PARAMETER);
+ break;
+ }
+
+ /*
+ * Disable the requested fixed event (by writing a zero to the
+ * enable register bit)
+ */
+
+ acpi_hw_register_access (ACPI_WRITE, TRUE, register_id, 0);
+ break;
+
+
+ case ACPI_EVENT_GPE:
+
+ /* Ensure that we have a valid GPE number */
+
+ if ((event >= NUM_GPE) ||
+ (acpi_gbl_gpe_valid[event] == ACPI_GPE_INVALID))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Disable the requested GPE number */
+
+ acpi_hw_disable_gpe (event);
+ break;
+
+
+ default:
+ status = AE_BAD_PARAMETER;
+ }
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_clear_event
+ *
+ * PARAMETERS: Event - The fixed event or GPE to be cleared
+ * Type - The type of event
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Clear an ACPI event (fixed and general purpose)
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_clear_event (
+ u32 event,
+ u32 type)
+{
+ ACPI_STATUS status = AE_OK;
+ u32 register_id;
+
+
+ /* The Type must be either Fixed Acpi_event or GPE */
+
+ switch (type)
+ {
+
+ case ACPI_EVENT_FIXED:
+
+ /* Decode the Fixed Acpi_event */
+
+ switch (event)
+ {
+ case ACPI_EVENT_PMTIMER:
+ register_id = TMR_STS;
+ break;
+
+ case ACPI_EVENT_GLOBAL:
+ register_id = GBL_STS;
+ break;
+
+ case ACPI_EVENT_POWER_BUTTON:
+ register_id = PWRBTN_STS;
+ break;
+
+ case ACPI_EVENT_SLEEP_BUTTON:
+ register_id = SLPBTN_STS;
+ break;
+
+ case ACPI_EVENT_RTC:
+ register_id = RTC_STS;
+ break;
+
+ default:
+ return (AE_BAD_PARAMETER);
+ break;
+ }
+
+ /*
+ * Clear the requested fixed event (By writing a one to the
+ * status register bit)
+ */
+
+ acpi_hw_register_access (ACPI_WRITE, TRUE, register_id, 1);
+ break;
+
+
+ case ACPI_EVENT_GPE:
+
+ /* Ensure that we have a valid GPE number */
+
+ if ((event >= NUM_GPE) ||
+ (acpi_gbl_gpe_valid[event] == ACPI_GPE_INVALID))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ acpi_hw_clear_gpe (event);
+ break;
+
+
+ default:
+
+ status = AE_BAD_PARAMETER;
+ }
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_get_event_status
+ *
+ * PARAMETERS: Event - The fixed event or GPE
+ * Type - The type of event
+ * Status - Where the current status of the event will
+ * be returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Obtains and returns the current status of the event
+ *
+ ******************************************************************************/
+
+
+ACPI_STATUS
+acpi_get_event_status (
+ u32 event,
+ u32 type,
+ ACPI_EVENT_STATUS *event_status)
+{
+ ACPI_STATUS status = AE_OK;
+ u32 register_id;
+
+
+ if (!event_status) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /* The Type must be either Fixed Acpi_event or GPE */
+
+ switch (type)
+ {
+
+ case ACPI_EVENT_FIXED:
+
+ /* Decode the Fixed Acpi_event */
+
+ switch (event)
+ {
+ case ACPI_EVENT_PMTIMER:
+ register_id = TMR_STS;
+ break;
+
+ case ACPI_EVENT_GLOBAL:
+ register_id = GBL_STS;
+ break;
+
+ case ACPI_EVENT_POWER_BUTTON:
+ register_id = PWRBTN_STS;
+ break;
+
+ case ACPI_EVENT_SLEEP_BUTTON:
+ register_id = SLPBTN_STS;
+ break;
+
+ case ACPI_EVENT_RTC:
+ register_id = RTC_STS;
+ break;
+
+ default:
+ return (AE_BAD_PARAMETER);
+ break;
+ }
+
+ /* Get the status of the requested fixed event */
+
+ *event_status = acpi_hw_register_access (ACPI_READ, TRUE, register_id);
+ break;
+
+
+ case ACPI_EVENT_GPE:
+
+ /* Ensure that we have a valid GPE number */
+
+ if ((event >= NUM_GPE) ||
+ (acpi_gbl_gpe_valid[event] == ACPI_GPE_INVALID))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /* Obtain status on the requested GPE number */
+
+ acpi_hw_get_gpe_status (event, event_status);
+ break;
+
+
+ default:
+ status = AE_BAD_PARAMETER;
+ }
+
+
+ return (status);
+}
+
diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c
new file mode 100644
index 000000000..c54c726e8
--- /dev/null
+++ b/drivers/acpi/events/evxfregn.c
@@ -0,0 +1,389 @@
+/******************************************************************************
+ *
+ * Module Name: evxfregn - External Interfaces, ACPI Operation Regions and
+ * Address Spaces.
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "hardware.h"
+#include "namesp.h"
+#include "events.h"
+#include "amlcode.h"
+#include "interp.h"
+
+#define _COMPONENT EVENT_HANDLING
+ MODULE_NAME ("evxfregn");
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_install_address_space_handler
+ *
+ * PARAMETERS: Device - Handle for the device
+ * Space_id - The address space ID
+ * Handler - Address of the handler
+ * Context - Value passed to the handler on each access
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install a handler for accesses on an address space controlled
+ * a specific device.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_install_address_space_handler (
+ ACPI_HANDLE device,
+ ACPI_ADDRESS_SPACE_TYPE space_id,
+ ADDRESS_SPACE_HANDLER handler,
+ ADDRESS_SPACE_SETUP setup,
+ void *context)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_OBJECT_INTERNAL *handler_obj;
+ ACPI_NAMED_OBJECT *obj_entry;
+ ACPI_STATUS status = AE_OK;
+ OBJECT_TYPE_INTERNAL type;
+ u16 flags = 0;
+
+
+ /* Parameter validation */
+
+ if ((!device) ||
+ ((!handler) && (handler != ACPI_DEFAULT_HANDLER)) ||
+ (space_id > ACPI_MAX_ADDRESS_SPACE))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+ /* Convert and validate the device handle */
+
+ obj_entry = acpi_ns_convert_handle_to_entry (device);
+ if (!obj_entry) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /*
+ * This registration is valid for only the types below
+ * and the root. This is where the default handlers
+ * get placed.
+ */
+
+ if ((obj_entry->type != ACPI_TYPE_DEVICE) &&
+ (obj_entry->type != ACPI_TYPE_PROCESSOR) &&
+ (obj_entry->type != ACPI_TYPE_THERMAL) &&
+ (obj_entry != acpi_gbl_root_object))
+ {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ if (handler == ACPI_DEFAULT_HANDLER) {
+ flags = ADDR_HANDLER_DEFAULT_INSTALLED;
+
+ switch (space_id)
+ {
+ case ADDRESS_SPACE_SYSTEM_MEMORY:
+ handler = acpi_aml_system_memory_space_handler;
+ setup = acpi_ev_system_memory_region_setup;
+ break;
+
+ case ADDRESS_SPACE_SYSTEM_IO:
+ handler = acpi_aml_system_io_space_handler;
+ setup = acpi_ev_io_space_region_setup;
+ break;
+
+ case ADDRESS_SPACE_PCI_CONFIG:
+ handler = acpi_aml_pci_config_space_handler;
+ setup = acpi_ev_pci_config_region_setup;
+ break;
+
+ default:
+ status = AE_NOT_EXIST;
+ goto unlock_and_exit;
+ break;
+ }
+ }
+
+ /*
+ * If the caller hasn't specified a setup routine, use the default
+ */
+ if (!setup) {
+ setup = acpi_ev_default_region_setup;
+ }
+
+ /*
+ * Check for an existing internal object
+ */
+
+ obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) obj_entry);
+ if (obj_desc) {
+ /*
+ * The object exists.
+ * Make sure the handler is not already installed.
+ */
+
+ /* check the address handler the user requested */
+
+ handler_obj = obj_desc->device.addr_handler;
+ while (handler_obj) {
+ /*
+ * We have an Address handler, see if user requested this
+ * address space.
+ */
+ if(handler_obj->addr_handler.space_id == space_id) {
+ status = AE_EXIST;
+ goto unlock_and_exit;
+ }
+
+ /*
+ * Move through the linked list of handlers
+ */
+ handler_obj = handler_obj->addr_handler.link;
+ }
+ }
+
+ else {
+ /* Obj_desc does not exist, create one */
+
+ if (obj_entry->type == ACPI_TYPE_ANY) {
+ type = ACPI_TYPE_DEVICE;
+ }
+
+ else {
+ type = obj_entry->type;
+ }
+
+ obj_desc = acpi_cm_create_internal_object (type);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ /* Init new descriptor */
+
+ obj_desc->common.type = (u8) type;
+
+ /* Attach the new object to the NTE */
+
+ status = acpi_ns_attach_object (device, obj_desc, (u8) type);
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_remove_reference (obj_desc);
+ goto unlock_and_exit;
+ }
+
+ /* TBD: [Investigate] Will this always be of type DEVICE? */
+
+ if (type == ACPI_TYPE_DEVICE) {
+ obj_desc->device.handle = device;
+ }
+ }
+
+ /*
+ * Now we can install the handler
+ *
+ * At this point we know that there is no existing handler.
+ * So, we just allocate the object for the handler and link it
+ * into the list.
+ */
+ handler_obj = acpi_cm_create_internal_object (INTERNAL_TYPE_ADDRESS_HANDLER);
+ if (!handler_obj) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ handler_obj->addr_handler.space_id = (u16) space_id;
+ handler_obj->addr_handler.hflags = flags;
+ handler_obj->addr_handler.link = obj_desc->device.addr_handler;
+ handler_obj->addr_handler.region_list = NULL;
+ handler_obj->addr_handler.nte = obj_entry;
+ handler_obj->addr_handler.handler = handler;
+ handler_obj->addr_handler.context = context;
+ handler_obj->addr_handler.setup = setup;
+
+ /*
+ * Now walk the namespace finding all of the regions this
+ * handler will manage.
+ *
+ * We start at the device and search the branch toward
+ * the leaf nodes until either the leaf is encountered or
+ * a device is detected that has an address handler of the
+ * same type.
+ *
+ * In either case we back up and search down the remainder
+ * of the branch
+ */
+ status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, device,
+ ACPI_INT32_MAX, NS_WALK_NO_UNLOCK,
+ acpi_ev_addr_handler_helper,
+ handler_obj, NULL);
+
+ /*
+ * Place this handler 1st on the list
+ */
+
+ handler_obj->common.reference_count =
+ (u16) (handler_obj->common.reference_count +
+ obj_desc->common.reference_count - 1);
+ obj_desc->device.addr_handler = handler_obj;
+
+
+unlock_and_exit:
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_remove_address_space_handler
+ *
+ * PARAMETERS: Space_id - The address space ID
+ * Handler - Address of the handler
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install a handler for accesses on an Operation Region
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_remove_address_space_handler (
+ ACPI_HANDLE device,
+ ACPI_ADDRESS_SPACE_TYPE space_id,
+ ADDRESS_SPACE_HANDLER handler)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_OBJECT_INTERNAL *handler_obj;
+ ACPI_OBJECT_INTERNAL *region_obj;
+ ACPI_OBJECT_INTERNAL **last_obj_ptr;
+ ACPI_NAMED_OBJECT *obj_entry;
+ ACPI_STATUS status = AE_OK;
+
+
+ /* Parameter validation */
+
+ if ((!device) ||
+ ((!handler) && (handler != ACPI_DEFAULT_HANDLER)) ||
+ (space_id > ACPI_MAX_ADDRESS_SPACE))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+ /* Convert and validate the device handle */
+
+ obj_entry = acpi_ns_convert_handle_to_entry (device);
+ if (!obj_entry) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+
+ /* Make sure the internal object exists */
+
+ obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) obj_entry);
+ if (!obj_desc) {
+ /*
+ * The object DNE.
+ */
+ status = AE_NOT_EXIST;
+ goto unlock_and_exit;
+ }
+
+ /*
+ * find the address handler the user requested
+ */
+
+ handler_obj = obj_desc->device.addr_handler;
+ last_obj_ptr = &obj_desc->device.addr_handler;
+ while (handler_obj) {
+ /*
+ * We have a handler, see if user requested this one
+ */
+
+ if(handler_obj->addr_handler.space_id == space_id) {
+ /*
+ * Got it, first dereference this in the Regions
+ */
+ region_obj = handler_obj->addr_handler.region_list;
+
+ /* Walk the handler's region list */
+
+ while (region_obj) {
+ /*
+ * First disassociate the handler from the region.
+ *
+ * NOTE: this doesn't mean that the region goes away
+ * The region is just inaccessible as indicated to
+ * the _REG method
+ */
+ acpi_ev_disassociate_region_from_handler(region_obj);
+
+ /*
+ * Walk the list, since we took the first region and it
+ * was removed from the list by the dissassociate call
+ * we just get the first item on the list again
+ */
+ region_obj = handler_obj->addr_handler.region_list;
+
+ }
+
+ /*
+ * Remove this Handler object from the list
+ */
+ *last_obj_ptr = handler_obj->addr_handler.link;
+
+ /*
+ * Now we can delete the handler object
+ */
+ acpi_cm_remove_reference (handler_obj);
+ acpi_cm_remove_reference (handler_obj);
+
+ goto unlock_and_exit;
+ }
+
+ /*
+ * Move through the linked list of handlers
+ */
+ last_obj_ptr = &handler_obj->addr_handler.link;
+ handler_obj = handler_obj->addr_handler.link;
+ }
+
+
+ /*
+ * The handler does not exist
+ */
+ status = AE_NOT_EXIST;
+
+
+unlock_and_exit:
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ return (status);
+}
+
+
diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c
new file mode 100644
index 000000000..22c5471d8
--- /dev/null
+++ b/drivers/acpi/hardware/hwacpi.c
@@ -0,0 +1,207 @@
+
+/******************************************************************************
+ *
+ * Module Name: hwacpi - ACPI hardware functions - mode and timer
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "hardware.h"
+
+
+#define _COMPONENT HARDWARE
+ MODULE_NAME ("hwacpi");
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_hw_set_mode
+ *
+ * PARAMETERS: Mode - SYS_MODE_ACPI or SYS_MODE_LEGACY
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Transitions the system into the requested mode or does nothing
+ * if the system is already in that mode.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_hw_set_mode (
+ u32 mode)
+{
+
+ ACPI_STATUS status = AE_ERROR;
+
+
+ if (mode == SYS_MODE_ACPI) {
+ /* BIOS should have disabled ALL fixed and GP events */
+
+ acpi_os_out8 (acpi_gbl_FACP->smi_cmd, acpi_gbl_FACP->acpi_enable);
+ }
+
+ else if (mode == SYS_MODE_LEGACY) {
+ /*
+ * BIOS should clear all fixed status bits and restore fixed event
+ * enable bits to default
+ */
+
+ acpi_os_out8 (acpi_gbl_FACP->smi_cmd, acpi_gbl_FACP->acpi_disable);
+ }
+
+ if (acpi_hw_get_mode () == mode) {
+ status = AE_OK;
+ }
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_hw
+
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: SYS_MODE_ACPI or SYS_MODE_LEGACY
+ *
+ * DESCRIPTION: Return current operating state of system. Determined by
+ * querying the SCI_EN bit.
+ *
+ ******************************************************************************/
+
+u32
+acpi_hw_get_mode (void)
+{
+
+
+ if (acpi_hw_register_access (ACPI_READ, ACPI_MTX_LOCK, (s32)SCI_EN)) {
+ return (SYS_MODE_ACPI);
+ }
+ else {
+ return (SYS_MODE_LEGACY);
+ }
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_hw_get_mode_capabilities
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: logical OR of SYS_MODE_ACPI and SYS_MODE_LEGACY determined at initial
+ * system state.
+ *
+ * DESCRIPTION: Returns capablities of system
+ *
+ ******************************************************************************/
+
+u32
+acpi_hw_get_mode_capabilities (void)
+{
+
+
+ if (!(acpi_gbl_system_flags & SYS_MODES_MASK)) {
+ if (acpi_hw_get_mode () == SYS_MODE_LEGACY) {
+ /*
+ * Assume that if this call is being made, Acpi_init has been called
+ * and ACPI support has been established by the presence of the
+ * tables. Therefore since we're in SYS_MODE_LEGACY, the system
+ * must support both modes
+ */
+
+ acpi_gbl_system_flags |= (SYS_MODE_ACPI | SYS_MODE_LEGACY);
+ }
+
+ else {
+ /* TBD: [Investigate] !!! this may be unsafe... */
+ /*
+ * system is is ACPI mode, so try to switch back to LEGACY to see if
+ * it is supported
+ */
+ acpi_hw_set_mode (SYS_MODE_LEGACY);
+
+ if (acpi_hw_get_mode () == SYS_MODE_LEGACY) {
+ /* Now in SYS_MODE_LEGACY, so both are supported */
+
+ acpi_gbl_system_flags |= (SYS_MODE_ACPI | SYS_MODE_LEGACY);
+ acpi_hw_set_mode (SYS_MODE_ACPI);
+ }
+
+ else {
+ /* Still in SYS_MODE_ACPI so this must be an ACPI only system */
+
+ acpi_gbl_system_flags |= SYS_MODE_ACPI;
+ }
+ }
+ }
+
+ return (acpi_gbl_system_flags & SYS_MODES_MASK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_hw_pmt_ticks
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: Current value of the ACPI PMT (timer)
+ *
+ * DESCRIPTION: Obtains current value of ACPI PMT
+ *
+ ******************************************************************************/
+
+u32
+acpi_hw_pmt_ticks (void)
+{
+ u32 ticks;
+
+ ticks = acpi_os_in32 (acpi_gbl_FACP->pm_tmr_blk);
+
+ return (ticks);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_hw_pmt_resolution
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: Number of bits of resolution in the PMT (either 24 or 32)
+ *
+ * DESCRIPTION: Obtains resolution of the ACPI PMT (either 24bit or 32bit)
+ *
+ ******************************************************************************/
+
+u32
+acpi_hw_pmt_resolution (void)
+{
+ if (0 == acpi_gbl_FACP->tmr_val_ext) {
+ return (24);
+ }
+
+ return (32);
+}
+
diff --git a/drivers/acpi/hardware/hwcpu32.c b/drivers/acpi/hardware/hwcpu32.c
new file mode 100644
index 000000000..46cff8a66
--- /dev/null
+++ b/drivers/acpi/hardware/hwcpu32.c
@@ -0,0 +1,716 @@
+/******************************************************************************
+ *
+ * Name: hwcpu32.c - CPU support for IA32 (Throttling, Cx_states)
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "namesp.h"
+#include "hardware.h"
+
+#define _COMPONENT HARDWARE
+ MODULE_NAME ("Hwcpu32");
+
+
+#define BIT_4 0x10 /* TBD: [investigate] is this correct? */
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_hw_enter_c1
+ *
+ * PARAMETERS: Pblk_address - Address of the processor control block
+ * Pm_timer_ticks - Number of PM timer ticks elapsed while asleep
+ *
+ * RETURN: Function status.
+ *
+ * DESCRIPTION: Set C1 state on IA32 processor (halt)
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_hw_enter_c1(
+ ACPI_IO_ADDRESS pblk_address,
+ u32 *pm_timer_ticks)
+{
+ u32 timer = 0;
+
+
+ if (!pm_timer_ticks) {
+ /*
+ * Enter C1:
+ * ---------
+ */
+ enable();
+ halt();
+ *pm_timer_ticks = ACPI_UINT32_MAX;
+ }
+ else {
+ timer = acpi_hw_pmt_ticks ();
+
+ /*
+ * Enter C1:
+ * ---------
+ */
+ enable ();
+ halt ();
+
+ /*
+ * Compute Time in C1:
+ * -------------------
+ */
+ timer = acpi_hw_pmt_ticks () - timer;
+
+ *pm_timer_ticks = timer;
+ }
+
+ return AE_OK;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_hw_enter_c2
+ *
+ * PARAMETERS: Pblk_address - Address of the processor control block
+ * Pm_timer_ticks - Number of PM timer ticks elapsed while asleep
+ *
+ * RETURN: <none>
+ *
+ * DESCRIPTION: Set C2 state on IA32 processor
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_hw_enter_c2(
+ ACPI_IO_ADDRESS pblk_address,
+ u32 *pm_timer_ticks)
+{
+ u32 timer = 0;
+
+
+ if (!pblk_address || !pm_timer_ticks) {
+ return AE_BAD_PARAMETER;
+ }
+
+ /*
+ * Disable interrupts before all C2/C3 transitions.
+ */
+ disable ();
+
+ timer = acpi_hw_pmt_ticks ();
+
+ /*
+ * Enter C2:
+ * ---------
+ * Read from the P_LVL2 (P_BLK+4) register to invoke a C2 transition.
+ */
+ acpi_os_in8 ((ACPI_IO_ADDRESS) (pblk_address + 4));
+
+ /*
+ * Perform Dummy Op:
+ * -----------------
+ * We have to do something useless after reading LVL2 because chipsets
+ * cannot guarantee that STPCLK# gets asserted in time to freeze execution.
+ */
+ acpi_os_in8 ((ACPI_IO_ADDRESS) acpi_gbl_FACP->pm2_cnt_blk);
+
+ /*
+ * Compute Time in C2:
+ * -------------------
+ */
+ timer = acpi_hw_pmt_ticks () - timer;
+
+ *pm_timer_ticks = timer;
+
+ /*
+ * Re-enable interrupts after coming out of C2/C3.
+ */
+ enable ();
+
+ return AE_OK;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_hw_enter_c3
+ *
+ * PARAMETERS: Pblk_address - Address of the processor control block
+ * Pm_timer_ticks - Number of PM timer ticks elapsed while asleep
+ *
+ * RETURN: Status of function
+ *
+ * DESCRIPTION: Set C3 state on IA32 processor (UP only, cache coherency via
+ * disabling bus mastering)
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_hw_enter_c3(
+ ACPI_IO_ADDRESS pblk_address,
+ u32 *pm_timer_ticks)
+{
+ u32 timer = 0;
+ u8 pm2_cnt_blk = 0;
+ u32 bus_master_status = 0;
+
+
+ if (!pblk_address || !pm_timer_ticks) {
+ return AE_BAD_PARAMETER;
+ }
+
+ /*
+ * Check the BM_STS bit, if it is set, do not enter C3
+ * but clear the bit (with a write) and exit, telling
+ * the calling module that we spent zero time in C3.
+ * If bus mastering continues, this action should
+ * eventually cause a demotion to C2
+ */
+ if (1 == (bus_master_status =
+ acpi_hw_register_access (ACPI_READ, ACPI_MTX_LOCK, (s32)BM_STS)))
+ {
+ /*
+ * Clear the BM_STS bit by setting it.
+ */
+ acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_LOCK, (s32)BM_STS, 1);
+ *pm_timer_ticks = 0;
+ return AE_OK;
+ }
+
+ /*
+ * Disable interrupts before all C2/C3 transitions.
+ */
+ disable();
+
+ /*
+ * Disable Bus Mastering:
+ * ----------------------
+ * Set the PM2_CNT.ARB_DIS bit (bit #0), preserving all other bits.
+ */
+ pm2_cnt_blk = acpi_os_in8 ((ACPI_IO_ADDRESS) acpi_gbl_FACP->pm2_cnt_blk);
+ pm2_cnt_blk |= 0x01;
+ acpi_os_out8 ((ACPI_IO_ADDRESS) acpi_gbl_FACP->pm2_cnt_blk, pm2_cnt_blk);
+
+ /*
+ * Get the timer base before entering C state
+ */
+ timer = acpi_hw_pmt_ticks ();
+
+ /*
+ * Enter C3:
+ * ---------
+ * Read from the P_LVL3 (P_BLK+5) register to invoke a C3 transition.
+ */
+ acpi_os_in8 ((ACPI_IO_ADDRESS)(pblk_address + 5));
+
+ /*
+ * Perform Dummy Op:
+ * -----------------
+ * We have to do something useless after reading LVL3 because chipsets
+ * cannot guarantee that STPCLK# gets asserted in time to freeze execution.
+ */
+ acpi_os_in8 ((ACPI_IO_ADDRESS) acpi_gbl_FACP->pm2_cnt_blk);
+
+ /*
+ * Immediately compute the time in the C state
+ */
+ timer = acpi_hw_pmt_ticks() - timer;
+
+ /*
+ * Re-Enable Bus Mastering:
+ * ------------------------
+ * Clear the PM2_CNT.ARB_DIS bit (bit #0), preserving all other bits.
+ */
+ pm2_cnt_blk = acpi_os_in8 ((ACPI_IO_ADDRESS) acpi_gbl_FACP->pm2_cnt_blk);
+ pm2_cnt_blk &= 0xFE;
+ acpi_os_out8 ((ACPI_IO_ADDRESS) acpi_gbl_FACP->pm2_cnt_blk, pm2_cnt_blk);
+
+ /* TBD: [Unhandled]: Support 24-bit timers (this algorithm assumes 32-bit) */
+
+ *pm_timer_ticks = timer;
+
+ /*
+ * Re-enable interrupts after coming out of C2/C3.
+ */
+ enable();
+
+ return AE_OK;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_hw_enter_cx
+ *
+ * PARAMETERS: Processor_handle - handle of the processor
+ *
+ * RETURN: Status of function
+ *
+ * DESCRIPTION: Invoke the currently active processor Cx handler to put this
+ * processor to sleep.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_hw_enter_cx (
+ ACPI_IO_ADDRESS pblk_address,
+ u32 *pm_timer_ticks)
+{
+
+ if (!acpi_hw_cx_handlers[acpi_hw_active_cx_state]) {
+ return AE_SUPPORT;
+ }
+
+ return (acpi_hw_cx_handlers[acpi_hw_active_cx_state] (pblk_address, pm_timer_ticks));
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_hw_set_cx
+ *
+ * PARAMETERS: State - value (1-3) of the Cx state to 'make active'
+ *
+ * RETURN: Function status.
+ *
+ * DESCRIPTION: Sets the state to use during calls to Acpi_hw_enter_cx().
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_hw_set_cx (
+ u32 cx_state)
+{
+ /*
+ * Supported State?
+ * ----------------
+ */
+ if ((cx_state < 1) || (cx_state > 3)) {
+ return AE_BAD_PARAMETER;
+ }
+
+ if (!acpi_hw_cx_handlers[cx_state]) {
+ return AE_SUPPORT;
+ }
+
+ /*
+ * New Cx State?
+ * -------------
+ * We only care when moving from one state to another...
+ */
+ if (acpi_hw_active_cx_state == cx_state) {
+ return AE_OK;
+ }
+
+ /*
+ * Prepare to Use New State:
+ * -------------------------
+ * If the new Cx_state is C3, the BM_RLD bit must be set to allow
+ * the generation of a bus master requets to cause the processor
+ * in the C3 state to transition to the C0 state.
+ */
+ switch (cx_state)
+ {
+ case 3:
+ acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_LOCK, (s32)BM_RLD, 1);
+ break;
+ }
+
+ /*
+ * Clean up from Old State:
+ * ------------------------
+ * If the old Cx_state was C3, the BM_RLD bit is reset. When the
+ * bit is reset, the generation of a bus master request does not
+ * effect any processor in the C3 state.
+ */
+ switch (acpi_hw_active_cx_state)
+ {
+ case 3:
+ acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_LOCK, (s32)BM_RLD, 0);
+ break;
+ }
+
+ /*
+ * Enable:
+ * -------
+ */
+ acpi_hw_active_cx_state = cx_state;
+
+ return AE_OK;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_hw_get_cx_info
+ *
+ * PARAMETERS: Cx_states - Information (latencies) on all Cx states
+ *
+ * RETURN: Status of function
+ *
+ * DESCRIPTION: This function is called both to initialize Cx handling
+ * and retrieve the current Cx information (latency values).
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_hw_get_cx_info (
+ u32 cx_states[])
+{
+ u8 SMP_system = FALSE;
+
+
+ if (!cx_states) {
+ return(AE_BAD_PARAMETER);
+ }
+
+ /*
+ * TBD: [Unhandled] need to init SMP_system using info from the MAPIC
+ * table.
+ */
+
+ /*
+ * Set Defaults:
+ * -------------
+ * C0 and C1 support is implied (but what about that PROC_C1 register
+ * in the FADT?!?!). Set C2/C3 to max. latency (not supported until
+ * proven otherwise).
+ */
+ cx_states[0] = 0;
+ cx_states[1] = 0;
+ cx_states[2] = MAX_CX_STATE_LATENCY;
+ cx_states[3] = MAX_CX_STATE_LATENCY;
+
+ /*
+ * C2 Supported?
+ * -------------
+ * We're only supporting C2 when the latency is <= 100 microseconds,
+ * and on SMP systems when P_LVL2_UP (which indicates C2 only on UP)
+ * is not set.
+ */
+ if (acpi_gbl_FACP->plvl2_lat <= 100) {
+ if (!SMP_system) {
+ acpi_hw_cx_handlers[2] = acpi_hw_enter_c2;
+ cx_states[2] = acpi_gbl_FACP->plvl2_lat;
+ }
+
+ else if (!acpi_gbl_FACP->plvl2_up) {
+ acpi_hw_cx_handlers[2] = acpi_hw_enter_c2;
+ cx_states[2] = acpi_gbl_FACP->plvl2_lat;
+ }
+ }
+
+ /*
+ * C3 Supported?
+ * -------------
+ * We're only supporting C3 on UP systems when the latency is
+ * <= 1000 microseconds and that include the ability to disable
+ * Bus Mastering while in C3 (ARB_DIS) but allows Bus Mastering
+ * requests to wake the system from C3 (BM_RLD). Note his method
+ * of maintaining cache coherency (disabling of bus mastering)
+ * cannot be used on SMP systems, and flushing caches (e.g. WBINVD)
+ * is simply too costly (at this time).
+ */
+ if (acpi_gbl_FACP->plvl3_lat <= 1000) {
+ if (!SMP_system && (acpi_gbl_FACP->pm2_cnt_blk &&
+ acpi_gbl_FACP->pm2_cnt_len))
+ {
+ acpi_hw_cx_handlers[3] = acpi_hw_enter_c3;
+ cx_states[3] = acpi_gbl_FACP->plvl3_lat;
+ }
+ }
+
+ return(AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_hw_get_cx_handler
+ *
+ * PARAMETERS: State - the Cx state
+ * Handler - pointer to location for the returned handler
+ *
+ * RETURN: Status of function
+ *
+ * DESCRIPTION: This function is called to get an installed Cx state handler.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_hw_get_cx_handler (
+ u32 cx_state,
+ ACPI_C_STATE_HANDLER *handler)
+{
+
+ if ((cx_state == 0) || (cx_state >= MAX_CX_STATES) || !handler) {
+ return(AE_BAD_PARAMETER);
+ }
+
+ *handler = acpi_hw_cx_handlers[cx_state];
+
+ return(AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_hw_set_cx_handler
+ *
+ * PARAMETERS: Cx_state - the Cx state
+ * Handler - new Cx state handler
+ *
+ * RETURN: Status of function
+ *
+ * DESCRIPTION: This function is called to install a new Cx state handler.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_hw_set_cx_handler (
+ u32 cx_state,
+ ACPI_C_STATE_HANDLER handler)
+{
+
+ if ((cx_state == 0) || (cx_state >= MAX_CX_STATES) || !handler) {
+ return(AE_BAD_PARAMETER);
+ }
+
+ acpi_hw_cx_handlers[cx_state] = handler;
+
+ return(AE_OK);
+}
+
+
+/**************************************************************************
+ *
+ * FUNCTION: Acpi_hw_local_pow
+ *
+ * PARAMETERS: x,y operands
+ *
+ * RETURN: result
+ *
+ * DESCRIPTION: Compute x ^ y
+ *
+ *************************************************************************/
+
+NATIVE_UINT
+acpi_hw_local_pow (
+ NATIVE_UINT x,
+ NATIVE_UINT y)
+{
+ NATIVE_UINT i;
+ NATIVE_UINT result = 1;
+
+
+ for (i = 0; i < y; i++) {
+ result = result * x;
+ }
+
+ return result;
+}
+
+
+/**************************************************************************
+ *
+ * FUNCTION: Acpi_hw_enable_throttling
+ *
+ * PARAMETERS: Pblk_address - Address of Pcnt (Processor Control)
+ * register
+ *
+ * RETURN: none
+ *
+ * DESCRIPTION: Enable throttling by setting the THT_EN bit.
+ *
+ *************************************************************************/
+
+void
+acpi_hw_enable_throttling (
+ ACPI_IO_ADDRESS pblk_address)
+{
+ u32 pblk_value;
+
+
+ pblk_value = acpi_os_in32 (pblk_address);
+ pblk_value = pblk_value | BIT_4;
+ acpi_os_out32 (pblk_address, pblk_value);
+
+ return;
+}
+
+
+/**************************************************************************
+ *
+ * FUNCTION: Acpi_hw_disable_throttling
+ *
+ * PARAMETERS: Pblk_address - Address of Pcnt (Processor Control)
+ * register
+ *
+ * RETURN: none
+ *
+ * DESCRIPTION:Disable throttling by clearing the THT_EN bit
+ *
+ *************************************************************************/
+
+void
+acpi_hw_disable_throttling (
+ ACPI_IO_ADDRESS pblk_address)
+{
+ u32 pblk_value;
+
+
+ pblk_value = acpi_os_in32 (pblk_address);
+ pblk_value = pblk_value & (~(u32)BIT_4);
+ acpi_os_out32 (pblk_address, pblk_value);
+
+ return;
+}
+
+
+/**************************************************************************
+ *
+ * FUNCTION: Acpi_hw_get_duty_cycle
+ *
+ * PARAMETERS: Duty_offset Pcnt register duty cycle field offset
+ * Pblk_address Pcnt register address in chipset
+ * Num_throttle_states # of CPU throttle states this system
+ * supports
+ *
+ * RETURN: none
+ *
+ * DESCRIPTION: Get the duty cycle from the chipset
+ *
+ *************************************************************************/
+
+u32
+acpi_hw_get_duty_cycle (
+ u8 duty_offset,
+ ACPI_IO_ADDRESS pblk_address,
+ u32 num_throttle_states)
+{
+ NATIVE_UINT index;
+ u32 duty32_value;
+ u32 pcnt_mask_off_duty_field;
+
+
+ /*
+ * Use Num_throttle_states - 1 as mask [ex. 8 - 1 = 7 (Fh)]
+ * and then shift it into the right position
+ */
+ pcnt_mask_off_duty_field = num_throttle_states - 1;
+
+ /*
+ * Read in the current value from the port
+ */
+ duty32_value = acpi_os_in32 ((ACPI_IO_ADDRESS) pblk_address);
+
+ /*
+ * Shift the the value to LSB
+ */
+ for (index = 0; index < (NATIVE_UINT) duty_offset; index++) {
+ duty32_value = duty32_value >> 1;
+ }
+
+ /*
+ * Get the duty field only
+ */
+ duty32_value = duty32_value & pcnt_mask_off_duty_field;
+
+ return ((u32) duty32_value);
+}
+
+
+/**************************************************************************
+ *
+ * FUNCTION: Acpi_hw_program_duty_cycle
+ *
+ * PARAMETERS: Duty_offset Pcnt register duty cycle field offset
+ * Duty_cycle duty cycle to program into chipset
+ * Pblk_address Pcnt register address in chipset
+ * Num_throttle_states # of CPU throttle states this system
+ * supports
+ *
+ * RETURN: none
+ *
+ * DESCRIPTION: Program chipset with specified duty cycle by bit-shifting the
+ * duty cycle bits to the appropriate offset, reading the duty
+ * cycle register, OR-ing in the duty cycle, and writing it to
+ * the Pcnt register.
+ *
+ *************************************************************************/
+
+void
+acpi_hw_program_duty_cycle (
+ u8 duty_offset,
+ u32 duty_cycle,
+ ACPI_IO_ADDRESS pblk_address,
+ u32 num_throttle_states)
+{
+ NATIVE_UINT index;
+ u32 duty32_value;
+ u32 pcnt_mask_off_duty_field;
+ u32 port_value;
+
+
+ /*
+ * valid Duty_cycle passed
+ */
+ duty32_value = duty_cycle;
+
+ /*
+ * use Num_throttle_states - 1 as mask [ex. 8 - 1 = 7 (Fh)]
+ * and then shift it into the right position
+ */
+ pcnt_mask_off_duty_field = num_throttle_states - 1;
+
+ /*
+ * Shift the mask
+ */
+ for (index = 0; index < (NATIVE_UINT) duty_offset; index++) {
+ pcnt_mask_off_duty_field = pcnt_mask_off_duty_field << 1;
+ duty32_value = duty32_value << 1;
+ }
+
+ /*
+ * Read in the current value from the port
+ */
+ port_value = acpi_os_in32 ((ACPI_IO_ADDRESS) pblk_address);
+
+ /*
+ * Mask off the duty field so we don't OR in junk!
+ */
+ port_value = port_value & (~pcnt_mask_off_duty_field);
+
+ /*
+ * OR in the bits we want to write out to the port
+ */
+ port_value = (port_value | duty32_value) & (~(u32)BIT_4);
+
+ /*
+ * write it to the port
+ */
+ acpi_os_out32 ((ACPI_IO_ADDRESS) pblk_address, port_value);
+
+ return;
+}
+
+ \ No newline at end of file
diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c
new file mode 100644
index 000000000..0862018c2
--- /dev/null
+++ b/drivers/acpi/hardware/hwgpe.c
@@ -0,0 +1,208 @@
+/******************************************************************************
+ *
+ * Module Name: hwgpe - Low level GPE enable/disable/clear functions
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "hardware.h"
+#include "namesp.h"
+#include "events.h"
+
+#define _COMPONENT HARDWARE
+ MODULE_NAME ("hwgpe");
+
+
+u8 decode_to8bit [8] = {1,2,4,8,16,32,64,128};
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_hw_enable_gpe
+ *
+ * PARAMETERS: Gpe_number - The GPE
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Enable a single GPE.
+ *
+ ******************************************************************************/
+
+void
+acpi_hw_enable_gpe (
+ u32 gpe_number)
+{
+ u8 in_byte;
+ u32 register_index;
+ u8 bit_mask;
+
+ /*
+ * Translate GPE number to index into global registers array.
+ */
+ register_index = acpi_gbl_gpe_valid[gpe_number];
+
+ /*
+ * Figure out the bit offset for this GPE within the target register.
+ */
+ bit_mask = decode_to8bit [MOD_8 (gpe_number)];
+
+ /*
+ * Read the current value of the register, set the appropriate bit
+ * to enable the GPE, and write out the new register.
+ */
+ in_byte = acpi_os_in8 (acpi_gbl_gpe_registers[register_index].enable_addr);
+ acpi_os_out8 (acpi_gbl_gpe_registers[register_index].enable_addr,
+ (u8)(in_byte | bit_mask));
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_hw_disable_gpe
+ *
+ * PARAMETERS: Gpe_number - The GPE
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Disable a single GPE.
+ *
+ ******************************************************************************/
+
+void
+acpi_hw_disable_gpe (
+ u32 gpe_number)
+{
+ u8 in_byte;
+ u32 register_index;
+ u8 bit_mask;
+
+ /*
+ * Translate GPE number to index into global registers array.
+ */
+ register_index = acpi_gbl_gpe_valid[gpe_number];
+
+ /*
+ * Figure out the bit offset for this GPE within the target register.
+ */
+ bit_mask = decode_to8bit [MOD_8 (gpe_number)];
+
+ /*
+ * Read the current value of the register, clear the appropriate bit,
+ * and write out the new register value to disable the GPE.
+ */
+ in_byte = acpi_os_in8 (acpi_gbl_gpe_registers[register_index].enable_addr);
+ acpi_os_out8 (acpi_gbl_gpe_registers[register_index].enable_addr,
+ (u8)(in_byte & ~bit_mask));
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_hw_clear_gpe
+ *
+ * PARAMETERS: Gpe_number - The GPE
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Clear a single GPE.
+ *
+ ******************************************************************************/
+
+void
+acpi_hw_clear_gpe (
+ u32 gpe_number)
+{
+ u32 register_index;
+ u8 bit_mask;
+
+ /*
+ * Translate GPE number to index into global registers array.
+ */
+ register_index = acpi_gbl_gpe_valid[gpe_number];
+
+ /*
+ * Figure out the bit offset for this GPE within the target register.
+ */
+ bit_mask = decode_to8bit [MOD_8 (gpe_number)];
+
+ /*
+ * Write a one to the appropriate bit in the status register to
+ * clear this GPE.
+ */
+ acpi_os_out8 (acpi_gbl_gpe_registers[register_index].status_addr, bit_mask);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_hw_get_gpe_status
+ *
+ * PARAMETERS: Gpe_number - The GPE
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Return the status of a single GPE.
+ *
+ ******************************************************************************/
+
+void
+acpi_hw_get_gpe_status (
+ u32 gpe_number,
+ ACPI_EVENT_STATUS *event_status)
+{
+ u8 in_byte = 0;
+ u32 register_index = 0;
+ u8 bit_mask = 0;
+
+ if (!event_status) {
+ return;
+ }
+
+ (*event_status) = 0;
+
+ /*
+ * Translate GPE number to index into global registers array.
+ */
+ register_index = acpi_gbl_gpe_valid[gpe_number];
+
+ /*
+ * Figure out the bit offset for this GPE within the target register.
+ */
+ bit_mask = decode_to8bit [MOD_8 (gpe_number)];
+
+ /*
+ * Enabled?:
+ */
+ in_byte = acpi_os_in8 (acpi_gbl_gpe_registers[register_index].enable_addr);
+
+ if (bit_mask & in_byte) {
+ (*event_status) |= ACPI_EVENT_FLAG_ENABLED;
+ }
+
+ /*
+ * Set?
+ */
+ in_byte = acpi_os_in8 (acpi_gbl_gpe_registers[register_index].status_addr);
+
+ if (bit_mask & in_byte) {
+ (*event_status) |= ACPI_EVENT_FLAG_SET;
+ }
+}
diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c
new file mode 100644
index 000000000..947bdd148
--- /dev/null
+++ b/drivers/acpi/hardware/hwregs.c
@@ -0,0 +1,608 @@
+
+/******************************************************************************
+ *
+ * Module Name: hwregs - Read/write access functions for the various ACPI
+ * control and status registers.
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "hardware.h"
+#include "namesp.h"
+
+#define _COMPONENT HARDWARE
+ MODULE_NAME ("hwregs");
+
+
+/* This matches the #defines in actypes.h. */
+
+ACPI_STRING sleep_state_table[] = {"\\_S0_","\\_S1_","\\_S2_","\\_S3_",
+ "\\_S4_","\\_S4_b","\\_S5_"};
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_hw_get_bit_shift
+ *
+ * PARAMETERS: Mask - Input mask to determine bit shift from.
+ * Must have at least 1 bit set.
+ *
+ * RETURN: Bit location of the lsb of the mask
+ *
+ * DESCRIPTION: Returns the bit number for the low order bit that's set.
+ *
+ ******************************************************************************/
+
+s32
+acpi_hw_get_bit_shift (
+ u32 mask)
+{
+ s32 shift;
+
+
+ for (shift = 0; ((mask >> shift) & 1) == 0; shift++) { ; }
+
+ return (shift);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_hw_clear_acpi_status
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: none
+ *
+ * DESCRIPTION: Clears all fixed and general purpose status bits
+ *
+ ******************************************************************************/
+
+void
+acpi_hw_clear_acpi_status (void)
+{
+ u16 gpe_length;
+ u16 index;
+
+
+ acpi_cm_acquire_mutex (ACPI_MTX_HARDWARE);
+
+ acpi_os_out16 (acpi_gbl_FACP->pm1a_evt_blk, (u16) ALL_FIXED_STS_BITS);
+
+ if (acpi_gbl_FACP->pm1b_evt_blk) {
+ acpi_os_out16 ((u16) acpi_gbl_FACP->pm1b_evt_blk,
+ (u16) ALL_FIXED_STS_BITS);
+ }
+
+ /* now clear the GPE Bits */
+
+ if (acpi_gbl_FACP->gpe0blk_len) {
+ gpe_length = (u16) DIV_2 (acpi_gbl_FACP->gpe0blk_len);
+
+ for (index = 0; index < gpe_length; index++) {
+ acpi_os_out8 ((acpi_gbl_FACP->gpe0blk + index), (u8) 0xff);
+ }
+ }
+
+ if (acpi_gbl_FACP->gpe1_blk_len) {
+ gpe_length = (u16) DIV_2 (acpi_gbl_FACP->gpe1_blk_len);
+
+ for (index = 0; index < gpe_length; index++) {
+ acpi_os_out8 ((acpi_gbl_FACP->gpe1_blk + index), (u8) 0xff);
+ }
+ }
+
+ acpi_cm_release_mutex (ACPI_MTX_HARDWARE);
+ return;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_hw_obtain_sleep_type_register_data
+ *
+ * PARAMETERS: Sleep_state - Numeric state requested
+ * *Slp_Typ_a - Pointer to byte to receive SLP_TYPa value
+ * *Slp_Typ_b - Pointer to byte to receive SLP_TYPb value
+ *
+ * RETURN: Status - ACPI status
+ *
+ * DESCRIPTION: Acpi_hw_obtain_sleep_type_register_data() obtains the SLP_TYP and
+ * SLP_TYPb values for the sleep state requested.
+ *
+
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_hw_obtain_sleep_type_register_data (
+ u8 sleep_state,
+ u8 *slp_typ_a,
+ u8 *slp_typ_b)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+
+
+ /*
+ * Validate parameters
+ */
+
+ if ((sleep_state > ACPI_S_STATES_MAX) ||
+ !slp_typ_a || !slp_typ_b)
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Acpi_evaluate the namespace object containing the values for this state
+ */
+
+ status = acpi_ns_evaluate_by_name (sleep_state_table[sleep_state], NULL, &obj_desc);
+ if (AE_OK == status) {
+ if (obj_desc) {
+ /*
+ * We got something, now ensure it is correct. The object must
+ * be a package and must have at least 2 numeric values as the
+ * two elements
+ */
+
+ if ((obj_desc->common.type != ACPI_TYPE_PACKAGE) ||
+ ((obj_desc->package.elements[0])->common.type !=
+ ACPI_TYPE_NUMBER) ||
+ ((obj_desc->package.elements[1])->common.type !=
+ ACPI_TYPE_NUMBER))
+ {
+ /* Invalid _Sx_ package type or value */
+
+ REPORT_ERROR ("Object type returned from interpreter differs from expected value");
+ status = AE_ERROR;
+ }
+ else {
+ /*
+ * Valid _Sx_ package size, type, and value
+ */
+ *slp_typ_a =
+ (u8) (obj_desc->package.elements[0])->number.value;
+
+ *slp_typ_b =
+ (u8) (obj_desc->package.elements[1])->number.value;
+ }
+
+ acpi_cm_remove_reference (obj_desc);
+ }
+ }
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_hw_register_access
+ *
+ * PARAMETERS: Read_write - Either ACPI_READ or ACPI_WRITE.
+ * Use_lock - Lock the hardware
+ * Register_id - index of ACPI register to access
+ * Value - (only used on write) value to write to the
+ * register. Shifted all the way right.
+ *
+ * RETURN: Value written to or read from specified register. This value
+ * is shifted all the way right.
+ *
+ * DESCRIPTION: Generic ACPI register read/write function.
+ *
+ ******************************************************************************/
+
+u32
+acpi_hw_register_access (
+ NATIVE_UINT read_write,
+ u8 use_lock,
+ u32 register_id,
+ ...) /* Value (only used on write) */
+{
+ u32 register_value = 0;
+ u32 mask = 0;
+ u32 value = 0;
+ ACPI_IO_ADDRESS gpe_reg = 0;
+
+
+ if (read_write == ACPI_WRITE) {
+ va_list marker;
+
+ va_start (marker, register_id);
+ value = va_arg (marker, s32);
+ va_end (marker);
+ }
+
+ /*
+ * TBD: [Restructure] May want to split the Acpi_event code and the
+ * Control code
+ */
+
+ /*
+ * Decode the Register ID
+ */
+
+ switch (register_id & REGISTER_BLOCK_MASK)
+ {
+ case PM1_EVT:
+
+ if (register_id < TMR_EN) {
+ /* status register */
+
+ if (ACPI_MTX_LOCK == use_lock) {
+ acpi_cm_acquire_mutex (ACPI_MTX_HARDWARE);
+ }
+
+
+ register_value = (u32) acpi_os_in16 (acpi_gbl_FACP->pm1a_evt_blk);
+ if (acpi_gbl_FACP->pm1b_evt_blk) {
+ register_value |= (u32) acpi_os_in16 (acpi_gbl_FACP->pm1b_evt_blk);
+ }
+
+ switch (register_id)
+ {
+ case TMR_STS:
+ mask = TMR_STS_MASK;
+ break;
+
+ case BM_STS:
+ mask = BM_STS_MASK;
+ break;
+
+ case GBL_STS:
+ mask = GBL_STS_MASK;
+ break;
+
+ case PWRBTN_STS:
+ mask = PWRBTN_STS_MASK;
+ break;
+
+ case SLPBTN_STS:
+ mask = SLPBTN_STS_MASK;
+ break;
+
+ case RTC_STS:
+ mask = RTC_STS_MASK;
+ break;
+
+ case WAK_STS:
+ mask = WAK_STS_MASK;
+ break;
+
+ default:
+ mask = 0;
+ break;
+ }
+
+ if (read_write == ACPI_WRITE) {
+ /*
+ * Status registers are different from the rest. Clear by
+ * writing 1, writing 0 has no effect. So, the only relevent
+ * information is the single bit we're interested in, all
+ * others should be written as 0 so they will be left
+ * unchanged
+ */
+
+ value <<= acpi_hw_get_bit_shift (mask);
+ value &= mask;
+
+ if (value) {
+ acpi_os_out16 (acpi_gbl_FACP->pm1a_evt_blk, (u16) value);
+
+ if (acpi_gbl_FACP->pm1b_evt_blk) {
+ acpi_os_out16 (acpi_gbl_FACP->pm1b_evt_blk, (u16) value);
+ }
+
+ register_value = 0;
+ }
+ }
+
+ if (ACPI_MTX_LOCK == use_lock) {
+ acpi_cm_release_mutex (ACPI_MTX_HARDWARE);
+ }
+ }
+
+ else {
+ /* enable register */
+
+ if (ACPI_MTX_LOCK == use_lock) {
+ acpi_cm_acquire_mutex (ACPI_MTX_HARDWARE);
+ }
+
+ register_value = (u32) acpi_os_in16 (acpi_gbl_FACP->pm1a_evt_blk +
+ DIV_2 (acpi_gbl_FACP->pm1_evt_len));
+
+ if (acpi_gbl_FACP->pm1b_evt_blk) {
+ register_value |= (u32) acpi_os_in16 (acpi_gbl_FACP->pm1b_evt_blk +
+ DIV_2 (acpi_gbl_FACP->pm1_evt_len));
+
+ }
+
+ switch (register_id)
+ {
+ case TMR_EN:
+ mask = TMR_EN_MASK;
+ break;
+
+ case GBL_EN:
+ mask = GBL_EN_MASK;
+ break;
+
+ case PWRBTN_EN:
+ mask = PWRBTN_EN_MASK;
+ break;
+
+ case SLPBTN_EN:
+ mask = SLPBTN_EN_MASK;
+ break;
+
+ case RTC_EN:
+ mask = RTC_EN_MASK;
+ break;
+
+ default:
+ mask = 0;
+ break;
+ }
+
+ if (read_write == ACPI_WRITE) {
+ register_value &= ~mask;
+ value <<= acpi_hw_get_bit_shift (mask);
+ value &= mask;
+ register_value |= value;
+
+ acpi_os_out16 ((acpi_gbl_FACP->pm1a_evt_blk +
+ DIV_2 (acpi_gbl_FACP->pm1_evt_len)),
+ (u16) register_value);
+
+ if (acpi_gbl_FACP->pm1b_evt_blk) {
+ acpi_os_out16 ((acpi_gbl_FACP->pm1b_evt_blk +
+ DIV_2 (acpi_gbl_FACP->pm1_evt_len)),
+ (u16) register_value);
+ }
+ }
+ if(ACPI_MTX_LOCK == use_lock) {
+ acpi_cm_release_mutex (ACPI_MTX_HARDWARE);
+ }
+ }
+ break;
+
+
+ case PM1_CONTROL:
+
+ register_value = 0;
+
+ if (ACPI_MTX_LOCK == use_lock) {
+ acpi_cm_acquire_mutex (ACPI_MTX_HARDWARE);
+ }
+
+ if (register_id != SLP_TYPE_B) {
+ /*
+ * SLP_TYPx registers are written differently
+ * than any other control registers with
+ * respect to A and B registers. The value
+ * for A may be different than the value for B
+ */
+
+ register_value = (u32) acpi_os_in16 (acpi_gbl_FACP->pm1a_cnt_blk);
+ }
+
+ if (acpi_gbl_FACP->pm1b_cnt_blk && register_id != (s32) SLP_TYPE_A) {
+ register_value |= (u32) acpi_os_in16 (acpi_gbl_FACP->pm1b_cnt_blk);
+ }
+
+ switch (register_id)
+ {
+ case SCI_EN:
+ mask = SCI_EN_MASK;
+ break;
+
+ case BM_RLD:
+ mask = BM_RLD_MASK;
+ break;
+
+ case GBL_RLS:
+ mask = GBL_RLS_MASK;
+ break;
+
+ case SLP_TYPE_A:
+ case SLP_TYPE_B:
+ mask = SLP_TYPE_X_MASK;
+ break;
+
+ case SLP_EN:
+ mask = SLP_EN_MASK;
+ break;
+
+ default:
+ mask = 0;
+ break;
+ }
+
+ if (read_write == ACPI_WRITE) {
+ register_value &= ~mask;
+ value <<= acpi_hw_get_bit_shift (mask);
+ value &= mask;
+ register_value |= value;
+
+ /*
+ * SLP_TYPE_x registers are written differently
+ * than any other control registers with
+ * respect to A and B registers. The value
+ * for A may be different than the value for B
+ */
+
+ if (register_id != SLP_TYPE_B) {
+ if (mask == SLP_EN_MASK) {
+ disable(); /* disable interrupts */
+ }
+
+ acpi_os_out16 (acpi_gbl_FACP->pm1a_cnt_blk, (u16) register_value);
+
+ if (mask == SLP_EN_MASK) {
+ /*
+ * Enable interrupts, the SCI handler is likely going to
+ * be invoked as soon as interrupts are enabled, since gpe's
+ * and most fixed resume events also generate SCI's.
+ */
+ enable();
+ }
+ }
+
+ if (acpi_gbl_FACP->pm1b_cnt_blk && register_id != (s32) SLP_TYPE_A) {
+ acpi_os_out16 (acpi_gbl_FACP->pm1b_cnt_blk, (u16) register_value);
+ }
+ }
+
+ if (ACPI_MTX_LOCK == use_lock) {
+ acpi_cm_release_mutex (ACPI_MTX_HARDWARE);
+ }
+ break;
+
+
+ case PM2_CONTROL:
+
+ if (ACPI_MTX_LOCK == use_lock) {
+ acpi_cm_acquire_mutex (ACPI_MTX_HARDWARE);
+ }
+
+ register_value = (u32) acpi_os_in16 (acpi_gbl_FACP->pm2_cnt_blk);
+ switch (register_id)
+ {
+ case ARB_DIS:
+ mask = ARB_DIS_MASK;
+ break;
+
+ default:
+ mask = 0;
+ break;
+ }
+
+ if (read_write == ACPI_WRITE) {
+ register_value &= ~mask;
+ value <<= acpi_hw_get_bit_shift (mask);
+ value &= mask;
+ register_value |= value;
+
+ acpi_os_out16 (acpi_gbl_FACP->pm2_cnt_blk, (u16) register_value);
+ }
+
+ if (ACPI_MTX_LOCK == use_lock) {
+ acpi_cm_release_mutex (ACPI_MTX_HARDWARE);
+ }
+ break;
+
+
+ case PM_TIMER:
+
+ register_value = acpi_os_in32 (acpi_gbl_FACP->pm_tmr_blk);
+ mask = 0xFFFFFFFF;
+ break;
+
+
+ case GPE1_EN_BLOCK:
+
+ gpe_reg = (acpi_gbl_FACP->gpe1_blk + acpi_gbl_FACP->gpe1_base) +
+ (gpe_reg + (DIV_2 (acpi_gbl_FACP->gpe1_blk_len)));
+
+
+ case GPE1_STS_BLOCK:
+
+ if (!gpe_reg) {
+ gpe_reg = (acpi_gbl_FACP->gpe1_blk + acpi_gbl_FACP->gpe1_base);
+ }
+
+
+ case GPE0_EN_BLOCK:
+
+ if (!gpe_reg) {
+ gpe_reg = acpi_gbl_FACP->gpe0blk + DIV_2 (acpi_gbl_FACP->gpe0blk_len);
+ }
+
+
+ case GPE0_STS_BLOCK:
+
+ if (!gpe_reg) {
+ gpe_reg = acpi_gbl_FACP->gpe0blk;
+ }
+
+ /* Determine the bit to be accessed */
+
+ mask = (((u32) register_id) & BIT_IN_REGISTER_MASK);
+ mask = 1 << (mask-1);
+
+ /* The base address of the GPE 0 Register Block */
+ /* Plus 1/2 the length of the GPE 0 Register Block */
+ /* The enable register is the register following the Status Register */
+ /* and each register is defined as 1/2 of the total Register Block */
+
+ /* This sets the bit within Enable_bit that needs to be written to */
+ /* the register indicated in Mask to a 1, all others are 0 */
+
+ if (mask > LOW_BYTE) {
+ /* Shift the value 1 byte to the right and add 1 to the register */
+
+ mask >>= ONE_BYTE;
+ gpe_reg++;
+ }
+
+ /* Now get the current Enable Bits in the selected Reg */
+
+ if(ACPI_MTX_LOCK == use_lock) {
+ acpi_cm_acquire_mutex (ACPI_MTX_HARDWARE);
+ }
+
+ register_value = (u32) acpi_os_in8 (gpe_reg);
+ if (read_write == ACPI_WRITE) {
+ register_value &= ~mask;
+ value <<= acpi_hw_get_bit_shift (mask);
+ value &= mask;
+ register_value |= value;
+
+ /* This write will put the Action state into the General Purpose */
+
+ /* Enable Register indexed by the value in Mask */
+
+ acpi_os_out8 (gpe_reg, (u8) register_value);
+ register_value = (u32) acpi_os_in8 (gpe_reg);
+ }
+
+ if(ACPI_MTX_LOCK == use_lock) {
+ acpi_cm_release_mutex (ACPI_MTX_HARDWARE);
+ }
+ break;
+
+
+ case PROCESSOR_BLOCK:
+ default:
+
+ mask = 0;
+ break;
+ }
+
+
+ register_value &= mask;
+ register_value >>= acpi_hw_get_bit_shift (mask);
+
+ return (register_value);
+}
diff --git a/drivers/acpi/hardware/hwxface.c b/drivers/acpi/hardware/hwxface.c
new file mode 100644
index 000000000..f92e59c5f
--- /dev/null
+++ b/drivers/acpi/hardware/hwxface.c
@@ -0,0 +1,576 @@
+
+/******************************************************************************
+ *
+ * Name: hwxface.c - Hardware access external interfaces
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "namesp.h"
+#include "hardware.h"
+
+#define _COMPONENT HARDWARE
+ MODULE_NAME ("hwxface");
+
+
+/******************************************************************************
+ *
+ * Hardware globals
+ *
+ ******************************************************************************/
+
+
+ACPI_C_STATE_HANDLER acpi_hw_cx_handlers[MAX_CX_STATES] =
+ {NULL, acpi_hw_enter_c1, NULL, NULL};
+
+u32 acpi_hw_active_cx_state = 1;
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_get_processor_throttling_info
+ *
+ * PARAMETERS: Processor_handle - handle for the cpu to get info about
+ * User_buffer - caller supplied buffer
+ *
+ * RETURN: Status of function
+ *
+ * DESCRIPTION: Get throttling capabilities for the processor, this routine
+ * builds the data directly into the callers buffer
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_get_processor_throttling_info (
+ ACPI_HANDLE processor_handle,
+ ACPI_BUFFER *user_buffer)
+{
+ NATIVE_UINT percent_step;
+ NATIVE_UINT next_percent;
+ NATIVE_UINT num_throttle_states;
+ NATIVE_UINT buffer_space_needed;
+ NATIVE_UINT i;
+ u8 duty_offset;
+ u8 duty_width;
+ ACPI_NAMED_OBJECT *cpu_entry;
+ ACPI_OBJECT_INTERNAL *cpu_obj;
+ ACPI_CPU_THROTTLING_STATE *state_ptr;
+
+
+ /*
+ * Have to at least have a buffer to return info in
+ */
+ if (!user_buffer) {
+ return(AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Convert and validate the device handle
+ */
+
+ cpu_entry = acpi_ns_convert_handle_to_entry (processor_handle);
+ if (!cpu_entry) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Check for an existing internal object
+ */
+
+ cpu_obj = acpi_ns_get_attached_object ((ACPI_HANDLE) cpu_entry);
+ if (!cpu_obj) {
+ return (AE_NOT_FOUND);
+ }
+
+ duty_offset = acpi_gbl_FACP->duty_offset;
+ duty_width = acpi_gbl_FACP->duty_width;
+
+ /*
+ * P0 must always have a P_BLK all others may be null
+ * in either case, we can't thottle a processor that has no P_BLK
+ *
+ * Also if no Duty width, one state and it is 100%
+ *
+ */
+ if (!cpu_obj->processor.pblk_length || !duty_width ||
+ (0xFFFF < cpu_obj->processor.pblk_address))
+ {
+ /*
+ * Acpi_even though we can't throttle, we still have one state (100%)
+ */
+ num_throttle_states = 1;
+ }
+
+ else {
+ num_throttle_states = (int) acpi_hw_local_pow (2,duty_width);
+ }
+
+ buffer_space_needed = num_throttle_states * sizeof (ACPI_CPU_THROTTLING_STATE);
+
+ if ((user_buffer->length < buffer_space_needed) || !user_buffer->pointer) {
+ user_buffer->length = buffer_space_needed;
+ return (AE_BUFFER_OVERFLOW);
+ }
+
+ user_buffer->length = buffer_space_needed;
+ state_ptr = (ACPI_CPU_THROTTLING_STATE *) user_buffer->pointer;
+ percent_step = 1000 / num_throttle_states;
+
+ /*
+ * Build each entry in the buffer. Note that we're using the value
+ * 1000 and dividing each state by 10 to better avoid round-off
+ * accumulation. Also note that the throttling STATES are ordered
+ * sequentially from 100% (state 0) on down (e.g. 87.5% = state 1),
+ * which is exactly opposite from duty cycle values (12.5% = state 1).
+ */
+ for (i = 0, next_percent = 1000; i < num_throttle_states; i++) {
+ state_ptr[i].state_number = i;
+ state_ptr[i].percent_of_clock = next_percent / 10;
+ next_percent -= percent_step;
+ }
+
+ return(AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_get_processor_throttling_state
+ *
+ * PARAMETERS: Processor_handle - handle for the cpu to throttle
+ * Throttle_state - throttling state to enter
+ *
+ * RETURN: Status of function
+ *
+ * DESCRIPTION: Get current hardware throttling state
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_get_processor_throttling_state (
+ ACPI_HANDLE processor_handle,
+ u32 *throttle_state)
+{
+ ACPI_NAMED_OBJECT *cpu_entry;
+ ACPI_OBJECT_INTERNAL *cpu_obj;
+ u32 num_throttle_states;
+ u32 duty_cycle;
+ u8 duty_offset;
+ u8 duty_width;
+
+
+ /* Convert and validate the device handle */
+
+ cpu_entry = acpi_ns_convert_handle_to_entry (processor_handle);
+ if (!cpu_entry || !throttle_state) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Check for an existing internal object */
+
+ cpu_obj = acpi_ns_get_attached_object ((ACPI_HANDLE) cpu_entry);
+ if (!cpu_obj) {
+ return (AE_NOT_FOUND);
+ }
+
+ duty_offset = acpi_gbl_FACP->duty_offset;
+ duty_width = acpi_gbl_FACP->duty_width;
+
+ /*
+ * Must have a valid P_BLK P0 must have a P_BLK all others may be null
+ * in either case, we can't thottle a processor that has no P_BLK
+ * that means we are in the only supported state (0 - 100%)
+ *
+ * also, if Duty_width is zero there are no additional states
+ */
+ if (!cpu_obj->processor.pblk_length || !duty_width ||
+ (0xFFFF < cpu_obj->processor.pblk_address))
+ {
+ *throttle_state = 0;
+ return(AE_OK);
+ }
+
+ num_throttle_states = (u32) acpi_hw_local_pow (2,duty_width);
+
+ /*
+ * Get the current duty cycle value.
+ */
+ duty_cycle = acpi_hw_get_duty_cycle (duty_offset,
+ cpu_obj->processor.pblk_address,
+ num_throttle_states);
+
+ /*
+ * Convert duty cycle to throttling state (invert).
+ */
+ if (duty_cycle == 0) {
+ *throttle_state = 0;
+ }
+
+ else {
+ *throttle_state = num_throttle_states - duty_cycle;
+ }
+
+ return(AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_set_processor_throttling_state
+ *
+ * PARAMETERS: Processor_handle - handle for the cpu to throttle
+ * Throttle_state - throttling state to enter
+ *
+ * RETURN: Status of function
+ *
+ * DESCRIPTION: Set hardware into requested throttling state, the handle
+ * passed in must have a valid P_BLK
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_set_processor_throttling_state (
+ ACPI_HANDLE processor_handle,
+ u32 throttle_state)
+{
+ ACPI_NAMED_OBJECT *cpu_entry;
+ ACPI_OBJECT_INTERNAL *cpu_obj;
+ u32 num_throttle_states = 0;
+ u8 duty_offset = 0;
+ u8 duty_width = 0;
+ u32 duty_cycle = 0;
+
+
+ /* Convert and validate the device handle */
+
+ cpu_entry = acpi_ns_convert_handle_to_entry (processor_handle);
+ if (!cpu_entry) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Check for an existing internal object */
+
+ cpu_obj = acpi_ns_get_attached_object ((ACPI_HANDLE) cpu_entry);
+ if (!cpu_obj) {
+ return (AE_NOT_FOUND);
+ }
+
+ duty_offset = acpi_gbl_FACP->duty_offset;
+ duty_width = acpi_gbl_FACP->duty_width;
+
+ /*
+ * Must have a valid P_BLK P0 must have a P_BLK all others may be null
+ * in either case, we can't thottle a processor that has no P_BLK
+ * that means we are in the only supported state (0 - 100%)
+ *
+ * also, if Duty_width is zero there are no additional states
+ */
+ if (!cpu_obj->processor.pblk_length || !duty_width ||
+ (0xFFFF < cpu_obj->processor.pblk_address))
+ {
+ /*
+ * If caller wants to set the state to the only state we handle
+ * we're done.
+ */
+ if (throttle_state == 0) {
+ return (AE_OK);
+ }
+
+ /*
+ * Can't set this state
+ */
+ return (AE_SUPPORT);
+ }
+
+ num_throttle_states = (int) acpi_hw_local_pow (2,duty_width);
+
+ /*
+ * Convert throttling state to duty cycle (invert).
+ */
+ if (throttle_state > 0) {
+ duty_cycle = num_throttle_states - throttle_state;
+ }
+
+ /*
+ * Turn off throttling (don't muck with the h/w while throttling).
+ */
+ acpi_hw_disable_throttling (cpu_obj->processor.pblk_address);
+
+ /*
+ * Program the throttling state.
+ */
+ acpi_hw_program_duty_cycle (duty_offset, duty_cycle,
+ cpu_obj->processor.pblk_address, num_throttle_states);
+
+ /*
+ * Only enable throttling for non-zero states (0 - 100%)
+ */
+ if (throttle_state) {
+ acpi_hw_enable_throttling (cpu_obj->processor.pblk_address);
+ }
+
+ return(AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_get_processor_cx_info
+ *
+ * PARAMETERS: Processor_handle - handle for the cpu return info about
+ * User_buffer - caller supplied buffer
+ *
+ * RETURN: Status of function
+ *
+ * DESCRIPTION: Get Cx state latencies, this routine
+ * builds the data directly into the callers buffer
+ *
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_get_processor_cx_info (
+ ACPI_HANDLE processor_handle,
+ ACPI_BUFFER *user_buffer)
+{
+ ACPI_STATUS status = AE_OK;
+ u32 cx_state_latencies[4] = {0, 0, 0, 0};
+ NATIVE_UINT buffer_space_needed = 0;
+ ACPI_CX_STATE *state_ptr = NULL;
+ NATIVE_UINT i = 0;
+
+
+ /*
+ * Have to at least have a buffer to return info in
+ */
+ if (!user_buffer) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_hw_get_cx_info (cx_state_latencies);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ buffer_space_needed = 4 * sizeof (ACPI_CX_STATE);
+
+ if ((user_buffer->length < buffer_space_needed) || !user_buffer->pointer) {
+ user_buffer->length = buffer_space_needed;
+ return (AE_BUFFER_OVERFLOW);
+ }
+
+ user_buffer->length = buffer_space_needed;
+
+ state_ptr = (ACPI_CX_STATE *) user_buffer->pointer;
+
+ for (i = 0; i < 4; i++) {
+ state_ptr[i].state_number = i;
+ state_ptr[i].latency = cx_state_latencies[i];
+ }
+
+ return (AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_set_processor_sleep_state
+ *
+ * PARAMETERS: Processor_handle - handle for the cpu return info about
+ * Cx_state - the Cx sleeping state (C1-C3) to make
+ * 'active'
+ *
+ * RETURN: Status of function
+ *
+ * DESCRIPTION: Sets which Cx state will be used during calls to
+ * Acpi_processor_sleep ()
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_set_processor_sleep_state (
+ ACPI_HANDLE processor_handle,
+ u32 cx_state)
+{
+ ACPI_STATUS status;
+
+
+ status = acpi_hw_set_cx (cx_state);
+
+ return (status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_processor_sleep
+ *
+ * PARAMETERS: Processor_handle - handle for the cpu to put to sleep (Cx)
+ * Time_sleeping - time (in microseconds) elapsed while
+ * sleeping
+ *
+ * RETURN: Status of function
+ *
+ * DESCRIPTION: Puts the processor into the currently active sleep state (Cx)
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_processor_sleep (
+ ACPI_HANDLE processor_handle,
+ u32 *pm_timer_ticks)
+{
+ ACPI_NAMED_OBJECT *cpu_entry = NULL;
+ ACPI_OBJECT_INTERNAL *cpu_obj = NULL;
+ ACPI_IO_ADDRESS pblk_address = 0;
+
+
+ /*
+ * Convert Processor_handle to Pblk_addres...
+ */
+
+ /* Convert and validate the device handle */
+
+ cpu_entry = acpi_ns_convert_handle_to_entry (processor_handle);
+ if (!cpu_entry) {
+ return AE_BAD_PARAMETER;
+ }
+
+ /* Check for an existing internal object */
+
+ cpu_obj = acpi_ns_get_attached_object ((ACPI_HANDLE) cpu_entry);
+ if (!cpu_obj) {
+ return AE_NOT_FOUND;
+ }
+
+ /* Get the processor register block (P_BLK) address */
+
+ pblk_address = cpu_obj->processor.pblk_address;
+ if (!cpu_obj->processor.pblk_length) {
+ /* Ensure a NULL addresss (note that P_BLK isn't required for C1) */
+
+ pblk_address = 0;
+ }
+
+ /*
+ * Enter the currently active Cx sleep state.
+ */
+ return acpi_hw_enter_cx (pblk_address, pm_timer_ticks);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_get_timer
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: Current value of the ACPI PMT (timer)
+ *
+ * DESCRIPTION: Obtains current value of ACPI PMT
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_get_timer (
+ u32 *out_ticks)
+{
+
+ if (!out_ticks) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ *out_ticks = acpi_hw_pmt_ticks ();
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_set_firmware_waking_vector
+ *
+ * PARAMETERS: Physical_address - Physical address of ACPI real mode
+ * entry point.
+ *
+ * RETURN: AE_OK or AE_ERROR
+ *
+ * DESCRIPTION: Access function for d_firmware_waking_vector field in FACS
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_set_firmware_waking_vector (
+ void *physical_address)
+{
+
+ /* Make sure that we have an FACS */
+
+ if (!acpi_gbl_FACS) {
+ return (AE_NO_ACPI_TABLES);
+ }
+
+ /* Set the vector */
+
+ * ((void **) acpi_gbl_FACS->firmware_waking_vector) = physical_address;
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_get_firmware_waking_vector
+ *
+ * PARAMETERS: *Physical_address - Output buffer where contents of
+ * the d_firmware_waking_vector field of
+ * the FACS will be stored.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Access function for d_firmware_waking_vector field in FACS
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_get_firmware_waking_vector (
+ void **physical_address)
+{
+
+ if (!physical_address) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Make sure that we have an FACS */
+
+ if (!acpi_gbl_FACS) {
+ return (AE_NO_ACPI_TABLES);
+ }
+
+ /* Get the vector */
+
+ *physical_address = * ((void **) acpi_gbl_FACS->firmware_waking_vector);
+
+
+ return (AE_OK);
+}
+
+
diff --git a/drivers/acpi/include/acenv.h b/drivers/acpi/include/acenv.h
new file mode 100644
index 000000000..f2738537f
--- /dev/null
+++ b/drivers/acpi/include/acenv.h
@@ -0,0 +1,302 @@
+
+/******************************************************************************
+ *
+ * Name: acenv.h - Generation environment specific items
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 __ACENV_H__
+#define __ACENV_H__
+
+
+/*
+ * Environment configuration. The purpose of this file is to interface to the
+ * local generation environment.
+ *
+ * 1) ACPI_USE_SYSTEM_CLIBRARY - Define this if linking to an actual C library.
+ * Otherwise, local versions of string/memory functions will be used.
+ * 2) ACPI_USE_STANDARD_HEADERS - Define this if linking to a C library and
+ * the standard header files may be used.
+ *
+ * The ACPI subsystem only uses low level C library functions that do not call
+ * operating system services and may therefore be inlined in the code.
+ *
+ * It may be necessary to tailor these include files to the target
+ * generation environment.
+ *
+ *
+ * Functions and constants used from each header:
+ *
+ * string.h: memcpy
+ * memset
+ * strcat
+ * strcmp
+ * strcpy
+ * strlen
+ * strncmp
+ * strncat
+ * strncpy
+ *
+ * stdlib.h: strtoul
+ *
+ * stdarg.h: va_list
+ * va_arg
+ * va_start
+ * va_end
+ *
+ */
+
+
+/*
+ * Environment-specific configuration
+ */
+
+#ifdef _LINUX
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <asm/system.h>
+
+/* Single threaded */
+
+#define ACPI_APPLICATION
+
+/* Use native Linux string library */
+
+#define ACPI_USE_SYSTEM_CLIBRARY
+
+/* Special functions */
+
+#define strtoul simple_strtoul
+
+#else
+
+/* All other environments */
+
+#define ACPI_USE_STANDARD_HEADERS
+
+#endif
+
+
+/******************************************************************************
+ *
+ * C library configuration
+ *
+ *****************************************************************************/
+
+#ifdef ACPI_USE_SYSTEM_CLIBRARY
+/*
+ * Use the standard C library headers.
+ * We want to keep these to a minimum.
+ *
+ */
+
+#ifdef ACPI_USE_STANDARD_HEADERS
+/*
+ * Use the standard headers from the standard locations
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#endif /* ACPI_USE_STANDARD_HEADERS */
+
+/*
+ * We will be linking to the standard Clib functions
+ */
+
+#define STRSTR(s1,s2) strstr((char *) (s1), (char *) (s2))
+#define STRUPR(s) strupr((char *) (s))
+#define STRLEN(s) strlen((char *) (s))
+#define STRCPY(d,s) strcpy((char *) (d), (char *) (s))
+#define STRNCPY(d,s,n) strncpy((char *) (d), (char *) (s), (n))
+#define STRNCMP(d,s,n) strncmp((char *) (d), (char *) (s), (n))
+#define STRCMP(d,s) strcmp((char *) (d), (char *) (s))
+#define STRCAT(d,s) strcat((char *) (d), (char *) (s))
+#define STRNCAT(d,s,n) strncat((char *) (d), (char *) (s), (n))
+#define STRTOUL(d,s,n) strtoul((char *) (d), (char **) (s), (n))
+#define MEMCPY(d,s,n) memcpy(d, s, (size_t) n)
+#define MEMSET(d,s,n) memset(d, s, (size_t) n)
+#define TOUPPER toupper
+#define TOLOWER tolower
+
+
+/******************************************************************************
+ *
+ * Not using native C library, use local implementations
+ *
+ *****************************************************************************/
+#else
+
+/*
+ * Use local definitions of C library macros and functions
+ * NOTE: The function implementations may not be as efficient
+ * as an inline or assembly code implementation provided by a
+ * native C library.
+ */
+
+#ifndef va_arg
+
+#ifndef _VALIST
+#define _VALIST
+typedef char *va_list;
+#endif /* _VALIST */
+
+/*
+ * Storage alignment properties
+ */
+
+#define _AUPBND (sizeof(int) - 1)
+#define _ADNBND (sizeof(int) - 1)
+
+/*
+ * Variable argument list macro definitions
+ */
+
+#define _bnd(X, bnd) (((sizeof(X)) + (bnd)) & (~(bnd)))
+#define va_arg(ap, T) (*(T *)(((ap) += ((_bnd(T, _AUPBND))) \
+ - (_bnd(T, _ADNBND)))))
+#define va_end(ap) (void)0
+#define va_start(ap, A) (void) ((ap) = (((char *)&(A)) \
+ + (_bnd(A, _AUPBND))))
+
+#endif /* va_arg */
+
+
+#define STRSTR(s1,s2) acpi_cm_strstr ((char *) (s1), (char *) (s2))
+#define STRUPR(s) acpi_cm_strupr ((char *) (s))
+#define STRLEN(s) acpi_cm_strlen ((char *) (s))
+#define STRCPY(d,s) acpi_cm_strcpy ((char *) (d), (char *) (s))
+#define STRNCPY(d,s,n) acpi_cm_strncpy ((char *) (d), (char *) (s), (n))
+#define STRNCMP(d,s,n) acpi_cm_strncmp ((char *) (d), (char *) (s), (n))
+#define STRCMP(d,s) acpi_cm_strcmp ((char *) (d), (char *) (s))
+#define STRCAT(d,s) acpi_cm_strcat ((char *) (d), (char *) (s))
+#define STRNCAT(d,s,n) acpi_cm_strncat ((char *) (d), (char *) (s), (n))
+#define STRTOUL(d,s,n) acpi_cm_strtoul ((char *) (d), (char **) (s), (n))
+#define MEMCPY(d,s,n) acpi_cm_memcpy ((void *) (d), (const void *) (s), (n))
+#define MEMSET(d,v,n) acpi_cm_memset ((void *) (d), (v), (n))
+#define TOUPPER acpi_cm_to_upper
+#define TOLOWER acpi_cm_to_lower
+
+#endif /* ACPI_USE_SYSTEM_CLIBRARY */
+
+
+/******************************************************************************
+ *
+ * Assembly code macros
+ *
+ *****************************************************************************/
+
+/*
+ * Handle platform- and compiler-specific assembly language differences.
+ *
+ * Notes:
+ * 1) Interrupt 3 is used to break into a debugger
+ * 2) Interrupts are turned off during ACPI register setup
+ */
+
+
+#ifdef __GNUC__
+
+#ifdef __ia64__
+#define _IA64
+#endif
+
+#define ACPI_ASM_MACROS
+#define causeinterrupt(level)
+#define BREAKPOINT3
+#define disable() __cli()
+#define enable() __sti()
+#define halt() __asm__ __volatile__ ("sti; hlt":::"memory")
+#define wbinvd()
+
+
+/*! [Begin] no source code translation
+ *
+ * A brief explanation as GNU inline assembly is a bit hairy
+ * %0 is the output parameter in EAX ("=a")
+ * %1 and %2 are the input parameters in ECX ("c") and an immediate value ("i") respectively
+ * All actual register references are preceded with "%%" as in "%%edx"
+ * Immediate values in the assembly are preceded by "$" as in "$0x1"
+ * The final asm parameter is the non-output registers altered by the operation
+ */
+#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
+ do { \
+ int dummy; \
+ asm("1: movl (%1),%%eax;" \
+ "movl %%eax,%%edx;" \
+ "andl %2,%%edx;" \
+ "btsl $0x1,%%edx;" \
+ "adcl $0x0,%%edx;" \
+ "lock; cmpxchgl %%edx,(%1);" \
+ "jnz 1b;" \
+ "cmpb $0x3,%%dl;" \
+ "sbbl %%eax,%%eax" \
+ :"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~1L):"dx"); \
+ } while(0)
+
+#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
+ do { \
+ int dummy; \
+ asm("1: movl (%1),%%eax;" \
+ "movl %%eax,%%edx;" \
+ "andl %2,%%edx;" \
+ "lock; cmpxchgl %%edx,(%1);" \
+ "jnz 1b;" \
+ "andl $0x1,%%eax" \
+ :"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~3L):"dx"); \
+ } while(0)
+/*! [End] no source code translation !*/
+
+#endif /* __GNUC__ */
+
+
+#ifndef ACPI_ASM_MACROS
+
+/* Unrecognized compiler, use defaults */
+
+#define ACPI_ASM_MACROS
+#define causeinterrupt(level)
+#define BREAKPOINT3
+#define disable()
+#define enable()
+#define halt()
+
+#define ACPI_ACQUIRE_GLOBAL_LOCK(Glptr, acq)
+#define ACPI_RELEASE_GLOBAL_LOCK(Glptr, acq)
+
+#endif /* ACPI_ASM_MACROS */
+
+
+#ifdef ACPI_APPLICATION
+
+/* Don't want software interrupts within a ring3 application */
+
+#undef causeinterrupt
+#undef BREAKPOINT3
+#define causeinterrupt(level)
+#define BREAKPOINT3
+#endif
+
+
+#endif /* __ACENV_H__ */
diff --git a/drivers/acpi/include/acexcep.h b/drivers/acpi/include/acexcep.h
new file mode 100644
index 000000000..4913ffd2c
--- /dev/null
+++ b/drivers/acpi/include/acexcep.h
@@ -0,0 +1,162 @@
+
+/******************************************************************************
+ *
+ * Name: acexcep.h - Exception codes returned by the ACPI subsystem
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 __ACEXCEP_H__
+#define __ACEXCEP_H__
+
+
+/*
+ * Exceptions returned by external ACPI interfaces
+ */
+
+#define ACPI_SUCCESS(a) (!(a))
+#define ACPI_FAILURE(a) (a)
+
+#define AE_OK (ACPI_STATUS) 0x0000
+#define AE_CTRL_RETURN_VALUE (ACPI_STATUS) 0x0001
+#define AE_CTRL_PENDING (ACPI_STATUS) 0x0002
+#define AE_CTRL_TERMINATE (ACPI_STATUS) 0x0003
+#define AE_CTRL_TRUE (ACPI_STATUS) 0x0004
+#define AE_CTRL_FALSE (ACPI_STATUS) 0x0005
+#define AE_CTRL_DEPTH (ACPI_STATUS) 0x0006
+#define AE_CTRL_RESERVED (ACPI_STATUS) 0x0007
+#define AE_AML_ERROR (ACPI_STATUS) 0x0008
+#define AE_AML_PARSE (ACPI_STATUS) 0x0009
+#define AE_AML_BAD_OPCODE (ACPI_STATUS) 0x000A
+#define AE_AML_NO_OPERAND (ACPI_STATUS) 0x000B
+#define AE_AML_OPERAND_TYPE (ACPI_STATUS) 0x000C
+#define AE_AML_OPERAND_VALUE (ACPI_STATUS) 0x000D
+#define AE_AML_UNINITIALIZED_LOCAL (ACPI_STATUS) 0x000E
+#define AE_AML_UNINITIALIZED_ARG (ACPI_STATUS) 0x000F
+#define AE_AML_UNINITIALIZED_ELEMENT (ACPI_STATUS) 0x0010
+#define AE_AML_NUMERIC_OVERFLOW (ACPI_STATUS) 0x0011
+#define AE_AML_REGION_LIMIT (ACPI_STATUS) 0x0012
+#define AE_AML_BUFFER_LIMIT (ACPI_STATUS) 0x0013
+#define AE_AML_PACKAGE_LIMIT (ACPI_STATUS) 0x0014
+#define AE_AML_DIVIDE_BY_ZERO (ACPI_STATUS) 0x0015
+#define AE_AML_BAD_NAME (ACPI_STATUS) 0x0016
+#define AE_AML_NAME_NOT_FOUND (ACPI_STATUS) 0x0017
+#define AE_AML_INTERNAL (ACPI_STATUS) 0x0018
+#define AE_AML_RESERVED (ACPI_STATUS) 0x0019
+#define AE_ERROR (ACPI_STATUS) 0x001A
+#define AE_NO_ACPI_TABLES (ACPI_STATUS) 0x001B
+#define AE_NO_NAMESPACE (ACPI_STATUS) 0x001C
+#define AE_NO_MEMORY (ACPI_STATUS) 0x001D
+#define AE_BAD_SIGNATURE (ACPI_STATUS) 0x001E
+#define AE_BAD_HEADER (ACPI_STATUS) 0x001F
+#define AE_BAD_CHECKSUM (ACPI_STATUS) 0x0020
+#define AE_BAD_PARAMETER (ACPI_STATUS) 0x0021
+#define AE_BAD_CHARACTER (ACPI_STATUS) 0x0022
+#define AE_BAD_PATHNAME (ACPI_STATUS) 0x0023
+#define AE_BAD_DATA (ACPI_STATUS) 0x0024
+#define AE_BAD_ADDRESS (ACPI_STATUS) 0x0025
+#define AE_NOT_FOUND (ACPI_STATUS) 0x0026
+#define AE_NOT_EXIST (ACPI_STATUS) 0x0027
+#define AE_EXIST (ACPI_STATUS) 0x0028
+#define AE_TYPE (ACPI_STATUS) 0x0029
+#define AE_NULL_OBJECT (ACPI_STATUS) 0x002A
+#define AE_NULL_ENTRY (ACPI_STATUS) 0x002B
+#define AE_BUFFER_OVERFLOW (ACPI_STATUS) 0x002C
+#define AE_STACK_OVERFLOW (ACPI_STATUS) 0x002D
+#define AE_STACK_UNDERFLOW (ACPI_STATUS) 0x002E
+#define AE_NOT_IMPLEMENTED (ACPI_STATUS) 0x002F
+#define AE_VERSION_MISMATCH (ACPI_STATUS) 0x0030
+#define AE_SUPPORT (ACPI_STATUS) 0x0031
+#define AE_SHARE (ACPI_STATUS) 0x0032
+#define AE_LIMIT (ACPI_STATUS) 0x0033
+#define AE_TIME (ACPI_STATUS) 0x0034
+#define AE_UNKNOWN_STATUS (ACPI_STATUS) 0x0035
+#define ACPI_MAX_STATUS (ACPI_STATUS) 0x0035
+#define ACPI_NUM_STATUS (ACPI_STATUS) 0x0036
+
+
+#ifdef DEFINE_ACPI_GLOBALS
+
+/*
+ * String versions of the exception codes above
+ * These strings must match the corresponding defines exactly
+ */
+static char *acpi_gbl_exception_names[] =
+{
+ "AE_OK",
+ "AE_CTRL_RETURN_VALUE",
+ "AE_CTRL_PENDING",
+ "AE_CTRL_TERMINATE",
+ "AE_CTRL_TRUE",
+ "AE_CTRL_FALSE",
+ "AE_CTRL_DEPTH",
+ "AE_CTRL_RESERVED",
+ "AE_AML_ERROR",
+ "AE_AML_PARSE",
+ "AE_AML_BAD_OPCODE",
+ "AE_AML_NO_OPERAND",
+ "AE_AML_OPERAND_TYPE",
+ "AE_AML_OPERAND_VALUE",
+ "AE_AML_UNINITIALIZED_LOCAL",
+ "AE_AML_UNINITIALIZED_ARG",
+ "AE_AML_UNINITIALIZED_ELEMENT",
+ "AE_AML_NUMERIC_OVERFLOW",
+ "AE_AML_REGION_LIMIT",
+ "AE_AML_BUFFER_LIMIT",
+ "AE_AML_PACKAGE_LIMIT",
+ "AE_AML_DIVIDE_BY_ZERO",
+ "AE_AML_BAD_NAME",
+ "AE_AML_NAME_NOT_FOUND",
+ "AE_AML_INTERNAL",
+ "AE_AML_RESERVED",
+ "AE_ERROR",
+ "AE_NO_ACPI_TABLES",
+ "AE_NO_NAMESPACE",
+ "AE_NO_MEMORY",
+ "AE_BAD_SIGNATURE",
+ "AE_BAD_HEADER",
+ "AE_BAD_CHECKSUM",
+ "AE_BAD_PARAMETER",
+ "AE_BAD_CHARACTER",
+ "AE_BAD_PATHNAME",
+ "AE_BAD_DATA",
+ "AE_BAD_ADDRESS",
+ "AE_NOT_FOUND",
+ "AE_NOT_EXIST",
+ "AE_EXIST",
+ "AE_TYPE",
+ "AE_NULL_OBJECT",
+ "AE_NULL_ENTRY",
+ "AE_BUFFER_OVERFLOW",
+ "AE_STACK_OVERFLOW",
+ "AE_STACK_UNDERFLOW",
+ "AE_NOT_IMPLEMENTED",
+ "AE_VERSION_MISMATCH",
+ "AE_SUPPORT",
+ "AE_SHARE",
+ "AE_LIMIT",
+ "AE_TIME",
+ "AE_UNKNOWN_STATUS"
+};
+
+#endif /* DEFINE_ACPI_GLOBALS */
+
+
+#endif /* __ACEXCEP_H__ */
diff --git a/drivers/acpi/include/acobject.h b/drivers/acpi/include/acobject.h
new file mode 100644
index 000000000..449e23bb4
--- /dev/null
+++ b/drivers/acpi/include/acobject.h
@@ -0,0 +1,508 @@
+
+/******************************************************************************
+ *
+ * Name: acobject.h - Definition of ACPI_OBJECT_INTERNAL (Internal object only)
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 _ACOBJECT_H
+#define _ACOBJECT_H
+
+#include "actypes.h"
+#include "macros.h"
+#include "internal.h"
+
+/*
+ * The ACPI_OBJECT_INTERNAL is used to pass AML operands from the dispatcher
+ * to the interpreter, and to keep track of the various handlers such as
+ * address space handlers and notify handlers. The object is a constant
+ * size in order to allow them to be cached and reused.
+ *
+ * All variants of the ACPI_OBJECT_INTERNAL are defined with the same
+ * sequence of field types, with fields that are not used in a particular
+ * variant being named "Reserved". This is not strictly necessary, but
+ * may in some circumstances simplify understanding if these structures
+ * need to be displayed in a debugger having limited (or no) support for
+ * union types. It also simplifies some debug code in Dump_table() which
+ * dumps multi-level values: fetching Buffer.Pointer suffices to pick up
+ * the value or next level for any of several types.
+ */
+
+/******************************************************************************
+ *
+ * Common Descriptors
+ *
+ *****************************************************************************/
+
+/*
+ * Common area for all objects.
+ *
+ * Data_type is used to differentiate between internal descriptors, and MUST
+ * be the first byte in this structure.
+ */
+
+
+#define ACPI_OBJECT_COMMON_HEADER /* Two 32-bit fields */\
+ u8 data_type; /* To differentiate various internal objs */\
+ u8 type; /* ACPI_OBJECT_TYPE */\
+ u8 size; /* Size of entire descriptor */\
+ u8 flags;\
+ u16 reference_count; /* For object deletion management */\
+ u16 acpi_cm_fill2;\
+ union acpi_obj_internal *next; \
+
+/* Defines for flag byte above */
+
+#define AO_STATIC_ALLOCATION 0x1
+
+
+/*
+ * Common bitfield for the field objects
+ */
+#define ACPI_COMMON_FIELD_INFO /* Three 32-bit values */\
+ u32 offset; /* Byte offset within containing object */\
+ u16 length; /* # of bits in buffer */ \
+ u8 granularity;\
+ u8 bit_offset; /* Bit offset within min read/write data unit */\
+ u8 access; /* Access_type */\
+ u8 lock_rule;\
+ u8 update_rule;\
+ u8 access_attribute;
+
+
+/******************************************************************************
+ *
+ * Individual Object Descriptors
+ *
+ *****************************************************************************/
+
+
+typedef struct /* COMMON */
+{
+ ACPI_OBJECT_COMMON_HEADER
+ UCHAR first_non_common_byte;
+
+} ACPI_OBJECT_COMMON;
+
+
+typedef struct /* NUMBER - has value */
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ u32 value;
+ u32 reserved2;
+ u32 reserved3;
+ u32 reserved4;
+
+ void *reserved_p1;
+ void *reserved_p2;
+ void *reserved_p3;
+ void *reserved_p4;
+ void *reserved_p5;
+
+} ACPI_OBJECT_NUMBER;
+
+
+typedef struct /* STRING - has length and pointer */
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ u32 length; /* # of bytes in string, excluding trailing null */
+ u32 reserved2;
+ u32 reserved3;
+ u32 reserved4;
+
+ char *pointer; /* String value in AML stream or in allocated space */
+ void *reserved_p2;
+ void *reserved_p3;
+ void *reserved_p4;
+ void *reserved_p5;
+
+} ACPI_OBJECT_STRING;
+
+
+typedef struct /* BUFFER - has length, sequence, and pointer */
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ u32 length; /* # of bytes in buffer */
+ u32 sequence; /* Sequential count of buffers created */
+ u32 reserved3;
+ u32 reserved4;
+
+ u8 *pointer; /* points to the buffer in allocated space */
+ void *reserved_p2;
+ void *reserved_p3;
+ void *reserved_p4;
+ void *reserved_p5;
+
+} ACPI_OBJECT_BUFFER;
+
+
+typedef struct /* PACKAGE - has count, elements, next element */
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ u32 count; /* # of elements in package */
+ u32 reserved2;
+ u32 reserved3;
+ u32 reserved4;
+
+ union acpi_obj_internal **elements; /* Array of pointers to Acpi_objects */
+ union acpi_obj_internal **next_element; /* used only while initializing */
+ void *reserved_p3;
+ void *reserved_p4;
+ void *reserved_p5;
+
+} ACPI_OBJECT_PACKAGE;
+
+
+typedef struct /* FIELD UNIT */
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ ACPI_COMMON_FIELD_INFO
+ u32 sequence; /* Container's sequence number */
+
+ union acpi_obj_internal *container; /* Containing object (Buffer) */
+ void *reserved_p2;
+ void *reserved_p3;
+ void *reserved_p4;
+ void *reserved_p5;
+
+} ACPI_OBJECT_FIELD_UNIT;
+
+
+typedef struct /* DEVICE - has handle and notification handler/context */
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ u32 reserved1;
+ u32 reserved2;
+ u32 reserved3;
+ u32 reserved4;
+
+ ACPI_HANDLE handle;
+ union acpi_obj_internal *sys_handler; /* Handler for system notifies */
+ union acpi_obj_internal *drv_handler; /* Handler for driver notifies */
+ union acpi_obj_internal *addr_handler; /* Handler for Address space */
+ void *reserved_p5;
+
+} ACPI_OBJECT_DEVICE;
+
+
+typedef struct /* EVENT */
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ u16 lock_count;
+ u16 thread_id;
+ u16 signal_count;
+ u16 fill1;
+ u32 reserved3;
+ u32 reserved4;
+
+ void *semaphore;
+ void *reserved_p2;
+ void *reserved_p3;
+ void *reserved_p4;
+ void *reserved_p5;
+
+} ACPI_OBJECT_EVENT;
+
+
+#define INFINITE_CONCURRENCY 0xFF
+
+typedef struct /* METHOD */
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ u8 method_flags;
+ u8 param_count;
+ u8 concurrency;
+ u8 fill1;
+ u32 pcode_length;
+ u32 table_length;
+ ACPI_OWNER_ID owning_id;
+ u16 reserved4;
+
+ u8 *pcode;
+ u8 *acpi_table;
+ void *parser_op;
+ void *semaphore;
+ void *reserved_p5;
+
+} ACPI_OBJECT_METHOD;
+
+
+typedef struct /* MUTEX */
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ u16 lock_count;
+ u16 thread_id;
+ u16 sync_level;
+ u16 fill1;
+ u32 reserved3;
+ u32 reserved4;
+
+ void *semaphore;
+ void *reserved_p2;
+ void *reserved_p3;
+ void *reserved_p4;
+ void *reserved_p5;
+
+} ACPI_OBJECT_MUTEX;
+
+/* Flags for Region */
+
+#define INITIAL_REGION_FLAGS 0x0000 /* value set when the region is created */
+#define REGION_AGRUMENT_DATA_VALID 0x0001 /* Addr/Len are set */
+#define REGION_INITIALIZED 0x0002 /* region init handler has been called */
+ /* this includes _REG method, if any */
+
+typedef struct /* REGION */
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ u16 space_id;
+ u16 region_flags; /* bits defined above */
+ u32 address;
+ u32 length;
+ u32 reserved4; /* Region Specific data (PCI _ADR) */
+
+ union acpi_obj_internal *method; /* Associated control method */
+ union acpi_obj_internal *addr_handler; /* Handler for system notifies */
+ union acpi_obj_internal *link; /* Link in list of regions */
+ /* list is owned by Addr_handler */
+ ACPI_NAMED_OBJECT *REGmethod; /* _REG method for this region (if any) */
+ ACPI_NAMED_OBJECT *nte; /* containing object */
+
+} ACPI_OBJECT_REGION;
+
+
+typedef struct /* POWER RESOURCE - has Handle and notification handler/context*/
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ u32 system_level;
+ u32 resource_order;
+ u32 reserved3;
+ u32 reserved4;
+
+ ACPI_HANDLE handle;
+ union acpi_obj_internal *sys_handler; /* Handler for system notifies */
+ union acpi_obj_internal *drv_handler; /* Handler for driver notifies */
+ void *reserved_p4;
+ void *reserved_p5;
+
+} ACPI_OBJECT_POWER_RESOURCE;
+
+
+typedef struct /* PROCESSOR - has Handle and notification handler/context*/
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ u32 proc_id;
+ ACPI_IO_ADDRESS pblk_address;
+ u16 fill1;
+ u32 pblk_length;
+ u32 reserved4;
+
+ ACPI_HANDLE handle;
+ union acpi_obj_internal *sys_handler; /* Handler for system notifies */
+ union acpi_obj_internal *drv_handler; /* Handler for driver notifies */
+ union acpi_obj_internal *addr_handler; /* Handler for Address space */
+ void *reserved_p5;
+
+} ACPI_OBJECT_PROCESSOR;
+
+
+typedef struct /* THERMAL ZONE - has Handle and Handler/Context */
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ u32 reserved1;
+ u32 reserved2;
+ u32 reserved3;
+ u32 reserved4;
+
+ ACPI_HANDLE handle;
+ union acpi_obj_internal *sys_handler; /* Handler for system notifies */
+ union acpi_obj_internal *drv_handler; /* Handler for driver notifies */
+ union acpi_obj_internal *addr_handler; /* Handler for Address space */
+ void *reserved_p5;
+
+} ACPI_OBJECT_THERMAL_ZONE;
+
+
+/*
+ * Internal types
+ */
+
+typedef struct /* FIELD */
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ ACPI_COMMON_FIELD_INFO
+ u32 reserved4;
+
+ union acpi_obj_internal *container; /* Containing object */
+ void *reserved_p2;
+ void *reserved_p3;
+ void *reserved_p4;
+ void *reserved_p5;
+
+} ACPI_OBJECT_FIELD;
+
+
+typedef struct /* BANK FIELD */
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ ACPI_COMMON_FIELD_INFO
+ u32 value; /* Value to store into Bank_select */
+
+ ACPI_HANDLE bank_select; /* Bank select register */
+ union acpi_obj_internal *container; /* Containing object */
+ void *reserved_p3;
+ void *reserved_p4;
+ void *reserved_p5;
+
+} ACPI_OBJECT_BANK_FIELD;
+
+
+typedef struct /* INDEX FIELD */
+{
+ /*
+ * No container pointer needed since the index and data register definitions
+ * will define how to access the respective registers
+ */
+ ACPI_OBJECT_COMMON_HEADER
+
+ ACPI_COMMON_FIELD_INFO
+ u32 value; /* Value to store into Index register */
+
+ ACPI_HANDLE index; /* Index register */
+ ACPI_HANDLE data; /* Data register */
+ void *reserved_p3;
+ void *reserved_p4;
+ void *reserved_p5;
+
+} ACPI_OBJECT_INDEX_FIELD;
+
+
+typedef struct /* NOTIFY HANDLER */
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ u32 reserved1;
+ u32 reserved2;
+ u32 reserved3;
+ u32 reserved4;
+
+ ACPI_NAMED_OBJECT *nte; /* Parent device */
+ NOTIFY_HANDLER handler;
+ void *context;
+ void *reserved_p4;
+ void *reserved_p5;
+
+} ACPI_OBJECT_NOTIFY_HANDLER;
+
+
+/* Flags for address handler */
+
+#define ADDR_HANDLER_DEFAULT_INSTALLED 0x1
+
+typedef struct /* ADDRESS HANDLER */
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ u16 space_id;
+ u16 hflags;
+ ADDRESS_SPACE_HANDLER handler;
+
+ ACPI_NAMED_OBJECT *nte; /* Parent device */
+ void *context;
+ ADDRESS_SPACE_SETUP setup;
+ union acpi_obj_internal *link; /* Link to next handler on device */
+ union acpi_obj_internal *region_list; /* regions using this handler */
+
+} ACPI_OBJECT_ADDR_HANDLER;
+
+
+/*
+ * The Reference object type is used for these opcodes:
+ * Arg[0-6], Local[0-7], Index_op, Name_op, Zero_op, One_op, Ones_op, Debug_op
+ */
+
+typedef struct /* Reference - Local object type */
+{
+ ACPI_OBJECT_COMMON_HEADER
+
+ u16 op_code;
+ u8 fill1;
+ u8 target_type; /* Used for Index_op */
+ u32 offset; /* Used for Arg_op, Local_op, and Index_op */
+ u32 reserved3;
+ u32 reserved4;
+
+ void *object; /* Name_op=>HANDLE to obj, Index_op=>ACPI_OBJECT_INTERNAL */
+ ACPI_NAMED_OBJECT *nte;
+ union acpi_obj_internal **where;
+ void *reserved_p4;
+ void *reserved_p5;
+
+} ACPI_OBJECT_REFERENCE;
+
+
+/******************************************************************************
+ *
+ * ACPI_OBJECT_INTERNAL Descriptor - a giant union of all of the above
+ *
+ *****************************************************************************/
+
+typedef union acpi_obj_internal
+{
+ ACPI_OBJECT_COMMON common;
+ ACPI_OBJECT_NUMBER number;
+ ACPI_OBJECT_STRING string;
+ ACPI_OBJECT_BUFFER buffer;
+ ACPI_OBJECT_PACKAGE package;
+ ACPI_OBJECT_FIELD_UNIT field_unit;
+ ACPI_OBJECT_DEVICE device;
+ ACPI_OBJECT_EVENT event;
+ ACPI_OBJECT_METHOD method;
+ ACPI_OBJECT_MUTEX mutex;
+ ACPI_OBJECT_REGION region;
+ ACPI_OBJECT_POWER_RESOURCE power_resource;
+ ACPI_OBJECT_PROCESSOR processor;
+ ACPI_OBJECT_THERMAL_ZONE thermal_zone;
+ ACPI_OBJECT_FIELD field;
+ ACPI_OBJECT_BANK_FIELD bank_field;
+ ACPI_OBJECT_INDEX_FIELD index_field;
+ ACPI_OBJECT_REFERENCE reference;
+ ACPI_OBJECT_NOTIFY_HANDLER notify_handler;
+ ACPI_OBJECT_ADDR_HANDLER addr_handler;
+
+} ACPI_OBJECT_INTERNAL;
+
+#endif /* _ACOBJECT_H */
diff --git a/drivers/acpi/include/acpi.h b/drivers/acpi/include/acpi.h
new file mode 100644
index 000000000..5dc0a853a
--- /dev/null
+++ b/drivers/acpi/include/acpi.h
@@ -0,0 +1,50 @@
+
+/******************************************************************************
+ *
+ * Name: acpi.h - Master include file, Publics and external data.
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 __ACPI_H__
+#define __ACPI_H__
+
+/*
+ * Common includes for all ACPI driver files
+ * We put them here because we don't want to duplicate them
+ * in the rest of the source code again and again.
+ */
+#include "config.h" /* Configuration constants */
+#include "acenv.h" /* Target environment specific items */
+#include "actypes.h" /* Fundamental data types */
+#include "acexcep.h" /* Local exception codes */
+#include "macros.h" /* C macros */
+#include "actables.h" /* Acpi table definitions */
+#include "internal.h" /* Internal data types */
+#include "output.h" /* Error output and Debug macros */
+#include "acpiosxf.h" /* Interfaces to the Acpi-to-OS layer*/
+#include "acpixf.h" /* Acpi core external interfaces */
+#include "acobject.h" /* Acpi internal object */
+#include "globals.h" /* All global variables */
+#include "hardware.h" /* Hardware defines and interfaces */
+#include "common.h" /* Common (global) interfaces */
+
+
+#endif /* __ACPI_H__ */
diff --git a/drivers/acpi/include/acpiosxf.h b/drivers/acpi/include/acpiosxf.h
new file mode 100644
index 000000000..6f5c30c56
--- /dev/null
+++ b/drivers/acpi/include/acpiosxf.h
@@ -0,0 +1,296 @@
+
+/******************************************************************************
+ *
+ * Name: acpiosd.h - All interfaces to the OS-dependent layer. These
+ * interfaces must be implemented by the OS-dependent
+ * front-end to the ACPI subsystem.
+ *
+ *****************************************************************************/
+
+
+/*
+ * Copyright (C) 2000 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 __ACPIOSD_H__
+#define __ACPIOSD_H__
+
+#include "acenv.h"
+#include "actypes.h"
+
+
+/* Priorities for Acpi_os_queue_for_execution */
+
+#define OSD_PRIORITY_HIGH 1
+#define OSD_PRIORITY_MED 2
+#define OSD_PRIORITY_LO 3
+#define OSD_PRIORITY_GPE OSD_PRIORITY_HIGH
+
+#define ACPI_NO_UNIT_LIMIT ((u32) -1)
+#define ACPI_MUTEX_SEM 1
+
+
+/*
+ * Types specific to the OS-dependent layer interfaces
+ */
+
+typedef
+u32 (*OSD_HANDLER) (
+ void *context);
+
+typedef
+void (*OSD_EXECUTION_CALLBACK) (
+ void *context);
+
+
+/*
+ * Initialization and shutdown primitives (Optional)
+ */
+
+ACPI_STATUS
+acpi_os_initialize (
+ void);
+
+ACPI_STATUS
+acpi_os_terminate (
+ void);
+
+/*
+ * Synchronization primitives
+ */
+
+ACPI_STATUS
+acpi_os_create_semaphore (
+ u32 max_units,
+ u32 initial_units,
+ ACPI_HANDLE *out_handle);
+
+ACPI_STATUS
+acpi_os_delete_semaphore (
+ ACPI_HANDLE handle);
+
+ACPI_STATUS
+acpi_os_wait_semaphore (
+ ACPI_HANDLE handle,
+ u32 units,
+ u32 timeout);
+
+ACPI_STATUS
+acpi_os_signal_semaphore (
+ ACPI_HANDLE handle,
+ u32 units);
+
+/*
+ * Memory allocation and mapping
+ */
+
+void *
+acpi_os_allocate (
+ u32 size);
+
+void *
+acpi_os_callocate (
+ u32 size);
+
+void
+acpi_os_free (
+ void * memory);
+
+ACPI_STATUS
+acpi_os_map_memory (
+ void *physical_address,
+ u32 length,
+ void **logical_address);
+
+void
+acpi_os_unmap_memory (
+ void *logical_address,
+ u32 length);
+
+
+/*
+ * Interrupt handlers
+ */
+
+ACPI_STATUS
+acpi_os_install_interrupt_handler (
+ u32 interrupt_number,
+ OSD_HANDLER service_routine,
+ void *context);
+
+ACPI_STATUS
+acpi_os_remove_interrupt_handler (
+ u32 interrupt_number,
+ OSD_HANDLER service_routine);
+
+
+/*
+ * Scheduling
+ */
+
+ACPI_STATUS
+acpi_os_queue_for_execution (
+ u32 priority,
+ OSD_EXECUTION_CALLBACK function,
+ void *context);
+
+void
+acpi_os_sleep (
+ u32 seconds,
+ u32 milliseconds);
+
+void
+acpi_os_sleep_usec (
+ u32 microseconds);
+
+/*
+ * Platform/Hardware independent I/O interfaces
+ */
+
+u8
+acpi_os_in8 (
+ ACPI_IO_ADDRESS in_port);
+
+
+u16
+acpi_os_in16 (
+ ACPI_IO_ADDRESS in_port);
+
+u32
+acpi_os_in32 (
+ ACPI_IO_ADDRESS in_port);
+
+void
+acpi_os_out8 (
+ ACPI_IO_ADDRESS out_port,
+ u8 value);
+
+void
+acpi_os_out16 (
+ ACPI_IO_ADDRESS out_port,
+ u16 value);
+
+void
+acpi_os_out32 (
+ ACPI_IO_ADDRESS out_port,
+ u32 value);
+
+
+/*
+ * Standard access to PCI configuration space
+ */
+
+ACPI_STATUS
+acpi_os_read_pci_cfg_byte (
+ u32 bus,
+ u32 device_function,
+ u32 register,
+ u8 *value);
+
+ACPI_STATUS
+acpi_os_read_pci_cfg_word (
+ u32 bus,
+ u32 device_function,
+ u32 register,
+ u16 *value);
+
+ACPI_STATUS
+acpi_os_read_pci_cfg_dword (
+ u32 bus,
+ u32 device_function,
+ u32 register,
+ u32 *value);
+
+ACPI_STATUS
+acpi_os_write_pci_cfg_byte (
+ u32 bus,
+ u32 device_function,
+ u32 register,
+ u8 value);
+
+ACPI_STATUS
+acpi_os_write_pci_cfg_word (
+ u32 bus,
+ u32 device_function,
+ u32 register,
+ u16 value);
+
+
+ACPI_STATUS
+acpi_os_write_pci_cfg_dword (
+ u32 bus,
+ u32 device_function,
+ u32 register,
+ u32 value);
+
+
+/*
+ * Miscellaneous
+ */
+
+ACPI_STATUS
+acpi_os_breakpoint (
+ char *message);
+
+u8
+acpi_os_readable (
+ void *pointer,
+ u32 length);
+
+
+u8
+acpi_os_writable (
+ void *pointer,
+ u32 length);
+
+
+/*
+ * Debug print routines
+ */
+
+s32
+acpi_os_printf (
+ const char *format,
+ ...);
+
+s32
+acpi_os_vprintf (
+ const char *format,
+ va_list args);
+
+/*
+ * Debug input
+ */
+
+u32
+acpi_os_get_line (
+ char *buffer);
+
+
+/*
+ * Debug
+ */
+
+void
+acpi_os_dbg_assert(
+ void *failed_assertion,
+ void *file_name,
+ u32 line_number,
+ char *message);
+
+
+#endif /* __ACPIOSD_H__ */
diff --git a/drivers/acpi/include/acpixf.h b/drivers/acpi/include/acpixf.h
new file mode 100644
index 000000000..cc2205b63
--- /dev/null
+++ b/drivers/acpi/include/acpixf.h
@@ -0,0 +1,299 @@
+
+/******************************************************************************
+ *
+ * Name: acxface.h - External interfaces to the ACPI subsystem
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 __ACXFACE_H__
+#define __ACXFACE_H__
+
+#include "actypes.h"
+#include "actables.h"
+
+/*
+ * Global interfaces
+ */
+
+ACPI_STATUS
+acpi_initialize (
+ ACPI_INIT_DATA *init_data);
+
+ACPI_STATUS
+acpi_terminate (
+ void);
+
+ACPI_STATUS
+acpi_enable (
+ void);
+
+ACPI_STATUS
+acpi_disable (
+ void);
+
+ACPI_STATUS
+acpi_get_system_info(
+ ACPI_BUFFER *ret_buffer);
+
+ACPI_STATUS
+acpi_format_exception (
+ ACPI_STATUS exception,
+ ACPI_BUFFER *out_buffer);
+
+
+/*
+ * ACPI table manipulation interfaces
+ */
+
+ACPI_STATUS
+acpi_load_firmware_tables (
+ void);
+
+ACPI_STATUS
+acpi_load_table (
+ ACPI_TABLE_HEADER *table_ptr);
+
+ACPI_STATUS
+acpi_unload_table (
+ ACPI_TABLE_TYPE table_type);
+
+ACPI_STATUS
+acpi_get_table_header (
+ ACPI_TABLE_TYPE table_type,
+ u32 instance,
+ ACPI_TABLE_HEADER *out_table_header);
+
+ACPI_STATUS
+acpi_get_table (
+ ACPI_TABLE_TYPE table_type,
+ u32 instance,
+ ACPI_BUFFER *ret_buffer);
+
+
+/*
+ * Namespace and name interfaces
+ */
+
+ACPI_STATUS
+acpi_load_namespace (
+ void);
+
+ACPI_STATUS
+acpi_walk_namespace (
+ ACPI_OBJECT_TYPE type,
+ ACPI_HANDLE start_object,
+ u32 max_depth,
+ WALK_CALLBACK user_function,
+ void *context,
+ void * *return_value);
+
+ACPI_STATUS
+acpi_get_name (
+ ACPI_HANDLE handle,
+ u32 name_type,
+ ACPI_BUFFER *ret_path_ptr);
+
+ACPI_STATUS
+acpi_get_handle (
+ ACPI_HANDLE parent,
+ ACPI_STRING pathname,
+ ACPI_HANDLE *ret_handle);
+
+
+/*
+ * Object manipulation and enumeration
+ */
+
+ACPI_STATUS
+acpi_evaluate_object (
+ ACPI_HANDLE object,
+ ACPI_STRING pathname,
+ ACPI_OBJECT_LIST *parameter_objects,
+ ACPI_BUFFER *return_object_buffer);
+
+ACPI_STATUS
+acpi_get_object_info (
+ ACPI_HANDLE device,
+ ACPI_DEVICE_INFO *info);
+
+ACPI_STATUS
+acpi_get_next_object (
+ ACPI_OBJECT_TYPE type,
+ ACPI_HANDLE parent,
+ ACPI_HANDLE child,
+ ACPI_HANDLE *out_handle);
+
+ACPI_STATUS
+acpi_get_type (
+ ACPI_HANDLE object,
+ ACPI_OBJECT_TYPE *out_type);
+
+ACPI_STATUS
+acpi_get_parent (
+ ACPI_HANDLE object,
+ ACPI_HANDLE *out_handle);
+
+
+/*
+ * Acpi_event handler interfaces
+ */
+
+ACPI_STATUS
+acpi_install_fixed_event_handler (
+ u32 acpi_event,
+ FIXED_EVENT_HANDLER handler,
+ void *context);
+
+ACPI_STATUS
+acpi_remove_fixed_event_handler (
+ u32 acpi_event,
+ FIXED_EVENT_HANDLER handler);
+
+ACPI_STATUS
+acpi_install_notify_handler (
+ ACPI_HANDLE device,
+ u32 handler_type,
+ NOTIFY_HANDLER handler,
+ void *context);
+
+ACPI_STATUS
+acpi_remove_notify_handler (
+ ACPI_HANDLE device,
+ u32 handler_type,
+ NOTIFY_HANDLER handler);
+
+ACPI_STATUS
+acpi_install_address_space_handler (
+ ACPI_HANDLE device,
+ ACPI_ADDRESS_SPACE_TYPE space_id,
+ ADDRESS_SPACE_HANDLER handler,
+ ADDRESS_SPACE_SETUP setup,
+ void *context);
+
+ACPI_STATUS
+acpi_remove_address_space_handler (
+ ACPI_HANDLE device,
+ ACPI_ADDRESS_SPACE_TYPE space_id,
+ ADDRESS_SPACE_HANDLER handler);
+
+ACPI_STATUS
+acpi_install_gpe_handler (
+ u32 gpe_number,
+ u32 type,
+ GPE_HANDLER handler,
+ void *context);
+
+ACPI_STATUS
+acpi_remove_gpe_handler (
+ u32 gpe_number,
+ GPE_HANDLER handler);
+
+ACPI_STATUS
+acpi_enable_event (
+ u32 acpi_event,
+ u32 type);
+
+ACPI_STATUS
+acpi_disable_event (
+ u32 acpi_event,
+ u32 type);
+
+ACPI_STATUS
+acpi_clear_event (
+ u32 acpi_event,
+ u32 type);
+
+ACPI_STATUS
+acpi_get_event_status (
+ u32 acpi_event,
+ u32 type,
+ ACPI_EVENT_STATUS *event_status);
+
+/*
+ * Resource interfaces
+ */
+
+ACPI_STATUS
+acpi_get_current_resources(
+ ACPI_HANDLE device_handle,
+ ACPI_BUFFER *ret_buffer);
+
+ACPI_STATUS
+acpi_get_possible_resources(
+ ACPI_HANDLE device_handle,
+ ACPI_BUFFER *ret_buffer);
+
+ACPI_STATUS
+acpi_set_current_resources (
+ ACPI_HANDLE device_handle,
+ ACPI_BUFFER *in_buffer);
+
+ACPI_STATUS
+acpi_get_irq_routing_table (
+ ACPI_HANDLE bus_device_handle,
+ ACPI_BUFFER *ret_buffer);
+
+
+/*
+ * Hardware (ACPI device) interfaces
+ */
+
+ACPI_STATUS
+acpi_set_firmware_waking_vector (
+ void *physical_address);
+
+ACPI_STATUS
+acpi_get_firmware_waking_vector (
+ void **physical_address);
+
+ACPI_STATUS
+acpi_get_processor_throttling_info (
+ ACPI_HANDLE processor_handle,
+ ACPI_BUFFER *user_buffer);
+
+ACPI_STATUS
+acpi_set_processor_throttling_state (
+ ACPI_HANDLE processor_handle,
+ u32 throttle_state);
+
+ACPI_STATUS
+acpi_get_processor_throttling_state (
+ ACPI_HANDLE processor_handle,
+ u32 *throttle_state);
+
+ACPI_STATUS
+acpi_get_processor_cx_info (
+ ACPI_HANDLE processor_handle,
+ ACPI_BUFFER *user_buffer);
+
+ACPI_STATUS
+acpi_set_processor_sleep_state (
+ ACPI_HANDLE processor_handle,
+ u32 cx_state);
+
+ACPI_STATUS
+acpi_processor_sleep (
+ ACPI_HANDLE processor_handle,
+ u32 *pm_timer_ticks);
+
+
+#endif /* __ACXFACE_H__ */
diff --git a/drivers/acpi/include/actables.h b/drivers/acpi/include/actables.h
new file mode 100644
index 000000000..67d2d84bb
--- /dev/null
+++ b/drivers/acpi/include/actables.h
@@ -0,0 +1,188 @@
+
+/******************************************************************************
+ *
+ * Name: actables.h - Table data structures defined in ACPI specification
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 __ACTABLES_H__
+#define __ACTABLES_H__
+
+
+/*
+ * Values for description table header signatures
+ */
+
+#define RSDP_SIG "RSD PTR " /* RSDT Pointer signature */
+#define APIC_SIG "APIC" /* Multiple APIC Description Table */
+#define DSDT_SIG "DSDT" /* Differentiated System Description Table */
+#define FACP_SIG "FACP" /* Fixed ACPI Description Table */
+#define FACS_SIG "FACS" /* Firmware ACPI Control Structure */
+#define PSDT_SIG "PSDT" /* Persistent System Description Table */
+#define RSDT_SIG "RSDT" /* Root System Description Table */
+#define SSDT_SIG "SSDT" /* Secondary System Description Table */
+#define SBST_SIG "SBST" /* Smart Battery Specification Table */
+#define BOOT_SIG "BOOT" /* Boot table */
+
+
+#define GL_OWNED 0x02 /* Ownership of global lock is bit 1 */
+
+/* values of Mapic.Model */
+
+#define DUAL_PIC 0
+#define MULTIPLE_APIC 1
+
+/* values of Type in APIC_HEADER */
+
+#define APIC_PROC 0
+#define APIC_IO 1
+
+
+/*
+ * Architecture-independent tables
+ * The architecture dependent tables are in separate files
+ */
+
+typedef struct /* Root System Descriptor Pointer */
+{
+ char signature [8]; /* contains "RSD PTR " */
+ u8 checksum; /* to make sum of struct == 0 */
+ char oem_id [6]; /* OEM identification */
+ u8 reserved; /* reserved - must be zero */
+ u32 rsdt_physical_address; /* physical address of RSDT */
+
+} ROOT_SYSTEM_DESCRIPTOR_POINTER;
+
+
+typedef struct /* ACPI common table header */
+{
+ char signature [4]; /* identifies type of table */
+ u32 length; /* length of table, in bytes,
+ * including header */
+ u8 revision; /* specification minor version # */
+ u8 checksum; /* to make sum of entire table == 0 */
+ char oem_id [6]; /* OEM identification */
+ char oem_table_id [8]; /* OEM table identification */
+ u32 oem_revision; /* OEM revision number */
+ char asl_compiler_id [4]; /* ASL compiler vendor ID */
+ u32 asl_compiler_revision; /* ASL compiler revision number */
+
+} ACPI_TABLE_HEADER;
+
+
+typedef struct /* APIC Table */
+{
+ ACPI_TABLE_HEADER header; /* table header */
+ u32 local_apic_address; /* Physical address for accessing local APICs */
+ u32 PCATcompat : 1; /* a one indicates system also has dual 8259s */
+ u32 reserved1 : 31;
+
+} APIC_TABLE;
+
+
+typedef struct /* APIC Header */
+{
+ u8 type; /* APIC type. Either APIC_PROC or APIC_IO */
+ u8 length; /* Length of APIC structure */
+
+} APIC_HEADER;
+
+
+typedef struct /* Processor APIC */
+{
+ APIC_HEADER header;
+ u8 processor_apic_id; /* ACPI processor id */
+ u8 local_apic_id; /* processor's local APIC id */
+ u32 processor_enabled: 1; /* Processor is usable if set */
+ u32 reserved1 : 32;
+
+} PROCESSOR_APIC;
+
+
+typedef struct /* IO APIC */
+{
+ APIC_HEADER header;
+ u8 io_apic_id; /* I/O APIC ID */
+ u8 reserved; /* reserved - must be zero */
+ u32 io_apic_address; /* APIC's physical address */
+ u32 vector; /* interrupt vector index where INTI
+ * lines start */
+} IO_APIC;
+
+
+/*
+** IA64 TODO: Add SAPIC Tables
+*/
+
+/*
+** IA64 TODO: Modify Smart Battery Description to comply with ACPI IA64
+** extensions.
+*/
+typedef struct /* Smart Battery Description Table */
+{
+ ACPI_TABLE_HEADER header;
+ u32 warning_level;
+ u32 low_level;
+ u32 critical_level;
+
+} SMART_BATTERY_DESCRIPTION_TABLE;
+
+
+/*
+ * ACPI Table information. We save the table address, length,
+ * and type of memory allocation (mapped or allocated) for each
+ * table for 1) when we exit, and 2) if a new table is installed
+ */
+
+#define ACPI_MEM_NOT_ALLOCATED 0
+#define ACPI_MEM_ALLOCATED 1
+#define ACPI_MEM_MAPPED 2
+
+#define ACPI_TABLE_SINGLE 0
+#define ACPI_TABLE_MULTIPLE 1
+
+
+/* Data about each known table type */
+
+typedef struct _acpi_table_support
+{
+ char *name;
+ char *signature;
+ u8 sig_length;
+ u8 flags;
+ u16 status;
+ void **global_ptr;
+
+} ACPI_TABLE_SUPPORT;
+
+
+/*
+ * Get the architecture-specific tables
+ */
+
+#ifdef IA64
+#include "actbl64.h"
+#else
+#include "actbl32.h"
+#endif
+
+
+#endif /* __ACTABLES_H__ */
diff --git a/drivers/acpi/include/actbl32.h b/drivers/acpi/include/actbl32.h
new file mode 100644
index 000000000..50e92fc30
--- /dev/null
+++ b/drivers/acpi/include/actbl32.h
@@ -0,0 +1,114 @@
+/******************************************************************************
+ *
+ * Name: actbl32.h - ACPI tables specific to IA32
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 __ACTBL32_H__
+#define __ACTBL32_H__
+
+
+/* IA32 Root System Description Table */
+
+typedef struct
+{
+ ACPI_TABLE_HEADER header; /* Table header */
+ void *table_offset_entry [1]; /* Array of pointers to other */
+ /* tables' headers */
+} ROOT_SYSTEM_DESCRIPTION_TABLE;
+
+
+/* IA32 Firmware ACPI Control Structure */
+
+typedef struct
+{
+ char signature[4]; /* signature "FACS" */
+ u32 length; /* length of structure, in bytes */
+ u32 hardware_signature; /* hardware configuration signature */
+ u32 firmware_waking_vector; /* ACPI OS waking vector */
+ u32 global_lock; /* Global Lock */
+ u32 S4_bios_f : 1; /* Indicates if S4_bIOS support is present */
+ u32 reserved1 : 31; /* must be 0 */
+ u8 resverved3 [40]; /* reserved - must be zero */
+
+} FIRMWARE_ACPI_CONTROL_STRUCTURE;
+
+
+/* IA32 Fixed ACPI Description Table */
+
+typedef struct
+{
+ ACPI_TABLE_HEADER header; /* table header */
+ ACPI_TBLPTR firmware_ctrl; /* Physical address of FACS */
+ ACPI_TBLPTR dsdt; /* Physical address of DSDT */
+ u8 model; /* System Interrupt Model */
+ u8 reserved1; /* reserved */
+ u16 sci_int; /* System vector of SCI interrupt */
+ ACPI_IO_ADDRESS smi_cmd; /* Port address of SMI command port */
+ u8 acpi_enable; /* value to write to smi_cmd to enable ACPI */
+ u8 acpi_disable; /* value to write to smi_cmd to disable ACPI */
+ u8 S4_bios_req; /* Value to write to SMI CMD to enter S4_bIOS state */
+ u8 reserved2; /* reserved - must be zero */
+ ACPI_IO_ADDRESS pm1a_evt_blk; /* Port address of Power Mgt 1a Acpi_event Reg Blk */
+ ACPI_IO_ADDRESS pm1b_evt_blk; /* Port address of Power Mgt 1b Acpi_event Reg Blk */
+ ACPI_IO_ADDRESS pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */
+ ACPI_IO_ADDRESS pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */
+ ACPI_IO_ADDRESS pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */
+ ACPI_IO_ADDRESS pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */
+ ACPI_IO_ADDRESS gpe0blk; /* Port addr of General Purpose Acpi_event 0 Reg Blk */
+ ACPI_IO_ADDRESS gpe1_blk; /* Port addr of General Purpose Acpi_event 1 Reg Blk */
+ u8 pm1_evt_len; /* Byte Length of ports at pm1_x_evt_blk */
+ u8 pm1_cnt_len; /* Byte Length of ports at pm1_x_cnt_blk */
+ u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */
+ u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */
+ u8 gpe0blk_len; /* Byte Length of ports at gpe0_blk */
+ u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */
+ u8 gpe1_base; /* offset in gpe model where gpe1 events start */
+ u8 reserved3; /* reserved */
+ u16 plvl2_lat; /* worst case HW latency to enter/exit C2 state */
+ u16 plvl3_lat; /* worst case HW latency to enter/exit C3 state */
+ u16 flush_size; /* Size of area read to flush caches */
+ u16 flush_stride; /* Stride used in flushing caches */
+ u8 duty_offset; /* bit location of duty cycle field in p_cnt reg */
+ u8 duty_width; /* bit width of duty cycle field in p_cnt reg */
+ u8 day_alrm; /* index to day-of-month alarm in RTC CMOS RAM */
+ u8 mon_alrm; /* index to month-of-year alarm in RTC CMOS RAM */
+ u8 century; /* index to century in RTC CMOS RAM */
+ u8 reserved4; /* reserved */
+ u8 reserved4a; /* reserved */
+ u8 reserved4b; /* reserved */
+ u32 wb_invd : 1; /* wbinvd instruction works properly */
+ u32 wb_invd_flush : 1; /* wbinvd flushes but does not invalidate */
+ u32 proc_c1 : 1; /* all processors support C1 state */
+ u32 plvl2_up : 1; /* C2 state works on MP system */
+ u32 pwr_button : 1; /* Power button is handled as a generic feature */
+ u32 sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */
+ u32 fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */
+ u32 rtcs4 : 1; /* RTC wakeup stat not possible from S4 */
+ u32 tmr_val_ext : 1; /* tmr_val is 32 bits */
+ u32 reserved5 : 23; /* reserved - must be zero */
+
+} FIXED_ACPI_DESCRIPTION_TABLE;
+
+
+#endif /* __ACTBL32_H__ */
+
+
diff --git a/drivers/acpi/include/actbl64.h b/drivers/acpi/include/actbl64.h
new file mode 100644
index 000000000..f2a331349
--- /dev/null
+++ b/drivers/acpi/include/actbl64.h
@@ -0,0 +1,115 @@
+
+/******************************************************************************
+ *
+ * Name: actbl64.h - ACPI tables specific to IA64
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 __ACTBL64_H__
+#define __ACTBL64_H__
+
+
+typedef UINT64 IO_ADDRESS; /* Only for clarity in declarations */
+
+
+/* IA64 Root System Description Table */
+
+typedef struct
+{
+ ACPI_TABLE_HEADER header; /* Table header */
+ u32 reserved_pad; /* IA64 alignment, must be 0 */
+ void *table_offset_entry [1]; /* Array of pointers to other */
+ /* tables' headers */
+} ROOT_SYSTEM_DESCRIPTION_TABLE;
+
+
+/* IA64 Firmware ACPI Control Structure */
+
+typedef struct
+{
+ char signature[4]; /* signature "FACS" */
+ u32 length; /* length of structure, in bytes */
+ u32 hardware_signature; /* hardware configuration signature */
+ u32 reserved4; /* must be 0 */
+ UINT64 firmware_waking_vector; /* ACPI OS waking vector */
+ UINT64 global_lock; /* Global Lock */
+ u32 S4_bios_f : 1; /* Indicates if S4_bIOS support is present */
+ u32 reserved1 : 31; /* must be 0 */
+ u8 resverved3 [28]; /* reserved - must be zero */
+
+} FIRMWARE_ACPI_CONTROL_STRUCTURE;
+
+
+/* IA64 Fixed ACPI Description Table */
+
+typedef struct
+{
+ ACPI_TABLE_HEADER header; /* table header */
+ u32 reserved_pad; /* IA64 alignment, must be 0 */
+ ACPI_TBLPTR firmware_ctrl; /* Physical address of FACS */
+ ACPI_TBLPTR acpi_dsdt; /* Physical address of DSDT */
+ u8 model; /* System Interrupt Model */
+ u8 address_space; /* Address Space Bitmask */
+ u16 sci_int; /* System vector of SCI interrupt */
+ u8 acpi_enable; /* value to write to smi_cmd to enable ACPI */
+ u8 acpi_disable; /* value to write to smi_cmd to disable ACPI */
+ u8 S4_bios_req; /* Value to write to SMI CMD to enter S4_bIOS state */
+ u8 reserved2; /* reserved - must be zero */
+ UINT64 smi_cmd; /* Port address of SMI command port */
+ UINT64 pm1a_evt_blk; /* Port address of Power Mgt 1a Acpi_event Reg Blk */
+ UINT64 pm1b_evt_blk; /* Port address of Power Mgt 1b Acpi_event Reg Blk */
+ UINT64 pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */
+ UINT64 pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */
+ UINT64 pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */
+ UINT64 pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */
+ UINT64 gpe0blk; /* Port addr of General Purpose Acpi_event 0 Reg Blk */
+ UINT64 gpe1_blk; /* Port addr of General Purpose Acpi_event 1 Reg Blk */
+ u8 pm1_evt_len; /* Byte Length of ports at pm1_x_evt_blk */
+ u8 pm1_cnt_len; /* Byte Length of ports at pm1_x_cnt_blk */
+ u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */
+ u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */
+ u8 gpe0blk_len; /* Byte Length of ports at gpe0_blk */
+ u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */
+ u8 gpe1_base; /* offset in gpe model where gpe1 events start */
+ u8 reserved3; /* reserved */
+ u16 Plvl2_lat; /* worst case HW latency to enter/exit C2 state */
+ u16 Plvl3_lat; /* worst case HW latency to enter/exit C3 state */
+ u8 day_alrm; /* index to day-of-month alarm in RTC CMOS RAM */
+ u8 mon_alrm; /* index to month-of-year alarm in RTC CMOS RAM */
+ u8 century; /* index to century in RTC CMOS RAM */
+ u8 reserved4; /* reserved */
+ u32 flush_cash : 1; /* PAL_FLUSH_CACHE is correctly supported */
+ u32 reserved5 : 1; /* reserved - must be zero */
+ u32 proc_c1 : 1; /* all processors support C1 state */
+ u32 Plvl2_up : 1; /* C2 state works on MP system */
+ u32 pwr_button : 1; /* Power button is handled as a generic feature */
+ u32 sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */
+ u32 fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */
+ u32 RTCS4 : 1; /* RTC wakeup stat not possible from S4 */
+ u32 tmr_val_ext : 1; /* tmr_val is 32 bits */
+ u32 dock_cap : 1; /* Supports Docking */
+ u32 reserved6 : 22; /* reserved - must be zero */
+
+} FIXED_ACPI_DESCRIPTION_TABLE;
+
+
+#endif /* __ACTBL64_H__ */
+
diff --git a/drivers/acpi/include/actypes.h b/drivers/acpi/include/actypes.h
new file mode 100644
index 000000000..669bb3b7f
--- /dev/null
+++ b/drivers/acpi/include/actypes.h
@@ -0,0 +1,970 @@
+
+/******************************************************************************
+ *
+ * Name: actypes.h - Common data types for the entire ACPI subsystem
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 _ACTYPES_H
+#define _ACTYPES_H
+
+/*! [Begin] no source code translation (keep the typedefs) */
+
+/*
+ * Data types - Fixed across all compilation models
+ *
+ * BOOLEAN Logical Boolean. 1 byte value containing a 0 for FALSE or a 1 for TRUE. Other values are undefined.
+ * INT8 8-bit (1 byte) signed value
+ * UINT8 8-bit (1 byte) unsigned value
+ * INT16 16-bit (2 byte) signed value
+ * UINT16 16-bit (2 byte) unsigned value
+ * INT32 32-bit (4 byte) signed value
+ * UINT32 32-bit (4 byte) unsigned value
+ * INT64 64-bit (8 byte) signed value
+ * UINT64 64-bit (8 byte) unsigned value
+ * NATIVE_INT 32-bit on IA-32, 64-bit on IA-64 signed value
+ * NATIVE_UINT 32-bit on IA-32, 64-bit on IA-64 unsigned value
+ * UCHAR Character. 1 byte unsigned value.
+ */
+
+#ifdef _IA64
+/*
+ * 64-bit type definitions
+ */
+typedef signed char INT8;
+typedef unsigned char UINT8;
+typedef unsigned char UCHAR;
+typedef short INT16;
+typedef unsigned short UINT16;
+typedef int INT32;
+typedef unsigned int UINT32;
+typedef long INT64;
+typedef unsigned long UINT64;
+
+typedef UINT64 NATIVE_UINT;
+typedef INT64 NATIVE_INT;
+
+typedef NATIVE_UINT ACPI_TBLPTR;
+typedef UINT64 ACPI_IO_ADDRESS;
+
+#define ALIGNED_ADDRESS_BOUNDARY 0x00000008
+
+/* (No hardware alignment support in IA64) */
+
+
+#elif _IA16
+/*
+ * 16-bit type definitions
+ */
+typedef signed char INT8;
+typedef unsigned char UINT8;
+typedef unsigned char UCHAR;
+typedef int INT16;
+typedef unsigned int UINT16;
+typedef long INT32;
+typedef unsigned long UINT32;
+
+typedef UINT16 NATIVE_UINT;
+typedef INT16 NATIVE_INT;
+
+typedef UINT32 ACPI_TBLPTR;
+typedef UINT32 ACPI_IO_ADDRESS;
+
+#define ALIGNED_ADDRESS_BOUNDARY 0x00000002
+#define _HW_ALIGNMENT_SUPPORT
+
+
+#else
+/*
+ * 32-bit type definitions (default)
+ */
+typedef signed char INT8;
+typedef unsigned char UINT8;
+typedef unsigned char UCHAR;
+typedef short INT16;
+typedef unsigned short UINT16;
+typedef int INT32;
+typedef unsigned int UINT32;
+
+typedef UINT32 NATIVE_UINT;
+typedef INT32 NATIVE_INT;
+
+typedef NATIVE_UINT ACPI_TBLPTR;
+typedef UINT32 ACPI_IO_ADDRESS;
+
+#define ALIGNED_ADDRESS_BOUNDARY 0x00000004
+#define _HW_ALIGNMENT_SUPPORT
+
+
+#endif
+
+
+
+/*
+ * Miscellaneous common types
+ */
+
+typedef UINT8 BOOLEAN;
+typedef UINT32 UINT32_BIT;
+typedef NATIVE_INT ACPI_PTRDIFF;
+typedef NATIVE_UINT ACPI_SIZE;
+
+
+/*
+ * Data type ranges
+ */
+
+#define ACPI_UCHAR_MAX (UCHAR) 0xFF
+#define ACPI_INT32_MAX (INT32) 0x7FFFFFFF
+#define ACPI_UINT32_MAX (UINT32) 0xFFFFFFFF
+
+
+#ifdef DEFINE_ALTERNATE_TYPES
+/*
+ * Types used only in translated source
+ */
+typedef INT8 s8;
+typedef INT16 s16;
+typedef INT32 s32;
+typedef UINT8 u8;
+typedef UINT16 u16;
+typedef UINT32 u32;
+#endif
+
+/*! [End] no source code translation !*/
+
+
+/*
+ * Useful defines
+ */
+
+#ifdef FALSE
+#undef FALSE
+#endif
+#define FALSE (1 == 0)
+
+#ifdef TRUE
+#undef TRUE
+#endif
+#define TRUE (1 == 1)
+
+#ifndef NULL
+#define NULL (void *) 0
+#endif
+
+
+/*
+ * Local datatypes
+ */
+
+typedef u32 ACPI_STATUS; /* All ACPI Exceptions */
+typedef u32 ACPI_NAME; /* 4-char ACPI name */
+typedef char* ACPI_STRING; /* Null terminated ASCII string */
+typedef void* ACPI_HANDLE; /* Actually a ptr to an NTE */
+
+
+/*
+ * Constants with special meanings
+ */
+
+#define ACPI_ROOT_OBJECT (ACPI_HANDLE)(-1)
+
+
+/*
+ * Sleep state constants
+ */
+#define ACPI_STATE_S0 (u8) 0
+#define ACPI_STATE_S1 (u8) 1
+#define ACPI_STATE_S2 (u8) 2
+#define ACPI_STATE_S3 (u8) 3
+#define ACPI_STATE_S4 (u8) 4
+#define ACPI_STATE_S4_bIOS (u8) 5
+#define ACPI_STATE_S5 (u8) 6
+#define ACPI_S_STATES_MAX ACPI_STATE_S5
+
+
+/*
+ * Table types. These values are passed to the table related APIs
+ */
+
+typedef u32 ACPI_TABLE_TYPE;
+
+#define ACPI_TABLE_RSDP (ACPI_TABLE_TYPE) 0
+#define ACPI_TABLE_APIC (ACPI_TABLE_TYPE) 1
+#define ACPI_TABLE_DSDT (ACPI_TABLE_TYPE) 2
+#define ACPI_TABLE_FACP (ACPI_TABLE_TYPE) 3
+#define ACPI_TABLE_FACS (ACPI_TABLE_TYPE) 4
+#define ACPI_TABLE_PSDT (ACPI_TABLE_TYPE) 5
+#define ACPI_TABLE_RSDT (ACPI_TABLE_TYPE) 6
+#define ACPI_TABLE_SSDT (ACPI_TABLE_TYPE) 7
+#define ACPI_TABLE_SBST (ACPI_TABLE_TYPE) 8
+#define ACPI_TABLE_BOOT (ACPI_TABLE_TYPE) 9
+#define ACPI_TABLE_MAX 9
+#define NUM_ACPI_TABLES 10
+
+
+/*
+ * Types associated with names. The first group of
+ * values correspond to the definition of the ACPI Object_type operator (See the ACPI Spec).
+ * Therefore, only add to the first group if the spec changes!
+ *
+ * Types must be kept in sync with the Acpi_ns_properties and Acpi_ns_type_names arrays
+ */
+
+typedef u32 ACPI_OBJECT_TYPE;
+typedef u8 OBJECT_TYPE_INTERNAL;
+
+#define ACPI_TYPE_ANY 0 /* 0x00 */
+#define ACPI_TYPE_NUMBER 1 /* 0x01 Byte/Word/Dword/Zero/One/Ones */
+#define ACPI_TYPE_STRING 2 /* 0x02 */
+#define ACPI_TYPE_BUFFER 3 /* 0x03 */
+#define ACPI_TYPE_PACKAGE 4 /* 0x04 Byte_const, multiple Data_term/Constant/Super_name */
+#define ACPI_TYPE_FIELD_UNIT 5 /* 0x05 */
+#define ACPI_TYPE_DEVICE 6 /* 0x06 Name, multiple Named_object */
+#define ACPI_TYPE_EVENT 7 /* 0x07 */
+#define ACPI_TYPE_METHOD 8 /* 0x08 Name, Byte_const, multiple Code */
+#define ACPI_TYPE_MUTEX 9 /* 0x09 */
+#define ACPI_TYPE_REGION 10 /* 0x0A */
+#define ACPI_TYPE_POWER 11 /* 0x0B Name,Byte_const,Word_const,multi Named_object */
+#define ACPI_TYPE_PROCESSOR 12 /* 0x0C Name,Byte_const,DWord_const,Byte_const,multi Nm_o */
+#define ACPI_TYPE_THERMAL 13 /* 0x0D Name, multiple Named_object */
+#define ACPI_TYPE_BUFFER_FIELD 14 /* 0x0E */
+#define ACPI_TYPE_DDB_HANDLE 15 /* 0x0F */
+#define ACPI_TYPE_DEBUG_OBJECT 16 /* 0x10 */
+
+#define ACPI_TYPE_MAX 16
+
+/*
+ * This section contains object types that do not relate to the ACPI Object_type operator.
+ * They are used for various internal purposes only. A numerical gap is provided in
+ * case additional "official" Object_types are added in the future. Also, values exceeding
+ * the largest official ACPI Object_type must not overlap with defined AML opcodes.
+ */
+#define INTERNAL_TYPE_BEGIN 25
+#define INTERNAL_TYPE_DEF_FIELD 25 /* 0x19 */
+#define INTERNAL_TYPE_BANK_FIELD 26 /* 0x1A */
+#define INTERNAL_TYPE_INDEX_FIELD 27 /* 0x1B */
+#define INTERNAL_TYPE_DEF_FIELD_DEFN 28 /* 0x1C Name, Byte_const, multiple Field_element */
+#define INTERNAL_TYPE_BANK_FIELD_DEFN 29 /* 0x1D 2 Name,DWord_const,Byte_const,multi Field_element */
+#define INTERNAL_TYPE_INDEX_FIELD_DEFN 30 /* 0x1E 2 Name, Byte_const, multiple Field_element */
+#define INTERNAL_TYPE_IF 31 /* 0x1F Op_code, multiple Code */
+#define INTERNAL_TYPE_ELSE 32 /* 0x20 multiple Code */
+#define INTERNAL_TYPE_WHILE 33 /* 0x21 Op_code, multiple Code */
+#define INTERNAL_TYPE_SCOPE 34 /* 0x22 Name, multiple Named_object */
+#define INTERNAL_TYPE_DEF_ANY 35 /* 0x23 type is Any, suppress search of enclosing scopes */
+#define INTERNAL_TYPE_REFERENCE 36 /* 0x24 Arg#, Local#, Name, Debug; used only in descriptors */
+#define INTERNAL_TYPE_ALIAS 37 /* 0x25 */
+#define INTERNAL_TYPE_NOTIFY 38 /* 0x26 */
+#define INTERNAL_TYPE_ADDRESS_HANDLER 39 /* 0x27 */
+#define INTERNAL_TYPE_METHOD_ARGUMENT 40 /* 0x28 */
+#define INTERNAL_TYPE_METHOD_LOCAL_VAR 41 /* 0x29 */
+
+#define INTERNAL_TYPE_MAX 41
+
+#define INTERNAL_TYPE_INVALID 42
+#define ACPI_TYPE_NOT_FOUND 0xFF
+
+/*
+ * Acpi_event Types:
+ * ------------
+ * Fixed & general purpose...
+ */
+
+typedef u32 ACPI_EVENT_TYPE;
+
+#define ACPI_EVENT_FIXED (ACPI_EVENT_TYPE) 0
+#define ACPI_EVENT_GPE (ACPI_EVENT_TYPE) 1
+
+/*
+ * Fixed events
+ */
+
+#define ACPI_EVENT_PMTIMER (ACPI_EVENT_TYPE) 0
+ /*
+ * There's no bus master event so index 1 is used for IRQ's that are not
+ * handled by the SCI handler
+ */
+#define ACPI_EVENT_NOT_USED (ACPI_EVENT_TYPE) 1
+#define ACPI_EVENT_GLOBAL (ACPI_EVENT_TYPE) 2
+#define ACPI_EVENT_POWER_BUTTON (ACPI_EVENT_TYPE) 3
+#define ACPI_EVENT_SLEEP_BUTTON (ACPI_EVENT_TYPE) 4
+#define ACPI_EVENT_RTC (ACPI_EVENT_TYPE) 5
+#define ACPI_EVENT_GENERAL (ACPI_EVENT_TYPE) 6
+#define ACPI_EVENT_MAX 6
+#define NUM_FIXED_EVENTS (ACPI_EVENT_TYPE) 7
+
+#define ACPI_GPE_INVALID 0xFF
+#define ACPI_GPE_MAX 0xFF
+#define NUM_GPE 256
+
+#define ACPI_EVENT_LEVEL_TRIGGERED (ACPI_EVENT_TYPE) 1
+#define ACPI_EVENT_EDGE_TRIGGERED (ACPI_EVENT_TYPE) 2
+
+/*
+ * Acpi_event Status:
+ * -------------
+ * The encoding of ACPI_EVENT_STATUS is illustrated below.
+ * Note that a set bit (1) indicates the property is TRUE
+ * (e.g. if bit 0 is set then the event is enabled).
+ * +---------------+-+-+
+ * | Bits 31:2 |1|0|
+ * +---------------+-+-+
+ * | | |
+ * | | +- Enabled?
+ * | +--- Set?
+ * +----------- <Reserved>
+ */
+typedef u32 ACPI_EVENT_STATUS;
+
+#define ACPI_EVENT_FLAG_ENABLED (ACPI_EVENT_STATUS) 0x01
+#define ACPI_EVENT_FLAG_SET (ACPI_EVENT_STATUS) 0x02
+
+
+/* Notify types */
+
+#define ACPI_SYSTEM_NOTIFY 0
+#define ACPI_DEVICE_NOTIFY 1
+#define ACPI_MAX_NOTIFY_HANDLER_TYPE 1
+
+#define MAX_SYS_NOTIFY 0x7f
+
+
+/* Address Space (Operation Region) Types */
+
+typedef u32 ACPI_ADDRESS_SPACE_TYPE;
+
+#define ADDRESS_SPACE_SYSTEM_MEMORY (ACPI_ADDRESS_SPACE_TYPE) 0
+#define ADDRESS_SPACE_SYSTEM_IO (ACPI_ADDRESS_SPACE_TYPE) 1
+#define ADDRESS_SPACE_PCI_CONFIG (ACPI_ADDRESS_SPACE_TYPE) 2
+#define ADDRESS_SPACE_EC (ACPI_ADDRESS_SPACE_TYPE) 3
+#define ADDRESS_SPACE_SMBUS (ACPI_ADDRESS_SPACE_TYPE) 4
+
+
+/*
+ * External ACPI object definition
+ */
+
+typedef union acpi_obj
+{
+ ACPI_OBJECT_TYPE type; /* See definition of Acpi_ns_type for values */
+ struct
+ {
+ ACPI_OBJECT_TYPE type;
+ u32 value; /* The actual number */
+ } number;
+
+ struct
+ {
+ ACPI_OBJECT_TYPE type;
+ u32 length; /* # of bytes in string, excluding trailing null */
+ char *pointer; /* points to the string value */
+ } string;
+
+ struct
+ {
+ ACPI_OBJECT_TYPE type;
+ u32 length; /* # of bytes in buffer */
+ u8 *pointer; /* points to the buffer */
+ } buffer;
+
+ struct
+ {
+ ACPI_OBJECT_TYPE type;
+ u32 fill1;
+ ACPI_HANDLE handle; /* object reference */
+ } reference;
+
+ struct
+ {
+ ACPI_OBJECT_TYPE type;
+ u32 count; /* # of elements in package */
+ union acpi_obj *elements; /* Pointer to an array of ACPI_OBJECTs */
+ } package;
+
+ struct
+ {
+ ACPI_OBJECT_TYPE type;
+ u32 proc_id;
+ u32 pblk_address;
+ u32 pblk_length;
+ } processor;
+
+ struct
+ {
+ ACPI_OBJECT_TYPE type;
+ u32 system_level;
+ u32 resource_order;
+ } power_resource;
+
+} ACPI_OBJECT, *PACPI_OBJECT;
+
+
+/*
+ * List of objects, used as a parameter list for control method evaluation
+ */
+
+typedef struct acpi_obj_list
+{
+ u32 count;
+ ACPI_OBJECT *pointer;
+
+} ACPI_OBJECT_LIST, *PACPI_OBJECT_LIST;
+
+
+/*
+ * Miscellaneous common Data Structures used by the interfaces
+ */
+
+typedef struct
+{
+ u32 length; /* Length in bytes of the buffer */
+ void *pointer; /* pointer to buffer */
+
+} ACPI_BUFFER;
+
+
+/*
+ * Name_type for Acpi_get_name
+ */
+
+#define ACPI_FULL_PATHNAME 0
+#define ACPI_SINGLE_NAME 1
+#define ACPI_NAME_TYPE_MAX 1
+
+
+/*
+ * Structure and flags for Acpi_get_system_info
+ */
+
+#define SYS_MODE_UNKNOWN 0x0000
+#define SYS_MODE_ACPI 0x0001
+#define SYS_MODE_LEGACY 0x0002
+#define SYS_MODES_MASK 0x0003
+
+/*
+ * ACPI CPU Cx state handler
+ */
+typedef
+ACPI_STATUS (*ACPI_SET_C_STATE_HANDLER) (
+ NATIVE_UINT pblk_address);
+
+/*
+ * ACPI Cx State info
+ */
+typedef struct
+{
+ u32 state_number;
+ u32 latency;
+} ACPI_CX_STATE;
+
+/*
+ * ACPI CPU throttling info
+ */
+typedef struct
+{
+ u32 state_number;
+ u32 percent_of_clock;
+} ACPI_CPU_THROTTLING_STATE;
+
+/*
+ * ACPI Table Info. One per ACPI table _type_
+ */
+typedef struct acpi_table_info
+{
+ u32 count;
+
+} ACPI_TABLE_INFO;
+
+
+/*
+ * System info returned by Acpi_get_system_info()
+ */
+
+typedef struct _acpi_sys_info
+{
+ u32 acpi_ca_version;
+ u32 flags;
+ u32 timer_resolution;
+ u32 reserved1;
+ u32 reserved2;
+ u32 debug_level;
+ u32 debug_layer;
+ u32 num_table_types;
+ ACPI_TABLE_INFO table_info [NUM_ACPI_TABLES];
+
+} ACPI_SYSTEM_INFO;
+
+
+/*
+ * System Initiailization data. This data is passed to ACPIInitialize
+ * copyied to global data and retained by ACPI CA
+ */
+
+typedef struct _acpi_init_data
+{
+ void *RSDP_physical_address; /* Address of RSDP, needed it it is */
+ /* not found in the IA32 manner */
+} ACPI_INIT_DATA;
+
+/*
+ * Various handlers and callback procedures
+ */
+
+typedef
+u32 (*FIXED_EVENT_HANDLER) (
+ void *context);
+
+typedef
+void (*GPE_HANDLER) (
+ void *context);
+
+typedef
+void (*NOTIFY_HANDLER) (
+ ACPI_HANDLE device,
+ u32 value,
+ void *context);
+
+#define ADDRESS_SPACE_READ 1
+#define ADDRESS_SPACE_WRITE 2
+
+typedef
+ACPI_STATUS (*ADDRESS_SPACE_HANDLER) (
+ u32 function,
+ u32 address,
+ u32 bit_width,
+ u32 *value,
+ void *context);
+
+#define ACPI_DEFAULT_HANDLER ((ADDRESS_SPACE_HANDLER) NULL)
+
+
+typedef
+ACPI_STATUS (*ADDRESS_SPACE_SETUP) (
+ ACPI_HANDLE region_handle,
+ u32 function,
+ void *handler_context,
+ void **return_context);
+
+#define ACPI_REGION_ACTIVATE 0
+#define ACPI_REGION_DEACTIVATE 1
+
+typedef
+ACPI_STATUS (*WALK_CALLBACK) (
+ ACPI_HANDLE obj_handle,
+ u32 nesting_level,
+ void *context,
+ void **return_value);
+
+
+/* Interrupt handler return values */
+
+#define INTERRUPT_NOT_HANDLED 0x00
+#define INTERRUPT_HANDLED 0x01
+
+
+/* Structure and flags for Acpi_get_device_info */
+
+#define ACPI_VALID_HID 0x1
+#define ACPI_VALID_UID 0x2
+#define ACPI_VALID_ADR 0x4
+#define ACPI_VALID_STA 0x8
+
+
+#define ACPI_COMMON_OBJ_INFO \
+ ACPI_OBJECT_TYPE type; /* ACPI object type */\
+ ACPI_NAME name; /* ACPI object Name */\
+ /*\
+ * TBD: [Restructure] Do we want or need these next two??\
+ */\
+ ACPI_HANDLE parent; /* Parent object */\
+ ACPI_HANDLE children; /* Linked list of children */\
+ u32 valid /* ????? */
+
+typedef struct
+{
+ ACPI_COMMON_OBJ_INFO;
+} ACPI_OBJ_INFO_HEADER;
+
+
+typedef struct
+{
+ ACPI_COMMON_OBJ_INFO;
+
+ /*
+ * TBD: [Restructure]: a HID or a _UID can return either a number or a string
+ */
+ char hardware_id [9]; /* _HID value if any */
+ char unique_id[9]; /* _UID value if any */
+ u32 address; /* _ADR value if any */
+ u32 current_status; /* _STA value */
+} ACPI_DEVICE_INFO;
+
+
+/* Context structs for address space handlers */
+
+typedef struct
+{
+ void *handler_context;
+ u32 seg;
+ u32 bus;
+ u32 dev_func;
+} PCI_HANDLER_CONTEXT;
+
+
+typedef struct
+{
+ void *handler_context;
+ char *mapped_physical_address;
+ char *mapped_logical_address;
+ u32 mapped_length;
+
+} MEM_HANDLER_CONTEXT;
+
+
+/*
+ * C-state handler
+ */
+
+typedef ACPI_STATUS (*ACPI_C_STATE_HANDLER) (ACPI_IO_ADDRESS, u32*);
+
+
+/*
+ * Definitions for Resource Attributes
+ */
+
+/*
+ * Memory Attributes
+ */
+#define READ_ONLY_MEMORY (u8) 0x00
+#define READ_WRITE_MEMORY (u8) 0x01
+
+#define NON_CACHEABLE_MEMORY (u8) 0x00
+#define CACHABLE_MEMORY (u8) 0x01
+#define WRITE_COMBINING_MEMORY (u8) 0x02
+#define PREFETCHABLE_MEMORY (u8) 0x03
+
+/*
+ * IO Attributes
+ * The ISA IO ranges are: n000-n0FFh, n400-n4_fFh, n800-n8_fFh, n_c00-n_cFFh.
+ * The non-ISA IO ranges are: n100-n3_fFh, n500-n7_fFh, n900-n_bFFh, n_cD0-n_fFFh.
+ */
+#define NON_ISA_ONLY_RANGES (u8) 0x01
+#define ISA_ONLY_RANGES (u8) 0x02
+#define ENTIRE_RANGE (NON_ISA_ONLY_RANGES | ISA_ONLY_RANGES)
+
+/*
+ * IO Port Descriptor Decode
+ */
+#define DECODE_10 (u8) 0x00 /* 10-bit IO address decode */
+#define DECODE_16 (u8) 0x01 /* 16-bit IO address decode */
+
+/*
+ * IRQ Attributes
+ */
+#define EDGE_SENSITIVE (u8) 0x00
+#define LEVEL_SENSITIVE (u8) 0x01
+
+#define ACTIVE_HIGH (u8) 0x00
+#define ACTIVE_LOW (u8) 0x01
+
+#define EXCLUSIVE (u8) 0x00
+#define SHARED (u8) 0x01
+
+/*
+ * DMA Attributes
+ */
+#define COMPATIBILITY (u8) 0x00
+#define TYPE_A (u8) 0x01
+#define TYPE_B (u8) 0x02
+#define TYPE_F (u8) 0x03
+
+#define NOT_BUS_MASTER (u8) 0x00
+#define BUS_MASTER (u8) 0x01
+
+#define TRANSFER_8 (u8) 0x00
+#define TRANSFER_8_16 (u8) 0x01
+#define TRANSFER_16 (u8) 0x02
+
+/*
+ * Start Dependent Functions Priority definitions
+ */
+#define GOOD_CONFIGURATION (u8) 0x00
+#define ACCEPTABLE_CONFIGURATION (u8) 0x01
+#define SUB_OPTIMAL_CONFIGURATION (u8) 0x02
+
+/*
+ * 16, 32 and 64-bit Address Descriptor resource types
+ */
+#define MEMORY_RANGE (u8) 0x00
+#define IO_RANGE (u8) 0x01
+#define BUS_NUMBER_RANGE (u8) 0x02
+
+#define ADDRESS_NOT_FIXED (u8) 0x00
+#define ADDRESS_FIXED (u8) 0x01
+
+#define POS_DECODE (u8) 0x00
+#define SUB_DECODE (u8) 0x01
+
+#define PRODUCER (u8) 0x00
+#define CONSUMER (u8) 0x01
+
+
+/*
+ * Structures used to describe device resources
+ */
+typedef struct
+{
+ u32 edge_level;
+ u32 active_high_low;
+ u32 shared_exclusive;
+ u32 number_of_interrupts;
+ u32 interrupts[1];
+
+} IRQ_RESOURCE;
+
+typedef struct
+{
+ u32 type;
+ u32 bus_master;
+ u32 transfer;
+ u32 number_of_channels;
+ u32 channels[1];
+
+} DMA_RESOURCE;
+
+typedef struct
+{
+ u32 compatibility_priority;
+ u32 performance_robustness;
+
+} START_DEPENDENT_FUNCTIONS_RESOURCE;
+
+/*
+ * END_DEPENDENT_FUNCTIONS_RESOURCE struct is not
+ * needed because it has no fields
+ */
+
+typedef struct
+{
+ u32 io_decode;
+ u32 min_base_address;
+ u32 max_base_address;
+ u32 alignment;
+ u32 range_length;
+
+} IO_RESOURCE;
+
+typedef struct
+{
+ u32 base_address;
+ u32 range_length;
+
+} FIXED_IO_RESOURCE;
+
+typedef struct
+{
+ u32 length;
+ u8 reserved[1];
+
+} VENDOR_RESOURCE;
+
+typedef struct
+{
+ u32 read_write_attribute;
+ u32 min_base_address;
+ u32 max_base_address;
+ u32 alignment;
+ u32 range_length;
+
+} MEMORY24_RESOURCE;
+
+typedef struct
+{
+ u32 read_write_attribute;
+ u32 min_base_address;
+ u32 max_base_address;
+ u32 alignment;
+ u32 range_length;
+
+} MEMORY32_RESOURCE;
+
+typedef struct
+{
+ u32 read_write_attribute;
+ u32 range_base_address;
+ u32 range_length;
+
+} FIXED_MEMORY32_RESOURCE;
+
+typedef struct
+{
+ u16 cache_attribute;
+ u16 read_write_attribute;
+
+} MEMORY_ATTRIBUTE;
+
+typedef struct
+{
+ u16 range_attribute;
+ u16 reserved;
+
+} IO_ATTRIBUTE;
+
+typedef struct
+{
+ u16 reserved1;
+ u16 reserved2;
+
+} BUS_ATTRIBUTE;
+
+typedef union
+{
+ MEMORY_ATTRIBUTE memory;
+ IO_ATTRIBUTE io;
+ BUS_ATTRIBUTE bus;
+
+} ATTRIBUTE_DATA;
+
+typedef struct
+{
+ u32 resource_type;
+ u32 producer_consumer;
+ u32 decode;
+ u32 min_address_fixed;
+ u32 max_address_fixed;
+ ATTRIBUTE_DATA attribute;
+ u32 granularity;
+ u32 min_address_range;
+ u32 max_address_range;
+ u32 address_translation_offset;
+ u32 address_length;
+ u32 resource_source_index;
+ u32 resource_source_string_length;
+ u8 resource_source[1];
+
+} ADDRESS16_RESOURCE;
+
+typedef struct
+{
+ u32 resource_type;
+ u32 producer_consumer;
+ u32 decode;
+ u32 min_address_fixed;
+ u32 max_address_fixed;
+ ATTRIBUTE_DATA attribute;
+ u32 granularity;
+ u32 min_address_range;
+ u32 max_address_range;
+ u32 address_translation_offset;
+ u32 address_length;
+ u32 resource_source_index;
+ u32 resource_source_string_length;
+ u8 resource_source[1];
+
+} ADDRESS32_RESOURCE;
+
+typedef struct
+{
+ u32 producer_consumer;
+ u32 edge_level;
+ u32 active_high_low;
+ u32 shared_exclusive;
+ u32 number_of_interrupts;
+ u32 interrupts[1];
+ u32 resource_source_index;
+ u32 resource_source_string_length;
+ u8 resource_source[1];
+
+} EXTENDED_IRQ_RESOURCE;
+
+typedef enum
+{
+ irq,
+ dma,
+ start_dependent_functions,
+ end_dependent_functions,
+ io,
+ fixed_io,
+ vendor_specific,
+ end_tag,
+ memory24,
+ memory32,
+ fixed_memory32,
+ address16,
+ address32,
+ extended_irq
+} RESOURCE_TYPE;
+
+typedef union
+{
+ IRQ_RESOURCE irq;
+ DMA_RESOURCE dma;
+ START_DEPENDENT_FUNCTIONS_RESOURCE start_dependent_functions;
+ IO_RESOURCE io;
+ FIXED_IO_RESOURCE fixed_io;
+ VENDOR_RESOURCE vendor_specific;
+ MEMORY24_RESOURCE memory24;
+ MEMORY32_RESOURCE memory32;
+ FIXED_MEMORY32_RESOURCE fixed_memory32;
+ ADDRESS16_RESOURCE address16;
+ ADDRESS32_RESOURCE address32;
+ EXTENDED_IRQ_RESOURCE extended_irq;
+} RESOURCE_DATA;
+
+typedef struct _resource_tag
+{
+ RESOURCE_TYPE id;
+ u32 length;
+ RESOURCE_DATA data;
+} RESOURCE;
+
+#define RESOURCE_LENGTH 12
+#define RESOURCE_LENGTH_NO_DATA 8
+
+/*
+ * END: Definitions for Resource Attributes
+ */
+
+/*
+ * Definitions for PCI Routing tables
+ */
+typedef struct
+{
+ u32 address;
+ u32 pin;
+ u32 source_index;
+ u8 source[1];
+
+} PRT_ENTRY;
+
+typedef struct _prt_tag
+{
+ u32 length;
+ PRT_ENTRY data;
+
+} PCI_ROUTING_TABLE;
+
+
+/*
+ * END: Definitions for PCI Routing tables
+ */
+
+#endif /* ACTYPES_H */
diff --git a/drivers/acpi/include/amlcode.h b/drivers/acpi/include/amlcode.h
new file mode 100644
index 000000000..464e0cd6b
--- /dev/null
+++ b/drivers/acpi/include/amlcode.h
@@ -0,0 +1,452 @@
+
+/******************************************************************************
+ *
+ * Name: amlcode.h - Definitions for AML, as included in "definition blocks"
+ * Declarations and definitions contained herein are derived
+ * directly from the ACPI specification.
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 __AMLCODE_H__
+#define __AMLCODE_H__
+
+
+/* primary opcodes */
+
+#define AML_NULL_CHAR (u16) 0x00
+
+#define AML_ZERO_OP (u16) 0x00
+#define AML_ONE_OP (u16) 0x01
+#define AML_UNASSIGNED (u16) 0x02
+#define AML_ALIAS_OP (u16) 0x06
+#define AML_NAME_OP (u16) 0x08
+#define AML_BYTE_OP (u16) 0x0a
+#define AML_WORD_OP (u16) 0x0b
+#define AML_DWORD_OP (u16) 0x0c
+#define AML_STRING_OP (u16) 0x0d
+#define AML_SCOPE_OP (u16) 0x10
+#define AML_BUFFER_OP (u16) 0x11
+#define AML_PACKAGE_OP (u16) 0x12
+#define AML_METHOD_OP (u16) 0x14
+#define AML_DUAL_NAME_PREFIX (u16) 0x2e
+#define AML_MULTI_NAME_PREFIX_OP (u16) 0x2f
+#define AML_NAME_CHAR_SUBSEQ (u16) 0x30
+#define AML_NAME_CHAR_FIRST (u16) 0x41
+#define AML_OP_PREFIX (u16) 0x5b
+#define AML_ROOT_PREFIX (u16) 0x5c
+#define AML_PARENT_PREFIX (u16) 0x5e
+#define AML_LOCAL_OP (u16) 0x60
+#define AML_LOCAL0 (u16) 0x60
+#define AML_LOCAL1 (u16) 0x61
+#define AML_LOCAL2 (u16) 0x62
+#define AML_LOCAL3 (u16) 0x63
+#define AML_LOCAL4 (u16) 0x64
+#define AML_LOCAL5 (u16) 0x65
+#define AML_LOCAL6 (u16) 0x66
+#define AML_LOCAL7 (u16) 0x67
+#define AML_ARG_OP (u16) 0x68
+#define AML_ARG0 (u16) 0x68
+#define AML_ARG1 (u16) 0x69
+#define AML_ARG2 (u16) 0x6a
+#define AML_ARG3 (u16) 0x6b
+#define AML_ARG4 (u16) 0x6c
+#define AML_ARG5 (u16) 0x6d
+#define AML_ARG6 (u16) 0x6e
+#define AML_STORE_OP (u16) 0x70
+#define AML_REF_OF_OP (u16) 0x71
+#define AML_ADD_OP (u16) 0x72
+#define AML_CONCAT_OP (u16) 0x73
+#define AML_SUBTRACT_OP (u16) 0x74
+#define AML_INCREMENT_OP (u16) 0x75
+#define AML_DECREMENT_OP (u16) 0x76
+#define AML_MULTIPLY_OP (u16) 0x77
+#define AML_DIVIDE_OP (u16) 0x78
+#define AML_SHIFT_LEFT_OP (u16) 0x79
+#define AML_SHIFT_RIGHT_OP (u16) 0x7a
+#define AML_BIT_AND_OP (u16) 0x7b
+#define AML_BIT_NAND_OP (u16) 0x7c
+#define AML_BIT_OR_OP (u16) 0x7d
+#define AML_BIT_NOR_OP (u16) 0x7e
+#define AML_BIT_XOR_OP (u16) 0x7f
+#define AML_BIT_NOT_OP (u16) 0x80
+#define AML_FIND_SET_LEFT_BIT_OP (u16) 0x81
+#define AML_FIND_SET_RIGHT_BIT_OP (u16) 0x82
+#define AML_DEREF_OF_OP (u16) 0x83
+#define AML_NOTIFY_OP (u16) 0x86
+#define AML_SIZE_OF_OP (u16) 0x87
+#define AML_INDEX_OP (u16) 0x88
+#define AML_MATCH_OP (u16) 0x89
+#define AML_DWORD_FIELD_OP (u16) 0x8a
+#define AML_WORD_FIELD_OP (u16) 0x8b
+#define AML_BYTE_FIELD_OP (u16) 0x8c
+#define AML_BIT_FIELD_OP (u16) 0x8d
+#define AML_TYPE_OP (u16) 0x8e
+#define AML_LAND_OP (u16) 0x90
+#define AML_LOR_OP (u16) 0x91
+#define AML_LNOT_OP (u16) 0x92
+#define AML_LEQUAL_OP (u16) 0x93
+#define AML_LGREATER_OP (u16) 0x94
+#define AML_LLESS_OP (u16) 0x95
+#define AML_IF_OP (u16) 0xa0
+#define AML_ELSE_OP (u16) 0xa1
+#define AML_WHILE_OP (u16) 0xa2
+#define AML_NOOP_CODE (u16) 0xa3
+#define AML_RETURN_OP (u16) 0xa4
+#define AML_BREAK_OP (u16) 0xa5
+#define AML_BREAK_POINT_OP (u16) 0xcc
+#define AML_ONES_OP (u16) 0xff
+
+/* prefixed opcodes */
+
+#define AML_EXTOP (u16) 0x005b
+
+
+#define AML_MUTEX_OP (u16) 0x5b01
+#define AML_EVENT_OP (u16) 0x5b02
+#define AML_SHIFT_RIGHT_BIT_OP (u16) 0x5b10
+#define AML_SHIFT_LEFT_BIT_OP (u16) 0x5b11
+#define AML_COND_REF_OF_OP (u16) 0x5b12
+#define AML_CREATE_FIELD_OP (u16) 0x5b13
+#define AML_LOAD_OP (u16) 0x5b20
+#define AML_STALL_OP (u16) 0x5b21
+#define AML_SLEEP_OP (u16) 0x5b22
+#define AML_ACQUIRE_OP (u16) 0x5b23
+#define AML_SIGNAL_OP (u16) 0x5b24
+#define AML_WAIT_OP (u16) 0x5b25
+#define AML_RESET_OP (u16) 0x5b26
+#define AML_RELEASE_OP (u16) 0x5b27
+#define AML_FROM_BCDOP (u16) 0x5b28
+#define AML_TO_BCDOP (u16) 0x5b29
+#define AML_UN_LOAD_OP (u16) 0x5b2a
+#define AML_REVISION_OP (u16) 0x5b30
+#define AML_DEBUG_OP (u16) 0x5b31
+#define AML_FATAL_OP (u16) 0x5b32
+#define AML_REGION_OP (u16) 0x5b80
+#define AML_DEF_FIELD_OP (u16) 0x5b81
+#define AML_DEVICE_OP (u16) 0x5b82
+#define AML_PROCESSOR_OP (u16) 0x5b83
+#define AML_POWER_RES_OP (u16) 0x5b84
+#define AML_THERMAL_ZONE_OP (u16) 0x5b85
+#define AML_INDEX_FIELD_OP (u16) 0x5b86
+#define AML_BANK_FIELD_OP (u16) 0x5b87
+
+
+/* Bogus opcodes (they are actually two separate opcodes) */
+
+#define AML_LGREATEREQUAL_OP (u16) 0x9295
+#define AML_LLESSEQUAL_OP (u16) 0x9294
+#define AML_LNOTEQUAL_OP (u16) 0x9293
+
+
+/* Internal opcodes */
+
+#define AML_NAMEPATH_OP (u16) 0x002d
+#define AML_NAMEDFIELD_OP (u16) 0x0030
+#define AML_RESERVEDFIELD_OP (u16) 0x0031
+#define AML_ACCESSFIELD_OP (u16) 0x0032
+#define AML_BYTELIST_OP (u16) 0x0033
+#define AML_STATICSTRING_OP (u16) 0x0034
+#define AML_METHODCALL_OP (u16) 0x0035
+
+
+/*
+ * argument types
+ */
+
+/*
+#define AML_ASCIICHARLIST_ARG 'A'
+#define AML_BYTEDATA_ARG 'b'
+#define AML_BYTELIST_ARG 'B'
+#define AML_DWORDDATA_ARG 'd'
+#define AML_DATAOBJECT_ARG 'o'
+#define AML_DATAOBJECTLIST_ARG 'O'
+#define AML_FIELDLIST_ARG 'F'
+#define AML_NAMESTRING_ARG 'n'
+#define AML_OBJECTLIST_ARG 'P'
+#define AML_PKGLENGTH_ARG 'p'
+#define AML_SUPERNAME_ARG 's'
+#define AML_TARGET_ARG 'l'
+#define AML_TERMARG_ARG 't'
+#define AML_TERMLIST_ARG 'T'
+#define AML_WORDDATA_ARG 'w'
+*/
+
+
+#define ARG_NONE 0x0
+
+/*
+ * Argument types for the AML Parser
+ * Each field in the Arg_types u32 is 5 bits, allowing for a maximum of 6 arguments.
+ * There can be up to 31 unique argument types
+ */
+
+#define ARGP_BYTEDATA 0x01
+#define ARGP_BYTELIST 0x02
+#define ARGP_CHARLIST 0x03
+#define ARGP_DATAOBJ 0x04
+#define ARGP_DATAOBJLIST 0x05
+#define ARGP_DWORDDATA 0x06
+#define ARGP_FIELDLIST 0x07
+#define ARGP_NAME 0x08
+#define ARGP_NAMESTRING 0x09
+#define ARGP_OBJLIST 0x0A
+#define ARGP_PKGLENGTH 0x0B
+#define ARGP_SUPERNAME 0x0C
+#define ARGP_TARGET 0x0D
+#define ARGP_TERMARG 0x0E
+#define ARGP_TERMLIST 0x0F
+#define ARGP_WORDDATA 0x10
+
+/*
+ * Resolved argument types for the AML Interpreter
+ * Each field in the Arg_types u32 is 5 bits, allowing for a maximum of 6 arguments.
+ * There can be up to 31 unique argument types
+ */
+
+#define ARGI_ANYTYPE 0x01
+#define ARGI_TARGETREF 0x02
+#define ARGI_REFERENCE 0x03
+#define ARGI_IF 0x04
+#define ARGI_NUMBER 0x05
+#define ARGI_STRING 0x06
+#define ARGI_BUFFER 0x07
+#define ARGI_PACKAGE 0x08
+#define ARGI_DATAOBJECT 0x09 /* Buffer, string, package or NTE reference - Used only by Size_of operator*/
+#define ARGI_COMPLEXOBJ 0x0A /* Buffer or package */
+#define ARGI_MUTEX 0x0B
+#define ARGI_EVENT 0x0C
+#define ARGI_REGION 0x0D
+#define ARGI_DDBHANDLE 0x0E
+
+#define ARGI_INVALID_OPCODE 0xFFFFFFFF
+
+
+/*
+ * hash offsets
+ */
+#define AML_EXTOP_HASH_OFFSET 22
+#define AML_LNOT_HASH_OFFSET 19
+
+
+/*
+ * opcode groups and types
+ */
+
+#define OPGRP_NAMED 0x01
+#define OPGRP_FIELD 0x02
+#define OPGRP_BYTELIST 0x04
+
+#define OPTYPE_UNDEFINED 0
+
+
+#define OPTYPE_LITERAL 1
+#define OPTYPE_CONSTANT 2
+#define OPTYPE_METHOD_ARGUMENT 3
+#define OPTYPE_LOCAL_VARIABLE 4
+#define OPTYPE_DATA_TERM 5
+
+/* Type 1 opcodes */
+
+#define OPTYPE_MONADIC1 6
+#define OPTYPE_DYADIC1 7
+
+
+/* Type 2 opcodes */
+
+#define OPTYPE_MONADIC2 8
+#define OPTYPE_MONADIC2_r 9
+#define OPTYPE_DYADIC2 10
+#define OPTYPE_DYADIC2_r 11
+#define OPTYPE_DYADIC2_s 12
+#define OPTYPE_INDEX 13
+#define OPTYPE_MATCH 14
+
+/* Generic for an op that returns a value */
+
+#define OPTYPE_METHOD_CALL 15
+
+
+/* Misc */
+
+#define OPTYPE_CREATE_FIELD 16
+#define OPTYPE_FATAL 17
+#define OPTYPE_CONTROL 18
+#define OPTYPE_RECONFIGURATION 19
+#define OPTYPE_NAMED_OBJECT 20
+
+#define OPTYPE_BOGUS 21
+
+
+/* Comparison operation codes for Match_op operator */
+
+typedef enum
+{
+ MATCH_MTR = 0,
+ MATCH_MEQ = 1,
+ MATCH_MLE = 2,
+ MATCH_MLT = 3,
+ MATCH_MGE = 4,
+ MATCH_MGT = 5
+
+} AML_MATCH_OPERATOR;
+
+#define MAX_MATCH_OPERATOR 5
+
+
+/* Field Access Types */
+
+#define ACCESS_TYPE_MASK 0x0f
+#define ACCESS_TYPE_SHIFT 0
+
+typedef enum
+{
+ ACCESS_ANY_ACC = 0,
+ ACCESS_BYTE_ACC = 1,
+ ACCESS_WORD_ACC = 2,
+ ACCESS_DWORD_ACC = 3,
+ ACCESS_BLOCK_ACC = 4,
+ ACCESS_SMBSEND_RECV_ACC = 5,
+ ACCESS_SMBQUICK_ACC = 6
+
+} AML_ACCESS_TYPE;
+
+
+/* Field Lock Rules */
+
+#define LOCK_RULE_MASK 0x10
+#define LOCK_RULE_SHIFT 4
+
+typedef enum
+{
+ GLOCK_NEVER_LOCK = 0,
+ GLOCK_ALWAYS_LOCK = 1
+
+} AML_LOCK_RULE;
+
+
+/* Field Update Rules */
+
+#define UPDATE_RULE_MASK 0x060
+#define UPDATE_RULE_SHIFT 5
+
+typedef enum
+{
+ UPDATE_PRESERVE = 0,
+ UPDATE_WRITE_AS_ONES = 1,
+ UPDATE_WRITE_AS_ZEROS = 2
+
+} AML_UPDATE_RULE;
+
+
+/* bit fields in Method_flags byte */
+
+#define METHOD_FLAGS_ARG_COUNT 0x07
+#define METHOD_FLAGS_SERIALIZED 0x08
+
+
+/* Array sizes. Used for range checking also */
+
+#define NUM_REGION_TYPES 5
+#define NUM_ACCESS_TYPES 7
+#define NUM_UPDATE_RULES 3
+#define NUM_MATCH_OPS 7
+#define NUM_OPCODES 256
+#define NUM_FIELD_NAMES 2
+
+/* External declarations of the AML tables */
+
+extern u8 acpi_gbl_aml [NUM_OPCODES];
+extern u16 acpi_gbl_pfx [NUM_OPCODES];
+extern char *acpi_gbl_short_ops [NUM_OPCODES];
+extern char *acpi_gbl_long_ops [NUM_OPCODES];
+extern char *acpi_gbl_region_types [NUM_REGION_TYPES];
+extern char *acpi_gbl_match_ops [NUM_MATCH_OPS];
+extern char *acpi_gbl_access_types [NUM_ACCESS_TYPES];
+extern char *acpi_gbl_update_rules [NUM_UPDATE_RULES];
+extern char *acpi_gbl_FEnames [NUM_FIELD_NAMES];
+
+
+/*
+ * AML tables
+ */
+
+#ifdef DEFINE_AML_GLOBALS
+
+/* Data used in keeping track of fields */
+
+char *acpi_gbl_FEnames[NUM_FIELD_NAMES] =
+{
+ "skip",
+ "?access?"
+}; /* FE = Field Element */
+
+
+/* Region type decoding */
+
+char *acpi_gbl_region_types[NUM_REGION_TYPES] =
+{
+ "System_memory",
+ "System_iO",
+ "PCIConfig",
+ "Embedded_control",
+ "SMBus"
+};
+
+
+char *acpi_gbl_match_ops[NUM_MATCH_OPS] =
+{
+ "Error",
+ "MTR",
+ "MEQ",
+ "MLE",
+ "MLT",
+ "MGE",
+ "MGT"
+};
+
+
+/* Access type decoding */
+
+char *acpi_gbl_access_types[NUM_ACCESS_TYPES] =
+{
+ "Any_acc",
+ "Byte_acc",
+ "Word_acc",
+ "DWord_acc",
+ "Block_acc",
+ "SMBSend_recv_acc",
+ "SMBQuick_acc"
+};
+
+
+/* Update rule decoding */
+
+char *acpi_gbl_update_rules[NUM_UPDATE_RULES] =
+{
+ "Preserve",
+ "Write_as_ones",
+ "Write_as_zeros"
+};
+
+
+#endif /* DEFINE_AML_GLOBALS */
+
+#endif /* __AMLCODE_H__ */
diff --git a/drivers/acpi/include/common.h b/drivers/acpi/include/common.h
new file mode 100644
index 000000000..f35ba795d
--- /dev/null
+++ b/drivers/acpi/include/common.h
@@ -0,0 +1,650 @@
+
+/******************************************************************************
+ *
+ * Name: common.h -- prototypes for the common (subsystem-wide) procedures
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 _COMMON_H
+#define _COMMON_H
+
+
+#define REF_INCREMENT (u16) 0
+#define REF_DECREMENT (u16) 1
+#define REF_FORCE_DELETE (u16) 2
+
+/* Acpi_cm_dump_buffer */
+
+#define DB_BYTE_DISPLAY 1
+#define DB_WORD_DISPLAY 2
+#define DB_DWORD_DISPLAY 4
+#define DB_QWORD_DISPLAY 8
+
+
+/* Global initialization interfaces */
+
+void
+acpi_cm_init_globals (
+ ACPI_INIT_DATA *init_data);
+
+void
+acpi_cm_terminate (
+ void);
+
+
+/*
+ * Acpi_cm_init - miscellaneous initialization and shutdown
+ */
+
+ACPI_STATUS
+acpi_cm_hardware_initialize (
+ void);
+
+ACPI_STATUS
+acpi_cm_subsystem_shutdown (
+ void);
+
+/*
+ * Acpi_cm_global - Global data structures and procedures
+ */
+
+char *
+acpi_cm_get_mutex_name (
+ u32 mutex_id);
+
+char *
+acpi_cm_get_type_name (
+ u32 type);
+
+u8
+acpi_cm_valid_object_type (
+ u32 type);
+
+ACPI_OWNER_ID
+acpi_cm_allocate_owner_id (
+ u32 id_type);
+
+
+/*
+ * Acpi_cm_clib - Local implementations of C library functions
+ */
+
+ACPI_SIZE
+acpi_cm_strlen (
+ const char *string);
+
+char *
+acpi_cm_strcpy (
+ char *dst_string,
+ const char *src_string);
+
+char *
+acpi_cm_strncpy (
+ char *dst_string,
+ const char *src_string,
+ ACPI_SIZE count);
+
+u32
+acpi_cm_strncmp (
+ const char *string1,
+ const char *string2,
+ ACPI_SIZE count);
+
+u32
+acpi_cm_strcmp (
+ const char *string1,
+ const char *string2);
+
+char *
+acpi_cm_strcat (
+ char *dst_string,
+ const char *src_string);
+
+char *
+acpi_cm_strncat (
+ char *dst_string,
+ const char *src_string,
+ ACPI_SIZE count);
+
+u32
+acpi_cm_strtoul (
+ const char *string,
+ char **terminator,
+ s32 base);
+
+char *
+acpi_cm_strstr (
+ char *string1,
+ char *string2);
+
+char *
+acpi_cm_strupr (
+ char *src_string);
+
+void *
+acpi_cm_memcpy (
+ void *dest,
+ const void *src,
+ ACPI_SIZE count);
+
+void *
+acpi_cm_memset (
+ void *dest,
+ s32 value,
+ ACPI_SIZE count);
+
+s32
+acpi_cm_to_upper (
+ s32 c);
+
+s32
+acpi_cm_to_lower (
+ s32 c);
+
+
+/*
+ * Acpi_cm_copy - Object construction and conversion interfaces
+ */
+
+ACPI_STATUS
+acpi_cm_build_simple_object(
+ ACPI_OBJECT_INTERNAL *obj,
+ ACPI_OBJECT *user_obj,
+ char *data_space,
+ u32 *buffer_space_used);
+
+ACPI_STATUS
+acpi_cm_build_package_object (
+ ACPI_OBJECT_INTERNAL *obj,
+ char *buffer,
+ u32 *space_used);
+
+ACPI_STATUS
+acpi_cm_build_external_object (
+ ACPI_OBJECT_INTERNAL *obj,
+ ACPI_BUFFER *ret_buffer);
+
+ACPI_STATUS
+acpi_cm_build_internal_simple_object(
+ ACPI_OBJECT *user_obj,
+ ACPI_OBJECT_INTERNAL *obj);
+
+ACPI_STATUS
+acpi_cm_build_internal_object (
+ ACPI_OBJECT *obj,
+ ACPI_OBJECT_INTERNAL *internal_obj);
+
+ACPI_STATUS
+acpi_cm_copy_internal_simple_object (
+ ACPI_OBJECT_INTERNAL *source_obj,
+ ACPI_OBJECT_INTERNAL *dest_obj);
+
+ACPI_STATUS
+acpi_cm_build_copy_internal_package_object (
+ ACPI_OBJECT_INTERNAL *source_obj,
+ ACPI_OBJECT_INTERNAL *dest_obj);
+
+
+/*
+ * Acpi_cm_create - Object creation
+ */
+
+ACPI_STATUS
+acpi_cm_update_object_reference (
+ ACPI_OBJECT_INTERNAL *object,
+ u16 action);
+
+ACPI_OBJECT_INTERNAL *
+_cm_create_internal_object (
+ char *module_name,
+ s32 line_number,
+ s32 component_id,
+ OBJECT_TYPE_INTERNAL type);
+
+
+/*
+ * Acpi_cm_debug - Debug interfaces
+ */
+
+s32
+get_debug_level (
+ void);
+
+void
+set_debug_level (
+ s32 level);
+
+void
+function_trace (
+ ACPI_STRING module_name,
+ s32 line_number,
+ s32 component_id,
+ ACPI_STRING function_name);
+
+void
+function_trace_ptr (
+ ACPI_STRING module_name,
+ s32 line_number,
+ s32 component_id,
+ ACPI_STRING function_name,
+ void *pointer);
+
+void
+function_trace_u32 (
+ ACPI_STRING module_name,
+ s32 line_number,
+ s32 component_id,
+ ACPI_STRING function_name,
+ u32 integer);
+
+void
+function_trace_str (
+ ACPI_STRING module_name,
+ s32 line_number,
+ s32 component_id,
+ ACPI_STRING function_name,
+ char *string);
+
+void
+function_exit (
+ ACPI_STRING module_name,
+ s32 line_number,
+ s32 component_id,
+ ACPI_STRING function_name);
+
+void
+function_status_exit (
+ ACPI_STRING module_name,
+ s32 line_number,
+ s32 component_id,
+ ACPI_STRING function_name,
+ ACPI_STATUS status);
+
+void
+function_value_exit (
+ ACPI_STRING module_name,
+ s32 line_number,
+ s32 component_id,
+ ACPI_STRING function_name,
+ NATIVE_UINT value);
+
+void
+function_ptr_exit (
+ ACPI_STRING module_name,
+ s32 line_number,
+ s32 component_id,
+ ACPI_STRING function_name,
+ char *ptr);
+
+void
+debug_print_prefix (
+ ACPI_STRING module_name,
+ s32 line_number);
+
+void
+debug_print (
+ ACPI_STRING module_name,
+ s32 line_number,
+ s32 component_id,
+ s32 print_level,
+ char *format, ...);
+
+void
+debug_print_raw (
+ char *format, ...);
+
+void
+_report_info (
+ ACPI_STRING module_name,
+ s32 line_number,
+ s32 component_id,
+ ACPI_STRING message);
+
+void
+_report_error (
+ ACPI_STRING module_name,
+ s32 line_number,
+ s32 component_id,
+ ACPI_STRING message);
+
+void
+_report_warning (
+ ACPI_STRING module_name,
+ s32 line_number,
+ s32 component_id,
+ ACPI_STRING message);
+
+void
+_report_success (
+ ACPI_STRING module_name,
+ s32 line_number,
+ s32 component_id,
+ ACPI_STRING message);
+
+void
+acpi_cm_dump_buffer (
+ char *buffer,
+ u32 count,
+ u32 display,
+ s32 component_id);
+
+
+/*
+ * Acpi_cm_delete - Object deletion
+ */
+
+void
+acpi_cm_delete_internal_obj (
+ ACPI_OBJECT_INTERNAL *object);
+
+void
+acpi_cm_delete_internal_package_object (
+ ACPI_OBJECT_INTERNAL *object);
+
+void
+acpi_cm_delete_internal_simple_object (
+ ACPI_OBJECT_INTERNAL *object);
+
+ACPI_STATUS
+acpi_cm_delete_internal_object_list (
+ ACPI_OBJECT_INTERNAL **obj_list);
+
+
+/*
+ * Acpi_cm_eval - object evaluation
+ */
+
+/* Method name strings */
+
+#define METHOD_NAME__HID "_HID"
+#define METHOD_NAME__UID "_UID"
+#define METHOD_NAME__ADR "_ADR"
+#define METHOD_NAME__STA "_STA"
+#define METHOD_NAME__REG "_REG"
+#define METHOD_NAME__SEG "_SEG"
+#define METHOD_NAME__BBN "_BBN"
+
+
+ACPI_STATUS
+acpi_cm_evaluate_numeric_object (
+ char *method_name,
+ ACPI_NAMED_OBJECT *acpi_device,
+ u32 *address);
+
+ACPI_STATUS
+acpi_cm_execute_HID (
+ ACPI_NAMED_OBJECT *acpi_device,
+ DEVICE_ID *hid);
+
+ACPI_STATUS
+acpi_cm_execute_STA (
+ ACPI_NAMED_OBJECT *acpi_device,
+ u32 *status_flags);
+
+ACPI_STATUS
+acpi_cm_execute_UID (
+ ACPI_NAMED_OBJECT *acpi_device,
+ DEVICE_ID *uid);
+
+
+/*
+ * Acpi_cm_error - exception interfaces
+ */
+
+char *
+acpi_cm_format_exception (
+ ACPI_STATUS status);
+
+
+/*
+ * Acpi_cm_mutex - mutual exclusion interfaces
+ */
+
+ACPI_STATUS
+acpi_cm_mutex_initialize (
+ void);
+
+void
+acpi_cm_mutex_terminate (
+ void);
+
+ACPI_STATUS
+acpi_cm_create_mutex (
+ ACPI_MUTEX_HANDLE mutex_id);
+
+ACPI_STATUS
+acpi_cm_delete_mutex (
+ ACPI_MUTEX_HANDLE mutex_id);
+
+ACPI_STATUS
+acpi_cm_acquire_mutex (
+ ACPI_MUTEX_HANDLE mutex_id);
+
+ACPI_STATUS
+acpi_cm_release_mutex (
+ ACPI_MUTEX_HANDLE mutex_id);
+
+
+/*
+ * Acpi_cm_object - internal object create/delete/cache routines
+ */
+
+#define acpi_cm_create_internal_object(t) _cm_create_internal_object(_THIS_MODULE,__LINE__,_COMPONENT,t)
+#define acpi_cm_allocate_object_desc() _cm_allocate_object_desc(_THIS_MODULE,__LINE__,_COMPONENT)
+
+void *
+_cm_allocate_object_desc (
+ char *module_name,
+ s32 line_number,
+ s32 component_id);
+
+void
+acpi_cm_delete_object_desc (
+ ACPI_OBJECT_INTERNAL *object);
+
+u8
+acpi_cm_valid_internal_object (
+ void *object);
+
+
+/*
+ * Acpi_cm_ref_cnt - Object reference count management
+ */
+
+void
+acpi_cm_add_reference (
+ ACPI_OBJECT_INTERNAL *object);
+
+void
+acpi_cm_remove_reference (
+ ACPI_OBJECT_INTERNAL *object);
+
+/*
+ * Acpi_cm_size - Object size routines
+ */
+
+ACPI_STATUS
+acpi_cm_get_simple_object_size (
+ ACPI_OBJECT_INTERNAL *obj,
+ u32 *obj_length);
+
+ACPI_STATUS
+acpi_cm_get_package_object_size (
+ ACPI_OBJECT_INTERNAL *obj,
+ u32 *obj_length);
+
+ACPI_STATUS
+acpi_cm_get_object_size(
+ ACPI_OBJECT_INTERNAL *obj,
+ u32 *obj_length);
+
+
+/*
+ * Acpi_cm_state - Generic state creation/cache routines
+ */
+
+void
+acpi_cm_push_generic_state (
+ ACPI_GENERIC_STATE **list_head,
+ ACPI_GENERIC_STATE *state);
+
+ACPI_GENERIC_STATE *
+acpi_cm_pop_generic_state (
+ ACPI_GENERIC_STATE **list_head);
+
+
+ACPI_GENERIC_STATE *
+acpi_cm_create_generic_state (
+ void);
+
+ACPI_GENERIC_STATE *
+acpi_cm_create_update_state (
+ ACPI_OBJECT_INTERNAL *object,
+ u16 action);
+
+ACPI_STATUS
+acpi_cm_create_update_state_and_push (
+ ACPI_OBJECT_INTERNAL *object,
+ u16 action,
+ ACPI_GENERIC_STATE **state_list);
+
+ACPI_GENERIC_STATE *
+acpi_cm_create_control_state (
+ void);
+
+void
+acpi_cm_delete_generic_state (
+ ACPI_GENERIC_STATE *state);
+
+void
+acpi_cm_delete_generic_state_cache (
+ void);
+
+void
+acpi_cm_delete_object_cache (
+ void);
+
+/*
+ * Acpi_cmutils
+ */
+
+u8
+acpi_cm_valid_acpi_name (
+ u32 name);
+
+u8
+acpi_cm_valid_acpi_character (
+ char character);
+
+
+/*
+ * Memory allocation functions and related macros.
+ * Macros that expand to include filename and line number
+ */
+
+void *
+_cm_allocate (
+ u32 size,
+ u32 component,
+ ACPI_STRING module,
+ s32 line);
+
+void *
+_cm_callocate (
+ u32 size,
+ u32 component,
+ ACPI_STRING module,
+ s32 line);
+
+void
+_cm_free (
+ void *address,
+ u32 component,
+ ACPI_STRING module,
+ s32 line);
+
+void
+acpi_cm_init_static_object (
+ ACPI_OBJECT_INTERNAL *obj_desc);
+
+#define acpi_cm_allocate(a) _cm_allocate(a,_COMPONENT,_THIS_MODULE,__LINE__)
+#define acpi_cm_callocate(a) _cm_callocate(a, _COMPONENT,_THIS_MODULE,__LINE__)
+#define acpi_cm_free(a) _cm_free(a,_COMPONENT,_THIS_MODULE,__LINE__)
+
+#ifndef ACPI_DEBUG
+
+#define acpi_cm_add_element_to_alloc_list(a,b,c,d,e,f)
+#define acpi_cm_delete_element_from_alloc_list(a,b,c,d)
+#define acpi_cm_dump_current_allocations(a,b)
+#define acpi_cm_dump_allocation_info()
+
+#define DECREMENT_OBJECT_METRICS(a)
+#define INCREMENT_OBJECT_METRICS(a)
+#define INITIALIZE_ALLOCATION_METRICS()
+
+#else
+
+#define INITIALIZE_ALLOCATION_METRICS() \
+ acpi_gbl_current_object_count = 0; \
+ acpi_gbl_current_object_size = 0; \
+ acpi_gbl_running_object_count = 0; \
+ acpi_gbl_running_object_size = 0; \
+ acpi_gbl_max_concurrent_object_count = 0; \
+ acpi_gbl_max_concurrent_object_size = 0; \
+ acpi_gbl_current_alloc_size = 0; \
+ acpi_gbl_current_alloc_count = 0; \
+ acpi_gbl_running_alloc_size = 0; \
+ acpi_gbl_running_alloc_count = 0; \
+ acpi_gbl_max_concurrent_alloc_size = 0; \
+ acpi_gbl_max_concurrent_alloc_count = 0
+
+#define DECREMENT_OBJECT_METRICS(a) \
+ acpi_gbl_current_object_count--; \
+ acpi_gbl_current_object_size -= a
+
+#define INCREMENT_OBJECT_METRICS(a) \
+ acpi_gbl_current_object_count++; \
+ acpi_gbl_running_object_count++; \
+ if (acpi_gbl_max_concurrent_object_count < acpi_gbl_current_object_count) \
+ { \
+ acpi_gbl_max_concurrent_object_count = acpi_gbl_current_object_count; \
+ } \
+ acpi_gbl_running_object_size += a; \
+ acpi_gbl_current_object_size += a; \
+ if (acpi_gbl_max_concurrent_object_size < acpi_gbl_current_object_size) \
+ { \
+ acpi_gbl_max_concurrent_object_size = acpi_gbl_current_object_size; \
+ }
+
+
+void
+acpi_cm_dump_allocation_info (
+ void);
+
+void
+acpi_cm_dump_current_allocations (
+ u32 component,
+ ACPI_STRING module);
+
+#endif
+
+
+#endif /* _COMMON_H */
diff --git a/drivers/acpi/include/config.h b/drivers/acpi/include/config.h
new file mode 100644
index 000000000..a0e77e113
--- /dev/null
+++ b/drivers/acpi/include/config.h
@@ -0,0 +1,185 @@
+
+/******************************************************************************
+ *
+ * Name: config.h - Global configuration constants
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 _CONFIG_H
+#define _CONFIG_H
+
+
+/******************************************************************************
+ *
+ * Compile-time options
+ *
+ *****************************************************************************/
+
+/*
+ * ACPI_DEBUG - This switch enables all the debug facilities of the ACPI
+ * subsystem. This includes the DEBUG_PRINT output statements
+ * When disabled, all DEBUG_PRINT statements are compiled out.
+ *
+ * ACPI_APPLICATION - Use this switch if the subsystem is going to be run
+ * at the application level.
+ *
+ */
+
+
+/******************************************************************************
+ *
+ * Subsystem Constants
+ *
+ *****************************************************************************/
+
+
+/* Version string */
+
+#define ACPI_CA_VERSION __DATE__
+
+/* Name of host operating system (returned by the _OS_ namespace object) */
+
+#ifdef _LINUX
+#define ACPI_OS_NAME "Linux"
+#else
+#define ACPI_OS_NAME "Intel ACPI/CA Core Subsystem"
+#endif
+
+
+/*
+ * How and when control methods will be parsed
+ * The default action is to parse all methods at table load time to verify them, but delete the parse trees
+ * to conserve memory. Methods are parsed just in time before execution and the parse tree is deleted
+ * when execution completes.
+ */
+#define METHOD_PARSE_AT_INIT 0x0 /* Parse at table init, never delete the method parse tree */
+#define METHOD_PARSE_JUST_IN_TIME 0x1 /* Parse only when a method is invoked */
+#define METHOD_DELETE_AT_COMPLETION 0x2 /* Delete parse tree on method completion */
+
+/* Default parsing configuration */
+
+#define METHOD_PARSE_CONFIGURATION (METHOD_PARSE_JUST_IN_TIME | METHOD_DELETE_AT_COMPLETION)
+
+
+/* Maximum objects in the various object caches */
+
+#define MAX_STATE_CACHE_DEPTH 24 /* State objects for stacks */
+#define MAX_PARSE_CACHE_DEPTH 512 /* Parse tree objects */
+#define MAX_OBJECT_CACHE_DEPTH 32 /* Interpreter operand objects */
+#define MAX_WALK_CACHE_DEPTH 2 /* Objects for parse tree walks (method execution) */
+
+/*
+ * Name_space Table size
+ *
+ * All tables are the same size to simplify the implementation.
+ * Tables may be extended by allocating additional tables that
+ * are in turn linked together to form a chain of tables.
+ */
+
+#define NS_TABLE_SIZE 16
+
+/* String size constants */
+
+#define MAX_STRING_LENGTH 512
+#define PATHNAME_MAX 256 /* A full namespace pathname */
+
+
+/* Maximum count for a semaphore object */
+
+#define MAX_SEMAPHORE_COUNT 256
+
+
+/* Max reference count (for debug only) */
+
+#define MAX_REFERENCE_COUNT 0x200
+
+
+/* Size of cached memory mapping for system memory operation region */
+
+#define SYSMEM_REGION_WINDOW_SIZE 4096
+
+
+/*
+ * Debugger threading model
+ * Use single threaded if the entire subsystem is contained in an application
+ * Use multiple threaded when the the subsystem is running in the kernel.
+ *
+ * By default the model is single threaded if ACPI_APPLICATION is set,
+ * multi-threaded if ACPI_APPLICATION is not set.
+ */
+
+#define DEBUGGER_SINGLE_THREADED 0
+#define DEBUGGER_MULTI_THREADED 1
+
+#ifdef ACPI_APPLICATION
+#define DEBUGGER_THREADING DEBUGGER_SINGLE_THREADED
+
+#else
+#define DEBUGGER_THREADING DEBUGGER_MULTI_THREADED
+#endif
+
+
+/******************************************************************************
+ *
+ * ACPI Specification constants (Do not change unless the specification changes)
+ *
+ *****************************************************************************/
+
+/*
+ * Method info (in WALK_STATE), containing local variables and argumetns
+ */
+
+#define MTH_NUM_LOCALS 8
+#define MTH_MAX_LOCAL 7
+
+#define MTH_NUM_ARGS 7
+#define MTH_MAX_ARG 6
+
+/*
+ * Operand Stack (in WALK_STATE), Must be large enough to contain MTH_MAX_ARG
+ */
+
+#define OBJ_NUM_OPERANDS 8
+#define OBJ_MAX_OPERAND 7
+
+/* Names within the namespace are 4 bytes long */
+
+#define ACPI_NAME_SIZE 4
+#define PATH_SEGMENT_LENGTH 5 /* 4 chars for name + 1 char for separator */
+#define PATH_SEPARATOR '.'
+
+
+/* Constants used in searching for the RSDP in low memory */
+
+#define LO_RSDP_WINDOW_BASE (void *) 0
+#define HI_RSDP_WINDOW_BASE (void *) 0xE0000
+#define LO_RSDP_WINDOW_SIZE 0x400
+#define HI_RSDP_WINDOW_SIZE 0x20000
+#define RSDP_SCAN_STEP 16
+
+
+/* Maximum nesting of package objects */
+
+#define MAX_PACKAGE_DEPTH 16
+
+
+#endif /* _CONFIG_H */
+
diff --git a/drivers/acpi/include/debugger.h b/drivers/acpi/include/debugger.h
new file mode 100644
index 000000000..0d27d59b3
--- /dev/null
+++ b/drivers/acpi/include/debugger.h
@@ -0,0 +1,394 @@
+
+/******************************************************************************
+ *
+ * Name: debugger.h - ACPI/AML debugger
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 __DEBUGGER_H__
+#define __DEBUGGER_H__
+
+
+#define DB_MAX_ARGS 8 /* Must be max method args + 1 */
+
+#define DB_COMMAND_PROMPT '-'
+#define DB_EXECUTE_PROMPT '%'
+
+
+extern int optind;
+extern char *optarg;
+extern u8 *aml_ptr;
+extern u32 acpi_aml_length;
+
+extern u8 opt_tables;
+extern u8 opt_disasm;
+extern u8 opt_stats;
+extern u8 opt_parse_jit;
+extern u8 opt_verbose;
+
+
+extern char *args[DB_MAX_ARGS];
+extern char line_buf[80];
+extern char scope_buf[40];
+extern char debug_filename[40];
+extern u8 output_to_file;
+extern char *buffer;
+extern char *filename;
+extern char *INDENT_STRING;
+extern u32 acpi_gbl_method_breakpoint;
+extern u8 acpi_gbl_db_output_flags;
+extern u32 acpi_gbl_db_debug_level;
+extern u32 acpi_gbl_db_console_debug_level;
+
+extern u32 num_names;
+extern u32 num_methods;
+extern u32 num_regions;
+extern u32 num_packages;
+extern u32 num_aliases;
+extern u32 num_devices;
+extern u32 num_field_defs;
+extern u32 num_thermal_zones;
+extern u32 num_named_objects;
+extern u32 num_grammar_elements;
+extern u32 num_method_elements ;
+extern u32 num_mutexes;
+extern u32 num_power_resources;
+extern u32 num_bank_fields ;
+extern u32 num_index_fields;
+extern u32 num_events;
+
+extern u32 size_of_parse_tree;
+extern u32 size_of_method_trees;
+extern u32 size_of_nTes;
+extern u32 size_of_acpi_objects;
+
+
+#define BUFFER_SIZE 4196
+
+#define DB_REDIRECTABLE_OUTPUT 0x01
+#define DB_CONSOLE_OUTPUT 0x02
+#define DB_DUPLICATE_OUTPUT 0x03
+
+
+typedef struct command_info
+{
+ char *name; /* Command Name */
+ char min_args; /* Minimum arguments required */
+
+} COMMAND_INFO;
+
+
+typedef struct argument_info
+{
+ char *name; /* Argument Name */
+
+} ARGUMENT_INFO;
+
+
+#define PARAM_LIST(pl) pl
+
+#define DBTEST_OUTPUT_LEVEL(lvl) if (opt_verbose)
+
+#define VERBOSE_PRINT(fp) DBTEST_OUTPUT_LEVEL(lvl) {\
+ acpi_os_printf PARAM_LIST(fp);}
+
+#define EX_NO_SINGLE_STEP 1
+#define EX_SINGLE_STEP 2
+
+
+/* Prototypes */
+
+
+/*
+ * dbapi - external debugger interfaces
+ */
+
+int
+acpi_db_initialize (
+ void);
+
+ACPI_STATUS
+acpi_db_single_step (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op,
+ u8 op_type);
+
+
+/*
+ * dbcmds - debug commands and output routines
+ */
+
+
+void
+acpi_db_display_table_info (
+ char *table_arg);
+
+void
+acpi_db_unload_acpi_table (
+ char *table_arg,
+ char *instance_arg);
+
+void
+acpi_db_set_method_breakpoint (
+ char *location,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op);
+
+void
+acpi_db_set_method_call_breakpoint (
+ ACPI_GENERIC_OP *op);
+
+void
+acpi_db_disassemble_aml (
+ char *statements,
+ ACPI_GENERIC_OP *op);
+
+void
+acpi_db_dump_namespace (
+ char *start_arg,
+ char *depth_arg);
+
+void
+acpi_db_dump_namespace_by_owner (
+ char *owner_arg,
+ char *depth_arg);
+
+void
+acpi_db_send_notify (
+ char *name,
+ u32 value);
+
+void
+acpi_db_set_method_data (
+ char *type_arg,
+ char *index_arg,
+ char *value_arg);
+
+ACPI_STATUS
+acpi_db_display_objects (
+ char *obj_type_arg,
+ char *display_count_arg);
+
+ACPI_STATUS
+acpi_db_find_name_in_namespace (
+ char *name_arg);
+
+void
+acpi_db_set_scope (
+ char *name);
+
+void
+acpi_db_find_references (
+ char *object_arg);
+
+
+/*
+ * dbdisasm - AML disassembler
+ */
+
+void
+acpi_db_display_op (
+ ACPI_GENERIC_OP *origin,
+ u32 num_opcodes);
+
+void
+acpi_db_display_namestring (
+ char *name);
+
+void
+acpi_db_display_path (
+ ACPI_GENERIC_OP *op);
+
+void
+acpi_db_display_opcode (
+ ACPI_GENERIC_OP *op);
+
+
+/*
+ * dbdisply - debug display commands
+ */
+
+
+void
+acpi_db_display_method_info (
+ ACPI_GENERIC_OP *op);
+
+void
+acpi_db_decode_and_display_object (
+ char *target,
+ char *output_type);
+
+void
+acpi_db_display_result_object (
+ ACPI_OBJECT_INTERNAL *ret_desc);
+
+ACPI_STATUS
+acpi_db_display_all_methods (
+ char *display_count_arg);
+
+void
+acpi_db_display_internal_object (
+ ACPI_OBJECT_INTERNAL *obj_desc);
+
+void
+acpi_db_display_arguments (
+ void);
+
+void
+acpi_db_display_locals (
+ void);
+
+void
+acpi_db_display_results (
+ void);
+
+void
+acpi_db_display_calling_tree (
+ void);
+
+void
+acpi_db_display_argument_object (
+ ACPI_OBJECT_INTERNAL *obj_desc);
+
+
+/*
+ * dbexec - debugger control method execution
+ */
+
+void
+acpi_db_execute (
+ char *name,
+ char **args,
+ u32 flags);
+
+void
+acpi_db_create_execution_threads (
+ char *num_threads_arg,
+ char *num_loops_arg,
+ char *method_name_arg);
+
+
+/*
+ * dbfileio - Debugger file I/O commands
+ */
+
+OBJECT_TYPE_INTERNAL
+acpi_db_match_argument (
+ char *user_argument,
+ ARGUMENT_INFO *arguments);
+
+
+void
+acpi_db_close_debug_file (
+ void);
+
+void
+acpi_db_open_debug_file (
+ char *name);
+
+ACPI_STATUS
+acpi_db_load_acpi_table (
+ char *filename);
+
+
+/*
+ * dbhistry - debugger HISTORY command
+ */
+
+void
+acpi_db_add_to_history (
+ char *command_line);
+
+void
+acpi_db_display_history (void);
+
+char *
+acpi_db_get_from_history (
+ char *command_num_arg);
+
+
+/*
+ * dbinput - user front-end to the AML debugger
+ */
+
+ACPI_STATUS
+acpi_db_command_dispatch (
+ char *input_buffer,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op);
+
+void
+acpi_db_execute_thread (
+ void *context);
+
+ACPI_STATUS
+acpi_db_user_commands (
+ char prompt,
+ ACPI_GENERIC_OP *op);
+
+
+/*
+ * dbstats - Generation and display of ACPI table statistics
+ */
+
+void
+acpi_db_generate_statistics (
+ ACPI_GENERIC_OP *root,
+ u8 is_method);
+
+
+ACPI_STATUS
+acpi_db_display_statistics (
+ char *type_arg);
+
+
+/*
+ * dbutils - AML debugger utilities
+ */
+
+void
+acpi_db_set_output_destination (
+ s32 where);
+
+void
+acpi_db_dump_buffer (
+ u32 address);
+
+void
+acpi_db_dump_object (
+ ACPI_OBJECT *obj_desc,
+ u32 level);
+
+void
+acpi_db_prep_namestring (
+ char *name);
+
+
+ACPI_STATUS
+acpi_db_second_pass_parse (
+ ACPI_GENERIC_OP *root);
+
+ACPI_NAMED_OBJECT*
+acpi_db_local_ns_lookup (
+ char *name);
+
+
+#endif /* __DEBUGGER_H__ */
diff --git a/drivers/acpi/include/dispatch.h b/drivers/acpi/include/dispatch.h
new file mode 100644
index 000000000..e1d44be7a
--- /dev/null
+++ b/drivers/acpi/include/dispatch.h
@@ -0,0 +1,383 @@
+/******************************************************************************
+ *
+ * Module Name: dispatch.h
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 _DISPATCH_H_
+#define _DISPATCH_H_
+
+
+#define NAMEOF_LOCAL_NTE "__L0"
+#define NAMEOF_ARG_NTE "__A0"
+
+
+/* For Acpi_ds_method_data_set_value */
+
+#define MTH_TYPE_LOCAL 0
+#define MTH_TYPE_ARG 1
+
+
+/* Common interfaces */
+
+ACPI_STATUS
+acpi_ds_obj_stack_push (
+ void *object,
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_ds_obj_stack_pop (
+ u32 pop_count,
+ ACPI_WALK_STATE *walk_state);
+
+void *
+acpi_ds_obj_stack_get_value (
+ u32 index,
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_ds_obj_stack_pop_object (
+ ACPI_OBJECT_INTERNAL **object,
+ ACPI_WALK_STATE *walk_state);
+
+
+/* dsregion - Op region support */
+
+ACPI_STATUS
+acpi_ds_get_region_arguments (
+ ACPI_OBJECT_INTERNAL *rgn_desc);
+
+
+/* dsctrl - Parser/Interpreter interface, control stack routines */
+
+/*
+ACPI_CTRL_STATE *
+Acpi_ds_create_control_state (void);
+
+void
+Acpi_ds_push_control_state (
+ ACPI_CTRL_STATE *Control_state,
+ ACPI_WALK_STATE *Walk_state);
+
+ACPI_CTRL_STATE *
+Acpi_ds_pop_control_state (
+ ACPI_WALK_STATE *Walk_state);
+*/
+
+ACPI_STATUS
+acpi_ds_exec_begin_control_op (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op);
+
+ACPI_STATUS
+acpi_ds_exec_end_control_op (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op);
+
+
+/* dsexec - Parser/Interpreter interface, method execution callbacks */
+
+ACPI_STATUS
+acpi_ds_exec_begin_op (
+ ACPI_WALK_STATE *state,
+ ACPI_GENERIC_OP *op);
+
+ACPI_STATUS
+acpi_ds_exec_end_op (
+ ACPI_WALK_STATE *state,
+ ACPI_GENERIC_OP *op);
+
+
+/* dsfield - Parser/Interpreter interface for AML fields */
+
+
+ACPI_STATUS
+acpi_ds_create_field (
+ ACPI_GENERIC_OP *op,
+ ACPI_HANDLE region,
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_ds_create_bank_field (
+ ACPI_GENERIC_OP *op,
+ ACPI_HANDLE region,
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_ds_create_index_field (
+ ACPI_GENERIC_OP *op,
+ ACPI_HANDLE region,
+ ACPI_WALK_STATE *walk_state);
+
+
+/* dsload - Parser/Interpreter interface, namespace load callbacks */
+
+ACPI_STATUS
+acpi_ds_load1_begin_op (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op);
+
+ACPI_STATUS
+acpi_ds_load1_end_op (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op);
+
+ACPI_STATUS
+acpi_ds_load2_begin_op (
+ ACPI_WALK_STATE *state,
+ ACPI_GENERIC_OP *op);
+
+ACPI_STATUS
+acpi_ds_load2_end_op (
+ ACPI_WALK_STATE *state,
+ ACPI_GENERIC_OP *op);
+
+
+/* dsmthdat - method data (locals/args) */
+
+
+ACPI_STATUS
+acpi_ds_method_data_delete_all (
+ ACPI_WALK_STATE *walk_state);
+
+u8
+acpi_ds_is_method_value (
+ ACPI_OBJECT_INTERNAL *obj_desc);
+
+OBJECT_TYPE_INTERNAL
+acpi_ds_method_data_get_type (
+ u32 type,
+ u32 index);
+
+ACPI_STATUS
+acpi_ds_method_data_get_value (
+ u32 type,
+ u32 index,
+ ACPI_OBJECT_INTERNAL **obj_desc);
+
+ACPI_STATUS
+acpi_ds_method_data_set_value (
+ u32 type,
+ u32 index,
+ ACPI_OBJECT_INTERNAL *obj_desc);
+
+ACPI_STATUS
+acpi_ds_method_data_delete_value (
+ u32 type,
+ u32 index);
+
+ACPI_STATUS
+acpi_ds_method_data_init_args (
+ ACPI_OBJECT_INTERNAL **params,
+ u32 param_count);
+
+ACPI_NAMED_OBJECT*
+acpi_ds_method_data_get_nte (
+ u32 type,
+ u32 index);
+
+ACPI_STATUS
+acpi_ds_method_data_init (
+ ACPI_WALK_STATE *walk_state);
+
+
+/* dsmethod - Parser/Interpreter interface - control method parsing */
+
+ACPI_STATUS
+acpi_ds_parse_method (
+ ACPI_HANDLE obj_handle);
+
+ACPI_STATUS
+acpi_ds_call_control_method (
+ ACPI_WALK_LIST *walk_list,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op);
+
+ACPI_STATUS
+acpi_ds_restart_control_method (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OBJECT_INTERNAL *return_desc);
+
+ACPI_STATUS
+acpi_ds_terminate_control_method (
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_ds_begin_method_execution (
+ ACPI_NAMED_OBJECT *method_entry,
+ ACPI_OBJECT_INTERNAL *obj_desc);
+
+
+/* dsobj - Parser/Interpreter interface - object initialization and conversion */
+
+ACPI_STATUS
+acpi_ds_init_one_object (
+ ACPI_HANDLE obj_handle,
+ u32 level,
+ void *context,
+ void **return_value);
+
+ACPI_STATUS
+acpi_ds_initialize_objects (
+ ACPI_TABLE_DESC *table_desc,
+ ACPI_NAMED_OBJECT *start_entry);
+
+ACPI_STATUS
+acpi_ds_build_internal_package_obj (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op,
+ ACPI_OBJECT_INTERNAL **obj_desc);
+
+ACPI_STATUS
+acpi_ds_build_internal_object (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op,
+ ACPI_OBJECT_INTERNAL **obj_desc_ptr);
+
+ACPI_STATUS
+acpi_ds_init_object_from_op (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op,
+ u16 opcode,
+ ACPI_OBJECT_INTERNAL *obj_desc);
+
+ACPI_STATUS
+acpi_ds_create_named_object (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_NAMED_OBJECT *entry,
+ ACPI_GENERIC_OP *op);
+
+
+/* dsregn - Parser/Interpreter interface - Op Region parsing */
+
+ACPI_STATUS
+acpi_ds_eval_region_operands (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op);
+
+ACPI_STATUS
+acpi_ds_initialize_region (
+ ACPI_HANDLE obj_handle);
+
+
+/* dsutils - Parser/Interpreter interface utility routines */
+
+void
+acpi_ds_delete_result_if_not_used (
+ ACPI_GENERIC_OP *op,
+ ACPI_OBJECT_INTERNAL *result_obj,
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_ds_create_operand (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *arg);
+
+ACPI_STATUS
+acpi_ds_create_operands (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *first_arg);
+
+ACPI_STATUS
+acpi_ds_resolve_operands (
+ ACPI_WALK_STATE *walk_state);
+
+OBJECT_TYPE_INTERNAL
+acpi_ds_map_opcode_to_data_type (
+ u16 opcode,
+ u32 *out_flags);
+
+OBJECT_TYPE_INTERNAL
+acpi_ds_map_named_opcode_to_data_type (
+ u16 opcode);
+
+
+/*
+ * dswscope - Scope Stack manipulation
+ */
+
+ACPI_STATUS
+acpi_ds_scope_stack_push (
+ ACPI_NAME_TABLE *new_scope,
+ OBJECT_TYPE_INTERNAL type,
+ ACPI_WALK_STATE *walk_state);
+
+
+ACPI_STATUS
+acpi_ds_scope_stack_pop (
+ ACPI_WALK_STATE *walk_state);
+
+void
+acpi_ds_scope_stack_clear (
+ ACPI_WALK_STATE *walk_state);
+
+
+/* Acpi_dswstate - parser WALK_STATE management routines */
+
+ACPI_WALK_STATE *
+acpi_ds_create_walk_state (
+ ACPI_OWNER_ID owner_id,
+ ACPI_GENERIC_OP *origin,
+ ACPI_OBJECT_INTERNAL *mth_desc,
+ ACPI_WALK_LIST *walk_list);
+
+ACPI_STATUS
+acpi_ds_obj_stack_delete_all (
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_ds_obj_stack_pop_and_delete (
+ u32 pop_count,
+ ACPI_WALK_STATE *walk_state);
+
+void
+acpi_ds_delete_walk_state (
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_WALK_STATE *
+acpi_ds_pop_walk_state (
+ ACPI_WALK_LIST *walk_list);
+
+ACPI_STATUS
+acpi_ds_result_stack_pop (
+ ACPI_OBJECT_INTERNAL **object,
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_ds_result_stack_push (
+ void *object,
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_ds_result_stack_clear (
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_WALK_STATE *
+acpi_ds_get_current_walk_state (
+ ACPI_WALK_LIST *walk_list);
+
+void
+acpi_ds_delete_walk_state_cache (
+ void);
+
+
+#endif /* _DISPATCH_H_ */ \ No newline at end of file
diff --git a/drivers/acpi/include/events.h b/drivers/acpi/include/events.h
new file mode 100644
index 000000000..398157004
--- /dev/null
+++ b/drivers/acpi/include/events.h
@@ -0,0 +1,209 @@
+
+/******************************************************************************
+ *
+ * Name: events.h - Acpi_event subcomponent prototypes and defines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 __EVENTS_H__
+#define __EVENTS_H__
+
+
+/*
+ * Acpi_evfixed - Fixed event handling
+ */
+
+ACPI_STATUS
+acpi_ev_fixed_event_initialize (
+ void);
+
+u32
+acpi_ev_fixed_event_detect (
+ void);
+
+u32
+acpi_ev_fixed_event_dispatch (
+ u32 acpi_event);
+
+
+/*
+ * Acpi_evglock - Global Lock support
+ */
+
+ACPI_STATUS
+acpi_ev_acquire_global_lock(
+ void);
+
+void
+acpi_ev_release_global_lock(
+ void);
+
+ACPI_STATUS
+acpi_ev_init_global_lock_handler (
+ void);
+
+
+/*
+ * Acpi_evgpe - GPE handling and dispatch
+ */
+
+ACPI_STATUS
+acpi_ev_gpe_initialize (
+ void);
+
+ACPI_STATUS
+acpi_ev_init_gpe_control_methods (
+ void);
+
+u32
+acpi_ev_gpe_dispatch (
+ u32 gpe_number);
+
+u32
+acpi_ev_gpe_detect (
+ void);
+
+
+/*
+ * Acpi_evnotify - Device Notify handling and dispatch
+ */
+
+void
+acpi_ev_notify_dispatch (
+ ACPI_HANDLE device,
+ u32 notify_value);
+
+
+/*
+ * Acpi_evregion - Address Space handling
+ */
+
+ACPI_STATUS
+acpi_ev_install_default_address_space_handlers (
+ void);
+
+ACPI_STATUS
+acpi_ev_address_space_dispatch (
+ ACPI_OBJECT_INTERNAL *region_obj,
+ u32 function,
+ u32 address,
+ u32 bit_width,
+ u32 *value);
+
+
+ACPI_STATUS
+acpi_ev_addr_handler_helper (
+ ACPI_HANDLE obj_handle,
+ u32 level,
+ void *context,
+ void **return_value);
+
+void
+acpi_ev_disassociate_region_from_handler(
+ ACPI_OBJECT_INTERNAL *region_obj);
+
+
+ACPI_STATUS
+acpi_ev_associate_region_and_handler(
+ ACPI_OBJECT_INTERNAL *handler_obj,
+ ACPI_OBJECT_INTERNAL *region_obj);
+
+
+/*
+ * Acpi_evregini - Region initialization and setup
+ */
+
+ACPI_STATUS
+acpi_ev_system_memory_region_setup (
+ ACPI_HANDLE handle,
+ u32 function,
+ void *handler_context,
+ void **return_context);
+
+ACPI_STATUS
+acpi_ev_io_space_region_setup (
+ ACPI_HANDLE handle,
+ u32 function,
+ void *handler_context,
+ void **return_context);
+
+ACPI_STATUS
+acpi_ev_pci_config_region_setup (
+ ACPI_HANDLE handle,
+ u32 function,
+ void *handler_context,
+ void **return_context);
+
+ACPI_STATUS
+acpi_ev_default_region_setup (
+ ACPI_HANDLE handle,
+ u32 function,
+ void *handler_context,
+ void **return_context);
+
+ACPI_STATUS
+acpi_ev_initialize_region (
+ ACPI_OBJECT_INTERNAL *region_obj,
+ u8 acpi_ns_locked);
+
+
+/*
+ * Acpi_evsci - SCI (System Control Interrupt) handling/dispatch
+ */
+
+u32
+acpi_ev_install_sci_handler (
+ void);
+
+ACPI_STATUS
+acpi_ev_remove_sci_handler (
+ void);
+
+s32
+acpi_ev_initialize_sCI (
+ s32 program_sCI);
+
+void
+acpi_ev_restore_acpi_state (
+ void);
+
+void
+acpi_ev_terminate (
+ void);
+
+
+/* Debug support */
+
+#ifdef ACPI_DEBUG
+
+s32
+acpi_ev_sci_count (
+ u32 acpi_event);
+
+#define DEBUG_INCREMENT_EVENT_COUNT(a) acpi_gbl_event_count[a]++;
+
+#else
+
+#define DEBUG_INCREMENT_EVENT_COUNT(a)
+#endif
+
+
+#endif /* __EVENTS_H__ */
diff --git a/drivers/acpi/include/globals.h b/drivers/acpi/include/globals.h
new file mode 100644
index 000000000..7857d6f39
--- /dev/null
+++ b/drivers/acpi/include/globals.h
@@ -0,0 +1,311 @@
+
+/******************************************************************************
+ *
+ * Name: globals.h - Declarations for global variables
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 __GLOBALS_H__
+#define __GLOBALS_H__
+
+
+/*
+ * Ensure that the globals are actually defined only once
+ */
+#ifdef DEFINE_ACPI_GLOBALS
+#define ACPI_EXTERN
+#else
+#define ACPI_EXTERN extern
+#endif
+
+
+extern char *msg_acpi_error_break;
+
+/*****************************************************************************
+ *
+ * Debug support
+ *
+ ****************************************************************************/
+
+/* Runtime configuration of debug print levels */
+
+extern u32 acpi_dbg_level;
+extern u32 acpi_dbg_layer;
+
+
+/* Procedure nesting level for debug output */
+
+extern u32 acpi_gbl_nesting_level;
+
+
+/*****************************************************************************
+ *
+ * ACPI Table globals
+ *
+ ****************************************************************************/
+
+/*
+ * Table pointers.
+ * Although these pointers are somewhat redundant with the global Acpi_table,
+ * they are convenient because they are typed pointers.
+ *
+ * These tables are single-table only; meaning that there can be at most one
+ * of each in the system. Each global points to the actual table.
+ *
+ */
+ACPI_EXTERN ROOT_SYSTEM_DESCRIPTOR_POINTER *acpi_gbl_RSDP;
+ACPI_EXTERN ROOT_SYSTEM_DESCRIPTION_TABLE *acpi_gbl_RSDT;
+ACPI_EXTERN FIRMWARE_ACPI_CONTROL_STRUCTURE *acpi_gbl_FACS;
+ACPI_EXTERN FIXED_ACPI_DESCRIPTION_TABLE *acpi_gbl_FACP;
+ACPI_EXTERN APIC_TABLE *acpi_gbl_APIC;
+ACPI_EXTERN ACPI_TABLE_HEADER *acpi_gbl_DSDT;
+ACPI_EXTERN ACPI_TABLE_HEADER *acpi_gbl_SBST;
+/*
+ * Since there may be multiple SSDTs and PSDTS, a single pointer is not
+ * sufficient; Therefore, there isn't one!
+ */
+
+
+/*
+ * ACPI Table info arrays
+ */
+extern ACPI_TABLE_DESC acpi_gbl_acpi_tables[NUM_ACPI_TABLES];
+extern ACPI_TABLE_SUPPORT acpi_gbl_acpi_table_data[NUM_ACPI_TABLES];
+
+/*
+ * Predefined mutex objects. This array contains the
+ * actual OS mutex handles, indexed by the local ACPI_MUTEX_HANDLEs.
+ * (The table maps local handles to the real OS handles)
+ */
+ACPI_EXTERN ACPI_MUTEX_INFO acpi_gbl_acpi_mutex_info [NUM_MTX];
+extern ACPI_INIT_DATA acpi_gbl_acpi_init_data;
+
+
+/*****************************************************************************
+ *
+ * Miscellaneous globals
+ *
+ ****************************************************************************/
+
+
+ACPI_EXTERN u8 *acpi_gbl_gpe0enable_register_save;
+ACPI_EXTERN u8 *acpi_gbl_gpe1_enable_register_save;
+ACPI_EXTERN ACPI_WALK_STATE *acpi_gbl_breakpoint_walk;
+ACPI_EXTERN ACPI_GENERIC_STATE *acpi_gbl_generic_state_cache;
+ACPI_EXTERN ACPI_GENERIC_OP *acpi_gbl_parse_cache;
+ACPI_EXTERN ACPI_OBJECT_INTERNAL *acpi_gbl_object_cache;
+ACPI_EXTERN ACPI_WALK_STATE *acpi_gbl_walk_state_cache;
+ACPI_EXTERN ACPI_HANDLE acpi_gbl_global_lock_semaphore;
+
+
+ACPI_EXTERN u32 acpi_gbl_global_lock_thread_count;
+ACPI_EXTERN u32 acpi_gbl_restore_acpi_chipset;
+ACPI_EXTERN u32 acpi_gbl_original_mode;
+ACPI_EXTERN u32 acpi_gbl_edge_level_save;
+ACPI_EXTERN u32 acpi_gbl_irq_enable_save;
+ACPI_EXTERN u32 acpi_gbl_rsdp_original_location;
+
+ACPI_EXTERN u32 acpi_gbl_state_cache_requests;
+ACPI_EXTERN u32 acpi_gbl_state_cache_hits;
+ACPI_EXTERN u32 acpi_gbl_parse_cache_requests;
+ACPI_EXTERN u32 acpi_gbl_parse_cache_hits;
+ACPI_EXTERN u32 acpi_gbl_object_cache_requests;
+ACPI_EXTERN u32 acpi_gbl_object_cache_hits;
+ACPI_EXTERN u32 acpi_gbl_walk_state_cache_requests;
+ACPI_EXTERN u32 acpi_gbl_walk_state_cache_hits;
+ACPI_EXTERN u32 acpi_gbl_ns_lookup_count;
+ACPI_EXTERN u32 acpi_gbl_ps_find_count;
+
+
+ACPI_EXTERN u16 acpi_gbl_generic_state_cache_depth;
+ACPI_EXTERN u16 acpi_gbl_parse_cache_depth;
+ACPI_EXTERN u16 acpi_gbl_object_cache_depth;
+ACPI_EXTERN u16 acpi_gbl_walk_state_cache_depth;
+ACPI_EXTERN u16 acpi_gbl_pm1_enable_register_save;
+ACPI_EXTERN u16 acpi_gbl_next_table_owner_id;
+ACPI_EXTERN u16 acpi_gbl_next_method_owner_id;
+
+ACPI_EXTERN u8 acpi_gbl_debugger_configuration;
+ACPI_EXTERN u8 acpi_gbl_global_lock_acquired;
+ACPI_EXTERN u8 acpi_gbl_global_lock_set; /* TBD: [Restructure] OBSOLETE?? */
+ACPI_EXTERN u8 acpi_gbl_step_to_next_call;
+ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present;
+
+
+ACPI_EXTERN ACPI_OBJECT_NOTIFY_HANDLER acpi_gbl_drv_notify;
+ACPI_EXTERN ACPI_OBJECT_NOTIFY_HANDLER acpi_gbl_sys_notify;
+
+
+extern u8 acpi_gbl_shutdown;
+extern u32 acpi_gbl_system_flags;
+extern u32 acpi_gbl_startup_flags;
+
+
+/*****************************************************************************
+ *
+ * Namespace globals
+ *
+ ****************************************************************************/
+
+#define NUM_NS_TYPES INTERNAL_TYPE_INVALID+1
+#define NUM_PREDEFINED_NAMES 9
+
+
+ACPI_EXTERN ACPI_NAME_TABLE acpi_gbl_root_name_table;
+ACPI_EXTERN ACPI_NAMED_OBJECT *acpi_gbl_root_object;
+
+extern u8 acpi_gbl_ns_properties[NUM_NS_TYPES];
+extern PREDEFINED_NAMES acpi_gbl_pre_defined_names [NUM_PREDEFINED_NAMES];
+
+
+/* Used to detect memory leaks (DEBUG ONLY) */
+
+#ifdef ACPI_DEBUG
+ACPI_EXTERN ALLOCATION_INFO *acpi_gbl_head_alloc_ptr;
+ACPI_EXTERN ALLOCATION_INFO *acpi_gbl_tail_alloc_ptr;
+#endif
+
+
+/*****************************************************************************
+ *
+ * Interpreter globals
+ *
+ ****************************************************************************/
+
+
+ACPI_EXTERN u32 acpi_gbl_when_to_parse_methods;
+ACPI_EXTERN ACPI_WALK_LIST *acpi_gbl_current_walk_list;
+
+/* Base of AML block, and pointer to current location in it */
+
+ACPI_EXTERN u8 *acpi_gbl_Pcode_base;
+ACPI_EXTERN u8 *acpi_gbl_Pcode;
+
+/*
+ * Length of AML block, and remaining length of current package.
+ */
+ACPI_EXTERN u32 acpi_gbl_Pcode_block_len;
+ACPI_EXTERN u32 acpi_gbl_Pcode_len;
+
+ACPI_EXTERN u32 acpi_gbl_buf_seq; /* Counts allocated Buffer descriptors */
+ACPI_EXTERN s32 acpi_gbl_named_object_err; /* Indicate if inc_error should be called */
+
+/*
+ * Handle to the last method found - used during pass1 of load
+ */
+ACPI_EXTERN ACPI_HANDLE acpi_gbl_last_method;
+
+/*
+ * Table of Address Space handlers
+ */
+
+ACPI_EXTERN ACPI_ADDRESS_SPACE_INFO acpi_gbl_address_spaces[ACPI_NUM_ADDRESS_SPACES];
+
+
+/* Control method single step flag */
+
+ACPI_EXTERN u8 acpi_gbl_cm_single_step;
+
+
+/*****************************************************************************
+ *
+ * Parser globals
+ *
+ ****************************************************************************/
+
+ACPI_EXTERN ACPI_GENERIC_OP *acpi_gbl_parsed_namespace_root;
+
+extern ACPI_OP_INFO acpi_gbl_aml_op_info[];
+extern u8 acpi_gbl_aml_op_info_index[256];
+extern char *acpi_gbl_parser_id;
+
+
+/*****************************************************************************
+ *
+ * Hardware globals
+ *
+ ****************************************************************************/
+
+extern ACPI_C_STATE_HANDLER acpi_hw_cx_handlers[MAX_CX_STATES];
+extern u32 acpi_hw_active_cx_state;
+
+
+/*****************************************************************************
+ *
+ * Event globals
+ *
+ ****************************************************************************/
+
+ACPI_EXTERN ACPI_FIXED_EVENT_INFO acpi_gbl_fixed_event_handlers[NUM_FIXED_EVENTS];
+
+ACPI_EXTERN ACPI_HANDLE acpi_gbl_gpe_obj_handle;
+ACPI_EXTERN u32 acpi_gbl_gpe_register_count;
+ACPI_EXTERN ACPI_GPE_REGISTERS *acpi_gbl_gpe_registers;
+ACPI_EXTERN ACPI_GPE_LEVEL_INFO *acpi_gbl_gpe_info;
+
+/*
+ * Gpe validation and translation table
+ * Indexed by the GPE number, returns GPE_INVALID if the GPE is not supported.
+ * Otherwise, returns a valid index into the global GPE table.
+ *
+ * This table is needed because the GPE numbers supported by block 1 do not
+ * have to be contiguous with the GPE numbers supported by block 0.
+ */
+ACPI_EXTERN u8 acpi_gbl_gpe_valid [NUM_GPE];
+
+/* Acpi_event counter for debug only */
+
+#ifdef ACPI_DEBUG
+ACPI_EXTERN u32 acpi_gbl_event_count[NUM_FIXED_EVENTS];
+#endif
+
+
+/*****************************************************************************
+ *
+ * Debugger globals
+ *
+ ****************************************************************************/
+
+ACPI_EXTERN u8 acpi_gbl_method_executing;
+ACPI_EXTERN u8 acpi_gbl_db_terminate_threads;
+
+
+/* Memory allocation metrics - Debug Only! */
+
+#ifdef ACPI_DEBUG
+
+ACPI_EXTERN u32 acpi_gbl_current_alloc_size;
+ACPI_EXTERN u32 acpi_gbl_current_alloc_count;
+ACPI_EXTERN u32 acpi_gbl_running_alloc_size;
+ACPI_EXTERN u32 acpi_gbl_running_alloc_count;
+ACPI_EXTERN u32 acpi_gbl_max_concurrent_alloc_size;
+ACPI_EXTERN u32 acpi_gbl_max_concurrent_alloc_count;
+ACPI_EXTERN u32 acpi_gbl_current_object_count;
+ACPI_EXTERN u32 acpi_gbl_current_object_size;
+ACPI_EXTERN u32 acpi_gbl_max_concurrent_object_count;
+ACPI_EXTERN u32 acpi_gbl_max_concurrent_object_size;
+ACPI_EXTERN u32 acpi_gbl_running_object_count;
+ACPI_EXTERN u32 acpi_gbl_running_object_size;
+
+#endif
+
+
+#endif /* __GLOBALS_H__ */
diff --git a/drivers/acpi/include/hardware.h b/drivers/acpi/include/hardware.h
new file mode 100644
index 000000000..4191f17dd
--- /dev/null
+++ b/drivers/acpi/include/hardware.h
@@ -0,0 +1,169 @@
+
+/******************************************************************************
+ *
+ * Name: hardware.h -- hardware specific interfaces
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 __HARDWARE_H__
+#define __HARDWARE_H__
+
+
+/* Prototypes */
+
+
+ACPI_STATUS
+acpi_hw_initialize(
+ void);
+
+ACPI_STATUS
+acpi_hw_shutdown(
+ void);
+
+ACPI_STATUS
+acpi_hw_initialize_system_info(
+ void);
+
+ACPI_STATUS
+acpi_hw_set_mode (
+ u32 mode);
+
+u32
+acpi_hw_get_mode (
+ void);
+
+u32
+acpi_hw_get_mode_capabilities (
+ void);
+
+/* Register I/O Prototypes */
+
+u32
+acpi_hw_register_access (
+ NATIVE_UINT read_write,
+ u8 use_lock,
+ u32 register_id, ... /* DWORD Value */);
+
+void
+acpi_hw_clear_acpi_status (
+ void);
+
+
+/* GPE support */
+
+void
+acpi_hw_enable_gpe (
+ u32 gpe_index);
+
+void
+acpi_hw_disable_gpe (
+ u32 gpe_index);
+
+void
+acpi_hw_clear_gpe (
+ u32 gpe_index);
+
+void
+acpi_hw_get_gpe_status (
+ u32 gpe_number,
+ ACPI_EVENT_STATUS *event_status);
+
+/* Sleep Prototypes */
+
+ACPI_STATUS
+acpi_hw_obtain_sleep_type_register_data (
+ u8 sleep_state,
+ u8 *slp_typ_a,
+ u8 *slp_typ_b);
+
+
+/* Cx State Prototypes */
+
+ACPI_STATUS
+acpi_hw_enter_c1(
+ ACPI_IO_ADDRESS pblk_address,
+ u32 *pm_timer_ticks);
+
+ACPI_STATUS
+acpi_hw_enter_c2(
+ ACPI_IO_ADDRESS pblk_address,
+ u32 *pm_timer_ticks);
+
+ACPI_STATUS
+acpi_hw_enter_c3(
+ ACPI_IO_ADDRESS pblk_address,
+ u32 *pm_timer_ticks);
+
+ACPI_STATUS
+acpi_hw_enter_cx (
+ ACPI_IO_ADDRESS pblk_address,
+ u32 *pm_timer_ticks);
+
+ACPI_STATUS
+acpi_hw_set_cx (
+ u32 cx_state);
+
+ACPI_STATUS
+acpi_hw_get_cx_info (
+ u32 cx_states[]);
+
+
+/* Throttling Prototypes */
+
+void
+acpi_hw_enable_throttling (
+ ACPI_IO_ADDRESS pblk_address);
+
+void
+acpi_hw_disable_throttling (
+ ACPI_IO_ADDRESS pblk_address);
+
+u32
+acpi_hw_get_duty_cycle (
+ u8 duty_offset,
+ ACPI_IO_ADDRESS pblk_address,
+ u32 num_throttle_states);
+
+void
+acpi_hw_program_duty_cycle (
+ u8 duty_offset,
+ u32 duty_cycle,
+ ACPI_IO_ADDRESS pblk_address,
+ u32 num_throttle_states);
+
+NATIVE_UINT
+acpi_hw_local_pow (
+ NATIVE_UINT x,
+ NATIVE_UINT y);
+
+
+/* ACPI Timer prototypes */
+
+u32
+acpi_hw_pmt_ticks (
+ void);
+
+u32
+acpi_hw_pmt_resolution (
+ void);
+
+
+#endif /* __HARDWARE_H__ */
diff --git a/drivers/acpi/include/internal.h b/drivers/acpi/include/internal.h
new file mode 100644
index 000000000..68c903cf7
--- /dev/null
+++ b/drivers/acpi/include/internal.h
@@ -0,0 +1,850 @@
+
+/******************************************************************************
+ *
+ * Name: internal.h - Internal data types used across the ACPI subsystem
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 _ACPI_INTERNAL_H
+#define _ACPI_INTERNAL_H
+
+#include "config.h"
+
+
+#define WAIT_FOREVER ((u32) -1)
+
+typedef void* ACPI_MUTEX;
+typedef u32 ACPI_MUTEX_HANDLE;
+
+
+/* Object descriptor types */
+
+#define ACPI_DESC_TYPE_INTERNAL 0xAA
+#define ACPI_DESC_TYPE_PARSER 0xBB
+#define ACPI_DESC_TYPE_STATE 0xCC
+#define ACPI_DESC_TYPE_WALK 0xDD
+#define ACPI_DESC_TYPE_NAMED 0xEE
+
+
+/*****************************************************************************
+ *
+ * Mutex typedefs and structs
+ *
+ ****************************************************************************/
+
+
+/*
+ * Predefined handles for the mutex objects used within the subsystem
+ * All mutex objects are automatically created by Acpi_cm_mutex_initialize.
+ * NOTE: any changes here must be reflected in the Acpi_gbl_Mutex_names table also!
+ */
+
+#define ACPI_MTX_HARDWARE 0
+#define ACPI_MTX_MEMORY 1
+#define ACPI_MTX_CACHES 2
+#define ACPI_MTX_TABLES 3
+#define ACPI_MTX_PARSER 4
+#define ACPI_MTX_DISPATCHER 5
+#define ACPI_MTX_INTERPRETER 6
+#define ACPI_MTX_EXECUTE 7
+#define ACPI_MTX_NAMESPACE 8
+#define ACPI_MTX_EVENTS 9
+#define ACPI_MTX_OP_REGIONS 10
+#define ACPI_MTX_DEBUG_CMD_READY 11
+#define ACPI_MTX_DEBUG_CMD_COMPLETE 12
+
+#define MAX_MTX 12
+#define NUM_MTX MAX_MTX+1
+
+
+#ifdef ACPI_DEBUG
+#ifdef DEFINE_ACPI_GLOBALS
+
+/* Names for the mutexes used in the subsystem */
+
+static char *acpi_gbl_mutex_names[] =
+{
+ "ACPI_MTX_Hardware",
+ "ACPI_MTX_Memory",
+ "ACPI_MTX_Caches",
+ "ACPI_MTX_Tables",
+ "ACPI_MTX_Parser",
+ "ACPI_MTX_Dispatcher",
+ "ACPI_MTX_Interpreter",
+ "ACPI_MTX_Execute",
+ "ACPI_MTX_Namespace",
+ "ACPI_MTX_Events",
+ "ACPI_MTX_Op_regions",
+ "ACPI_MTX_Debug_cmd_ready",
+ "ACPI_MTX_Debug_cmd_complete"
+};
+
+#endif
+#endif
+
+
+/* Table for the global mutexes */
+
+typedef struct acpi_mutex_info
+{
+ ACPI_MUTEX mutex;
+ u32 use_count;
+ u8 locked;
+
+} ACPI_MUTEX_INFO;
+
+
+/* Lock flag parameter for various interfaces */
+
+#define ACPI_MTX_DO_NOT_LOCK 0
+#define ACPI_MTX_LOCK 1
+
+
+typedef u16 ACPI_OWNER_ID;
+#define OWNER_TYPE_TABLE 0x0
+#define OWNER_TYPE_METHOD 0x1
+#define FIRST_METHOD_ID 0x0000
+#define FIRST_TABLE_ID 0x8000
+
+/* TBD: [Restructure] get rid of the need for this! */
+
+#define TABLE_ID_DSDT (ACPI_OWNER_ID) 0xD1D1
+
+/*****************************************************************************
+ *
+ * Namespace typedefs and structs
+ *
+ ****************************************************************************/
+
+
+/* Operational modes of the AML interpreter/scanner */
+
+typedef enum
+{
+ IMODE_LOAD_PASS1 = 0x01,
+ IMODE_LOAD_PASS2 = 0x02,
+ IMODE_EXECUTE = 0x0E
+
+} OPERATING_MODE;
+
+
+/*
+ * The Acpi_named_object describes a named object that appears in the AML
+ * An Acpi_name_table is used to store Acpi_named_objects.
+ *
+ * Data_type is used to differentiate between internal descriptors, and MUST
+ * be the first byte in this structure.
+ */
+
+typedef struct acpi_named_object
+{
+ u8 data_type;
+ u8 type; /* Type associated with this name */
+ u8 this_index; /* Entry number */
+ u8 flags;
+ u32 name; /* ACPI Name, always 4 chars per ACPI spec */
+
+
+ void *object; /* Pointer to attached ACPI object (optional) */
+ struct acpi_name_table *child_table; /* Scope owned by this name (optional) */
+ ACPI_OWNER_ID owner_id; /* ID of owner - either an ACPI table or a method */
+ u16 reference_count; /* Current count of references and children */
+
+#ifdef _IA64
+ u32 fill1; /* 64-bit alignment */
+#endif
+
+} ACPI_NAMED_OBJECT;
+
+
+typedef struct acpi_name_table
+{
+ struct acpi_name_table *next_table;
+ struct acpi_name_table *parent_table;
+ ACPI_NAMED_OBJECT *parent_entry;
+ ACPI_NAMED_OBJECT entries[1];
+
+} ACPI_NAME_TABLE;
+
+
+#define ENTRY_NOT_FOUND NULL
+
+
+/* NTE flags */
+
+#define NTE_AML_ATTACHMENT 0x1
+
+
+/*
+ * ACPI Table Descriptor. One per ACPI table
+ */
+typedef struct acpi_table_desc
+{
+ struct acpi_table_desc *prev;
+ struct acpi_table_desc *next;
+ struct acpi_table_desc *installed_desc;
+ ACPI_TABLE_HEADER *pointer;
+ void *base_pointer;
+ u8 *aml_pointer;
+ u32 aml_length;
+ u32 length;
+ u32 count;
+ ACPI_OWNER_ID table_id;
+ u8 type;
+ u8 allocation;
+ u8 loaded_into_namespace;
+
+} ACPI_TABLE_DESC;
+
+
+typedef struct
+{
+ char *search_for;
+ ACPI_HANDLE *list;
+ s32 *count;
+
+} FIND_CONTEXT;
+
+
+typedef struct
+{
+ ACPI_NAME_TABLE *name_table;
+ u32 position;
+ u8 table_full;
+
+} NS_SEARCH_DATA;
+
+
+/*
+ * Predefined Namespace items
+ */
+#define ACPI_MAX_ADDRESS_SPACE 255
+#define ACPI_NUM_ADDRESS_SPACES 256
+
+
+typedef struct
+{
+ char *name;
+ ACPI_OBJECT_TYPE type;
+ char *val;
+
+} PREDEFINED_NAMES;
+
+
+/*****************************************************************************
+ *
+ * Event typedefs and structs
+ *
+ ****************************************************************************/
+
+
+/* Status bits. */
+
+#define ACPI_STATUS_PMTIMER 0x0001
+#define ACPI_STATUS_GLOBAL 0x0020
+#define ACPI_STATUS_POWER_BUTTON 0x0100
+#define ACPI_STATUS_SLEEP_BUTTON 0x0200
+#define ACPI_STATUS_RTC_ALARM 0x0400
+
+/* Enable bits. */
+
+#define ACPI_ENABLE_PMTIMER 0x0001
+#define ACPI_ENABLE_GLOBAL 0x0020
+#define ACPI_ENABLE_POWER_BUTTON 0x0100
+#define ACPI_ENABLE_SLEEP_BUTTON 0x0200
+#define ACPI_ENABLE_RTC_ALARM 0x0400
+
+
+/*
+ * Entry in the Address_space (AKA Operation Region) table
+ */
+
+typedef struct
+{
+ ADDRESS_SPACE_HANDLER handler;
+ void *context;
+
+} ACPI_ADDRESS_SPACE_INFO;
+
+
+/* Values and addresses of the GPE registers (both banks) */
+
+typedef struct
+{
+ u8 status; /* Current value of status reg */
+ u8 enable; /* Current value of enable reg */
+ u16 status_addr; /* Address of status reg */
+ u16 enable_addr; /* Address of enable reg */
+ u8 gpe_base; /* Base GPE number */
+
+} ACPI_GPE_REGISTERS;
+
+
+#define ACPI_GPE_LEVEL_TRIGGERED 1
+#define ACPI_GPE_EDGE_TRIGGERED 2
+
+
+/* Information about each particular GPE level */
+
+typedef struct
+{
+ u8 type; /* Level or Edge */
+
+ ACPI_HANDLE method_handle; /* Method handle for direct (fast) execution */
+ GPE_HANDLER handler; /* Address of handler, if any */
+ void *context; /* Context to be passed to handler */
+
+} ACPI_GPE_LEVEL_INFO;
+
+
+/* Information about each particular fixed event */
+
+typedef struct
+{
+ FIXED_EVENT_HANDLER handler; /* Address of handler. */
+ void *context; /* Context to be passed to handler */
+
+} ACPI_FIXED_EVENT_INFO;
+
+
+/* Information used during field processing */
+
+typedef struct
+{
+ u8 skip_field;
+ u8 field_flag;
+ u32 pkg_length;
+
+} ACPI_FIELD_INFO;
+
+
+/*****************************************************************************
+ *
+ * Parser typedefs and structs
+ *
+ ****************************************************************************/
+
+
+#define OP_INFO_TYPE 0x1F
+#define OP_INFO_HAS_ARGS 0x20
+#define OP_INFO_CHILD_LOCATION 0xC0
+
+/*
+ * AML opcode, name, and argument layout
+ */
+typedef struct acpi_op_info
+{
+ u16 opcode; /* AML opcode */
+ u8 flags; /* Opcode type, Has_args flag */
+ u32 parse_args; /* Grammar/Parse time arguments */
+ u32 runtime_args; /* Interpret time arguments */
+
+ DEBUG_ONLY_MEMBERS (
+ char *name) /* op name (debug only) */
+
+} ACPI_OP_INFO;
+
+
+typedef union acpi_op_value
+{
+ u32 integer; /* integer constant */
+ u32 size; /* bytelist or field size */
+ char *string; /* NULL terminated string */
+ u8 *buffer; /* buffer or string */
+ char *name; /* NULL terminated string */
+ struct acpi_generic_op *arg; /* arguments and contained ops */
+ ACPI_NAMED_OBJECT *entry; /* entry in interpreter namespace tbl */
+
+} ACPI_OP_VALUE;
+
+
+#define ACPI_COMMON_OP \
+ u8 data_type; /* To differentiate various internal objs */\
+ u8 flags; /* Type of Op */\
+ u16 opcode; /* AML opcode */\
+ u32 aml_offset; /* offset of declaration in AML */\
+ struct acpi_generic_op *parent; /* parent op */\
+ struct acpi_generic_op *next; /* next op */\
+ DEBUG_ONLY_MEMBERS (\
+ char op_name[16]) /* op name (debug only) */\
+ /* NON-DEBUG members below: */\
+ void *acpi_named_object;/* for use by interpreter */\
+ ACPI_OP_VALUE value; /* Value or args associated with the opcode */\
+
+
+/*
+ * generic operation (eg. If, While, Store)
+ */
+typedef struct acpi_generic_op
+{
+ ACPI_COMMON_OP
+} ACPI_GENERIC_OP;
+
+
+/*
+ * operation with a name (eg. Scope, Method, Name, Named_field, ...)
+ */
+typedef struct acpi_named_op
+{
+ ACPI_COMMON_OP
+ u32 name; /* 4-byte name or zero if no name */
+
+} ACPI_NAMED_OP;
+
+
+/*
+ * special operation for methods and regions (parsing must be deferred
+ * until a first pass parse is completed)
+ */
+typedef struct acpi_deferred_op
+{
+ ACPI_COMMON_OP
+ u32 name; /* 4-byte name or 0 if none */
+ u32 body_length; /* AML body size */
+ u8 *body; /* AML body */
+ u16 thread_count; /* Count of threads currently executing a method */
+
+} ACPI_DEFERRED_OP;
+
+
+/*
+ * special operation for bytelists (Byte_list only)
+ */
+typedef struct acpi_bytelist_op
+{
+ ACPI_COMMON_OP
+ u8 *data; /* bytelist data */
+
+} ACPI_BYTELIST_OP;
+
+
+/*
+ * Parse state - one state per parser invocation and each control
+ * method.
+ */
+
+typedef struct acpi_parse_state
+{
+ u8 *aml_start; /* first AML byte */
+ u8 *aml; /* next AML byte */
+ u8 *aml_end; /* (last + 1) AML byte */
+ u8 *pkg_end; /* current package end */
+ ACPI_GENERIC_OP *start_op; /* root of parse tree */
+ struct acpi_parse_scope *scope; /* current scope */
+ struct acpi_parse_scope *scope_avail; /* unused (extra) scope structs */
+ struct acpi_parse_state *next;
+
+} ACPI_PARSE_STATE;
+
+
+/*
+ * Parse scope - one per ACPI scope
+ */
+
+typedef struct acpi_parse_scope
+{
+ ACPI_GENERIC_OP *op; /* current op being parsed */
+ u8 *arg_end; /* current argument end */
+ u8 *pkg_end; /* current package end */
+ struct acpi_parse_scope *parent; /* parent scope */
+ u32 arg_list; /* next argument to parse */
+ u32 arg_count; /* Number of fixed arguments */
+
+} ACPI_PARSE_SCOPE;
+
+
+/*****************************************************************************
+ *
+ * Generic "state" object for stacks
+ *
+ ****************************************************************************/
+
+
+#define CONTROL_NORMAL 0xC0
+#define CONTROL_CONDITIONAL_EXECUTING 0xC1
+#define CONTROL_PREDICATE_EXECUTING 0xC2
+#define CONTROL_PREDICATE_FALSE 0xC3
+#define CONTROL_PREDICATE_TRUE 0xC4
+
+
+#define ACPI_STATE_COMMON /* Two 32-bit fields and a pointer */\
+ u8 data_type; /* To differentiate various internal objs */\
+ u8 flags; \
+ u16 value; \
+ u16 state; \
+ u16 acpi_eval; \
+ void *next; \
+
+typedef struct acpi_common_state
+{
+ ACPI_STATE_COMMON
+} ACPI_COMMON_STATE;
+
+
+/*
+ * Update state - used to traverse complex objects such as packages
+ */
+typedef struct acpi_update_state
+{
+ ACPI_STATE_COMMON
+ union acpi_obj_internal *object;
+
+} ACPI_UPDATE_STATE;
+
+/*
+ * Control state - one per if/else and while constructs.
+ * Allows nesting of these constructs
+ */
+typedef struct acpi_control_state
+{
+ ACPI_STATE_COMMON
+ ACPI_GENERIC_OP *predicate_op; /* Start of if/while predicate */
+
+} ACPI_CONTROL_STATE;
+
+
+/*
+ * Scope state - current scope during namespace lookups
+ */
+
+typedef struct acpi_scope_state
+{
+ ACPI_STATE_COMMON
+ ACPI_NAME_TABLE *name_table;
+
+} ACPI_SCOPE_STATE;
+
+
+typedef union acpi_gen_state
+{
+ ACPI_COMMON_STATE common;
+ ACPI_CONTROL_STATE control;
+ ACPI_UPDATE_STATE update;
+ ACPI_SCOPE_STATE scope;
+
+} ACPI_GENERIC_STATE;
+
+
+/*****************************************************************************
+ *
+ * Tree walking typedefs and structs
+ *
+ ****************************************************************************/
+
+
+/*
+ * Walk state - current state of a parse tree walk. Used for both a leisurely stroll through
+ * the tree (for whatever reason), and for control method execution.
+ */
+
+#define NEXT_OP_DOWNWARD 1
+#define NEXT_OP_UPWARD 2
+
+typedef struct acpi_walk_state
+{
+ u8 data_type; /* To differentiate various internal objs */\
+ ACPI_OWNER_ID owner_id; /* Owner of objects created during the walk */
+ u8 last_predicate; /* Result of last predicate */
+ u8 next_op_info; /* Info about Next_op */
+ u8 num_operands; /* Stack pointer for Operands[] array */
+ u8 num_results; /* Stack pointer for Results[] array */
+ u8 current_result; /* */
+
+ struct acpi_walk_state *next; /* Next Walk_state in list */
+ ACPI_GENERIC_OP *origin; /* Start of walk */
+ ACPI_GENERIC_OP *prev_op; /* Last op that was processed */
+ ACPI_GENERIC_OP *next_op; /* next op to be processed */
+ ACPI_GENERIC_STATE *control_state; /* List of control states (nested IFs) */
+ ACPI_GENERIC_STATE *scope_info; /* Stack of nested scopes */
+ union acpi_obj_internal *return_desc; /* Return object, if any */
+ union acpi_obj_internal *method_desc; /* Method descriptor if running a method */
+ ACPI_GENERIC_OP *method_call_op; /* Method_call Op if running a method */
+ union acpi_obj_internal *operands[OBJ_NUM_OPERANDS]; /* Operands passed to the interpreter */
+ union acpi_obj_internal *results[OBJ_NUM_OPERANDS]; /* Accumulated results */
+ struct acpi_named_object arguments[MTH_NUM_ARGS]; /* Control method arguments */
+ struct acpi_named_object local_variables[MTH_NUM_LOCALS]; /* Control method locals */
+
+
+} ACPI_WALK_STATE;
+
+
+/*
+ * Walk list - head of a tree of walk states. Multiple walk states are created when there
+ * are nested control methods executing.
+ */
+typedef struct acpi_walk_list
+{
+
+ ACPI_WALK_STATE *walk_state;
+
+} ACPI_WALK_LIST;
+
+
+typedef
+ACPI_STATUS (*INTERPRETER_CALLBACK) (
+ ACPI_WALK_STATE *state,
+ ACPI_GENERIC_OP *op);
+
+
+/* Info used by Acpi_ps_init_objects */
+
+typedef struct init_walk_info
+{
+ u32 method_count;
+ u32 op_region_count;
+ ACPI_TABLE_DESC *table_desc;
+
+} INIT_WALK_INFO;
+
+
+/* TBD: [Restructure] Merge with struct above */
+
+typedef struct acpi_walk_info
+{
+ u32 debug_level;
+ u32 owner_id;
+
+} ACPI_WALK_INFO;
+
+
+/*****************************************************************************
+ *
+ * Hardware and PNP
+ *
+ ****************************************************************************/
+
+
+/* Sleep states */
+
+#define SLWA_DEBUG_LEVEL 4
+#define GTS_CALL 0
+#define GTS_WAKE 1
+
+/* Cx States */
+
+#define MAX_CX_STATE_LATENCY 0xFFFFFFFF
+#define MAX_CX_STATES 4
+
+/*
+ * The #define's and enum below establish an abstract way of identifying what
+ * register block and register is to be accessed. Do not change any of the
+ * values as they are used in switch statements and offset calculations.
+ */
+
+#define REGISTER_BLOCK_MASK 0xFF00
+#define BIT_IN_REGISTER_MASK 0x00FF
+#define PM1_EVT 0x0100
+#define PM1_CONTROL 0x0200
+#define PM2_CONTROL 0x0300
+#define PM_TIMER 0x0400
+#define PROCESSOR_BLOCK 0x0500
+#define GPE0_STS_BLOCK 0x0600
+#define GPE0_EN_BLOCK 0x0700
+#define GPE1_STS_BLOCK 0x0800
+#define GPE1_EN_BLOCK 0x0900
+
+enum
+{
+ /* PM1 status register ids */
+
+ TMR_STS = (PM1_EVT | 0x01),
+ BM_STS,
+ GBL_STS,
+ PWRBTN_STS,
+ SLPBTN_STS,
+ RTC_STS,
+ WAK_STS,
+
+ /* PM1 enable register ids */
+
+ TMR_EN,
+ /* need to skip 1 enable number since there's no bus master enable register */
+ GBL_EN = (PM1_EVT | 0x0A),
+ PWRBTN_EN,
+ SLPBTN_EN,
+ RTC_EN,
+
+ /* PM1 control register ids */
+
+ SCI_EN = (PM1_CONTROL | 0x01),
+ BM_RLD,
+ GBL_RLS,
+ SLP_TYPE_A,
+ SLP_TYPE_B,
+ SLP_EN,
+
+ /* PM2 control register ids */
+
+ ARB_DIS = (PM2_CONTROL | 0x01),
+
+ /* PM Timer register ids */
+
+ TMR_VAL = (PM_TIMER | 0x01),
+
+ GPE0_STS = (GPE0_STS_BLOCK | 0x01),
+ GPE0_EN = (GPE0_EN_BLOCK | 0x01),
+
+ GPE1_STS = (GPE1_STS_BLOCK | 0x01),
+ GPE1_EN = (GPE0_EN_BLOCK | 0x01),
+
+ /* Last register value is one less than LAST_REG */
+
+ LAST_REG
+};
+
+
+#define TMR_STS_MASK 0x0001
+#define BM_STS_MASK 0x0010
+#define GBL_STS_MASK 0x0020
+#define PWRBTN_STS_MASK 0x0100
+#define SLPBTN_STS_MASK 0x0200
+#define RTC_STS_MASK 0x0400
+#define WAK_STS_MASK 0x8000
+
+#define ALL_FIXED_STS_BITS (TMR_STS_MASK | BM_STS_MASK | GBL_STS_MASK | PWRBTN_STS_MASK | \
+ SLPBTN_STS_MASK | RTC_STS_MASK | WAK_STS_MASK)
+
+#define TMR_EN_MASK 0x0001
+#define GBL_EN_MASK 0x0020
+#define PWRBTN_EN_MASK 0x0100
+#define SLPBTN_EN_MASK 0x0200
+#define RTC_EN_MASK 0x0400
+
+#define SCI_EN_MASK 0x0001
+#define BM_RLD_MASK 0x0002
+#define GBL_RLS_MASK 0x0004
+#define SLP_TYPE_X_MASK 0x1C00
+#define SLP_EN_MASK 0x2000
+
+#define ARB_DIS_MASK 0x0001
+
+#define GPE0_STS_MASK
+#define GPE0_EN_MASK
+
+#define GPE1_STS_MASK
+#define GPE1_EN_MASK
+
+
+#define ACPI_READ 1
+#define ACPI_WRITE 2
+
+#define LOW_BYTE 0x00FF
+#define ONE_BYTE 0x08
+
+#ifndef SET
+ #define SET 1
+#endif
+#ifndef CLEAR
+ #define CLEAR 0
+#endif
+
+
+/* Plug and play */
+
+/* Pnp and ACPI data */
+
+#define VERSION_NO 0x01
+#define LOGICAL_DEVICE_ID 0x02
+#define COMPATIBLE_DEVICE_ID 0x03
+#define IRQ_FORMAT 0x04
+#define DMA_FORMAT 0x05
+#define START_DEPENDENT_TAG 0x06
+#define END_DEPENDENT_TAG 0x07
+#define IO_PORT_DESCRIPTOR 0x08
+#define FIXED_LOCATION_IO_DESCRIPTOR 0x09
+#define RESERVED_TYPE0 0x0A
+#define RESERVED_TYPE1 0x0B
+#define RESERVED_TYPE2 0x0C
+#define RESERVED_TYPE3 0x0D
+#define SMALL_VENDOR_DEFINED 0x0E
+#define END_TAG 0x0F
+
+/* Pnp and ACPI data */
+
+#define MEMORY_RANGE_24 0x81
+#define ISA_MEMORY_RANGE 0x81
+#define LARGE_VENDOR_DEFINED 0x84
+#define EISA_MEMORY_RANGE 0x85
+#define MEMORY_RANGE_32 0x85
+#define FIXED_EISA_MEMORY_RANGE 0x86
+#define FIXED_MEMORY_RANGE_32 0x86
+
+/* ACPI only data */
+
+#define DWORD_ADDRESS_SPACE 0x87
+#define WORD_ADDRESS_SPACE 0x88
+#define EXTENDED_IRQ 0x89
+
+/* MUST HAVES */
+
+
+typedef enum
+{
+ DWORD_DEVICE_ID,
+ STRING_PTR_DEVICE_ID,
+ STRING_DEVICE_ID
+
+} DEVICE_ID_TYPE;
+
+typedef struct
+{
+ DEVICE_ID_TYPE type;
+ union
+ {
+ u32 number;
+ char *string_ptr;
+ char buffer[9];
+ } data;
+
+} DEVICE_ID;
+
+
+/*****************************************************************************
+ *
+ * Debug
+ *
+ ****************************************************************************/
+
+
+/* Entry for a memory allocation (debug only) */
+
+#ifdef ACPI_DEBUG
+
+#define MEM_MALLOC 0
+#define MEM_CALLOC 1
+#define MAX_MODULE_NAME 16
+
+typedef struct allocation_info
+{
+ struct allocation_info *previous;
+ struct allocation_info *next;
+ void *address;
+ u32 size;
+ u32 component;
+ u32 line;
+ char module[MAX_MODULE_NAME];
+ u8 alloc_type;
+
+} ALLOCATION_INFO;
+
+#endif
+
+#endif
diff --git a/drivers/acpi/include/interp.h b/drivers/acpi/include/interp.h
new file mode 100644
index 000000000..75db528da
--- /dev/null
+++ b/drivers/acpi/include/interp.h
@@ -0,0 +1,660 @@
+
+/******************************************************************************
+ *
+ * Name: interp.h - Interpreter subcomponent prototypes and defines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 __INTERP_H__
+#define __INTERP_H__
+
+
+#include "actypes.h"
+#include "acobject.h"
+
+
+#define WALK_OPERANDS &(walk_state->operands [walk_state->num_operands -1])
+
+
+/* Interpreter constants */
+
+#define AML_END_OF_BLOCK -1
+#define PUSH_PKG_LENGTH 1
+#define DO_NOT_PUSH_PKG_LENGTH 0
+
+
+#define STACK_TOP 0
+#define STACK_BOTTOM (u32) -1
+
+/* Constants for global "When_to_parse_methods" */
+
+#define METHOD_PARSE_AT_INIT 0x0
+#define METHOD_PARSE_JUST_IN_TIME 0x1
+#define METHOD_DELETE_AT_COMPLETION 0x2
+
+
+ACPI_STATUS
+acpi_aml_resolve_operands (
+ u16 opcode,
+ ACPI_OBJECT_INTERNAL **stack_ptr);
+
+
+/*
+ * amxface - External interpreter interfaces
+ */
+
+ACPI_STATUS
+acpi_aml_load_table (
+ ACPI_TABLE_TYPE table_id);
+
+ACPI_STATUS
+acpi_aml_execute_method (
+ ACPI_NAMED_OBJECT *method_entry,
+ ACPI_OBJECT_INTERNAL **params,
+ ACPI_OBJECT_INTERNAL **return_obj_desc);
+
+
+/*
+ * amcopy - Interpreter object copy support
+ */
+
+ACPI_STATUS
+acpi_aml_build_copy_internal_package_object (
+ ACPI_OBJECT_INTERNAL *source_obj,
+ ACPI_OBJECT_INTERNAL *dest_obj);
+
+
+/*
+ * amfield - ACPI AML (p-code) execution - field manipulation
+ */
+
+
+ACPI_STATUS
+acpi_aml_read_field (
+ ACPI_OBJECT_INTERNAL *obj_desc,
+ void *buffer,
+ u32 buffer_length,
+ u32 byte_length,
+ u32 datum_length,
+ u32 bit_granularity,
+ u32 byte_granularity);
+
+ACPI_STATUS
+acpi_aml_write_field (
+ ACPI_OBJECT_INTERNAL *obj_desc,
+ void *buffer,
+ u32 buffer_length,
+ u32 byte_length,
+ u32 datum_length,
+ u32 bit_granularity,
+ u32 byte_granularity);
+
+ACPI_STATUS
+acpi_aml_setup_field (
+ ACPI_OBJECT_INTERNAL *obj_desc,
+ ACPI_OBJECT_INTERNAL *rgn_desc,
+ s32 field_bit_width);
+
+ACPI_STATUS
+acpi_aml_read_field_data (
+ ACPI_OBJECT_INTERNAL *obj_desc,
+ u32 field_byte_offset,
+ u32 field_bit_width,
+ u32 *value);
+
+ACPI_STATUS
+acpi_aml_access_named_field (
+ s32 mode,
+ ACPI_HANDLE named_field,
+ void *buffer,
+ u32 length);
+
+ACPI_STATUS
+acpi_aml_set_named_field_value (
+ ACPI_HANDLE named_field,
+ void *buffer,
+ u32 length);
+
+ACPI_STATUS
+acpi_aml_get_named_field_value (
+ ACPI_HANDLE named_field,
+ void *buffer,
+ u32 length);
+
+
+/*
+ * ammisc - ACPI AML (p-code) execution - specific opcodes
+ */
+
+ACPI_STATUS
+acpi_aml_exec_create_field (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_aml_exec_reconfiguration (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_aml_exec_fatal (
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_aml_exec_index (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OBJECT_INTERNAL **return_desc);
+
+ACPI_STATUS
+acpi_aml_exec_match (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OBJECT_INTERNAL **return_desc);
+
+ACPI_STATUS
+acpi_aml_exec_create_mutex (
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_aml_exec_create_processor (
+ ACPI_GENERIC_OP *op,
+ ACPI_HANDLE processor_nTE);
+
+ACPI_STATUS
+acpi_aml_exec_create_power_resource (
+ ACPI_GENERIC_OP *op,
+ ACPI_HANDLE processor_nTE);
+
+ACPI_STATUS
+acpi_aml_exec_create_region (
+ u8 *aml_ptr,
+ u32 acpi_aml_length,
+ u32 region_space,
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_aml_exec_create_event (
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_aml_exec_create_alias (
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_aml_exec_create_method (
+ u8 *aml_ptr,
+ u32 acpi_aml_length,
+ u32 method_flags,
+ ACPI_HANDLE method);
+
+
+/*
+ * amprep - ACPI AML (p-code) execution - prep utilities
+ */
+
+ACPI_STATUS
+acpi_aml_prep_def_field_value (
+ ACPI_NAMED_OBJECT *this_entry,
+ ACPI_HANDLE region,
+ u8 field_flags,
+ u8 field_attribute,
+ u32 field_position,
+ u32 field_length);
+
+ACPI_STATUS
+acpi_aml_prep_bank_field_value (
+ ACPI_NAMED_OBJECT *this_entry,
+ ACPI_HANDLE region,
+ ACPI_HANDLE bank_reg,
+ u32 bank_val,
+ u8 field_flags,
+ u8 field_attribute,
+ u32 field_position,
+ u32 field_length);
+
+ACPI_STATUS
+acpi_aml_prep_index_field_value (
+ ACPI_NAMED_OBJECT *this_entry,
+ ACPI_HANDLE index_reg,
+ ACPI_HANDLE data_reg,
+ u8 field_flags,
+ u8 field_attribute,
+ u32 field_position,
+ u32 field_length);
+
+ACPI_STATUS
+acpi_aml_prep_operands (
+ char *types,
+ ACPI_OBJECT_INTERNAL **stack_ptr);
+
+
+/*
+ * iepstack - package stack utilities
+ */
+
+/*
+u32
+Acpi_aml_pkg_stack_level (
+ void);
+
+void
+Acpi_aml_clear_pkg_stack (
+ void);
+
+ACPI_STATUS
+Acpi_aml_pkg_push_length (
+ u32 Length,
+ OPERATING_MODE Load_exec_mode);
+
+ACPI_STATUS
+Acpi_aml_pkg_push_exec_length (
+ u32 Length);
+
+ACPI_STATUS
+Acpi_aml_pkg_push_exec (
+ u8 *Code,
+ u32 Len);
+
+ACPI_STATUS
+Acpi_aml_pkg_pop_length (
+ s32 No_err_under,
+ OPERATING_MODE Load_exec_mode);
+
+ACPI_STATUS
+Acpi_aml_pkg_pop_exec_length (
+ void);
+
+ACPI_STATUS
+Acpi_aml_pkg_pop_exec (
+ void);
+
+*/
+
+/*
+ * amsystem - Interface to OS services
+ */
+
+u16
+acpi_aml_system_thread_id (
+ void);
+
+ACPI_STATUS
+acpi_aml_system_do_notify_op (
+ ACPI_OBJECT_INTERNAL *value,
+ ACPI_OBJECT_INTERNAL *obj_desc);
+
+void
+acpi_aml_system_do_suspend(
+ u32 time);
+
+void
+acpi_aml_system_do_stall (
+ u32 time);
+
+ACPI_STATUS
+acpi_aml_system_acquire_mutex(
+ ACPI_OBJECT_INTERNAL *time,
+ ACPI_OBJECT_INTERNAL *obj_desc);
+
+ACPI_STATUS
+acpi_aml_system_release_mutex(
+ ACPI_OBJECT_INTERNAL *obj_desc);
+
+ACPI_STATUS
+acpi_aml_system_signal_event(
+ ACPI_OBJECT_INTERNAL *obj_desc);
+
+ACPI_STATUS
+acpi_aml_system_wait_event(
+ ACPI_OBJECT_INTERNAL *time,
+ ACPI_OBJECT_INTERNAL *obj_desc);
+
+ACPI_STATUS
+acpi_aml_system_reset_event(
+ ACPI_OBJECT_INTERNAL *obj_desc);
+
+ACPI_STATUS
+acpi_aml_system_wait_semaphore (
+ ACPI_HANDLE semaphore,
+ u32 timeout);
+
+
+/*
+ * ammonadic - ACPI AML (p-code) execution, monadic operators
+ */
+
+ACPI_STATUS
+acpi_aml_exec_monadic1 (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_aml_exec_monadic2 (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OBJECT_INTERNAL **return_desc);
+
+ACPI_STATUS
+acpi_aml_exec_monadic2_r (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OBJECT_INTERNAL **return_desc);
+
+
+/*
+ * amdyadic - ACPI AML (p-code) execution, dyadic operators
+ */
+
+ACPI_STATUS
+acpi_aml_exec_dyadic1 (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_aml_exec_dyadic2 (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OBJECT_INTERNAL **return_desc);
+
+ACPI_STATUS
+acpi_aml_exec_dyadic2_r (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OBJECT_INTERNAL **return_desc);
+
+ACPI_STATUS
+acpi_aml_exec_dyadic2_s (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OBJECT_INTERNAL **return_desc);
+
+
+/*
+ * amresolv - Object resolution and get value functions
+ */
+
+ACPI_STATUS
+acpi_aml_resolve_to_value (
+ ACPI_OBJECT_INTERNAL **stack_ptr);
+
+ACPI_STATUS
+acpi_aml_resolve_entry_to_value (
+ ACPI_NAMED_OBJECT **stack_ptr);
+
+ACPI_STATUS
+acpi_aml_resolve_object_to_value (
+ ACPI_OBJECT_INTERNAL **stack_ptr);
+
+ACPI_STATUS
+acpi_aml_get_field_unit_value (
+ ACPI_OBJECT_INTERNAL *field_desc,
+ ACPI_OBJECT_INTERNAL *result_desc);
+
+
+/*
+ * amcode - Scanner AML code manipulation routines
+ */
+
+s32
+acpi_aml_avail (
+ ACPI_SIZE n);
+
+s32
+acpi_aml_peek (
+ void);
+
+s32
+acpi_aml_get_pcode_byte (
+ u8 *pcode);
+
+u16
+acpi_aml_peek_op (
+ void);
+
+u8 *
+acpi_aml_consume_bytes (
+ ACPI_SIZE bytes);
+
+ACPI_SIZE
+acpi_aml_consume_stream_bytes (
+ ACPI_SIZE bytes_to_get,
+ u8 *aml_buffer);
+
+void
+acpi_aml_consume_package (
+ OPERATING_MODE load_exec_mode);
+
+void
+acpi_aml_set_pcode_input (
+ u8 *base,
+ u32 length);
+
+ACPI_STATUS
+acpi_aml_set_method (
+ void *object);
+
+ACPI_STATUS
+acpi_aml_prep_exec (
+ u8 *pcode,
+ u32 pcode_length);
+
+ACPI_HANDLE
+acpi_aml_get_pcode_handle (
+ void);
+
+void
+acpi_aml_get_current_location (
+ ACPI_OBJECT_INTERNAL *method_desc);
+
+void
+acpi_aml_set_current_location (
+ ACPI_OBJECT_INTERNAL *method_desc);
+
+
+/*
+ * amdump - Scanner debug output routines
+ */
+
+void
+acpi_aml_show_hex_value (
+ s32 byte_count,
+ u8 *aml_ptr,
+ s32 lead_space);
+
+void
+acpi_aml_dump_buffer (
+ ACPI_SIZE length);
+
+
+ACPI_STATUS
+acpi_aml_dump_operand (
+ ACPI_OBJECT_INTERNAL *entry_desc);
+
+void
+acpi_aml_dump_operands (
+ ACPI_OBJECT_INTERNAL **operands,
+ OPERATING_MODE interpreter_mode,
+ char *ident,
+ s32 num_levels,
+ char *note,
+ char *module_name,
+ s32 line_number);
+
+void
+acpi_aml_dump_object_descriptor (
+ ACPI_OBJECT_INTERNAL *object,
+ u32 flags);
+
+
+void
+acpi_aml_dump_acpi_named_object (
+ ACPI_NAMED_OBJECT *entry,
+ u32 flags);
+
+
+/*
+ * amnames - interpreter/scanner name load/execute
+ */
+
+char *
+acpi_aml_allocate_name_string (
+ u32 prefix_count,
+ u32 num_name_segs);
+
+s32
+acpi_aml_good_char (
+ s32 character);
+
+ACPI_STATUS
+acpi_aml_exec_name_segment (
+ u8 **in_aml_address,
+ char *name_string);
+
+ACPI_STATUS
+acpi_aml_get_name_string (
+ OBJECT_TYPE_INTERNAL data_type,
+ u8 *in_aml_address,
+ char **out_name_string,
+ u32 *out_name_length);
+
+u32
+acpi_aml_decode_package_length (
+ u32 last_pkg_len);
+
+
+ACPI_STATUS
+acpi_aml_do_name (
+ ACPI_OBJECT_TYPE data_type,
+ OPERATING_MODE load_exec_mode);
+
+
+/*
+ * amstore - Object store support
+ */
+
+ACPI_STATUS
+acpi_aml_exec_store (
+ ACPI_OBJECT_INTERNAL *op1,
+ ACPI_OBJECT_INTERNAL *res);
+
+ACPI_STATUS
+acpi_aml_store_object_to_object (
+ ACPI_OBJECT_INTERNAL *val_desc,
+ ACPI_OBJECT_INTERNAL *dest_desc);
+
+ACPI_STATUS
+acpi_aml_store_object_to_nte (
+ ACPI_OBJECT_INTERNAL *val_desc,
+ ACPI_NAMED_OBJECT *entry);
+
+
+/*
+ * amutils - interpreter/scanner utilities
+ */
+
+void
+acpi_aml_enter_interpreter (
+ void);
+
+void
+acpi_aml_exit_interpreter (
+ void);
+
+u8
+acpi_aml_validate_object_type (
+ ACPI_OBJECT_TYPE type);
+
+u8
+acpi_aml_acquire_global_lock (
+ u32 rule);
+
+ACPI_STATUS
+acpi_aml_release_global_lock (
+ u8 locked);
+
+void
+acpi_aml_append_operand_diag(
+ char *name,
+ s32 line,
+ u16 op_code,
+ ACPI_OBJECT_INTERNAL **operands,
+ s32 Noperands);
+
+u32
+acpi_aml_buf_seq (
+ void);
+
+s32
+acpi_aml_digits_needed (
+ s32 value,
+ s32 base);
+
+ACPI_STATUS
+acpi_aml_eisa_id_to_string (
+ u32 numeric_id,
+ char *out_string);
+
+
+/*
+ * amregion - default Op_region handlers
+ */
+
+ACPI_STATUS
+acpi_aml_system_memory_space_handler (
+ u32 function,
+ u32 address,
+ u32 bit_width,
+ u32 *value,
+ void *context);
+
+ACPI_STATUS
+acpi_aml_system_io_space_handler (
+ u32 function,
+ u32 address,
+ u32 bit_width,
+ u32 *value,
+ void *context);
+
+ACPI_STATUS
+acpi_aml_pci_config_space_handler (
+ u32 function,
+ u32 address,
+ u32 bit_width,
+ u32 *value,
+ void *context);
+
+ACPI_STATUS
+acpi_aml_embedded_controller_space_handler (
+ u32 function,
+ u32 address,
+ u32 bit_width,
+ u32 *value,
+ void *context);
+
+ACPI_STATUS
+acpi_aml_sm_bus_space_handler (
+ u32 function,
+ u32 address,
+ u32 bit_width,
+ u32 *value,
+ void *context);
+
+
+#endif /* __INTERP_H__ */
diff --git a/drivers/acpi/include/macros.h b/drivers/acpi/include/macros.h
new file mode 100644
index 000000000..7584ee8fa
--- /dev/null
+++ b/drivers/acpi/include/macros.h
@@ -0,0 +1,423 @@
+
+/******************************************************************************
+ *
+ * Name: macros.h - C macros for the entire subsystem.
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 __MACROS_H__
+#define __MACROS_H__
+
+/*
+ * Data manipulation macros
+ */
+
+#ifndef LOWORD
+#define LOWORD(l) ((u16)(NATIVE_UINT)(l))
+#endif
+
+#ifndef HIWORD
+#define HIWORD(l) ((u16)((((NATIVE_UINT)(l)) >> 16) & 0xFFFF))
+#endif
+
+#ifndef LOBYTE
+#define LOBYTE(l) ((u8)(u16)(l))
+#endif
+
+#ifndef HIBYTE
+#define HIBYTE(l) ((u8)((((u16)(l)) >> 8) & 0xFF))
+#endif
+
+#define BIT0(x) ((((x) & 0x01) > 0) ? 1 : 0)
+#define BIT1(x) ((((x) & 0x02) > 0) ? 1 : 0)
+#define BIT2(x) ((((x) & 0x04) > 0) ? 1 : 0)
+
+#define BIT3(x) ((((x) & 0x08) > 0) ? 1 : 0)
+#define BIT4(x) ((((x) & 0x10) > 0) ? 1 : 0)
+#define BIT5(x) ((((x) & 0x20) > 0) ? 1 : 0)
+#define BIT6(x) ((((x) & 0x40) > 0) ? 1 : 0)
+#define BIT7(x) ((((x) & 0x80) > 0) ? 1 : 0)
+
+#define LOW_BASE(w) ((u16) ((w) & 0x0000FFFF))
+#define MID_BASE(b) ((u8) (((b) & 0x00FF0000) >> 16))
+#define HI_BASE(b) ((u8) (((b) & 0xFF000000) >> 24))
+#define LOW_LIMIT(w) ((u16) ((w) & 0x0000FFFF))
+#define HI_LIMIT(b) ((u8) (((b) & 0x00FF0000) >> 16))
+
+
+ /*
+ * Extract a byte of data using a pointer. Any more than a byte and we
+ * get into potential aligment issues -- see the STORE macros below
+ */
+#define GET8(addr) (*(u8*)(addr))
+
+
+/*
+ * Macros for moving data around to/from buffers that are possibly unaligned.
+ * If the hardware supports the transfer of unaligned data, just do the store.
+ * Otherwise, we have to move one byte at a time.
+ */
+
+#ifdef _HW_ALIGNMENT_SUPPORT
+
+/* The hardware supports unaligned transfers, just do the move */
+
+#define MOVE_UNALIGNED16_TO_16(d,s) *(u16*)(d) = *(u16*)(s)
+#define MOVE_UNALIGNED32_TO_32(d,s) *(u32*)(d) = *(u32*)(s)
+#define MOVE_UNALIGNED16_TO_32(d,s) *(u32*)(d) = *(u16*)(s)
+
+#else
+/*
+ * The hardware does not support unaligned transfers. We must move the
+ * data one byte at a time. These macros work whether the source or
+ * the destination (or both) is/are unaligned.
+ */
+
+#define MOVE_UNALIGNED16_TO_16(d,s) {((char *)(d))[0] = ((char *)(s))[0];\
+ ((char *)(d))[1] = ((char *)(s))[1];}
+
+#define MOVE_UNALIGNED32_TO_32(d,s) {((char *)(d))[0] = ((char *)(s))[0];\
+ ((char *)(d))[1] = ((char *)(s))[1];\
+ ((char *)(d))[2] = ((char *)(s))[2];\
+ ((char *)(d))[3] = ((char *)(s))[3];}
+
+#define MOVE_UNALIGNED16_TO_32(d,s) {(*(u32*)(d)) = 0; MOVE_UNALIGNED16_TO_16(d,s);}
+
+#endif
+
+
+/*
+ * Fast power-of-two math macros for non-optimized compilers
+ */
+
+#define _DIV(value,power_of2) ((value) >> (power_of2))
+#define _MUL(value,power_of2) ((value) << (power_of2))
+#define _MOD(value,divisor) ((value) & ((divisor) -1))
+
+#define DIV_2(a) _DIV(a,1)
+#define MUL_2(a) _MUL(a,1)
+#define MOD_2(a) _MOD(a,2)
+
+#define DIV_4(a) _DIV(a,2)
+#define MUL_4(a) _MUL(a,2)
+#define MOD_4(a) _MOD(a,4)
+
+#define DIV_8(a) _DIV(a,3)
+#define MUL_8(a) _MUL(a,3)
+#define MOD_8(a) _MOD(a,8)
+
+#define DIV_16(a) _DIV(a,4)
+#define MUL_16(a) _MUL(a,4)
+#define MOD_16(a) _MOD(a,16)
+
+
+/*
+ * Rounding macros (Power of two boundaries only)
+ */
+
+#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1)))
+#define ROUND_UP(value,boundary) (((value) + ((boundary)-1)) & (~((boundary)-1)))
+
+#define ROUND_DOWN_TO_32_BITS(a) ROUND_DOWN(a,4)
+#define ROUND_DOWN_TO_NATIVE_WORD(a) ROUND_DOWN(a,ALIGNED_ADDRESS_BOUNDARY)
+
+#define ROUND_UP_TO_32_bITS(a) ROUND_UP(a,4)
+#define ROUND_UP_TO_NATIVE_WORD(a) ROUND_UP(a,ALIGNED_ADDRESS_BOUNDARY)
+
+
+#ifdef DEBUG_ASSERT
+#undef DEBUG_ASSERT
+#endif
+
+
+/*
+ * An ACPI_HANDLE (which is actually an ACPI_NAMED_OBJECT*) can appear in some contexts,
+ * such as on ap_obj_stack, where a pointer to an ACPI_OBJECT_INTERNAL can also
+ * appear. This macro is used to distinguish them.
+ *
+ * The Data_type field is the first field in both structures.
+ */
+
+#define VALID_DESCRIPTOR_TYPE(d,t) (((ACPI_NAMED_OBJECT*)d)->data_type == t)
+
+
+/* Macro to test the object type */
+
+#define IS_THIS_OBJECT_TYPE(d,t) (((ACPI_OBJECT_INTERNAL *)d)->common.type == (u8)t)
+
+
+/*
+ * Macro to check if a pointer is within an ACPI table.
+ * Parameter (a) is the pointer to check. Parameter (b) must be defined
+ * as a pointer to an ACPI_TABLE_HEADER. (b+1) then points past the header,
+ * and ((u8 *)b+b->Length) points one byte past the end of the table.
+ */
+
+#ifndef _IA16
+#define IS_IN_ACPI_TABLE(a,b) (((u8 *)(a) >= (u8 *)(b + 1)) &&\
+ ((u8 *)(a) < ((u8 *)b + b->length)))
+
+#else
+#define IS_IN_ACPI_TABLE(a,b) (_segment)(a) == (_segment)(b) &&\
+ (((u8 *)(a) >= (u8 *)(b + 1)) &&\
+ ((u8 *)(a) < ((u8 *)b + b->length)))
+#endif
+
+/*
+ * Macros for the master AML opcode table
+ */
+
+#ifdef ACPI_DEBUG
+#define OP_INFO_ENTRY(opcode,flags,name,Pargs,Iargs) {opcode,flags,Pargs,Iargs,name}
+#else
+#define OP_INFO_ENTRY(opcode,flags,name,Pargs,Iargs) {opcode,flags,Pargs,Iargs}
+#endif
+
+#define ARG_TYPE_WIDTH 5
+#define ARG_1(x) ((u32)(x))
+#define ARG_2(x) ((u32)(x) << (1 * ARG_TYPE_WIDTH))
+#define ARG_3(x) ((u32)(x) << (2 * ARG_TYPE_WIDTH))
+#define ARG_4(x) ((u32)(x) << (3 * ARG_TYPE_WIDTH))
+#define ARG_5(x) ((u32)(x) << (4 * ARG_TYPE_WIDTH))
+#define ARG_6(x) ((u32)(x) << (5 * ARG_TYPE_WIDTH))
+
+#define ARGI_LIST1(a) (ARG_1(a))
+#define ARGI_LIST2(a,b) (ARG_1(b)|ARG_2(a))
+#define ARGI_LIST3(a,b,c) (ARG_1(c)|ARG_2(b)|ARG_3(a))
+#define ARGI_LIST4(a,b,c,d) (ARG_1(d)|ARG_2(c)|ARG_3(b)|ARG_4(a))
+#define ARGI_LIST5(a,b,c,d,e) (ARG_1(e)|ARG_2(d)|ARG_3(c)|ARG_4(b)|ARG_5(a))
+#define ARGI_LIST6(a,b,c,d,e,f) (ARG_1(f)|ARG_2(e)|ARG_3(d)|ARG_4(c)|ARG_5(b)|ARG_6(a))
+
+#define ARGP_LIST1(a) (ARG_1(a))
+#define ARGP_LIST2(a,b) (ARG_1(a)|ARG_2(b))
+#define ARGP_LIST3(a,b,c) (ARG_1(a)|ARG_2(b)|ARG_3(c))
+#define ARGP_LIST4(a,b,c,d) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d))
+#define ARGP_LIST5(a,b,c,d,e) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)|ARG_5(e))
+#define ARGP_LIST6(a,b,c,d,e,f) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)|ARG_5(e)|ARG_6(f))
+
+#define GET_CURRENT_ARG_TYPE(list) (list & 0x1F)
+#define INCREMENT_ARG_LIST(list) (list >>= ARG_TYPE_WIDTH)
+
+
+/*
+ * Reporting macros that are never compiled out
+ */
+
+/*
+ * Error reporting. These versions add callers module and line#. Since
+ * _THIS_MODULE gets compiled out when ACPI_DEBUG isn't defined, only
+ * use it in debug mode.
+ */
+
+#ifdef ACPI_DEBUG
+
+#define REPORT_INFO(a) _report_info(_THIS_MODULE,__LINE__,_COMPONENT,a)
+#define REPORT_ERROR(a) _report_error(_THIS_MODULE,__LINE__,_COMPONENT,a)
+#define REPORT_WARNING(a) _report_warning(_THIS_MODULE,__LINE__,_COMPONENT,a)
+#define REPORT_SUCCESS(a) _report_success(_THIS_MODULE,__LINE__,_COMPONENT,a)
+
+#else
+
+#define REPORT_INFO(a) _report_info("",__LINE__,_COMPONENT,a)
+#define REPORT_ERROR(a) _report_error("",__LINE__,_COMPONENT,a)
+#define REPORT_WARNING(a) _report_warning("",__LINE__,_COMPONENT,a)
+#define REPORT_SUCCESS(a) _report_success("",__LINE__,_COMPONENT,a)
+
+#endif
+
+/* Error reporting. These versions pass thru the module and line# */
+
+#define _REPORT_INFO(a,b,c,d) _report_info(a,b,c,d)
+#define _REPORT_ERROR(a,b,c,d) _report_error(a,b,c,d)
+#define _REPORT_WARNING(a,b,c,d) _report_warning(a,b,c,d)
+
+/* Buffer dump macros */
+
+#define DUMP_BUFFER(a,b) acpi_cm_dump_buffer((char *)a,b,DB_BYTE_DISPLAY,_COMPONENT)
+
+/*
+ * Debug macros that are conditionally compiled
+ */
+
+#ifdef ACPI_DEBUG
+
+#define MODULE_NAME(name) static char *_THIS_MODULE = name
+
+/*
+ * Function entry tracing.
+ * The first parameter should be the procedure name as a quoted string. This is declared
+ * as a local string ("_Proc_name) so that it can be also used by the function exit macros below.
+ */
+
+#define FUNCTION_TRACE(a) char * _proc_name = a;\
+ function_trace(_THIS_MODULE,__LINE__,_COMPONENT,a)
+#define FUNCTION_TRACE_PTR(a,b) char * _proc_name = a;\
+ function_trace_ptr(_THIS_MODULE,__LINE__,_COMPONENT,a,(void *)b)
+#define FUNCTION_TRACE_U32(a,b) char * _proc_name = a;\
+ function_trace_u32(_THIS_MODULE,__LINE__,_COMPONENT,a,(u32)b)
+#define FUNCTION_TRACE_STR(a,b) char * _proc_name = a;\
+ function_trace_str(_THIS_MODULE,__LINE__,_COMPONENT,a,(char *)b)
+/*
+ * Function exit tracing.
+ * WARNING: These macros include a return statement. This is usually considered
+ * bad form, but having a separate exit macro is very ugly and difficult to maintain.
+ * One of the FUNCTION_TRACE macros above must be used in conjunction with these macros
+ * so that "_Proc_name" is defined.
+ */
+#define return_VOID {function_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name);return;}
+#define return_ACPI_STATUS(s) {function_status_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name,s);return(s);}
+#define return_VALUE(s) {function_value_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name,(NATIVE_UINT)s);return(s);}
+#define return_PTR(s) {function_ptr_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name,(char *)s);return(s);}
+
+
+/* Conditional execution */
+
+#define DEBUG_EXEC(a) a;
+#define NORMAL_EXEC(a)
+
+#define DEBUG_DEFINE(a) a;
+#define DEBUG_ONLY_MEMBERS(a) a;
+
+
+/* Stack and buffer dumping */
+
+#define DUMP_STACK_ENTRY(a) acpi_aml_dump_operand(a)
+#define DUMP_OPERANDS(a,b,c,d,e) acpi_aml_dump_operands(a,b,c,d,e,_THIS_MODULE,__LINE__)
+
+
+#define DUMP_ENTRY(a,b) acpi_ns_dump_entry (a,b)
+#define DUMP_TABLES(a,b) acpi_ns_dump_tables(a,b)
+#define DUMP_PATHNAME(a,b,c,d) acpi_ns_dump_pathname(a,b,c,d)
+#define BREAK_MSG(a) acpi_os_breakpoint (a)
+
+/*
+ * Generate INT3 on ACPI_ERROR (Debug only!)
+ */
+
+#define ERROR_BREAK
+#ifdef ERROR_BREAK
+#define BREAK_ON_ERROR(lvl) if ((lvl)&ACPI_ERROR) acpi_os_breakpoint("Fatal error encountered\n")
+#else
+#define BREAK_ON_ERROR(lvl)
+#endif
+
+/*
+ * Master debug print macros
+ * Print iff:
+ * 1) Debug print for the current component is enabled
+ * 2) Debug error level or trace level for the print statement is enabled
+ *
+ */
+
+#define PARAM_LIST(pl) pl
+
+#define TEST_DEBUG_SWITCH(lvl) if (((lvl) & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))
+
+#define DEBUG_PRINT(lvl,fp) TEST_DEBUG_SWITCH(lvl) {\
+ debug_print_prefix (_THIS_MODULE,__LINE__);\
+ debug_print_raw PARAM_LIST(fp);\
+ BREAK_ON_ERROR(lvl);}
+
+#define DEBUG_PRINT_RAW(lvl,fp) TEST_DEBUG_SWITCH(lvl) {\
+ debug_print_raw PARAM_LIST(fp);}
+
+
+/* Assert macros */
+
+#define ACPI_ASSERT(exp) if(!(exp)) \
+ acpi_os_dbg_assert(#exp, __FILE__, __LINE__, "Failed Assertion")
+
+#define DEBUG_ASSERT(msg, exp) if(!(exp)) \
+ acpi_os_dbg_assert(#exp, __FILE__, __LINE__, msg)
+
+
+#else
+/*
+ * This is the non-debug case -- make everything go away,
+ * leaving no executable debug code!
+ */
+
+#define MODULE_NAME(name)
+#define _THIS_MODULE ""
+
+#define DEBUG_EXEC(a)
+#define NORMAL_EXEC(a) a;
+
+#define DEBUG_DEFINE(a)
+#define DEBUG_ONLY_MEMBERS(a)
+#define FUNCTION_TRACE(a)
+#define FUNCTION_TRACE_PTR(a,b)
+#define FUNCTION_TRACE_U32(a,b)
+#define FUNCTION_TRACE_STR(a,b)
+#define FUNCTION_EXIT
+#define FUNCTION_STATUS_EXIT(s)
+#define FUNCTION_VALUE_EXIT(s)
+#define DUMP_STACK_ENTRY(a)
+#define DUMP_OPERANDS(a,b,c,d,e)
+#define DUMP_ENTRY(a,b)
+#define DUMP_TABLES(a,b)
+#define DUMP_PATHNAME(a,b,c,d)
+#define DEBUG_PRINT(l,f)
+#define DEBUG_PRINT_RAW(l,f)
+#define BREAK_MSG(a)
+
+#define return_VOID return
+#define return_ACPI_STATUS(s) return(s)
+#define return_VALUE(s) return(s)
+#define return_PTR(s) return(s)
+
+#define ACPI_ASSERT(exp)
+#define DEBUG_ASSERT(msg, exp)
+
+#endif
+
+
+/*
+ * For 16-bit code, we want to shrink some things even though
+ * we are using ACPI_DEBUG to get the debug output
+ */
+#ifdef _IA16
+#undef DEBUG_ONLY_MEMBERS
+#define DEBUG_ONLY_MEMBERS(a)
+#undef OP_INFO_ENTRY
+#define OP_INFO_ENTRY(opcode,flags,name,Pargs,Iargs) {opcode,flags,Pargs,Iargs}
+#endif
+
+
+#ifndef ACPI_DEBUG
+
+#define ADD_OBJECT_NAME(a,b)
+
+#else
+
+
+/*
+ * 1) Set name to blanks
+ * 2) Copy the object name
+ */
+
+#define ADD_OBJECT_NAME(a,b) MEMSET (a->common.name, ' ', sizeof (a->common.name));\
+ STRNCPY (a->common.name, acpi_gbl_ns_type_names[b], sizeof (a->common.name))
+
+#endif
+
+
+#endif /* MACROS_H */
diff --git a/drivers/acpi/include/namesp.h b/drivers/acpi/include/namesp.h
new file mode 100644
index 000000000..378b8a8c8
--- /dev/null
+++ b/drivers/acpi/include/namesp.h
@@ -0,0 +1,424 @@
+
+/******************************************************************************
+ *
+ * Name: namesp.h - Namespace subcomponent prototypes and defines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 __NAMESPACE_H__
+#define __NAMESPACE_H__
+
+#include "actables.h"
+
+
+/* To search the entire name space, pass this as Search_base */
+
+#define NS_ALL ((ACPI_HANDLE)0)
+
+/*
+ * Elements of Acpi_ns_properties are bit significant
+ * and should be one-to-one with values of ACPI_OBJECT_TYPE
+ */
+#define NSP_NORMAL 0
+#define NSP_NEWSCOPE 1 /* a definition of this type opens a name scope */
+#define NSP_LOCAL 2 /* suppress search of enclosing scopes */
+
+
+/* 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_SYS_BUS_NAME (u32) 0x5F53425F /* Sys bus name is "_SB_" */
+
+#define NS_ROOT_PATH "/"
+#define NS_SYSTEM_BUS "_SB_"
+
+
+/* Flags for Acpi_ns_lookup, Acpi_ns_search_and_enter */
+
+#define NS_NO_UPSEARCH 0
+#define NS_SEARCH_PARENT 0x01
+#define NS_DONT_OPEN_SCOPE 0x02
+#define NS_NO_PEER_SEARCH 0x04
+
+#define NS_WALK_UNLOCK TRUE
+#define NS_WALK_NO_UNLOCK FALSE
+
+
+ACPI_STATUS
+acpi_ns_walk_namespace (
+ OBJECT_TYPE_INTERNAL type,
+ ACPI_HANDLE start_object,
+ u32 max_depth,
+ u8 unlock_before_callback,
+ WALK_CALLBACK user_function,
+ void *context,
+ void **return_value);
+
+
+ACPI_NAMED_OBJECT*
+acpi_ns_get_next_object (
+ OBJECT_TYPE_INTERNAL type,
+ ACPI_NAMED_OBJECT *parent,
+ ACPI_NAMED_OBJECT *child);
+
+
+ACPI_STATUS
+acpi_ns_delete_namespace_by_owner (
+ u16 table_id);
+
+void
+acpi_ns_free_table_entry (
+ ACPI_NAMED_OBJECT *entry);
+
+
+/* Namespace loading - nsload */
+
+ACPI_STATUS
+acpi_ns_parse_table (
+ ACPI_TABLE_DESC *table_desc,
+ ACPI_NAME_TABLE *scope);
+
+ACPI_STATUS
+acpi_ns_load_table (
+ ACPI_TABLE_DESC *table_desc,
+ ACPI_NAMED_OBJECT *entry);
+
+ACPI_STATUS
+acpi_ns_load_table_by_type (
+ ACPI_TABLE_TYPE table_type);
+
+
+/*
+ * Top-level namespace access - nsaccess
+ */
+
+
+ACPI_STATUS
+acpi_ns_root_initialize (
+ void);
+
+ACPI_STATUS
+acpi_ns_lookup (
+ ACPI_GENERIC_STATE *scope_info,
+ char *name,
+ OBJECT_TYPE_INTERNAL type,
+ OPERATING_MODE interpreter_mode,
+ u32 flags,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_NAMED_OBJECT **ret_entry);
+
+
+/*
+ * Table allocation/deallocation - nsalloc
+ */
+
+ACPI_NAME_TABLE *
+acpi_ns_allocate_name_table (
+ u32 num_entries);
+
+ACPI_STATUS
+acpi_ns_delete_namespace_subtree (
+ ACPI_NAMED_OBJECT *parent_handle);
+
+void
+acpi_ns_detach_object (
+ ACPI_HANDLE object);
+
+void
+acpi_ns_delete_name_table (
+ ACPI_NAME_TABLE *name_table);
+
+
+/*
+ * Namespace modification - nsmodify
+ */
+
+ACPI_STATUS
+acpi_ns_unload_namespace (
+ ACPI_HANDLE handle);
+
+ACPI_STATUS
+acpi_ns_delete_subtree (
+ ACPI_HANDLE start_handle);
+
+
+/*
+ * Namespace dump/print utilities - nsdump
+ */
+
+void
+acpi_ns_dump_tables (
+ ACPI_HANDLE search_base,
+ s32 max_depth);
+
+void
+acpi_ns_dump_entry (
+ ACPI_HANDLE handle,
+ u32 debug_level);
+
+ACPI_STATUS
+acpi_ns_dump_pathname (
+ ACPI_HANDLE handle,
+ char *msg,
+ u32 level,
+ u32 component);
+
+void
+acpi_ns_dump_root_devices (
+ void);
+
+void
+acpi_ns_dump_objects (
+ OBJECT_TYPE_INTERNAL type,
+ u32 max_depth,
+ u32 ownder_id,
+ ACPI_HANDLE start_handle);
+
+
+/*
+ * Namespace evaluation functions - nseval
+ */
+
+ACPI_STATUS
+acpi_ns_evaluate_by_handle (
+ ACPI_NAMED_OBJECT *object_nte,
+ ACPI_OBJECT_INTERNAL **params,
+ ACPI_OBJECT_INTERNAL **return_object);
+
+ACPI_STATUS
+acpi_ns_evaluate_by_name (
+ char *pathname,
+ ACPI_OBJECT_INTERNAL **params,
+ ACPI_OBJECT_INTERNAL **return_object);
+
+ACPI_STATUS
+acpi_ns_evaluate_relative (
+ ACPI_NAMED_OBJECT *object_nte,
+ char *pathname,
+ ACPI_OBJECT_INTERNAL **params,
+ ACPI_OBJECT_INTERNAL **return_object);
+
+ACPI_STATUS
+acpi_ns_execute_control_method (
+ ACPI_NAMED_OBJECT *method_entry,
+ ACPI_OBJECT_INTERNAL **params,
+ ACPI_OBJECT_INTERNAL **return_obj_desc);
+
+ACPI_STATUS
+acpi_ns_get_object_value (
+ ACPI_NAMED_OBJECT *object_entry,
+ ACPI_OBJECT_INTERNAL **return_obj_desc);
+
+
+/*
+ * Parent/Child/Peer utility functions - nsfamily
+ */
+
+ACPI_NAME
+acpi_ns_find_parent_name (
+ ACPI_NAMED_OBJECT *entry_to_search);
+
+u8
+acpi_ns_exist_downstream_sibling (
+ ACPI_NAMED_OBJECT *this_entry);
+
+
+/*
+ * Scope manipulation - nsscope
+ */
+
+s32
+acpi_ns_opens_scope (
+ OBJECT_TYPE_INTERNAL type);
+
+char *
+acpi_ns_name_of_scope (
+ ACPI_NAME_TABLE *scope);
+
+char *
+acpi_ns_name_of_current_scope (
+ ACPI_WALK_STATE *walk_state);
+
+ACPI_STATUS
+acpi_ns_handle_to_pathname (
+ ACPI_HANDLE obj_handle,
+ u32 *buf_size,
+ char *user_buffer);
+
+u8
+acpi_ns_pattern_match (
+ ACPI_NAMED_OBJECT *obj_entry,
+ char *search_for);
+
+ACPI_STATUS
+acpi_ns_name_compare (
+ ACPI_HANDLE obj_handle,
+ u32 level,
+ void *context,
+ void **return_value);
+
+void
+acpi_ns_low_find_names (
+ ACPI_NAMED_OBJECT *this_entry,
+ char *search_for,
+ s32 *count,
+ ACPI_HANDLE list[],
+ s32 max_depth);
+
+ACPI_HANDLE *
+acpi_ns_find_names (
+ char *search_for,
+ ACPI_HANDLE search_base,
+ s32 max_depth);
+
+ACPI_STATUS
+acpi_ns_get_named_object (
+ char *pathname,
+ ACPI_NAME_TABLE *in_scope,
+ ACPI_NAMED_OBJECT **out_nte);
+
+/*
+ * Object management for NTEs - nsobject
+ */
+
+ACPI_STATUS
+acpi_ns_attach_method (
+ ACPI_HANDLE obj_handle,
+ u8 *pcode_addr,
+ u32 pcode_length);
+
+ACPI_STATUS
+acpi_ns_attach_object (
+ ACPI_HANDLE obj_handle,
+ ACPI_HANDLE value,
+ OBJECT_TYPE_INTERNAL type);
+
+
+void *
+acpi_ns_compare_value (
+ ACPI_HANDLE obj_handle,
+ u32 level,
+ void *obj_desc);
+
+ACPI_HANDLE
+acpi_ns_find_attached_object (
+ ACPI_OBJECT_INTERNAL *obj_desc,
+ ACPI_HANDLE search_base,
+ s32 max_depth);
+
+
+/*
+ * Namespace searching and entry - nssearch
+ */
+
+ACPI_STATUS
+acpi_ns_search_and_enter (
+ u32 entry_name,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_NAME_TABLE *name_table,
+ OPERATING_MODE interpreter_mode,
+ OBJECT_TYPE_INTERNAL type,
+ u32 flags,
+ ACPI_NAMED_OBJECT **ret_entry);
+
+void
+acpi_ns_initialize_table (
+ ACPI_NAME_TABLE *new_table,
+ ACPI_NAME_TABLE *parent_scope,
+ ACPI_NAMED_OBJECT *parent_entry);
+
+ACPI_STATUS
+acpi_ns_search_one_scope (
+ u32 entry_name,
+ ACPI_NAME_TABLE *name_table,
+ OBJECT_TYPE_INTERNAL type,
+ ACPI_NAMED_OBJECT **ret_entry,
+ NS_SEARCH_DATA *ret_info);
+
+
+/*
+ * Utility functions - nsutils
+ */
+
+u8
+acpi_ns_valid_root_prefix (
+ char prefix);
+
+u8
+acpi_ns_valid_path_separator (
+ char sep);
+
+OBJECT_TYPE_INTERNAL
+acpi_ns_get_type (
+ ACPI_HANDLE obj_handle);
+
+void *
+acpi_ns_get_attached_object (
+ ACPI_HANDLE obj_handle);
+
+s32
+acpi_ns_local (
+ OBJECT_TYPE_INTERNAL type);
+
+ACPI_STATUS
+acpi_ns_internalize_name (
+ char *dotted_name,
+ char **converted_name);
+
+ACPI_STATUS
+acpi_ns_externalize_name (
+ u32 internal_name_length,
+ char *internal_name,
+ u32 *converted_name_length,
+ char **converted_name);
+
+s32
+is_ns_object (
+ ACPI_OBJECT_INTERNAL *p_oD);
+
+s32
+acpi_ns_mark_nS(
+ void);
+
+ACPI_NAMED_OBJECT*
+acpi_ns_convert_handle_to_entry (
+ ACPI_HANDLE handle);
+
+ACPI_HANDLE
+acpi_ns_convert_entry_to_handle(
+ ACPI_NAMED_OBJECT*nte);
+
+void
+acpi_ns_terminate (
+ void);
+
+ACPI_NAMED_OBJECT *
+acpi_ns_get_parent_entry (
+ ACPI_NAMED_OBJECT *this_entry);
+
+
+ACPI_NAMED_OBJECT *
+acpi_ns_get_next_valid_entry (
+ ACPI_NAMED_OBJECT *this_entry);
+
+
+#endif /* __NAMESPACE_H__ */
diff --git a/drivers/acpi/include/output.h b/drivers/acpi/include/output.h
new file mode 100644
index 000000000..a3be12a38
--- /dev/null
+++ b/drivers/acpi/include/output.h
@@ -0,0 +1,124 @@
+
+/******************************************************************************
+ *
+ * Name: output.h -- debug output
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 _OUTPUT_H
+#define _OUTPUT_H
+
+/*
+ * Debug levels and component IDs. These are used to control the
+ * granularity of the output of the DEBUG_PRINT macro -- on a per-
+ * component basis and a per-exception-type basis.
+ */
+
+/* Component IDs -- used in the global "Debug_layer" */
+
+#define GLOBAL 0x00000001
+#define COMMON 0x00000002
+#define PARSER 0x00000004
+#define DISPATCHER 0x00000008
+#define INTERPRETER 0x00000010
+#define NAMESPACE 0x00000020
+#define RESOURCE_MANAGER 0x00000040
+#define TABLE_MANAGER 0x00000080
+#define EVENT_HANDLING 0x00000100
+#define HARDWARE 0x00000200
+#define MISCELLANEOUS 0x00000400
+#define OS_DEPENDENT 0x00000800
+
+#define BUS_MANAGER 0x00001000
+
+#define PROCESSOR_CONTROL 0x00002000
+#define SYSTEM_CONTROL 0x00004000
+#define THERMAL_CONTROL 0x00008000
+#define POWER_CONTROL 0x00010000
+
+#define EMBEDDED_CONTROLLER 0x00020000
+#define BATTERY 0x00040000
+
+#define DEBUGGER 0x00100000
+#define ALL_COMPONENTS 0x001FFFFF
+
+
+/* Exception level -- used in the global "Debug_level" */
+
+#define ACPI_OK 0x00000001
+#define ACPI_INFO 0x00000002
+#define ACPI_WARN 0x00000004
+#define ACPI_ERROR 0x00000008
+#define ACPI_FATAL 0x00000010
+#define ACPI_DEBUG_OBJECT 0x00000020
+#define ACPI_ALL 0x0000003F
+
+
+/* Trace level -- also used in the global "Debug_level" */
+
+#define TRACE_PARSE 0x00000100
+#define TRACE_DISPATCH 0x00000200
+#define TRACE_LOAD 0x00000400
+#define TRACE_EXEC 0x00000800
+#define TRACE_NAMES 0x00001000
+#define TRACE_OPREGION 0x00002000
+#define TRACE_BFIELD 0x00004000
+#define TRACE_TRASH 0x00008000
+#define TRACE_TABLES 0x00010000
+#define TRACE_FUNCTIONS 0x00020000
+#define TRACE_VALUES 0x00040000
+#define TRACE_OBJECTS 0x00080000
+#define TRACE_ALLOCATIONS 0x00100000
+#define TRACE_RESOURCES 0x00200000
+#define TRACE_IO 0x00400000
+#define TRACE_INTERRUPTS 0x00800000
+#define TRACE_USER_REQUESTS 0x01000000
+#define TRACE_PACKAGE 0x02000000
+#define TRACE_MUTEX 0x04000000
+
+#define TRACE_ALL 0x0FFFFF00
+
+
+/* Exceptionally verbose output -- also used in the global "Debug_level" */
+
+#define VERBOSE_AML_DISASSEMBLE 0x10000000
+#define VERBOSE_INFO 0x20000000
+#define VERBOSE_TABLES 0x40000000
+#define VERBOSE_EVENTS 0x80000000
+
+#define VERBOSE_ALL 0x70000000
+
+
+/* Defaults for Debug_level, debug and normal */
+
+#define DEBUG_DEFAULT (ACPI_OK | ACPI_WARN | ACPI_ERROR | ACPI_DEBUG_OBJECT | TRACE_TABLES | TRACE_IO)
+#define NORMAL_DEFAULT (ACPI_OK | ACPI_WARN | ACPI_ERROR | ACPI_DEBUG_OBJECT)
+#define DEBUG_ALL (VERBOSE_AML_DISASSEMBLE | TRACE_ALL | ACPI_ALL)
+
+/* Misc defines */
+
+#define HEX 0x01
+#define ASCII 0x02
+#define FULL_ADDRESS 0x04
+#define CHARS_PER_LINE 16 /* used in Dump_buf function */
+
+
+#endif /* _OUTPUT_H */
diff --git a/drivers/acpi/include/parser.h b/drivers/acpi/include/parser.h
new file mode 100644
index 000000000..ed146756a
--- /dev/null
+++ b/drivers/acpi/include/parser.h
@@ -0,0 +1,327 @@
+/******************************************************************************
+ *
+ * Module Name: parser.h - AML Parser subcomponent prototypes and defines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 _PARSER_H_
+#define _PARSER_H_
+
+
+#define OP_HAS_RETURN_VALUE 1
+
+/* variable # arguments */
+
+#define ACPI_VAR_ARGS ACPI_UINT32_MAX
+
+/* maximum virtual address */
+
+#define ACPI_MAX_AML ((u8 *)(~0UL))
+
+
+#define PARSE_DELETE_TREE 1
+
+
+/* psapi - Parser external interfaces */
+
+ACPI_STATUS
+acpi_psx_load_table (
+ u8 *pcode_addr,
+ s32 pcode_length);
+
+ACPI_STATUS
+acpi_psx_execute (
+ ACPI_NAMED_OBJECT *method_entry,
+ ACPI_OBJECT_INTERNAL **params,
+ ACPI_OBJECT_INTERNAL **return_obj_desc);
+
+
+u8
+acpi_ps_is_namespace_object_op (
+ u16 opcode);
+u8
+acpi_ps_is_namespace_op (
+ u16 opcode);
+
+
+/******************************************************************************
+ *
+ * Parser interfaces
+ *
+ *****************************************************************************/
+
+
+/* psargs - Parse AML opcode arguments */
+
+u8 *
+acpi_ps_get_next_package_end (
+ ACPI_PARSE_STATE *parser_state);
+
+char *
+acpi_ps_get_next_namestring (
+ ACPI_PARSE_STATE *parser_state);
+
+void
+acpi_ps_get_next_simple_arg (
+ ACPI_PARSE_STATE *parser_state,
+ s32 arg_type, /* type of argument */
+ ACPI_GENERIC_OP *arg); /* (OUT) argument data */
+
+void
+acpi_ps_get_next_namepath (
+ ACPI_PARSE_STATE *parser_state,
+ ACPI_GENERIC_OP *arg,
+ u32 *arg_count,
+ u8 method_call);
+
+ACPI_GENERIC_OP *
+acpi_ps_get_next_field (
+ ACPI_PARSE_STATE *parser_state);
+
+ACPI_GENERIC_OP *
+acpi_ps_get_next_arg (
+ ACPI_PARSE_STATE *parser_state,
+ s32 arg_type,
+ u32 *arg_count);
+
+
+/* psopcode - AML Opcode information */
+
+ACPI_OP_INFO *
+acpi_ps_get_opcode_info (
+ u16 opcode);
+
+char *
+acpi_ps_get_opcode_name (
+ u16 opcode);
+
+
+/* psparse - top level parsing routines */
+
+void
+acpi_ps_delete_parse_tree (
+ ACPI_GENERIC_OP *root);
+
+ACPI_STATUS
+acpi_ps_parse_loop (
+ ACPI_PARSE_STATE *parser_state,
+ ACPI_WALK_STATE *walk_state,
+ u32 parse_flags);
+
+
+ACPI_STATUS
+acpi_ps_parse_aml (
+ ACPI_GENERIC_OP *start_scope,
+ u8 *aml,
+ u32 acpi_aml_size,
+ u32 parse_flags);
+
+ACPI_STATUS
+acpi_ps_parse_table (
+ u8 *aml,
+ s32 aml_size,
+ INTERPRETER_CALLBACK descending_callback,
+ INTERPRETER_CALLBACK ascending_callback,
+ ACPI_GENERIC_OP **root_object);
+
+u16
+acpi_ps_peek_opcode (
+ ACPI_PARSE_STATE *state);
+
+
+/* psscope - Scope stack management routines */
+
+
+ACPI_STATUS
+acpi_ps_init_scope (
+ ACPI_PARSE_STATE *parser_state,
+ ACPI_GENERIC_OP *root);
+
+ACPI_GENERIC_OP *
+acpi_ps_get_parent_scope (
+ ACPI_PARSE_STATE *state);
+
+u8
+acpi_ps_has_completed_scope (
+ ACPI_PARSE_STATE *parser_state);
+
+void
+acpi_ps_pop_scope (
+ ACPI_PARSE_STATE *parser_state,
+ ACPI_GENERIC_OP **op,
+ u32 *arg_list);
+
+ACPI_STATUS
+acpi_ps_push_scope (
+ ACPI_PARSE_STATE *parser_state,
+ ACPI_GENERIC_OP *op,
+ u32 remaining_args,
+ u32 arg_count);
+
+void
+acpi_ps_cleanup_scope (
+ ACPI_PARSE_STATE *state);
+
+
+/* pstree - parse tree manipulation routines */
+
+void
+acpi_ps_append_arg(
+ ACPI_GENERIC_OP *op,
+ ACPI_GENERIC_OP *arg);
+
+ACPI_GENERIC_OP*
+acpi_ps_find (
+ ACPI_GENERIC_OP *scope,
+ char *path,
+ u16 opcode,
+ u32 create);
+
+ACPI_GENERIC_OP *
+acpi_ps_get_arg(
+ ACPI_GENERIC_OP *op,
+ u32 argn);
+
+ACPI_GENERIC_OP *
+acpi_ps_get_child (
+ ACPI_GENERIC_OP *op);
+
+ACPI_GENERIC_OP *
+acpi_ps_get_depth_next (
+ ACPI_GENERIC_OP *origin,
+ ACPI_GENERIC_OP *op);
+
+
+/* pswalk - parse tree walk routines */
+
+ACPI_STATUS
+acpi_ps_walk_parsed_aml (
+ ACPI_GENERIC_OP *start_op,
+ ACPI_GENERIC_OP *end_op,
+ ACPI_OBJECT_INTERNAL *mth_desc,
+ ACPI_NAME_TABLE *start_scope,
+ ACPI_OBJECT_INTERNAL **params,
+ ACPI_OBJECT_INTERNAL **caller_return_desc,
+ ACPI_OWNER_ID owner_id,
+ INTERPRETER_CALLBACK descending_callback,
+ INTERPRETER_CALLBACK ascending_callback);
+
+ACPI_STATUS
+acpi_ps_get_next_walk_op (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op,
+ INTERPRETER_CALLBACK ascending_callback);
+
+
+/* psutils - parser utilities */
+
+void
+acpi_ps_init_op (
+ ACPI_GENERIC_OP *op,
+ u16 opcode);
+
+ACPI_GENERIC_OP *
+acpi_ps_alloc_op (
+ u16 opcode);
+
+void
+acpi_ps_free_op (
+ ACPI_GENERIC_OP *op);
+
+void
+acpi_ps_delete_parse_cache (
+ void);
+
+u8
+acpi_ps_is_leading_char (
+ s32 c);
+
+u8
+acpi_ps_is_prefix_char (
+ s32 c);
+
+u8
+acpi_ps_is_named_op (
+ u16 opcode);
+
+u8
+acpi_ps_is_named_object_op (
+ u16 opcode);
+
+u8
+acpi_ps_is_deferred_op (
+ u16 opcode);
+
+u8
+acpi_ps_is_bytelist_op(
+ u16 opcode);
+
+u8
+acpi_ps_is_field_op(
+ u16 opcode);
+
+u8
+acpi_ps_is_create_field_op (
+ u16 opcode);
+
+ACPI_NAMED_OP*
+acpi_ps_to_named_op(
+ ACPI_GENERIC_OP *op);
+
+ACPI_DEFERRED_OP *
+acpi_ps_to_deferred_op (
+ ACPI_GENERIC_OP *op);
+
+ACPI_BYTELIST_OP*
+acpi_ps_to_bytelist_op(
+ ACPI_GENERIC_OP *op);
+
+u32
+acpi_ps_get_name(
+ ACPI_GENERIC_OP *op);
+
+void
+acpi_ps_set_name(
+ ACPI_GENERIC_OP *op,
+ u32 name);
+
+
+/* psdump - display parser tree */
+
+s32
+acpi_ps_sprint_path (
+ char *buffer_start,
+ u32 buffer_size,
+ ACPI_GENERIC_OP *op);
+
+s32
+acpi_ps_sprint_op (
+ char *buffer_start,
+ u32 buffer_size,
+ ACPI_GENERIC_OP *op);
+
+void
+acpi_ps_show (
+ ACPI_GENERIC_OP *op);
+
+
+#endif /* _PARSER_H_ */
diff --git a/drivers/acpi/include/resource.h b/drivers/acpi/include/resource.h
new file mode 100644
index 000000000..b87032ddb
--- /dev/null
+++ b/drivers/acpi/include/resource.h
@@ -0,0 +1,300 @@
+/******************************************************************************
+ *
+ * Name: resource.h - Resource Manager function prototypes
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 __RESOURCE_H__
+#define __RESOURCE_H__
+
+#include "actypes.h"
+#include "acobject.h"
+
+/*
+ * Function prototypes called from Acpi* APIs
+ */
+
+ACPI_STATUS
+acpi_rs_get_prt_method_data (
+ ACPI_HANDLE handle,
+ ACPI_BUFFER *ret_buffer);
+
+
+ACPI_STATUS
+acpi_rs_get_crs_method_data (
+ ACPI_HANDLE handle,
+ ACPI_BUFFER *ret_buffer);
+
+ACPI_STATUS
+acpi_rs_get_prs_method_data (
+ ACPI_HANDLE handle,
+ ACPI_BUFFER *ret_buffer);
+
+ACPI_STATUS
+acpi_rs_set_srs_method_data (
+ ACPI_HANDLE handle,
+ ACPI_BUFFER *ret_buffer);
+
+ACPI_STATUS
+acpi_rs_create_resource_list (
+ ACPI_OBJECT_INTERNAL *byte_stream_buffer,
+ u8 *output_buffer,
+ u32 *output_buffer_length);
+
+ACPI_STATUS
+acpi_rs_create_byte_stream (
+ RESOURCE *linked_list_buffer,
+ u8 *output_buffer,
+ u32 *output_buffer_length);
+
+ACPI_STATUS
+acpi_rs_create_pci_routing_table (
+ ACPI_OBJECT_INTERNAL *method_return_object,
+ u8 *output_buffer,
+ u32 *output_buffer_length);
+
+
+/*
+ *Function prototypes called from Acpi_rs_create*APIs
+ */
+
+void
+acpi_rs_dump_resource_list (
+ RESOURCE *resource);
+
+void
+acpi_rs_dump_irq_list (
+ u8 *route_table);
+
+ACPI_STATUS
+acpi_rs_get_byte_stream_start (
+ u8 *byte_stream_buffer,
+ u8 **byte_stream_start,
+ u32 *size);
+
+ACPI_STATUS
+acpi_rs_calculate_list_length (
+ u8 *byte_stream_buffer,
+ u32 byte_stream_buffer_length,
+ u32 *size_needed);
+
+ACPI_STATUS
+acpi_rs_calculate_byte_stream_length (
+ RESOURCE *linked_list_buffer,
+ u32 *size_needed);
+
+ACPI_STATUS
+acpi_rs_byte_stream_to_list (
+ u8 *byte_stream_buffer,
+ u32 byte_stream_buffer_length,
+ u8 **output_buffer);
+
+ACPI_STATUS
+acpi_rs_list_to_byte_stream (
+ RESOURCE *linked_list,
+ u32 byte_stream_size_needed,
+ u8 **output_buffer);
+
+ACPI_STATUS
+acpi_rs_io_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size);
+
+ACPI_STATUS
+acpi_rs_fixed_io_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size);
+
+ACPI_STATUS
+acpi_rs_io_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed);
+
+ACPI_STATUS
+acpi_rs_fixed_io_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed);
+
+ACPI_STATUS
+acpi_rs_irq_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size);
+
+ACPI_STATUS
+acpi_rs_irq_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed);
+
+ACPI_STATUS
+acpi_rs_dma_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size);
+
+ACPI_STATUS
+acpi_rs_dma_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed);
+
+ACPI_STATUS
+acpi_rs_address16_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size);
+
+ACPI_STATUS
+acpi_rs_address16_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed);
+
+ACPI_STATUS
+acpi_rs_address32_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size);
+
+ACPI_STATUS
+acpi_rs_address32_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed);
+
+ACPI_STATUS
+acpi_rs_start_dependent_functions_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size);
+
+ACPI_STATUS
+acpi_rs_end_dependent_functions_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size);
+
+ACPI_STATUS
+acpi_rs_start_dependent_functions_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed);
+
+ACPI_STATUS
+acpi_rs_end_dependent_functions_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed);
+
+ACPI_STATUS
+acpi_rs_memory24_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size);
+
+ACPI_STATUS
+acpi_rs_memory24_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed);
+
+ACPI_STATUS
+acpi_rs_memory32_range_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size
+);
+
+ACPI_STATUS
+acpi_rs_fixed_memory32_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size);
+
+ACPI_STATUS
+acpi_rs_memory32_range_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed);
+
+ACPI_STATUS
+acpi_rs_fixed_memory32_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed);
+
+ACPI_STATUS
+acpi_rs_extended_irq_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size);
+
+ACPI_STATUS
+acpi_rs_extended_irq_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed);
+
+ACPI_STATUS
+acpi_rs_end_tag_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size);
+
+ACPI_STATUS
+acpi_rs_end_tag_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed);
+
+ACPI_STATUS
+acpi_rs_vendor_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size);
+
+ACPI_STATUS
+acpi_rs_vendor_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed);
+
+
+#endif /*__RESOURCE_H__ */
diff --git a/drivers/acpi/include/tables.h b/drivers/acpi/include/tables.h
new file mode 100644
index 000000000..d3566489e
--- /dev/null
+++ b/drivers/acpi/include/tables.h
@@ -0,0 +1,168 @@
+
+/******************************************************************************
+ *
+ * Name: tables.h - ACPI table management
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 __TABLES_H__
+#define __TABLES_H__
+
+#include "actypes.h"
+#include "actables.h"
+
+
+/* Used in Acpi_tb_map_acpi_table for size parameter if table header is to be used */
+
+#define SIZE_IN_HEADER 0
+
+
+ACPI_STATUS
+acpi_tb_handle_to_object (
+ u16 table_id,
+ ACPI_TABLE_DESC **table_desc);
+
+
+/*
+ * Acpi_tbfac - FACP, FACS utilities
+ */
+
+ACPI_STATUS
+acpi_tb_get_table_facs (
+ char *buffer_ptr,
+ ACPI_TABLE_DESC *table_info);
+
+
+/*
+ * Acpi_tbget - Table "get" routines
+ */
+
+ACPI_STATUS
+acpi_tb_get_table_ptr (
+ ACPI_TABLE_TYPE table_type,
+ u32 instance,
+ ACPI_TABLE_HEADER **table_ptr_loc);
+
+ACPI_STATUS
+acpi_tb_get_table (
+ void *physical_address,
+ char *buffer_ptr,
+ ACPI_TABLE_DESC *table_info);
+
+
+/*
+ * Acpi_tbgetall - Get all firmware ACPI tables
+ */
+
+ACPI_STATUS
+acpi_tb_get_all_tables (
+ u32 number_of_tables,
+ char *buffer_ptr);
+
+
+/*
+ * Acpi_tbinstall - Table installation
+ */
+
+ACPI_STATUS
+acpi_tb_install_table (
+ char *table_ptr,
+ ACPI_TABLE_DESC *table_info);
+
+ACPI_STATUS
+acpi_tb_recognize_table (
+ char *table_ptr,
+ ACPI_TABLE_DESC *table_info);
+
+ACPI_STATUS
+acpi_tb_init_table_descriptor (
+ ACPI_TABLE_TYPE table_type,
+ ACPI_TABLE_DESC *table_info);
+
+
+/*
+ * Acpi_tbremove - Table removal and deletion
+ */
+
+void
+acpi_tb_delete_acpi_tables (
+ void);
+
+void
+acpi_tb_delete_acpi_table (
+ ACPI_TABLE_TYPE type);
+
+ACPI_TABLE_DESC *
+acpi_tb_delete_single_table (
+ ACPI_TABLE_DESC *table_desc);
+
+void
+acpi_tb_free_acpi_tables_of_type (
+ ACPI_TABLE_DESC *table_info);
+
+
+/*
+ * Acpi_tbrsd - RSDP, RSDT utilities
+ */
+
+ACPI_STATUS
+acpi_tb_get_table_rsdt (
+ u32 *number_of_tables);
+
+char *
+acpi_tb_scan_memory_for_rsdp (
+ char *start_address,
+ u32 length);
+
+ACPI_STATUS
+acpi_tb_find_rsdp (
+ ACPI_TABLE_DESC *table_info);
+
+
+/*
+ * Acpi_tbutils - common table utilities
+ */
+
+u8
+acpi_tb_system_table_pointer (
+ void *where);
+
+ACPI_STATUS
+acpi_tb_map_acpi_table (
+ void *physical_address,
+ u32 *size,
+ void **logical_address);
+
+ACPI_STATUS
+acpi_tb_verify_table_checksum (
+ ACPI_TABLE_HEADER *table_header);
+
+u8
+acpi_tb_checksum (
+ void *buffer,
+ u32 length);
+
+ACPI_STATUS
+acpi_tb_validate_table_header (
+ ACPI_TABLE_HEADER *table_header);
+
+
+#endif /* __TABLES_H__ */
diff --git a/drivers/acpi/interpreter/amconfig.c b/drivers/acpi/interpreter/amconfig.c
new file mode 100644
index 000000000..8d4e4f26b
--- /dev/null
+++ b/drivers/acpi/interpreter/amconfig.c
@@ -0,0 +1,303 @@
+
+/******************************************************************************
+ *
+ * Module Name: amconfig - Namespace reconfiguration (Load/Unload opcodes)
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "interp.h"
+#include "amlcode.h"
+#include "namesp.h"
+#include "events.h"
+#include "tables.h"
+#include "dispatch.h"
+
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("amconfig");
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_load_table
+ *
+ * PARAMETERS: Rgn_desc - Op region where the table will be obtained
+ * Ddb_handle - Where a handle to the table will be returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Load an ACPI table
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_load_table (
+ ACPI_OBJECT_INTERNAL *rgn_desc,
+ ACPI_HANDLE *ddb_handle)
+{
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL *table_desc = NULL;
+ char *table_ptr;
+ char *table_data_ptr;
+ ACPI_TABLE_HEADER table_header;
+ ACPI_TABLE_DESC table_info;
+ u32 i;
+
+
+ /* TBD: [Unhandled] Object can be either a field or an opregion */
+
+
+ /* Get the table header */
+
+ table_header.length = 0;
+ for (i = 0; i < sizeof (ACPI_TABLE_HEADER); i++) {
+ status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_READ,
+ i, 8, (u32 *) ((char *) &table_header + i));
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+ /* Allocate a buffer for the entire table */
+
+ table_ptr = acpi_cm_allocate (table_header.length);
+ if (!table_ptr) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Copy the header to the buffer */
+
+ MEMCPY (table_ptr, &table_header, sizeof (ACPI_TABLE_HEADER));
+ table_data_ptr = table_ptr + sizeof (ACPI_TABLE_HEADER);
+
+
+ /* Get the table from the op region */
+
+ for (i = 0; i < table_header.length; i++) {
+ status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_READ,
+ i, 8, (u32 *) (table_data_ptr + i));
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+ }
+
+
+ /* Table must be either an SSDT or a PSDT */
+
+ if ((!STRNCMP (table_header.signature,
+ acpi_gbl_acpi_table_data[ACPI_TABLE_PSDT].signature,
+ acpi_gbl_acpi_table_data[ACPI_TABLE_PSDT].sig_length)) &&
+ (!STRNCMP (table_header.signature,
+ acpi_gbl_acpi_table_data[ACPI_TABLE_SSDT].signature,
+ acpi_gbl_acpi_table_data[ACPI_TABLE_SSDT].sig_length)))
+ {
+ status = AE_BAD_SIGNATURE;
+ goto cleanup;
+ }
+
+ /* Create an object to be the table handle */
+
+ table_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REFERENCE);
+ if (!table_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+
+ /* Install the new table into the local data structures */
+
+ table_info.pointer = (ACPI_TABLE_HEADER *) table_ptr;
+ table_info.length = table_header.length;
+ table_info.allocation = ACPI_MEM_ALLOCATED;
+ table_info.base_pointer = table_ptr;
+
+ status = acpi_tb_install_table (NULL, &table_info);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Add the table to the namespace */
+
+ status = acpi_load_namespace ();
+ if (ACPI_FAILURE (status)) {
+ /* TBD: [Errors] Unload the table on failure ? */
+
+ goto cleanup;
+ }
+
+ /* TBD: [Investigate] we need a pointer to the table desc */
+
+ /* Init the table handle */
+
+ table_desc->reference.op_code = AML_LOAD_OP;
+ table_desc->reference.object = table_info.installed_desc;
+
+ *ddb_handle = table_desc;
+
+ return (status);
+
+
+cleanup:
+
+ acpi_cm_free (table_desc);
+ acpi_cm_free (table_ptr);
+ return (status);
+
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_unload_table
+ *
+ * PARAMETERS: Ddb_handle - Handle to a previously loaded table
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Unload an ACPI table
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_unload_table (
+ ACPI_HANDLE ddb_handle)
+{
+ ACPI_STATUS status = AE_NOT_IMPLEMENTED;
+ ACPI_OBJECT_INTERNAL *table_desc = (ACPI_OBJECT_INTERNAL *) ddb_handle;
+ ACPI_TABLE_DESC *table_info;
+
+
+ /* Validate the handle */
+ /* TBD: [Errors] Wasn't this done earlier? */
+
+ if ((!ddb_handle) ||
+ (!VALID_DESCRIPTOR_TYPE (ddb_handle, ACPI_DESC_TYPE_INTERNAL)) ||
+ (((ACPI_OBJECT_INTERNAL *)ddb_handle)->common.type !=
+ INTERNAL_TYPE_REFERENCE))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /* Get the actual table descriptor from the Ddb_handle */
+
+ table_info = (ACPI_TABLE_DESC *) table_desc->reference.object;
+
+ /*
+ * Delete the entire namespace under this table NTE
+ * (Offset contains the Table_id)
+ */
+
+ status = acpi_ns_delete_namespace_by_owner (table_info->table_id);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Delete the table itself */
+
+ acpi_tb_delete_single_table (table_info->installed_desc);
+
+ /* Delete the table descriptor (Ddb_handle) */
+
+ acpi_cm_remove_reference (table_desc);
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_reconfiguration
+ *
+ * PARAMETERS: Opcode - The opcode to be executed
+ * Walk_state - Current state of the parse tree walk
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Reconfiguration opcodes such as LOAD and UNLOAD
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_reconfiguration (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL *region_desc = NULL;
+ ACPI_HANDLE *ddb_handle;
+
+
+ /* Resolve the operands */
+
+ status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS);
+ /* Get the table handle, common for both opcodes */
+
+ status |= acpi_ds_obj_stack_pop_object ((ACPI_OBJECT_INTERNAL **) &ddb_handle,
+ walk_state);
+
+ switch (opcode)
+ {
+
+ case AML_LOAD_OP:
+
+ /* Get the region or field descriptor */
+
+ status |= acpi_ds_obj_stack_pop_object (&region_desc, walk_state);
+ if (status != AE_OK) {
+ acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, opcode,
+ WALK_OPERANDS, 2);
+ goto cleanup2;
+ }
+
+ status = acpi_aml_exec_load_table (region_desc, ddb_handle);
+ break;
+
+
+ case AML_UN_LOAD_OP:
+
+ if (status != AE_OK) {
+ acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, opcode,
+ WALK_OPERANDS, 1);
+ goto cleanup1;
+ }
+
+ status = acpi_aml_exec_unload_table (ddb_handle);
+ break;
+
+
+ default:
+
+ status = AE_AML_BAD_OPCODE;
+ break;
+ }
+
+
+cleanup2:
+ acpi_cm_remove_reference (region_desc);
+
+cleanup1:
+ return (status);
+}
+
diff --git a/drivers/acpi/interpreter/amcreate.c b/drivers/acpi/interpreter/amcreate.c
new file mode 100644
index 000000000..f5c95bc11
--- /dev/null
+++ b/drivers/acpi/interpreter/amcreate.c
@@ -0,0 +1,871 @@
+
+/******************************************************************************
+ *
+ * Module Name: amcreate - Named object creation
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "interp.h"
+#include "amlcode.h"
+#include "namesp.h"
+#include "events.h"
+#include "dispatch.h"
+
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("amcreate");
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_create_field
+ *
+ * PARAMETERS: Opcode - The opcode to be executed
+ * Operands - List of operands for the opcode
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute Create_field operators: Create_bit_field_op,
+ * Create_byte_field_op, Create_word_field_op, Create_dWord_field_op,
+ * Create_field_op (which define fields in buffers)
+ *
+ * ALLOCATION: Deletes Create_field_op's count operand descriptor
+ *
+ *
+ * ACPI SPECIFICATION REFERENCES:
+ * Def_create_bit_field := Create_bit_field_op Src_buf Bit_idx Name_string
+ * Def_create_byte_field := Create_byte_field_op Src_buf Byte_idx Name_string
+ * Def_create_dWord_field := Create_dWord_field_op Src_buf Byte_idx Name_string
+ * Def_create_field := Create_field_op Src_buf Bit_idx Num_bits Name_string
+ * Def_create_word_field := Create_word_field_op Src_buf Byte_idx Name_string
+ * Bit_index := Term_arg=>Integer
+ * Byte_index := Term_arg=>Integer
+ * Num_bits := Term_arg=>Integer
+ * Source_buff := Term_arg=>Buffer
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_create_field (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_OBJECT_INTERNAL *res_desc = NULL;
+ ACPI_OBJECT_INTERNAL *cnt_desc = NULL;
+ ACPI_OBJECT_INTERNAL *off_desc = NULL;
+ ACPI_OBJECT_INTERNAL *src_desc = NULL;
+ ACPI_OBJECT_INTERNAL *field_desc;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ OBJECT_TYPE_INTERNAL res_type;
+ ACPI_STATUS status;
+ u32 num_operands = 3;
+ u32 offset;
+ u32 bit_offset;
+ u16 bit_count;
+ u8 type_found;
+
+
+ /* Resolve the operands */
+
+ status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS);
+
+ /* Get the operands */
+
+ status |= acpi_ds_obj_stack_pop_object (&res_desc, walk_state);
+ if (AML_CREATE_FIELD_OP == opcode) {
+ num_operands = 4;
+ status |= acpi_ds_obj_stack_pop_object (&cnt_desc, walk_state);
+ }
+
+ status |= acpi_ds_obj_stack_pop_object (&off_desc, walk_state);
+ status |= acpi_ds_obj_stack_pop_object (&src_desc, walk_state);
+
+ if (status != AE_OK) {
+ /* Invalid parameters on object stack */
+
+ acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, opcode,
+ WALK_OPERANDS, 3);
+ goto cleanup;
+ }
+
+
+ offset = off_desc->number.value;
+
+
+ /*
+ * If Res_desc is a Name, it will be a direct name pointer after
+ * Acpi_aml_resolve_operands()
+ */
+
+ if (!VALID_DESCRIPTOR_TYPE (res_desc, ACPI_DESC_TYPE_NAMED)) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+
+ /*
+ * Setup the Bit offsets and counts, according to the opcode
+ */
+
+ switch (opcode)
+ {
+
+ /* Def_create_bit_field */
+
+ case AML_BIT_FIELD_OP:
+
+ /* Offset is in bits, Field is a bit */
+
+ bit_offset = offset;
+ bit_count = 1;
+ break;
+
+
+ /* Def_create_byte_field */
+
+ case AML_BYTE_FIELD_OP:
+
+ /* Offset is in bytes, field is a byte */
+
+ bit_offset = 8 * offset;
+ bit_count = 8;
+ break;
+
+
+ /* Def_create_word_field */
+
+ case AML_WORD_FIELD_OP:
+
+ /* Offset is in bytes, field is a word */
+
+ bit_offset = 8 * offset;
+ bit_count = 16;
+ break;
+
+
+ /* Def_create_dWord_field */
+
+ case AML_DWORD_FIELD_OP:
+
+ /* Offset is in bytes, field is a dword */
+
+ bit_offset = 8 * offset;
+ bit_count = 32;
+ break;
+
+
+ /* Def_create_field */
+
+ case AML_CREATE_FIELD_OP:
+
+ /* Offset is in bits, count is in bits */
+
+ bit_offset = offset;
+ bit_count = (u16) cnt_desc->number.value;
+ break;
+
+
+ default:
+
+ status = AE_AML_BAD_OPCODE;
+ goto cleanup;
+ }
+
+
+ /*
+ * Setup field according to the object type
+ */
+
+ switch (src_desc->common.type)
+ {
+
+ /* Source_buff := Term_arg=>Buffer */
+
+ case ACPI_TYPE_BUFFER:
+
+ if (bit_offset + (u32) bit_count >
+ (8 * (u32) src_desc->buffer.length))
+ {
+ status = AE_AML_BUFFER_LIMIT;
+ goto cleanup;
+ }
+
+
+ /* Allocate an object for the field */
+
+ field_desc = acpi_cm_create_internal_object (ACPI_TYPE_FIELD_UNIT);
+ if (!field_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Construct the field object */
+
+ field_desc->field_unit.access = (u8) ACCESS_ANY_ACC;
+ field_desc->field_unit.lock_rule = (u8) GLOCK_NEVER_LOCK;
+ field_desc->field_unit.update_rule = (u8) UPDATE_PRESERVE;
+ field_desc->field_unit.length = bit_count;
+ field_desc->field_unit.bit_offset = (u8) (bit_offset % 8);
+ field_desc->field_unit.offset = DIV_8 (bit_offset);
+ field_desc->field_unit.container = src_desc;
+ field_desc->field_unit.sequence = src_desc->buffer.sequence;
+
+ /* An additional reference for Src_desc */
+
+ acpi_cm_add_reference (src_desc);
+
+ break;
+
+
+ /* Improper object type */
+
+ default:
+
+ type_found = src_desc->common.type;
+
+ if ((type_found > (u8) INTERNAL_TYPE_REFERENCE) ||
+ !acpi_cm_valid_object_type (type_found))
+
+
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+
+ if (AML_CREATE_FIELD_OP == opcode) {
+ /* Delete object descriptor unique to Create_field */
+
+ acpi_cm_remove_reference (cnt_desc);
+ cnt_desc = NULL;
+ }
+
+ /*
+ * This operation is supposed to cause the destination Name to refer
+ * to the defined Field_unit -- it must not store the constructed
+ * Field_unit object (or its current value) in some location that the
+ * Name may already be pointing to. So, if the Name currently contains
+ * a reference which would cause Acpi_aml_exec_store() to perform an indirect
+ * store rather than setting the value of the Name itself, clobber that
+ * reference before calling Acpi_aml_exec_store().
+ */
+
+ res_type = acpi_ns_get_type (res_desc);
+
+ /* Type of Name's existing value */
+
+ switch (res_type)
+ {
+
+ case ACPI_TYPE_FIELD_UNIT:
+
+ case INTERNAL_TYPE_ALIAS:
+ case INTERNAL_TYPE_BANK_FIELD:
+ case INTERNAL_TYPE_DEF_FIELD:
+ case INTERNAL_TYPE_INDEX_FIELD:
+
+ obj_desc = acpi_ns_get_attached_object (res_desc);
+ if (obj_desc) {
+ /*
+ * There is an existing object here; delete it and zero out the
+ * NTE
+ */
+
+ acpi_cm_remove_reference (obj_desc);
+ acpi_ns_attach_object (res_desc, NULL, ACPI_TYPE_ANY);
+ }
+
+ /* Set the type to ANY (or the store below will fail) */
+
+ ((ACPI_NAMED_OBJECT*) res_desc)->type = ACPI_TYPE_ANY;
+
+ break;
+
+
+ default:
+
+ break;
+ }
+
+
+ /* Store constructed field descriptor in result location */
+
+ status = acpi_aml_exec_store (field_desc, res_desc);
+
+ /*
+ * If the field descriptor was not physically stored (or if a failure
+ * above), we must delete it
+ */
+ if (field_desc->common.reference_count <= 1) {
+ acpi_cm_remove_reference (field_desc);
+ }
+
+
+cleanup:
+
+ /* Always delete the operands */
+
+ acpi_cm_remove_reference (off_desc);
+ acpi_cm_remove_reference (src_desc);
+
+ if (AML_CREATE_FIELD_OP == opcode) {
+ acpi_cm_remove_reference (cnt_desc);
+ }
+
+ /* On failure, delete the result descriptor */
+
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_remove_reference (res_desc); /* Result descriptor */
+ }
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_create_alias
+ *
+ * PARAMETERS: Operands - List of operands for the opcode
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new named alias
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_create_alias (
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_NAMED_OBJECT *src_entry;
+ ACPI_NAMED_OBJECT *alias_entry;
+ ACPI_STATUS status;
+
+
+ /* Get the source/alias operands (both NTEs) */
+
+ status = acpi_ds_obj_stack_pop_object ((ACPI_OBJECT_INTERNAL **) &src_entry,
+ walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Don't pop it, it gets popped later */
+
+ alias_entry = acpi_ds_obj_stack_get_value (0, walk_state);
+
+ /* Add an additional reference to the object */
+
+ acpi_cm_add_reference (src_entry->object);
+
+ /*
+ * Attach the original source NTE to the new Alias NTE.
+ */
+ status = acpi_ns_attach_object (alias_entry, src_entry->object,
+ src_entry->type);
+
+
+ /*
+ * The new alias assumes the type of the source, but it points
+ * to the same object. The reference count of the object has two
+ * additional references to prevent deletion out from under either the
+ * source or the alias NTE
+ */
+
+ /* Since both operands are NTEs, we don't need to delete them */
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_create_event
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new event object
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_create_event (
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+
+
+ BREAKPOINT3;
+
+ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_EVENT);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Create the actual OS semaphore */
+
+ /* TBD: [Investigate] should be created with 0 or 1 units? */
+
+ status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 1,
+ &obj_desc->event.semaphore);
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_remove_reference (obj_desc);
+ goto cleanup;
+ }
+
+ /* Attach object to the NTE */
+
+ status = acpi_ns_attach_object (acpi_ds_obj_stack_get_value (0, walk_state),
+ obj_desc, (u8) ACPI_TYPE_EVENT);
+ if (ACPI_FAILURE (status)) {
+ acpi_os_delete_semaphore (obj_desc->event.semaphore);
+ acpi_cm_remove_reference (obj_desc);
+ goto cleanup;
+ }
+
+
+cleanup:
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_create_mutex
+ *
+ * PARAMETERS: Interpreter_mode - Current running mode (load1/Load2/Exec)
+ * Operands - List of operands for the opcode
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new mutex object
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_create_mutex (
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_OBJECT_INTERNAL *sync_desc;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+
+
+ /* Get the operand */
+
+ status = acpi_ds_obj_stack_pop_object (&sync_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Attempt to allocate a new object */
+
+ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_MUTEX);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Create the actual OS semaphore */
+
+ status = acpi_os_create_semaphore (1, 1, &obj_desc->mutex.semaphore);
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_remove_reference (obj_desc);
+ goto cleanup;
+ }
+
+ obj_desc->mutex.sync_level = (u8) sync_desc->number.value;
+
+ /* Obj_desc was on the stack top, and the name is below it */
+
+ status = acpi_ns_attach_object (acpi_ds_obj_stack_get_value (0, walk_state),
+ obj_desc, (u8) ACPI_TYPE_MUTEX);
+ if (ACPI_FAILURE (status)) {
+ acpi_os_delete_semaphore (obj_desc->mutex.semaphore);
+ acpi_cm_remove_reference (obj_desc);
+ goto cleanup;
+ }
+
+
+cleanup:
+
+ /* Always delete the operand */
+
+ acpi_cm_remove_reference (sync_desc);
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_create_region
+ *
+ * PARAMETERS: Aml_ptr - Pointer to the region declaration AML
+ * Aml_length - Max length of the declaration AML
+ * Operands - List of operands for the opcode
+ * Interpreter_mode - Load1/Load2/Execute
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new operation region object
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_create_region (
+ u8 *aml_ptr,
+ u32 aml_length,
+ u32 region_space,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL *obj_desc_region;
+ ACPI_HANDLE *entry;
+
+
+ if (region_space >= NUM_REGION_TYPES) {
+ /* TBD: [Errors] should this return an error, or should we just keep
+ * going? */
+
+ REPORT_WARNING ("Unable to decode the Region_space");
+ }
+
+
+ /* Get the NTE from the object stack */
+
+ entry = acpi_ds_obj_stack_get_value (0, walk_state);
+
+
+ /* Create the region descriptor */
+
+ obj_desc_region = acpi_cm_create_internal_object (ACPI_TYPE_REGION);
+ if (!obj_desc_region) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * Allocate a method object for this region.
+ */
+ obj_desc_region->region.method = acpi_cm_create_internal_object (
+ ACPI_TYPE_METHOD);
+ if (!obj_desc_region->region.method) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Init the region from the operands */
+
+ obj_desc_region->region.space_id = (u16) region_space;
+ obj_desc_region->region.address = 0;
+ obj_desc_region->region.length = 0;
+ obj_desc_region->region.region_flags = 0;
+
+ /*
+ * Remember location in AML stream of address & length
+ * operands since they need to be evaluated at run time.
+ */
+ obj_desc_region->region.method->method.pcode = aml_ptr;
+ obj_desc_region->region.method->method.pcode_length = aml_length;
+
+
+ /* Install the new region object in the parent NTE */
+
+ obj_desc_region->region.nte = (ACPI_NAMED_OBJECT*) entry;
+
+ status = acpi_ns_attach_object (entry, obj_desc_region,
+ (u8) ACPI_TYPE_REGION);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+cleanup:
+
+ if (status != AE_OK) {
+ /* Delete region object and method subobject */
+
+ if (obj_desc_region) {
+ /* Remove deletes both objects! */
+
+ acpi_cm_remove_reference (obj_desc_region);
+ obj_desc_region = NULL;
+ }
+ }
+
+
+ /*
+ * If we have a valid region, initialize it
+ */
+ if (obj_desc_region) {
+ /*
+ * TBD: [Errors] Is there anything we can or could do when this
+ * fails?
+ * We need to do something useful with a failure.
+ */
+ /* Namespace IS locked */
+
+ (void *) acpi_ev_initialize_region (obj_desc_region, TRUE);
+
+ }
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_create_processor
+ *
+ * PARAMETERS: Op - Op containing the Processor definition and
+ * args
+ * Processor_nTE - NTE for the containing NTE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new processor object and populate the fields
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_create_processor (
+ ACPI_GENERIC_OP *op,
+ ACPI_HANDLE processor_nTE)
+{
+ ACPI_STATUS status;
+ ACPI_GENERIC_OP *arg;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+
+
+ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_PROCESSOR);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ return (status);
+ }
+
+ /* Install the new processor object in the parent NTE */
+
+ status = acpi_ns_attach_object (processor_nTE, obj_desc,
+ (u8) ACPI_TYPE_PROCESSOR);
+ if (ACPI_FAILURE (status)) {
+ return(status);
+ }
+
+ arg = op->value.arg;
+
+ /* check existence */
+
+ if (!arg) {
+ status = AE_AML_NO_OPERAND;
+ return (status);
+ }
+
+ /* First arg is the Processor ID */
+
+ obj_desc->processor.proc_id = (u8) arg->value.integer;
+
+ /* Move to next arg and check existence */
+
+ arg = arg->next;
+ if (!arg) {
+ status = AE_AML_NO_OPERAND;
+ return (status);
+ }
+
+ /* Second arg is the PBlock Address */
+
+ obj_desc->processor.pblk_address = (ACPI_IO_ADDRESS) arg->value.integer;
+
+ /* Move to next arg and check existence */
+
+ arg = arg->next;
+ if (!arg) {
+ status = AE_AML_NO_OPERAND;
+ return (status);
+ }
+
+ /* Third arg is the PBlock Length */
+
+ obj_desc->processor.pblk_length = (u8) arg->value.integer;
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_create_power_resource
+ *
+ * PARAMETERS: Op - Op containing the Power_resource definition
+ * and args
+ * Power_res_nTE - NTE for the containing NTE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new Power_resource object and populate the fields
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_create_power_resource (
+ ACPI_GENERIC_OP *op,
+ ACPI_HANDLE power_res_nTE)
+{
+ ACPI_STATUS status;
+ ACPI_GENERIC_OP *arg;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+
+
+ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_POWER);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ return (status);
+ }
+
+ /* Install the new power resource object in the parent NTE */
+
+ status = acpi_ns_attach_object (power_res_nTE, obj_desc,
+ (u8) ACPI_TYPE_POWER);
+ if (ACPI_FAILURE (status)) {
+ return(status);
+ }
+
+ arg = op->value.arg;
+
+ /* check existence */
+
+ if (!arg) {
+ status = AE_AML_NO_OPERAND;
+ return (status);
+ }
+
+ /* First arg is the System_level */
+
+ obj_desc->power_resource.system_level = (u8) arg->value.integer;
+
+ /* Move to next arg and check existence */
+
+ arg = arg->next;
+ if (!arg) {
+ status = AE_AML_NO_OPERAND;
+ return (status);
+ }
+
+ /* Second arg is the PBlock Address */
+
+ obj_desc->power_resource.resource_order = (u16) arg->value.integer;
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_create_method
+ *
+ * PARAMETERS: Interpreter_mode - Current running mode (load1/Load2/Exec)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new mutex object
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_create_method (
+ u8 *aml_ptr,
+ u32 aml_length,
+ u32 method_flags,
+ ACPI_HANDLE method)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_STATUS status;
+
+
+ /* Create a new method object */
+
+ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_METHOD);
+ if (!obj_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Get the method's AML pointer/length from the Op */
+
+ obj_desc->method.pcode = aml_ptr;
+ obj_desc->method.pcode_length = aml_length;
+
+ /*
+ * First argument is the Method Flags (contains parameter count for the
+ * method)
+ */
+
+ obj_desc->method.method_flags = (u8) method_flags;
+ obj_desc->method.param_count = (u8) (method_flags &
+ METHOD_FLAGS_ARG_COUNT);
+
+ /*
+ * Get the concurrency count
+ * If required, a semaphore will be created for this method when it is
+ * parsed.
+ *
+ * TBD: [Future] for APCI 2.0, there will be a Sync_level value, not
+ * just a flag
+ * Concurrency = Sync_level + 1;.
+ */
+
+ if (method_flags & METHOD_FLAGS_SERIALIZED) {
+ obj_desc->method.concurrency = 1;
+ }
+ else {
+ obj_desc->method.concurrency = INFINITE_CONCURRENCY;
+ }
+
+ /* Mark the Method as not parsed yet */
+
+ obj_desc->method.parser_op = NULL;
+
+ /*
+ * Another +1 gets added when Acpi_psx_execute is called,
+ * no need for: Obj_desc->Method.Pcode++;
+ */
+
+ obj_desc->method.acpi_table = NULL; /* TBD: [Restructure] was (u8 *) Pcode_addr; */
+ obj_desc->method.table_length = 0; /* TBD: [Restructure] needed? (u32) (Walk_state->aml_end - Pcode_addr); */
+
+ /* Attach the new object to the method NTE */
+
+ status = acpi_ns_attach_object (method, obj_desc, (u8) ACPI_TYPE_METHOD);
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_free (obj_desc);
+ }
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/interpreter/amdyadic.c b/drivers/acpi/interpreter/amdyadic.c
new file mode 100644
index 000000000..7c32edd0e
--- /dev/null
+++ b/drivers/acpi/interpreter/amdyadic.c
@@ -0,0 +1,750 @@
+
+/******************************************************************************
+ *
+ * Module Name: amdyadic - ACPI AML (p-code) execution for dyadic operators
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "namesp.h"
+#include "interp.h"
+#include "events.h"
+#include "amlcode.h"
+#include "dispatch.h"
+
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("amdyadic");
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_dyadic1
+ *
+ * PARAMETERS: Opcode - The opcode to be executed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute Type 1 dyadic operator with numeric operands:
+ * Notify_op
+ *
+ * ALLOCATION: Deletes both operands
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_dyadic1 (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc = NULL;
+ ACPI_OBJECT_INTERNAL *val_desc = NULL;
+ ACPI_NAMED_OBJECT *entry;
+ ACPI_STATUS status = AE_OK;
+
+
+ /* Resolve all operands */
+
+ status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS);
+ /* Get the operands */
+
+ status |= acpi_ds_obj_stack_pop_object (&val_desc, walk_state);
+ status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ /* Invalid parameters on object stack */
+
+ acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, opcode,
+ WALK_OPERANDS, 2);
+ goto cleanup;
+ }
+
+
+ /* Examine the opcode */
+
+ switch (opcode)
+ {
+
+ /* Def_notify := Notify_op Notify_object Notify_value */
+
+ case AML_NOTIFY_OP:
+
+ /* The Obj_desc is actually an NTE */
+
+ entry = (ACPI_NAMED_OBJECT*) obj_desc;
+ obj_desc = NULL;
+
+ /* Object must be a device or thermal zone */
+
+ if (entry && val_desc) {
+ switch (entry->type)
+ {
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_THERMAL:
+
+ /*
+ * Requires that Device and Thermal_zone be compatible
+ * mappings
+ */
+
+ /* Dispatch the notify to the appropriate handler */
+
+ acpi_ev_notify_dispatch (entry, val_desc->number.value);
+ break;
+
+ default:
+ status = AE_AML_OPERAND_TYPE;
+ }
+ }
+ break;
+
+ default:
+ status = AE_AML_BAD_OPCODE;
+ }
+
+
+cleanup:
+
+ /* Always delete both operands */
+
+ acpi_cm_remove_reference (val_desc);
+ acpi_cm_remove_reference (obj_desc);
+
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_dyadic2_r
+ *
+ * PARAMETERS: Opcode - The opcode to be executed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute Type 2 dyadic operator with numeric operands and
+ * one or two result operands.
+ *
+ * ALLOCATION: Deletes one operand descriptor -- other remains on stack
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_dyadic2_r (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OBJECT_INTERNAL **return_desc)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc = NULL;
+ ACPI_OBJECT_INTERNAL *obj_desc2 = NULL;
+ ACPI_OBJECT_INTERNAL *res_desc = NULL;
+ ACPI_OBJECT_INTERNAL *res_desc2 = NULL;
+ ACPI_OBJECT_INTERNAL *ret_desc = NULL;
+ ACPI_OBJECT_INTERNAL *ret_desc2 = NULL;
+ ACPI_STATUS status = AE_OK;
+ u32 remainder;
+ s32 num_operands = 3;
+ char *new_buf;
+
+
+ /* Resolve all operands */
+
+ status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS);
+ /* Get all operands */
+
+ if (AML_DIVIDE_OP == opcode) {
+ num_operands = 4;
+ status |= acpi_ds_obj_stack_pop_object (&res_desc2, walk_state);
+ }
+
+ status |= acpi_ds_obj_stack_pop_object (&res_desc, walk_state);
+ status |= acpi_ds_obj_stack_pop_object (&obj_desc2, walk_state);
+ status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state);
+ if (status != AE_OK) {
+ acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, opcode,
+ &(walk_state->operands [walk_state->num_operands -1]),
+ num_operands);
+ goto cleanup;
+ }
+
+
+ /* Create an internal return object if necessary */
+
+ switch (opcode)
+ {
+ case AML_ADD_OP:
+ case AML_BIT_AND_OP:
+ case AML_BIT_NAND_OP:
+ case AML_BIT_OR_OP:
+ case AML_BIT_NOR_OP:
+ case AML_BIT_XOR_OP:
+ case AML_DIVIDE_OP:
+ case AML_MULTIPLY_OP:
+ case AML_SHIFT_LEFT_OP:
+ case AML_SHIFT_RIGHT_OP:
+ case AML_SUBTRACT_OP:
+
+ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER);
+ if (!ret_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ break;
+ }
+
+
+ /*
+ * Execute the opcode
+ */
+
+ switch (opcode)
+ {
+
+ /* Def_add := Add_op Operand1 Operand2 Result */
+
+ case AML_ADD_OP:
+
+ ret_desc->number.value = obj_desc->number.value +
+ obj_desc2->number.value;
+ break;
+
+
+ /* Def_and := And_op Operand1 Operand2 Result */
+
+ case AML_BIT_AND_OP:
+
+ ret_desc->number.value = obj_desc->number.value &
+ obj_desc2->number.value;
+ break;
+
+
+ /* Def_nAnd := NAnd_op Operand1 Operand2 Result */
+
+ case AML_BIT_NAND_OP:
+
+ ret_desc->number.value = ~(obj_desc->number.value &
+ obj_desc2->number.value);
+ break;
+
+
+ /* Def_or := Or_op Operand1 Operand2 Result */
+
+ case AML_BIT_OR_OP:
+
+ ret_desc->number.value = obj_desc->number.value |
+ obj_desc2->number.value;
+ break;
+
+
+ /* Def_nOr := NOr_op Operand1 Operand2 Result */
+
+ case AML_BIT_NOR_OP:
+
+ ret_desc->number.value = ~(obj_desc->number.value |
+ obj_desc2->number.value);
+ break;
+
+
+ /* Def_xOr := XOr_op Operand1 Operand2 Result */
+
+ case AML_BIT_XOR_OP:
+
+ ret_desc->number.value = obj_desc->number.value ^
+ obj_desc2->number.value;
+ break;
+
+
+ /* Def_divide := Divide_op Dividend Divisor Remainder Quotient */
+
+ case AML_DIVIDE_OP:
+
+ if ((u32) 0 == obj_desc2->number.value) {
+ REPORT_ERROR ("Aml_exec_dyadic2_r/Divide_op: Divide by zero");
+
+ status = AE_AML_DIVIDE_BY_ZERO;
+ goto cleanup;
+ }
+
+ ret_desc2 = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER);
+ if (!ret_desc2) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ remainder = obj_desc->number.value %
+ obj_desc2->number.value;
+ ret_desc->number.value = remainder;
+
+ /* Result (what we used to call the quotient) */
+
+ ret_desc2->number.value = obj_desc->number.value /
+ obj_desc2->number.value;
+ break;
+
+
+ /* Def_multiply := Multiply_op Operand1 Operand2 Result */
+
+ case AML_MULTIPLY_OP:
+
+ ret_desc->number.value = obj_desc->number.value *
+ obj_desc2->number.value;
+ break;
+
+
+ /* Def_shift_left := Shift_left_op Operand Shift_count Result */
+
+ case AML_SHIFT_LEFT_OP:
+
+ ret_desc->number.value = obj_desc->number.value <<
+ obj_desc2->number.value;
+ break;
+
+
+ /* Def_shift_right := Shift_right_op Operand Shift_count Result */
+
+ case AML_SHIFT_RIGHT_OP:
+
+ ret_desc->number.value = obj_desc->number.value >>
+ obj_desc2->number.value;
+ break;
+
+
+ /* Def_subtract := Subtract_op Operand1 Operand2 Result */
+
+ case AML_SUBTRACT_OP:
+
+ ret_desc->number.value = obj_desc->number.value -
+ obj_desc2->number.value;
+ break;
+
+
+ /* Def_concat := Concat_op Data1 Data2 Result */
+
+ case AML_CONCAT_OP:
+
+ if (obj_desc2->common.type != obj_desc->common.type) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+ /* Both operands are now known to be the same */
+
+ if (ACPI_TYPE_STRING == obj_desc->common.type) {
+ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_STRING);
+ if (!ret_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Operand1 is string */
+
+ new_buf = acpi_cm_allocate (obj_desc->string.length +
+ obj_desc2->string.length + 1);
+ if (!new_buf) {
+ REPORT_ERROR
+ ("Aml_exec_dyadic2_r/Concat_op: String allocation failure");
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ STRCPY (new_buf, (char *) obj_desc->string.pointer);
+ STRCPY (new_buf + obj_desc->string.length,
+ (char *) obj_desc2->string.pointer);
+
+ /* Point the return object to the new string */
+
+ ret_desc->string.pointer = new_buf;
+ ret_desc->string.length = obj_desc->string.length +=
+ obj_desc2->string.length;
+ }
+
+ else {
+ /* Operand1 is not a string ==> must be a buffer */
+
+ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_BUFFER);
+ if (!ret_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ new_buf = acpi_cm_allocate (obj_desc->buffer.length +
+ obj_desc2->buffer.length);
+ if (!new_buf) {
+ /* Only bail out if the buffer is small */
+
+ /* TBD: [Investigate] what is the point of this code? */
+
+ if (obj_desc->buffer.length + obj_desc2->buffer.length < 1024) {
+ REPORT_ERROR
+ ("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure");
+ return (AE_NO_MEMORY);
+ }
+
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ MEMCPY (new_buf, obj_desc->buffer.pointer,
+ obj_desc->buffer.length);
+ MEMCPY (new_buf + obj_desc->buffer.length, obj_desc2->buffer.pointer,
+ obj_desc2->buffer.length);
+
+ /*
+ * Point the return object to the new buffer
+ */
+
+ ret_desc->buffer.pointer = (u8 *) new_buf;
+ ret_desc->buffer.length = obj_desc->buffer.length +
+ obj_desc2->buffer.length;
+ }
+ break;
+
+
+ default:
+
+ status = AE_AML_BAD_OPCODE;
+ goto cleanup;
+ }
+
+
+ /*
+ * Store the result of the operation (which is now in Obj_desc) into
+ * the result descriptor, or the location pointed to by the result
+ * descriptor (Res_desc).
+ */
+
+ if ((status = acpi_aml_exec_store (ret_desc, res_desc)) != AE_OK) {
+ goto cleanup;
+ }
+
+ if (AML_DIVIDE_OP == opcode) {
+ status = acpi_aml_exec_store (ret_desc2, res_desc2);
+
+ /*
+ * Since the remainder is not returned, remove a reference to
+ * the object we created earlier
+ */
+
+ acpi_cm_remove_reference (ret_desc2);
+ }
+
+
+cleanup:
+
+ /* Always delete the operands */
+
+ acpi_cm_remove_reference (obj_desc);
+ acpi_cm_remove_reference (obj_desc2);
+
+
+ /* Delete return object on error */
+
+ if (ACPI_FAILURE (status)) {
+ /* On failure, delete the result ops */
+
+ acpi_cm_remove_reference (res_desc);
+ acpi_cm_remove_reference (res_desc2);
+
+ if (ret_desc) {
+ /* And delete the internal return object */
+
+ acpi_cm_remove_reference (ret_desc);
+ ret_desc = NULL;
+ }
+ }
+
+ /* Set the return object and exit */
+
+ *return_desc = ret_desc;
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_dyadic2_s
+ *
+ * PARAMETERS: Opcode - The opcode to be executed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute Type 2 dyadic synchronization operator
+ *
+ * ALLOCATION: Deletes one operand descriptor -- other remains on stack
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_dyadic2_s (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OBJECT_INTERNAL **return_desc)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_OBJECT_INTERNAL *time_desc;
+ ACPI_OBJECT_INTERNAL *ret_desc = NULL;
+ ACPI_STATUS status;
+
+
+ /* Resolve all operands */
+
+ status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS);
+ /* Get all operands */
+
+ status |= acpi_ds_obj_stack_pop_object (&time_desc, walk_state);
+ status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state);
+ if (status != AE_OK) {
+ /* Invalid parameters on object stack */
+
+ acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, opcode,
+ WALK_OPERANDS, 2);
+ goto cleanup;
+ }
+
+
+ /* Create the internal return object */
+
+ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER);
+ if (!ret_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Default return value is FALSE, operation did not time out */
+
+ ret_desc->number.value = 0;
+
+
+ /* Examine the opcode */
+
+ switch (opcode)
+ {
+
+ /* Def_acquire := Acquire_op Mutex_object Timeout */
+
+ case AML_ACQUIRE_OP:
+
+ status = acpi_aml_system_acquire_mutex (time_desc, obj_desc);
+ break;
+
+
+ /* Def_wait := Wait_op Acpi_event_object Timeout */
+
+ case AML_WAIT_OP:
+
+ status = acpi_aml_system_wait_event (time_desc, obj_desc);
+ break;
+
+
+ default:
+
+ status = AE_AML_BAD_OPCODE;
+ goto cleanup;
+ }
+
+
+ /*
+ * Return a boolean indicating if operation timed out
+ * (TRUE) or not (FALSE)
+ */
+
+ if (status == AE_TIME) {
+ ret_desc->number.value = (u32)(-1); /* TRUE, op timed out */
+ status = AE_OK;
+ }
+
+
+cleanup:
+
+ /* Delete params */
+
+ acpi_cm_remove_reference (time_desc);
+ acpi_cm_remove_reference (obj_desc);
+
+ /* Delete return object on error */
+
+ if (ACPI_FAILURE (status) &&
+ (ret_desc))
+ {
+ acpi_cm_remove_reference (ret_desc);
+ ret_desc = NULL;
+ }
+
+
+ /* Set the return object and exit */
+
+ *return_desc = ret_desc;
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_dyadic2
+ *
+ * PARAMETERS: Opcode - The opcode to be executed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute Type 2 dyadic operator with numeric operands and
+ * no result operands
+ *
+ * ALLOCATION: Deletes one operand descriptor -- other remains on stack
+ * containing result value
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_dyadic2 (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OBJECT_INTERNAL **return_desc)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_OBJECT_INTERNAL *obj_desc2;
+ ACPI_OBJECT_INTERNAL *ret_desc = NULL;
+ ACPI_STATUS status;
+ u8 lboolean;
+
+
+ /* Resolve all operands */
+
+ status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS);
+ /* Get all operands */
+
+ status |= acpi_ds_obj_stack_pop_object (&obj_desc2, walk_state);
+ status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state);
+ if (status != AE_OK) {
+ /* Invalid parameters on object stack */
+
+ acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, opcode,
+ WALK_OPERANDS, 2);
+ goto cleanup;
+ }
+
+
+ /* Create the internal return object */
+
+ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER);
+ if (!ret_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * Execute the Opcode
+ */
+
+ lboolean = FALSE;
+ switch (opcode)
+ {
+
+ /* Def_lAnd := LAnd_op Operand1 Operand2 */
+
+ case AML_LAND_OP:
+
+ lboolean = (u8) (obj_desc->number.value &&
+ obj_desc2->number.value);
+ break;
+
+
+ /* Def_lEqual := LEqual_op Operand1 Operand2 */
+
+ case AML_LEQUAL_OP:
+
+ lboolean = (u8) (obj_desc->number.value ==
+ obj_desc2->number.value);
+ break;
+
+
+ /* Def_lGreater := LGreater_op Operand1 Operand2 */
+
+ case AML_LGREATER_OP:
+
+ lboolean = (u8) (obj_desc->number.value >
+ obj_desc2->number.value);
+ break;
+
+
+ /* Def_lLess := LLess_op Operand1 Operand2 */
+
+ case AML_LLESS_OP:
+
+ lboolean = (u8) (obj_desc->number.value <
+ obj_desc2->number.value);
+ break;
+
+
+ /* Def_lOr := LOr_op Operand1 Operand2 */
+
+ case AML_LOR_OP:
+
+ lboolean = (u8) (obj_desc->number.value ||
+ obj_desc2->number.value);
+ break;
+
+
+ default:
+
+ status = AE_AML_BAD_OPCODE;
+ goto cleanup;
+ break;
+ }
+
+
+ /* Set return value to logical TRUE (all ones) or FALSE (zero) */
+
+ if (lboolean) {
+ ret_desc->number.value = 0xffffffff;
+ }
+ else {
+ ret_desc->number.value = 0;
+ }
+
+
+cleanup:
+
+ /* Always delete operands */
+
+ acpi_cm_remove_reference (obj_desc);
+ acpi_cm_remove_reference (obj_desc2);
+
+
+ /* Delete return object on error */
+
+ if (ACPI_FAILURE (status) &&
+ (ret_desc))
+ {
+ acpi_cm_remove_reference (ret_desc);
+ ret_desc = NULL;
+ }
+
+
+ /* Set the return object and exit */
+
+ *return_desc = ret_desc;
+ return (status);
+}
+
+
diff --git a/drivers/acpi/interpreter/amfield.c b/drivers/acpi/interpreter/amfield.c
new file mode 100644
index 000000000..c77593854
--- /dev/null
+++ b/drivers/acpi/interpreter/amfield.c
@@ -0,0 +1,327 @@
+/******************************************************************************
+ *
+ * Module Name: amfield - ACPI AML (p-code) execution - field manipulation
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "dispatch.h"
+#include "interp.h"
+#include "amlcode.h"
+#include "namesp.h"
+#include "hardware.h"
+#include "events.h"
+
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("amfield");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_setup_field
+ *
+ * PARAMETERS: *Obj_desc - Field to be read or written
+ * *Rgn_desc - Region containing field
+ * Field_bit_width - Field Width in bits (8, 16, or 32)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Common processing for Acpi_aml_read_field and Acpi_aml_write_field
+ *
+ * ACPI SPECIFICATION REFERENCES:
+ * Each of the Type1_opcodes is defined as specified in in-line
+ * comments below. For each one, use the following definitions.
+ *
+ * Def_bit_field := Bit_field_op Src_buf Bit_idx Destination
+ * Def_byte_field := Byte_field_op Src_buf Byte_idx Destination
+ * Def_create_field := Create_field_op Src_buf Bit_idx Num_bits Name_string
+ * Def_dWord_field := DWord_field_op Src_buf Byte_idx Destination
+ * Def_word_field := Word_field_op Src_buf Byte_idx Destination
+ * Bit_index := Term_arg=>Integer
+ * Byte_index := Term_arg=>Integer
+ * Destination := Name_string
+ * Num_bits := Term_arg=>Integer
+ * Source_buf := Term_arg=>Buffer
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_setup_field (
+ ACPI_OBJECT_INTERNAL *obj_desc,
+ ACPI_OBJECT_INTERNAL *rgn_desc,
+ s32 field_bit_width)
+{
+ ACPI_STATUS status = AE_OK;
+ s32 field_byte_width;
+
+
+ /* Parameter validation */
+
+ if (!obj_desc || !rgn_desc) {
+ return (AE_AML_NO_OPERAND);
+ }
+
+ if (ACPI_TYPE_REGION != rgn_desc->common.type) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+
+ /*
+ * Init and validate Field width
+ * Possible values are 1, 2, 4
+ */
+
+ field_byte_width = DIV_8 (field_bit_width);
+
+ if ((field_bit_width != 8) &&
+ (field_bit_width != 16) &&
+ (field_bit_width != 32))
+ {
+ return (AE_AML_OPERAND_VALUE);
+ }
+
+
+ /*
+ * If the address and length have not been previously evaluated,
+ * evaluate them and save the results.
+ */
+ if (!(rgn_desc->region.region_flags & REGION_AGRUMENT_DATA_VALID)) {
+
+ status = acpi_ds_get_region_arguments (rgn_desc);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+
+ /*
+ * If (offset rounded up to next multiple of field width)
+ * exceeds region length, indicate an error.
+ */
+
+ if (rgn_desc->region.length <
+ (obj_desc->field.offset & ~((u32) field_byte_width - 1)) +
+ field_byte_width)
+ {
+ /*
+ * Offset rounded up to next multiple of field width
+ * exceeds region length, indicate an error
+ */
+
+ return (AE_AML_REGION_LIMIT);
+ }
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_access_named_field
+ *
+ * PARAMETERS: Mode - ACPI_READ or ACPI_WRITE
+ * Named_field - Handle for field to be accessed
+ * *Buffer - Value(s) to be read or written
+ * Buffer_length - Number of bytes to transfer
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Read or write a named field
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_access_named_field (
+ s32 mode,
+ ACPI_HANDLE named_field,
+ void *buffer,
+ u32 buffer_length)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc = NULL;
+ ACPI_STATUS status = AE_OK;
+ u8 locked = FALSE;
+ u32 bit_granularity = 0;
+ u32 byte_granularity;
+ u32 datum_length;
+ u32 actual_byte_length;
+ u32 byte_field_length;
+
+
+ /* Get the attached field object */
+
+ obj_desc = acpi_ns_get_attached_object (named_field);
+ if (!obj_desc) {
+ return (AE_AML_INTERNAL);
+ }
+
+ /* Check the type */
+
+ if (INTERNAL_TYPE_DEF_FIELD != acpi_ns_get_type (named_field)) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ /* Obj_desc valid and Named_field is a defined field */
+
+
+ /* Double-check that the attached object is also a field */
+
+ if (INTERNAL_TYPE_DEF_FIELD != obj_desc->common.type) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+
+ /*
+ * Granularity was decoded from the field access type
+ * (Any_acc will be the same as Byte_acc)
+ */
+
+ bit_granularity = obj_desc->field_unit.granularity;
+ byte_granularity = DIV_8 (bit_granularity);
+
+ /*
+ * Check if request is too large for the field, and silently truncate
+ * if necessary
+ */
+
+ /* TBD: [Errors] should an error be returned in this case? */
+
+ byte_field_length = (u32) DIV_8 (obj_desc->field_unit.length + 7);
+
+
+ actual_byte_length = buffer_length;
+ if (buffer_length > byte_field_length) {
+ actual_byte_length = byte_field_length;
+
+ }
+
+
+ /* Convert byte count to datum count, round up if necessary */
+
+ datum_length = (actual_byte_length + (byte_granularity-1)) / byte_granularity;
+
+
+ /* Get the global lock if needed */
+
+ locked = acpi_aml_acquire_global_lock (obj_desc->field_unit.lock_rule);
+
+
+ /* Perform the actual read or write of the buffer */
+
+ switch (mode)
+ {
+ case ACPI_READ:
+
+ status = acpi_aml_read_field (obj_desc, buffer, buffer_length,
+ actual_byte_length, datum_length,
+ bit_granularity, byte_granularity);
+ break;
+
+
+ case ACPI_WRITE:
+
+ status = acpi_aml_write_field (obj_desc, buffer, buffer_length,
+ actual_byte_length, datum_length,
+ bit_granularity, byte_granularity);
+ break;
+
+
+ default:
+
+ status = AE_BAD_PARAMETER;
+ break;
+ }
+
+
+ /* Release global lock if we acquired it earlier */
+
+ acpi_aml_release_global_lock (locked);
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_set_named_field_value
+ *
+ * PARAMETERS: Named_field - Handle for field to be set
+ * Buffer - Bytes to be stored
+ * Buffer_length - Number of bytes to be stored
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Store the given value into the field
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_set_named_field_value (
+ ACPI_HANDLE named_field,
+ void *buffer,
+ u32 buffer_length)
+{
+ ACPI_STATUS status;
+
+
+ if (!named_field) {
+ return (AE_AML_INTERNAL);
+ }
+
+ status = acpi_aml_access_named_field (ACPI_WRITE, named_field, buffer,
+ buffer_length);
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_get_named_field_value
+ *
+ * PARAMETERS: Named_field - Handle for field to be read
+ * *Buffer - Where to store value read from field
+ * Buffer_length - Max length to read
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieve the value of the given field
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_get_named_field_value (
+ ACPI_HANDLE named_field,
+ void *buffer,
+ u32 buffer_length)
+{
+ ACPI_STATUS status;
+
+
+ if ((!named_field) || (!buffer)) {
+ return (AE_AML_INTERNAL);
+ }
+
+ status = acpi_aml_access_named_field (ACPI_READ, named_field, buffer,
+ buffer_length);
+ return (status);
+}
+
diff --git a/drivers/acpi/interpreter/amfldio.c b/drivers/acpi/interpreter/amfldio.c
new file mode 100644
index 000000000..bde4d5f12
--- /dev/null
+++ b/drivers/acpi/interpreter/amfldio.c
@@ -0,0 +1,654 @@
+/******************************************************************************
+ *
+ * Module Name: amfldio - Aml Field I/O
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "interp.h"
+#include "amlcode.h"
+#include "namesp.h"
+#include "hardware.h"
+#include "events.h"
+
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("amfldio");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_read_field_data
+ *
+ * PARAMETERS: *Obj_desc - Field to be read
+ * *Value - Where to store value
+ * Field_bit_width - Field Width in bits (8, 16, or 32)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieve the value of the given field
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_read_field_data (
+ ACPI_OBJECT_INTERNAL *obj_desc,
+ u32 field_byte_offset,
+ u32 field_bit_width,
+ u32 *value)
+{
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL *rgn_desc = NULL;
+ u32 address;
+ u32 local_value = 0;
+ s32 field_byte_width;
+
+
+ /* Obj_desc is validated by callers */
+
+ if (obj_desc) {
+ rgn_desc = obj_desc->field.container;
+ }
+
+
+ field_byte_width = DIV_8 (field_bit_width);
+ status = acpi_aml_setup_field (obj_desc, rgn_desc, field_bit_width);
+ if (AE_OK != status) {
+ return (status);
+ }
+
+ /* Setup_field validated Rgn_desc and Field_bit_width */
+
+ if (!value) {
+ value = &local_value; /* support reads without saving value */
+ }
+
+
+ /*
+ * Round offset down to next multiple of
+ * field width, add region base address and offset within the field
+ */
+
+ address = rgn_desc->region.address +
+ (obj_desc->field.offset & ~((u32) field_byte_width - 1)) +
+ field_byte_offset;
+
+
+
+
+ /* Invoke the appropriate Address_space/Op_region handler */
+
+ status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_READ,
+ address, field_bit_width, value);
+
+
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_read_field
+ *
+ * PARAMETERS: *Obj_desc - Field to be read
+ * *Value - Where to store value
+ * Field_bit_width - Field Width in bits (8, 16, or 32)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieve the value of the given field
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_read_field (
+ ACPI_OBJECT_INTERNAL *obj_desc,
+ void *buffer,
+ u32 buffer_length,
+ u32 byte_length,
+ u32 datum_length,
+ u32 bit_granularity,
+ u32 byte_granularity)
+{
+ ACPI_STATUS status;
+ u32 this_field_byte_offset;
+ u32 this_field_datum_offset;
+ u32 previous_raw_datum;
+ u32 this_raw_datum;
+ u32 valid_field_bits;
+ u32 mask;
+ u32 merged_datum = 0;
+
+
+ /*
+ * Clear the caller's buffer (the whole buffer length as given)
+ * This is very important, especially in the cases where a byte is read,
+ * but the buffer is really a u32 (4 bytes).
+ */
+
+ MEMSET (buffer, 0, buffer_length);
+
+ /* Read the first raw datum to prime the loop */
+
+ this_field_byte_offset = 0;
+ this_field_datum_offset= 0;
+
+ status = acpi_aml_read_field_data (obj_desc, this_field_byte_offset, bit_granularity,
+ &previous_raw_datum);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* We might actually be done if the request fits in one datum */
+
+ if ((datum_length == 1) &&
+ ((obj_desc->field.bit_offset + obj_desc->field_unit.length) <=
+ (u16) bit_granularity))
+ {
+ merged_datum = previous_raw_datum;
+
+ merged_datum = (merged_datum >> obj_desc->field.bit_offset);
+
+ valid_field_bits = obj_desc->field_unit.length % bit_granularity;
+ if (valid_field_bits) {
+ mask = (((u32) 1 << valid_field_bits) - (u32) 1);
+ merged_datum &= mask;
+ }
+
+
+ /*
+ * Place the Merged_datum into the proper format and return buffer
+ * field
+ */
+
+ switch (byte_granularity)
+ {
+ case 1:
+ ((u8 *) buffer) [this_field_datum_offset] = (u8) merged_datum;
+ break;
+
+ case 2:
+ MOVE_UNALIGNED16_TO_16 (&(((u16 *) buffer)[this_field_datum_offset]), &merged_datum);
+ break;
+
+ case 4:
+ MOVE_UNALIGNED32_TO_32 (&(((u32 *) buffer)[this_field_datum_offset]), &merged_datum);
+ break;
+ }
+
+ this_field_byte_offset = 1;
+ this_field_datum_offset = 1;
+ }
+
+ else {
+ /* We need to get more raw data to complete one or more field data */
+
+ while (this_field_datum_offset < datum_length) {
+ /*
+ * Get the next raw datum, it contains bits of the current
+ * field datum
+ */
+
+ status = acpi_aml_read_field_data (obj_desc,
+ this_field_byte_offset + byte_granularity,
+ bit_granularity, &this_raw_datum);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Before merging the data, make sure the unused bits are clear */
+
+ switch (byte_granularity)
+ {
+ case 1:
+ this_raw_datum &= 0x000000FF;
+ previous_raw_datum &= 0x000000FF;
+ break;
+
+ case 2:
+ this_raw_datum &= 0x0000FFFF;
+ previous_raw_datum &= 0x0000FFFF;
+ break;
+ }
+
+ /*
+ * Put together bits of the two raw data to make a complete
+ * field datum
+ */
+
+ if (obj_desc->field.bit_offset != 0) {
+ merged_datum =
+ (previous_raw_datum >> obj_desc->field.bit_offset) |
+ (this_raw_datum << (bit_granularity - obj_desc->field.bit_offset));
+ }
+
+ else {
+ merged_datum = previous_raw_datum;
+ }
+
+ /*
+ * Now store the datum in the caller's buffer, according to
+ * the data type
+ */
+
+ switch (byte_granularity)
+ {
+ case 1:
+ ((u8 *) buffer) [this_field_datum_offset] = (u8) merged_datum;
+ break;
+
+ case 2:
+ MOVE_UNALIGNED16_TO_16 (&(((u16 *) buffer) [this_field_datum_offset]), &merged_datum);
+ break;
+
+ case 4:
+ MOVE_UNALIGNED32_TO_32 (&(((u32 *) buffer) [this_field_datum_offset]), &merged_datum);
+ break;
+ }
+
+
+ /*
+ * Save the most recent datum since it contains bits of
+ * the *next* field datum
+ */
+
+ previous_raw_datum = this_raw_datum;
+
+ this_field_byte_offset += byte_granularity;
+ this_field_datum_offset++;
+
+ } /* while */
+ }
+
+cleanup:
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_write_field_data
+ *
+ * PARAMETERS: *Obj_desc - Field to be set
+ * Value - Value to store
+ * Field_bit_width - Field Width in bits (8, 16, or 32)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Store the value into the given field
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_write_field_data (
+ ACPI_OBJECT_INTERNAL *obj_desc,
+ u32 field_byte_offset,
+ u32 field_bit_width,
+ u32 value)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_OBJECT_INTERNAL *rgn_desc = NULL;
+ u32 address;
+ s32 field_byte_width;
+
+
+ /* Obj_desc is validated by callers */
+
+ if (obj_desc) {
+ rgn_desc = obj_desc->field.container;
+ }
+
+ field_byte_width = DIV_8 (field_bit_width);
+ status = acpi_aml_setup_field (obj_desc, rgn_desc, field_bit_width);
+ if (AE_OK != status) {
+ return (status);
+ }
+
+
+ /*
+ * Round offset down to next multiple of
+ * field width, add region base address and offset within the field
+ */
+
+ address = rgn_desc->region.address +
+ (obj_desc->field.offset & ~((u32) field_byte_width - 1)) +
+ field_byte_offset;
+
+
+ /* Invoke the appropriate Address_space/Op_region handler */
+
+ status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_WRITE,
+ address, field_bit_width, &value);
+
+
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_aml_write_field_data_with_update_rule
+ *
+ * PARAMETERS: *Obj_desc - Field to be set
+ * Value - Value to store
+ * Field_bit_width - Field Width in bits (8, 16, or 32)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Apply the field update rule to a field write
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_aml_write_field_data_with_update_rule (
+ ACPI_OBJECT_INTERNAL *obj_desc,
+ u32 mask,
+ u32 field_value,
+ u32 this_field_byte_offset,
+ u32 bit_granularity)
+{
+ ACPI_STATUS status = AE_OK;
+ u32 merged_value;
+ u32 current_value;
+
+
+ /* Start with the new bits */
+
+ merged_value = field_value;
+
+ /* Check if update rule needs to be applied (not if mask is all ones) */
+
+
+ /* Decode the update rule */
+
+ switch (obj_desc->field.update_rule)
+ {
+
+ case UPDATE_PRESERVE:
+
+ /*
+ * Read the current contents of the byte/word/dword containing
+ * the field, and merge with the new field value.
+ */
+ status = acpi_aml_read_field_data (obj_desc, this_field_byte_offset,
+ bit_granularity, &current_value);
+ merged_value |= (current_value & ~mask);
+ break;
+
+
+ case UPDATE_WRITE_AS_ONES:
+
+ /* Set positions outside the field to all ones */
+
+ merged_value |= ~mask;
+ break;
+
+
+ case UPDATE_WRITE_AS_ZEROS:
+
+ /* Set positions outside the field to all zeros */
+
+ merged_value &= mask;
+ break;
+
+
+ default:
+ status = AE_AML_OPERAND_VALUE;
+ }
+
+
+ /* Write the merged value */
+
+ if (ACPI_SUCCESS (status)) {
+ status = acpi_aml_write_field_data (obj_desc, this_field_byte_offset,
+ bit_granularity, merged_value);
+ }
+
+ return status;
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_aml_write_field
+ *
+ * PARAMETERS: *Obj_desc - Field to be set
+ * Value - Value to store
+ * Field_bit_width - Field Width in bits (8, 16, or 32)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Store the value into the given field
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_aml_write_field (
+ ACPI_OBJECT_INTERNAL *obj_desc,
+ void *buffer,
+ u32 buffer_length,
+ u32 byte_length,
+ u32 datum_length,
+ u32 bit_granularity,
+ u32 byte_granularity)
+{
+ ACPI_STATUS status;
+ u32 this_field_byte_offset;
+ u32 this_field_datum_offset;
+ u32 mask;
+ u32 merged_datum;
+ u32 previous_raw_datum;
+ u32 this_raw_datum;
+ u32 field_value;
+ u32 valid_field_bits;
+
+
+ /*
+ * Break the request into up to three parts:
+ * non-aligned part at start, aligned part in middle, non-aligned part
+ * at end --- Just like an I/O request ---
+ */
+
+ this_field_byte_offset = 0;
+ this_field_datum_offset= 0;
+
+ /* Get a datum */
+
+ switch (byte_granularity)
+ {
+ case 1:
+ previous_raw_datum = ((u8 *) buffer) [this_field_datum_offset];
+ break;
+
+ case 2:
+ MOVE_UNALIGNED16_TO_32 (&previous_raw_datum, &(((u16 *) buffer) [this_field_datum_offset]));
+ break;
+
+ case 4:
+ MOVE_UNALIGNED32_TO_32 (&previous_raw_datum, &(((u32 *) buffer) [this_field_datum_offset]));
+ break;
+
+ default:
+ status = AE_AML_OPERAND_VALUE;
+ goto cleanup;
+ }
+
+
+ /*
+ * Write a partial field datum if field does not begin on a datum boundary
+ *
+ * Construct Mask with 1 bits where the field is, 0 bits elsewhere
+ *
+ * 1) Bits above the field
+ */
+
+ mask = (((u32)(-1)) << (u32)obj_desc->field.bit_offset);
+
+ /* 2) Only the bottom 5 bits are valid for a shift operation. */
+
+ if ((obj_desc->field.bit_offset + obj_desc->field_unit.length) < 32) {
+ /* Bits above the field */
+
+ mask &= (~(((u32)(-1)) << ((u32)obj_desc->field.bit_offset +
+ (u32)obj_desc->field_unit.length)));
+ }
+
+ /* 3) Shift and mask the value into the field position */
+
+ field_value = (previous_raw_datum << obj_desc->field.bit_offset) & mask;
+
+ status = acpi_aml_write_field_data_with_update_rule (obj_desc, mask, field_value,
+ this_field_byte_offset,
+ bit_granularity);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+
+ /* If the field fits within one datum, we are done. */
+
+ if ((datum_length == 1) &&
+ ((obj_desc->field.bit_offset + obj_desc->field_unit.length) <=
+ (u16) bit_granularity))
+ {
+ goto cleanup;
+ }
+
+ /*
+ * We don't need to worry about the update rule for these data, because
+ * all of the bits are part of the field.
+ *
+ * Can't write the last datum, however, because it might contain bits that
+ * are not part of the field -- the update rule must be applied.
+ */
+
+ while (this_field_datum_offset < (datum_length - 1)) {
+ this_field_datum_offset++;
+
+ /* Get the next raw datum, it contains bits of the current field datum... */
+
+ switch (byte_granularity)
+ {
+ case 1:
+ this_raw_datum = ((u8 *) buffer) [this_field_datum_offset];
+ break;
+
+ case 2:
+ MOVE_UNALIGNED16_TO_32 (&this_raw_datum, &(((u16 *) buffer) [this_field_datum_offset]));
+ break;
+
+ case 4:
+ MOVE_UNALIGNED32_TO_32 (&this_raw_datum, &(((u32 *) buffer) [this_field_datum_offset]));
+ break;
+
+ default:
+ status = AE_AML_OPERAND_VALUE;
+ goto cleanup;
+ }
+
+ /*
+ * Put together bits of the two raw data to make a complete field
+ * datum
+ */
+
+ if (obj_desc->field.bit_offset != 0) {
+ merged_datum =
+ (previous_raw_datum >> (bit_granularity - obj_desc->field.bit_offset)) |
+ (this_raw_datum << obj_desc->field.bit_offset);
+ }
+
+ else {
+ merged_datum = this_raw_datum;
+ }
+
+ /* Now write the completed datum */
+
+
+ status = acpi_aml_write_field_data (obj_desc,
+ this_field_byte_offset + byte_granularity,
+ bit_granularity, merged_datum);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+
+ /*
+ * Save the most recent datum since it contains bits of
+ * the *next* field datum
+ */
+
+ previous_raw_datum = this_raw_datum;
+
+ this_field_byte_offset += byte_granularity;
+
+ } /* while */
+
+
+ /* Write a partial field datum if field does not end on a datum boundary */
+
+ if ((obj_desc->field_unit.length + obj_desc->field_unit.bit_offset) %
+ bit_granularity)
+ {
+ switch (byte_granularity)
+ {
+ case 1:
+ this_raw_datum = ((u8 *) buffer) [this_field_datum_offset];
+ break;
+
+ case 2:
+ MOVE_UNALIGNED16_TO_32 (&this_raw_datum, &(((u16 *) buffer) [this_field_datum_offset]));
+ break;
+
+ case 4:
+ MOVE_UNALIGNED32_TO_32 (&this_raw_datum, &(((u32 *) buffer) [this_field_datum_offset]));
+ break;
+ }
+
+ /* Construct Mask with 1 bits where the field is, 0 bits elsewhere */
+
+ valid_field_bits = ((obj_desc->field_unit.length % bit_granularity) +
+ obj_desc->field.bit_offset);
+
+ mask = (((u32) 1 << valid_field_bits) - (u32) 1);
+
+ /* Shift and mask the value into the field position */
+
+ field_value = (previous_raw_datum >>
+ (bit_granularity - obj_desc->field.bit_offset)) & mask;
+
+ status = acpi_aml_write_field_data_with_update_rule (obj_desc, mask, field_value, this_field_byte_offset + 1,
+ bit_granularity);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+ }
+
+
+cleanup:
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/interpreter/ammisc.c b/drivers/acpi/interpreter/ammisc.c
new file mode 100644
index 000000000..cc5d24c9e
--- /dev/null
+++ b/drivers/acpi/interpreter/ammisc.c
@@ -0,0 +1,533 @@
+
+/******************************************************************************
+ *
+ * Module Name: ammisc - ACPI AML (p-code) execution - specific opcodes
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "interp.h"
+#include "amlcode.h"
+#include "dispatch.h"
+
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("ammisc");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_fatal
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: Status. If the OS returns from the OSD call, we just keep
+ * on going.
+ *
+ * DESCRIPTION: Execute Fatal operator
+ *
+ * ACPI SPECIFICATION REFERENCES:
+ * Def_fatal := Fatal_op Fatal_type Fatal_code Fatal_arg
+ * Fatal_type := Byte_data
+ * Fatal_code := DWord_data
+ * Fatal_arg := Term_arg=>Integer
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_fatal (
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_OBJECT_INTERNAL *type_desc;
+ ACPI_OBJECT_INTERNAL *code_desc;
+ ACPI_OBJECT_INTERNAL *arg_desc;
+ ACPI_STATUS status;
+
+
+ /* Resolve operands */
+
+ status = acpi_aml_resolve_operands (AML_FATAL_OP, WALK_OPERANDS);
+ /* Get operands */
+
+ status |= acpi_ds_obj_stack_pop_object (&arg_desc, walk_state);
+ status |= acpi_ds_obj_stack_pop_object (&code_desc, walk_state);
+ status |= acpi_ds_obj_stack_pop_object (&type_desc, walk_state);
+ if (status != AE_OK) {
+ /* invalid parameters on object stack */
+
+ acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__,
+ (u16) AML_FATAL_OP, WALK_OPERANDS, 3);
+ goto cleanup;
+ }
+
+
+ /* Def_fatal := Fatal_op Fatal_type Fatal_code Fatal_arg */
+
+
+ /*
+ * TBD: [Unhandled] call OSD interface to notify OS of fatal error
+ * requiring shutdown!
+ */
+
+
+cleanup:
+
+ /* Free the operands */
+
+ acpi_cm_remove_reference (arg_desc);
+ acpi_cm_remove_reference (code_desc);
+ acpi_cm_remove_reference (type_desc);
+
+
+ /* If we get back from the OS call, we might as well keep going. */
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_index
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute Index operator
+ *
+ * ALLOCATION: Deletes one operand descriptor -- other remains on stack
+ *
+ * ACPI SPECIFICATION REFERENCES:
+ * Def_index := Index_op Buff_pkg_obj Index_value Result
+ * Index_value := Term_arg=>Integer
+ * Name_string := <Root_char Name_path> | <Prefix_path Name_path>
+ * Result := Super_name
+ * Super_name := Name_string | Arg_obj | Local_obj | Debug_obj | Def_index
+ * Local4_op | Local5_op | Local6_op | Local7_op
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_index (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OBJECT_INTERNAL **return_desc)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_OBJECT_INTERNAL *idx_desc;
+ ACPI_OBJECT_INTERNAL *res_desc;
+ ACPI_OBJECT_INTERNAL *ret_desc = NULL;
+ ACPI_OBJECT_INTERNAL *tmp_desc;
+ ACPI_STATUS status;
+
+
+ /* Resolve operands */
+ /* First operand can be either a package or a buffer */
+
+ status = acpi_aml_resolve_operands (AML_INDEX_OP, WALK_OPERANDS);
+ /* Get all operands */
+
+ status |= acpi_ds_obj_stack_pop_object (&res_desc, walk_state);
+ status |= acpi_ds_obj_stack_pop_object (&idx_desc, walk_state);
+ status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state);
+ if (status != AE_OK) {
+ /* Invalid parameters on object stack */
+
+ acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__,
+ (u16) AML_INDEX_OP, WALK_OPERANDS, 3);
+ goto cleanup;
+ }
+
+
+ /* Create the internal return object */
+
+ ret_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REFERENCE);
+ if (!ret_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+
+ /*
+ * At this point, the Obj_desc operand is either a Package or a Buffer
+ */
+
+ if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
+ /* Object to be indexed is a Package */
+
+ if (idx_desc->number.value >= obj_desc->package.count) {
+ status = AE_AML_PACKAGE_LIMIT;
+ goto cleanup;
+ }
+
+ if ((res_desc->common.type == INTERNAL_TYPE_REFERENCE) &&
+ (res_desc->reference.op_code == AML_ZERO_OP))
+ {
+ /*
+ * There is no actual result descriptor (the Zero_op Result
+ * descriptor is a placeholder), so just delete the placeholder and
+ * return a reference to the package element
+ */
+
+ acpi_cm_remove_reference (res_desc);
+ }
+
+ else {
+ /*
+ * Each element of the package is an internal object. Get the one
+ * we are after.
+ */
+
+ tmp_desc = obj_desc->package.elements[idx_desc->number.value];
+ ret_desc->reference.op_code = AML_INDEX_OP;
+ ret_desc->reference.target_type = tmp_desc->common.type;
+ ret_desc->reference.object = tmp_desc;
+
+ status = acpi_aml_exec_store (ret_desc, res_desc);
+ ret_desc->reference.object = NULL;
+ }
+
+ /*
+ * The local return object must always be a reference to the package element,
+ * not the element itself.
+ */
+ ret_desc->reference.op_code = AML_INDEX_OP;
+ ret_desc->reference.target_type = ACPI_TYPE_PACKAGE;
+ ret_desc->reference.where = &obj_desc->package.elements[idx_desc->number.value];
+ }
+
+ else {
+ /* Object to be indexed is a Buffer */
+
+ if (idx_desc->number.value >= obj_desc->buffer.length) {
+ status = AE_AML_BUFFER_LIMIT;
+ goto cleanup;
+ }
+
+ ret_desc->reference.op_code = AML_INDEX_OP;
+ ret_desc->reference.target_type = ACPI_TYPE_BUFFER_FIELD;
+ ret_desc->reference.object = obj_desc;
+ ret_desc->reference.offset = idx_desc->number.value;
+
+ status = acpi_aml_exec_store (ret_desc, res_desc);
+ }
+
+
+cleanup:
+
+ /* Always delete operands */
+
+ acpi_cm_remove_reference (obj_desc);
+ acpi_cm_remove_reference (idx_desc);
+
+ /* Delete return object on error */
+
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_remove_reference (res_desc);
+
+ if (ret_desc) {
+ acpi_cm_remove_reference (ret_desc);
+ ret_desc = NULL;
+ }
+ }
+
+ /* Set the return object and exit */
+
+ *return_desc = ret_desc;
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_match
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute Match operator
+ *
+ * ACPI SPECIFICATION REFERENCES:
+ * Def_match := Match_op Search_pkg Opcode1 Operand1
+ * Opcode2 Operand2 Start_index
+ * Opcode1 := Byte_data: MTR, MEQ, MLE, MLT, MGE, or MGT
+ * Opcode2 := Byte_data: MTR, MEQ, MLE, MLT, MGE, or MGT
+ * Operand1 := Term_arg=>Integer
+ * Operand2 := Term_arg=>Integer
+ * Search_pkg := Term_arg=>Package_object
+ * Start_index := Term_arg=>Integer
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_match (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OBJECT_INTERNAL **return_desc)
+{
+ ACPI_OBJECT_INTERNAL *pkg_desc;
+ ACPI_OBJECT_INTERNAL *op1_desc;
+ ACPI_OBJECT_INTERNAL *V1_desc;
+ ACPI_OBJECT_INTERNAL *op2_desc;
+ ACPI_OBJECT_INTERNAL *V2_desc;
+ ACPI_OBJECT_INTERNAL *start_desc;
+ ACPI_OBJECT_INTERNAL *ret_desc = NULL;
+ ACPI_STATUS status;
+ u32 index;
+ u32 match_value = (u32) -1;
+
+
+ /* Resolve all operands */
+
+ status = acpi_aml_resolve_operands (AML_MATCH_OP, WALK_OPERANDS);
+ /* Get all operands */
+
+ status |= acpi_ds_obj_stack_pop_object (&start_desc, walk_state);
+ status |= acpi_ds_obj_stack_pop_object (&V2_desc, walk_state);
+ status |= acpi_ds_obj_stack_pop_object (&op2_desc, walk_state);
+ status |= acpi_ds_obj_stack_pop_object (&V1_desc, walk_state);
+ status |= acpi_ds_obj_stack_pop_object (&op1_desc, walk_state);
+ status |= acpi_ds_obj_stack_pop_object (&pkg_desc, walk_state);
+
+ if (status != AE_OK) {
+ /* Invalid parameters on object stack */
+
+ acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__,
+ (u16) AML_MATCH_OP, WALK_OPERANDS, 6);
+ goto cleanup;
+ }
+
+ /* Validate match comparison sub-opcodes */
+
+ if ((op1_desc->number.value > MAX_MATCH_OPERATOR) ||
+ (op2_desc->number.value > MAX_MATCH_OPERATOR))
+ {
+ status = AE_AML_OPERAND_VALUE;
+ goto cleanup;
+ }
+
+ index = start_desc->number.value;
+ if (index >= (u32) pkg_desc->package.count) {
+ status = AE_AML_PACKAGE_LIMIT;
+ goto cleanup;
+ }
+
+ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER);
+ if (!ret_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+
+ }
+
+ /*
+ * Examine each element until a match is found. Within the loop,
+ * "continue" signifies that the current element does not match
+ * and the next should be examined.
+ * Upon finding a match, the loop will terminate via "break" at
+ * the bottom. If it terminates "normally", Match_value will be -1
+ * (its initial value) indicating that no match was found. When
+ * returned as a Number, this will produce the Ones value as specified.
+ */
+
+ for ( ; index < pkg_desc->package.count; ++index) {
+ /*
+ * Treat any NULL or non-numeric elements as non-matching.
+ * TBD [Unhandled] - if an element is a Name,
+ * should we examine its value?
+ */
+ if (!pkg_desc->package.elements[index] ||
+ ACPI_TYPE_NUMBER != pkg_desc->package.elements[index]->common.type)
+ {
+ continue;
+ }
+
+ /*
+ * Within these switch statements:
+ * "break" (exit from the switch) signifies a match;
+ * "continue" (proceed to next iteration of enclosing
+ * "for" loop) signifies a non-match.
+ */
+ switch (op1_desc->number.value)
+ {
+
+ case MATCH_MTR: /* always true */
+
+ break;
+
+
+ case MATCH_MEQ: /* true if equal */
+
+ if (pkg_desc->package.elements[index]->number.value
+ != V1_desc->number.value)
+ {
+ continue;
+ }
+ break;
+
+
+ case MATCH_MLE: /* true if less than or equal */
+
+ if (pkg_desc->package.elements[index]->number.value
+ > V1_desc->number.value)
+ {
+ continue;
+ }
+ break;
+
+
+ case MATCH_MLT: /* true if less than */
+
+ if (pkg_desc->package.elements[index]->number.value
+ >= V1_desc->number.value)
+ {
+ continue;
+ }
+ break;
+
+
+ case MATCH_MGE: /* true if greater than or equal */
+
+ if (pkg_desc->package.elements[index]->number.value
+ < V1_desc->number.value)
+ {
+ continue;
+ }
+ break;
+
+
+ case MATCH_MGT: /* true if greater than */
+
+ if (pkg_desc->package.elements[index]->number.value
+ <= V1_desc->number.value)
+ {
+ continue;
+ }
+ break;
+
+
+ default: /* undefined */
+
+ continue;
+ }
+
+
+ switch(op2_desc->number.value)
+ {
+
+ case MATCH_MTR:
+
+ break;
+
+
+ case MATCH_MEQ:
+
+ if (pkg_desc->package.elements[index]->number.value
+ != V2_desc->number.value)
+ {
+ continue;
+ }
+ break;
+
+
+ case MATCH_MLE:
+
+ if (pkg_desc->package.elements[index]->number.value
+ > V2_desc->number.value)
+ {
+ continue;
+ }
+ break;
+
+
+ case MATCH_MLT:
+
+ if (pkg_desc->package.elements[index]->number.value
+ >= V2_desc->number.value)
+ {
+ continue;
+ }
+ break;
+
+
+ case MATCH_MGE:
+
+ if (pkg_desc->package.elements[index]->number.value
+ < V2_desc->number.value)
+ {
+ continue;
+ }
+ break;
+
+
+ case MATCH_MGT:
+
+ if (pkg_desc->package.elements[index]->number.value
+ <= V2_desc->number.value)
+ {
+ continue;
+ }
+ break;
+
+
+ default:
+
+ continue;
+ }
+
+ /* Match found: exit from loop */
+
+ match_value = index;
+ break;
+ }
+
+ /* Match_value is the return value */
+
+ ret_desc->number.value = match_value;
+
+
+cleanup:
+
+ /* Free the operands */
+
+ acpi_cm_remove_reference (start_desc);
+ acpi_cm_remove_reference (V2_desc);
+ acpi_cm_remove_reference (op2_desc);
+ acpi_cm_remove_reference (V1_desc);
+ acpi_cm_remove_reference (op1_desc);
+ acpi_cm_remove_reference (pkg_desc);
+
+
+ /* Delete return object on error */
+
+ if (ACPI_FAILURE (status) &&
+ (ret_desc))
+ {
+ acpi_cm_remove_reference (ret_desc);
+ ret_desc = NULL;
+ }
+
+
+ /* Set the return object and exit */
+
+ *return_desc = ret_desc;
+ return (status);
+}
diff --git a/drivers/acpi/interpreter/ammonad.c b/drivers/acpi/interpreter/ammonad.c
new file mode 100644
index 000000000..b8ab73097
--- /dev/null
+++ b/drivers/acpi/interpreter/ammonad.c
@@ -0,0 +1,954 @@
+
+/******************************************************************************
+ *
+ * Module Name: ammonad - ACPI AML (p-code) execution for monadic operators
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "dispatch.h"
+#include "interp.h"
+#include "amlcode.h"
+#include "namesp.h"
+
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("ammonad");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_get_object_reference
+ *
+ * PARAMETERS: Obj_desc - Create a reference to this object
+ * Ret_desc - Where to store the reference
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Obtain and return a "reference" to the target object
+ * Common code for the Ref_of_op and the Cond_ref_of_op.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_get_object_reference (
+ ACPI_OBJECT_INTERNAL *obj_desc,
+ ACPI_OBJECT_INTERNAL **ret_desc)
+{
+ ACPI_STATUS status = AE_OK;
+
+
+ if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_INTERNAL)) {
+ if (obj_desc->common.type != INTERNAL_TYPE_REFERENCE) {
+ *ret_desc = NULL;
+ status = AE_TYPE;
+ goto cleanup;
+ }
+
+ /*
+ * Not a Name -- an indirect name pointer would have
+ * been converted to a direct name pointer in Acpi_aml_resolve_operands
+ */
+ switch (obj_desc->reference.op_code)
+ {
+ case AML_LOCAL_OP:
+
+ *ret_desc = (void *) acpi_ds_method_data_get_nte (MTH_TYPE_LOCAL,
+ (obj_desc->reference.offset));
+ break;
+
+
+ case AML_ARG_OP:
+
+ *ret_desc = (void *) acpi_ds_method_data_get_nte (MTH_TYPE_ARG,
+ (obj_desc->reference.offset));
+ break;
+
+
+ default:
+
+ *ret_desc = NULL;
+ status = AE_AML_INTERNAL;
+ goto cleanup;
+ }
+
+ }
+
+ else if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) {
+ /* Must be a named object; Just return the NTE */
+
+ *ret_desc = obj_desc;
+ }
+
+ else {
+ *ret_desc = NULL;
+ status = AE_TYPE;
+ }
+
+
+cleanup:
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_monadic1
+ *
+ * PARAMETERS: Opcode - The opcode to be executed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute Type 1 monadic operator with numeric operand on
+ * object stack
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_monadic1 (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_STATUS status;
+
+
+ /* Resolve all operands */
+
+ status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS);
+ /* Get all operands */
+
+ status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state);
+ if (status != AE_OK) {
+ acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__,
+ opcode, WALK_OPERANDS, 1);
+ goto cleanup;
+ }
+
+
+ /* Examine the opcode */
+
+ switch (opcode)
+ {
+
+ /* Def_release := Release_op Mutex_object */
+
+ case AML_RELEASE_OP:
+
+ status = acpi_aml_system_release_mutex (obj_desc);
+ break;
+
+
+ /* Def_reset := Reset_op Acpi_event_object */
+
+ case AML_RESET_OP:
+
+ status = acpi_aml_system_reset_event (obj_desc);
+ break;
+
+
+ /* Def_signal := Signal_op Acpi_event_object */
+
+ case AML_SIGNAL_OP:
+
+ status = acpi_aml_system_signal_event (obj_desc);
+ break;
+
+
+ /* Def_sleep := Sleep_op Msec_time */
+
+ case AML_SLEEP_OP:
+
+ acpi_aml_system_do_suspend (obj_desc->number.value);
+ break;
+
+
+ /* Def_stall := Stall_op Usec_time */
+
+ case AML_STALL_OP:
+
+ acpi_aml_system_do_stall (obj_desc->number.value);
+ break;
+
+
+ /* Unknown opcode */
+
+ default:
+
+ status = AE_AML_BAD_OPCODE;
+ break;
+
+ } /* switch */
+
+
+cleanup:
+
+ /* Always delete the operand */
+
+ acpi_cm_remove_reference (obj_desc);
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_monadic2_r
+ *
+ * PARAMETERS: Opcode - The opcode to be executed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute Type 2 monadic operator with numeric operand and
+ * result operand on operand stack
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_monadic2_r (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OBJECT_INTERNAL **return_desc)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_OBJECT_INTERNAL *res_desc;
+ ACPI_OBJECT_INTERNAL *ret_desc = NULL;
+ ACPI_OBJECT_INTERNAL *ret_desc2 = NULL;
+ u32 res_val;
+ ACPI_STATUS status;
+ s32 d0;
+ s32 d1;
+ s32 d2;
+ s32 d3;
+
+
+ /* Resolve all operands */
+
+ status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS);
+ /* Get all operands */
+
+ status |= acpi_ds_obj_stack_pop_object (&res_desc, walk_state);
+ status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state);
+ if (status != AE_OK) {
+ acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__,
+ opcode, WALK_OPERANDS, 2);
+ goto cleanup;
+ }
+
+
+ /* Create a return object of type NUMBER for most opcodes */
+
+ switch (opcode)
+ {
+ case AML_BIT_NOT_OP:
+ case AML_FIND_SET_LEFT_BIT_OP:
+ case AML_FIND_SET_RIGHT_BIT_OP:
+ case AML_FROM_BCDOP:
+ case AML_TO_BCDOP:
+ case AML_COND_REF_OF_OP:
+
+ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER);
+ if (!ret_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ break;
+ }
+
+
+ switch (opcode)
+ {
+ /* Def_not := Not_op Operand Result */
+
+ case AML_BIT_NOT_OP:
+
+ ret_desc->number.value = ~obj_desc->number.value;
+ break;
+
+
+ /* Def_find_set_left_bit := Find_set_left_bit_op Operand Result */
+
+ case AML_FIND_SET_LEFT_BIT_OP:
+
+ ret_desc->number.value = obj_desc->number.value;
+ for (res_val = 0; ret_desc->number.value && res_val < 33; ++res_val) {
+ ret_desc->number.value >>= 1;
+ }
+
+ ret_desc->number.value = res_val;
+ break;
+
+
+ /* Def_find_set_right_bit := Find_set_right_bit_op Operand Result */
+
+ case AML_FIND_SET_RIGHT_BIT_OP:
+
+ ret_desc->number.value = obj_desc->number.value;
+ for (res_val = 0; ret_desc->number.value && res_val < 33; ++res_val) {
+ ret_desc->number.value <<= 1;
+ }
+
+ ret_desc->number.value = res_val == 0 ? 0 : 33 - res_val;
+ break;
+
+
+ /* Def_from_bDC := From_bCDOp BCDValue Result */
+
+ case AML_FROM_BCDOP:
+
+ d0 = (s32) (obj_desc->number.value & 15);
+ d1 = (s32) (obj_desc->number.value >> 4 & 15);
+ d2 = (s32) (obj_desc->number.value >> 8 & 15);
+ d3 = (s32) (obj_desc->number.value >> 12 & 15);
+
+ if (d0 > 9 || d1 > 9 || d2 > 9 || d3 > 9) {
+ status = AE_AML_NUMERIC_OVERFLOW;
+ goto cleanup;
+ }
+
+ ret_desc->number.value = d0 + d1 * 10 + d2 * 100 + d3 * 1000;
+ break;
+
+
+ /* Def_to_bDC := To_bCDOp Operand Result */
+
+ case AML_TO_BCDOP:
+
+
+ if (obj_desc->number.value > 9999) {
+ status = AE_AML_NUMERIC_OVERFLOW;
+ goto cleanup;
+ }
+
+ ret_desc->number.value
+ = obj_desc->number.value % 10
+ + (obj_desc->number.value / 10 % 10 << 4)
+ + (obj_desc->number.value / 100 % 10 << 8)
+ + (obj_desc->number.value / 1000 % 10 << 12);
+
+ break;
+
+
+ /* Def_cond_ref_of := Cond_ref_of_op Source_object Result */
+
+ case AML_COND_REF_OF_OP:
+
+ /*
+ * This op is a little strange because the internal return value is
+ * different than the return value stored in the result descriptor
+ * (There are really two return values)
+ */
+
+ if ((ACPI_NAMED_OBJECT*) obj_desc == acpi_gbl_root_object) {
+ /*
+ * This means that the object does not exist in the namespace,
+ * return FALSE
+ */
+
+ ret_desc->number.value = 0;
+
+ /*
+ * Must delete the result descriptor since there is no reference
+ * being returned
+ */
+
+ acpi_cm_remove_reference (res_desc);
+ goto cleanup;
+ }
+
+ /* Get the object reference and store it */
+
+ status = acpi_aml_get_object_reference (obj_desc, &ret_desc2);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ status = acpi_aml_exec_store (ret_desc2, res_desc);
+
+ /* The object exists in the namespace, return TRUE */
+
+ ret_desc->number.value = (u32) -1;
+ goto cleanup;
+ break;
+
+
+ case AML_STORE_OP:
+
+ /*
+ * A store operand is typically a number, string, buffer or lvalue
+ * TBD: [Unhandled] What about a store to a package?
+ */
+
+ /*
+ * Do the store, and be careful about deleting the source object,
+ * since the object itself may have been stored.
+ */
+
+ status = acpi_aml_exec_store (obj_desc, res_desc);
+ if (ACPI_FAILURE (status)) {
+ /* On failure, just delete the Obj_desc */
+
+ acpi_cm_remove_reference (obj_desc);
+ }
+
+ else {
+ /*
+ * Normally, we would remove a reference on the Obj_desc parameter;
+ * But since it is being used as the internal return object
+ * (meaning we would normally increment it), the two cancel out,
+ * and we simply don't do anything.
+ */
+ *return_desc = obj_desc;
+ }
+
+ obj_desc = NULL;
+ return (status);
+
+ break;
+
+
+ case AML_DEBUG_OP:
+
+ /* Reference, returning an Reference */
+
+ return (AE_OK);
+ break;
+
+
+ /*
+ * These are obsolete opcodes
+ */
+
+ /* Def_shift_left_bit := Shift_left_bit_op Source Bit_num */
+ /* Def_shift_right_bit := Shift_right_bit_op Source Bit_num */
+
+ case AML_SHIFT_LEFT_BIT_OP:
+ case AML_SHIFT_RIGHT_BIT_OP:
+
+ status = AE_SUPPORT;
+ goto cleanup;
+ break;
+
+
+ default:
+
+ status = AE_AML_BAD_OPCODE;
+ goto cleanup;
+ }
+
+
+ status = acpi_aml_exec_store (ret_desc, res_desc);
+
+
+cleanup:
+ /* Always delete the operand object */
+
+ acpi_cm_remove_reference (obj_desc);
+
+ /* Delete return object(s) on error */
+
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_remove_reference (res_desc); /* Result descriptor */
+ if (ret_desc) {
+ acpi_cm_remove_reference (ret_desc);
+ ret_desc = NULL;
+ }
+ }
+
+ /* Set the return object and exit */
+
+ *return_desc = ret_desc;
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_monadic2
+ *
+ * PARAMETERS: Opcode - The opcode to be executed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute Type 2 monadic operator with numeric operand:
+ * Deref_of_op, Ref_of_op, Size_of_op, Type_op, Increment_op,
+ * Decrement_op, LNot_op,
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_monadic2 (
+ u16 opcode,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OBJECT_INTERNAL **return_desc)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_OBJECT_INTERNAL *tmp_desc;
+ ACPI_OBJECT_INTERNAL *ret_desc = NULL;
+ ACPI_STATUS status;
+ u32 type;
+ u32 value;
+
+
+ /* Resolve all operands */
+
+ status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS);
+ /* Get all operands */
+
+ status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state);
+ if (status != AE_OK) {
+ acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__,
+ opcode, WALK_OPERANDS, 1);
+ goto cleanup;
+ }
+
+
+ /* Get the operand and decode the opcode */
+
+
+ switch (opcode)
+ {
+
+ /* Def_lNot := LNot_op Operand */
+
+ case AML_LNOT_OP:
+
+ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER);
+ if (!ret_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ ret_desc->number.value = !obj_desc->number.value;
+ break;
+
+
+ /* Def_decrement := Decrement_op Target */
+ /* Def_increment := Increment_op Target */
+
+ case AML_DECREMENT_OP:
+ case AML_INCREMENT_OP:
+
+ /*
+ * Since we are expecting an Reference on the top of the stack, it
+ * can be either an NTE or an internal object.
+ *
+ * TBD: [Future] This may be the prototype code for all cases where
+ * an Reference is expected!! 10/99
+ */
+
+ if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) {
+ ret_desc = obj_desc;
+ }
+
+ else {
+ /*
+ * Duplicate the Reference in a new object so that we can resolve it
+ * without destroying the original Reference object
+ */
+
+ ret_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REFERENCE);
+ if (!ret_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ ret_desc->reference.op_code = obj_desc->reference.op_code;
+ ret_desc->reference.offset = obj_desc->reference.offset;
+ ret_desc->reference.object = obj_desc->reference.object;
+ }
+
+
+ /*
+ * Convert the Ret_desc Reference to a Number
+ * (This deletes the original Ret_desc)
+ */
+
+ status = acpi_aml_resolve_operands (AML_LNOT_OP, &ret_desc);
+ if (status != AE_OK) {
+ acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__,
+ opcode, WALK_OPERANDS, 1);
+ goto cleanup;
+ }
+
+ /* Do the actual increment or decrement */
+
+ if (AML_INCREMENT_OP == opcode) {
+ ret_desc->number.value++;
+ }
+ else {
+ ret_desc->number.value--;
+ }
+
+ /* Store the result back in the original descriptor */
+
+ status = acpi_aml_exec_store (ret_desc, obj_desc);
+
+ /* Objdesc was just deleted (because it is an Reference) */
+
+ obj_desc = NULL;
+
+ break;
+
+
+ /* Def_object_type := Object_type_op Source_object */
+
+ case AML_TYPE_OP:
+
+ if (INTERNAL_TYPE_REFERENCE == obj_desc->common.type) {
+ /*
+ * Not a Name -- an indirect name pointer would have
+ * been converted to a direct name pointer in Resolve_operands
+ */
+ switch (obj_desc->reference.op_code)
+ {
+ case AML_ZERO_OP:
+ case AML_ONE_OP:
+ case AML_ONES_OP:
+
+ /* Constants are of type Number */
+
+ type = ACPI_TYPE_NUMBER;
+ break;
+
+
+ case AML_DEBUG_OP:
+
+ /* Per 1.0b spec, Debug object is of type Debug_object */
+
+ type = ACPI_TYPE_DEBUG_OBJECT;
+ break;
+
+
+ case AML_INDEX_OP:
+
+ /* Get the type of this reference (index into another object) */
+
+ type = obj_desc->reference.target_type;
+ if (type == ACPI_TYPE_PACKAGE) {
+ /*
+ * The main object is a package, we want to get the type
+ * of the individual package element that is referenced by
+ * the index.
+ */
+ type = (*(obj_desc->reference.where))->common.type;
+ }
+
+ break;
+
+
+ case AML_LOCAL_OP:
+
+ type = acpi_ds_method_data_get_type (MTH_TYPE_LOCAL,
+ (obj_desc->reference.offset));
+ break;
+
+
+ case AML_ARG_OP:
+
+ type = acpi_ds_method_data_get_type (MTH_TYPE_ARG,
+ (obj_desc->reference.offset));
+ break;
+
+
+ default:
+
+ status = AE_AML_INTERNAL;
+ goto cleanup;
+ }
+ }
+
+ else {
+ /*
+ * Since we passed Acpi_aml_resolve_operands("l") and it's not a
+ * Reference, it must be a direct name pointer.
+ */
+ type = acpi_ns_get_type ((ACPI_HANDLE) obj_desc);
+ }
+
+ /* Allocate a descriptor to hold the type. */
+
+ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER);
+ if (!ret_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ ret_desc->number.value = type;
+ break;
+
+
+ /* Def_size_of := Size_of_op Source_object */
+
+ case AML_SIZE_OF_OP:
+
+ if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) {
+ obj_desc = acpi_ns_get_attached_object (obj_desc);
+ }
+
+ if (!obj_desc) {
+ value = 0;
+ }
+
+ else {
+ switch (obj_desc->common.type)
+ {
+
+ case ACPI_TYPE_BUFFER:
+
+ value = obj_desc->buffer.length;
+ break;
+
+
+ case ACPI_TYPE_STRING:
+
+ value = obj_desc->string.length;
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+
+ value = obj_desc->package.count;
+ break;
+
+ case INTERNAL_TYPE_REFERENCE:
+
+ value = 4;
+ break;
+
+ default:
+
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+ }
+
+ /*
+ * Now that we have the size of the object, create a result
+ * object to hold the value
+ */
+
+ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER);
+ if (!ret_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ ret_desc->number.value = value;
+ break;
+
+
+ /* Def_ref_of := Ref_of_op Source_object */
+
+ case AML_REF_OF_OP:
+
+ status = acpi_aml_get_object_reference (obj_desc, &ret_desc);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+ break;
+
+
+ /* Def_deref_of := Deref_of_op Obj_reference */
+
+ case AML_DEREF_OF_OP:
+
+
+ /* Check for a method local or argument */
+
+ if (!VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) {
+ /*
+ * Must resolve/dereference the local/arg reference first
+ */
+ switch (obj_desc->reference.op_code)
+ {
+ /* Set Obj_desc to the value of the local/arg */
+
+ case AML_LOCAL_OP:
+
+ acpi_ds_method_data_get_value (MTH_TYPE_LOCAL,
+ (obj_desc->reference.offset), &tmp_desc);
+
+ /*
+ * Delete our reference to the input object and
+ * point to the object just retrieved
+ */
+ acpi_cm_remove_reference (obj_desc);
+ obj_desc = tmp_desc;
+ break;
+
+
+ case AML_ARG_OP:
+
+ acpi_ds_method_data_get_value (MTH_TYPE_ARG,
+ (obj_desc->reference.offset), &tmp_desc);
+
+ /*
+ * Delete our reference to the input object and
+ * point to the object just retrieved
+ */
+ acpi_cm_remove_reference (obj_desc);
+ obj_desc = tmp_desc;
+ break;
+
+ default:
+
+ /* Index op - handled below */
+ break;
+ }
+ }
+
+
+ /* Obj_desc may have changed from the code above */
+
+ if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) {
+ /* Get the actual object from the NTE (This is the dereference) */
+
+ ret_desc = ((ACPI_NAMED_OBJECT*) obj_desc)->object;
+
+ /* Returning a pointer to the object, add another reference! */
+
+ acpi_cm_add_reference (ret_desc);
+ }
+
+ else {
+ /*
+ * This must be a reference object produced by the Index
+ * ASL operation -- check internal opcode
+ */
+
+ if ((obj_desc->reference.op_code != AML_INDEX_OP) &&
+ (obj_desc->reference.op_code != AML_REF_OF_OP))
+ {
+ status = AE_TYPE;
+ goto cleanup;
+ }
+
+
+ switch (obj_desc->reference.op_code)
+ {
+ case AML_INDEX_OP:
+
+ /*
+ * Supported target types for the Index operator are
+ * 1) A Buffer
+ * 2) A Package
+ */
+
+ if (obj_desc->reference.target_type == ACPI_TYPE_BUFFER_FIELD) {
+ /*
+ * The target is a buffer, we must create a new object that
+ * contains one element of the buffer, the element pointed
+ * to by the index.
+ *
+ * NOTE: index into a buffer is NOT a pointer to a
+ * sub-buffer of the main buffer, it is only a pointer to a
+ * single element (byte) of the buffer!
+ */
+ ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER);
+ if (!ret_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ tmp_desc = obj_desc->reference.object;
+ ret_desc->number.value =
+ tmp_desc->buffer.pointer[obj_desc->reference.offset];
+
+ /* TBD: [Investigate] (see below) Don't add an additional
+ * ref!
+ */
+ }
+
+ else if (obj_desc->reference.target_type == ACPI_TYPE_PACKAGE) {
+ /*
+ * The target is a package, we want to return the referenced
+ * element of the package. We must add another reference to
+ * this object, however.
+ */
+
+ ret_desc = *(obj_desc->reference.where);
+ if (!ret_desc) {
+ /*
+ * We can't return a NULL dereferenced value. This is
+ * an uninitialized package element and is thus a
+ * severe error.
+ */
+
+ status = AE_AML_UNINITIALIZED_ELEMENT;
+ goto cleanup;
+ }
+
+ acpi_cm_add_reference (ret_desc);
+ }
+
+ else {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+ break;
+
+
+ case AML_REF_OF_OP:
+
+ ret_desc = obj_desc->reference.object;
+
+ /* Add another reference to the object! */
+
+ acpi_cm_add_reference (ret_desc);
+ break;
+ }
+ }
+
+ break;
+
+
+ default:
+
+ status = AE_AML_BAD_OPCODE;
+ goto cleanup;
+ }
+
+
+cleanup:
+
+ if (obj_desc) {
+ acpi_cm_remove_reference (obj_desc);
+ }
+
+ /* Delete return object on error */
+
+ if (ACPI_FAILURE (status) &&
+ (ret_desc))
+ {
+ acpi_cm_remove_reference (ret_desc);
+ ret_desc = NULL;
+ }
+
+ *return_desc = ret_desc;
+ return (status);
+}
+
diff --git a/drivers/acpi/interpreter/amnames.c b/drivers/acpi/interpreter/amnames.c
new file mode 100644
index 000000000..f6222b3b9
--- /dev/null
+++ b/drivers/acpi/interpreter/amnames.c
@@ -0,0 +1,440 @@
+
+/******************************************************************************
+ *
+ * Module Name: amnames - interpreter/scanner name load/execute
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "interp.h"
+#include "amlcode.h"
+#include "namesp.h"
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("amnames");
+
+
+/* AML Package Length encodings */
+
+#define ACPI_AML_PACKAGE_TYPE1 0x40
+#define ACPI_AML_PACKAGE_TYPE2 0x4000
+#define ACPI_AML_PACKAGE_TYPE3 0x400000
+#define ACPI_AML_PACKAGE_TYPE4 0x40000000
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_allocate_name_string
+ *
+ * PARAMETERS: Prefix_count - Count of parent levels. Special cases:
+ * (-1) = root, 0 = none
+ * Num_name_segs - count of 4-character name segments
+ *
+ * RETURN: A pointer to the allocated string segment. This segment must
+ * be deleted by the caller.
+ *
+ * DESCRIPTION: Allocate a buffer for a name string. Ensure allocated name
+ * string is long enough, and set up prefix if any.
+ *
+ ******************************************************************************/
+
+char *
+acpi_aml_allocate_name_string (
+ u32 prefix_count,
+ u32 num_name_segs)
+{
+ char *temp_ptr;
+ char *name_string;
+ u32 size_needed;
+
+
+ /*
+ * Allow room for all \ and ^ prefixes, all segments, and a Multi_name_prefix.
+ * Also, one byte for the null terminator.
+ * This may actually be somewhat longer than needed.
+ */
+
+ if (prefix_count == (u32) -1) {
+ /* Special case for root */
+
+ size_needed = 1 + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1;
+ }
+ else {
+ size_needed = prefix_count + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1;
+ }
+
+ /*
+ * Allocate a buffer for the name.
+ * This buffer must be deleted by the caller!
+ */
+
+ name_string = acpi_cm_allocate ((ACPI_SIZE) size_needed);
+ if (!name_string) {
+ REPORT_ERROR ("Aml_allocate_name_string: name allocation failure");
+ return (NULL);
+ }
+
+ temp_ptr = name_string;
+
+ /* Set up Root or Parent prefixes if needed */
+
+ if (prefix_count == (u32) -1) {
+ *temp_ptr++ = AML_ROOT_PREFIX;
+ }
+
+ else {
+ while (prefix_count--) {
+ *temp_ptr++ = AML_PARENT_PREFIX;
+ }
+ }
+
+
+ /* Set up Dual or Multi prefixes if needed */
+
+ if (num_name_segs > 2) {
+ /* Set up multi prefixes */
+
+ *temp_ptr++ = AML_MULTI_NAME_PREFIX_OP;
+ *temp_ptr++ = (char) num_name_segs;
+ }
+
+ else if (2 == num_name_segs) {
+ /* Set up dual prefixes */
+
+ *temp_ptr++ = AML_DUAL_NAME_PREFIX;
+ }
+
+ /*
+ * Terminate string following prefixes. Acpi_aml_exec_name_segment() will
+ * append the segment(s)
+ */
+
+ *temp_ptr = 0;
+
+ return (name_string);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_decode_package_length
+ *
+ * PARAMETERS: Last_pkg_len - latest value decoded by Do_pkg_length() for
+ * most recently examined package or field
+ *
+ * RETURN: Number of bytes contained in package length encoding
+ *
+ * DESCRIPTION: Decodes the Package Length. Upper 2 bits are are used to
+ * tell if type 1, 2, 3, or 4.
+ * 0x3F = Max 1 byte encoding,
+ * 0xFFF = Max 2 byte encoding,
+ * 0xFFFFF = Max 3 Byte encoding,
+ * 0xFFFFFFFFF = Max 4 Byte encoding.
+ *
+ ******************************************************************************/
+
+u32
+acpi_aml_decode_package_length (
+ u32 last_pkg_len)
+{
+ u32 num_bytes = 0;
+
+
+ if (last_pkg_len < ACPI_AML_PACKAGE_TYPE1) {
+ num_bytes = 1;
+ }
+
+ else if (last_pkg_len < ACPI_AML_PACKAGE_TYPE2) {
+ num_bytes = 2;
+ }
+
+ else if (last_pkg_len < ACPI_AML_PACKAGE_TYPE3) {
+ num_bytes = 3;
+ }
+
+ else if (last_pkg_len < ACPI_AML_PACKAGE_TYPE4) {
+ num_bytes = 4;
+ }
+
+ return (num_bytes);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_name_segment
+ *
+ * PARAMETERS: Interpreter_mode - Current running mode (load1/Load2/Exec)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute a name segment (4 bytes)
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_name_segment (
+ u8 **in_aml_address,
+ char *name_string)
+{
+ u8 *aml_address = *in_aml_address;
+ ACPI_STATUS status = AE_OK;
+ s32 index;
+ char char_buf[5];
+
+
+ /*
+ * If first character is a digit, then we know that we aren't looking at a
+ * valid name segment
+ */
+
+ char_buf[0] = *aml_address;
+
+ if ('0' <= char_buf[0] && char_buf[0] <= '9') {
+ return (AE_CTRL_PENDING);
+ }
+
+ for (index = 4;
+ (index > 0) && (acpi_cm_valid_acpi_character (*aml_address));
+ --index)
+ {
+ char_buf[4 - index] = *aml_address++;
+ }
+
+
+ /* Valid name segment */
+
+ if (0 == index) {
+ /* Found 4 valid characters */
+
+ char_buf[4] = '\0';
+
+ if (name_string) {
+ STRCAT (name_string, char_buf);
+ }
+
+ }
+
+ else if (4 == index) {
+ /*
+ * First character was not a valid name character,
+ * so we are looking at something other than a name.
+ */
+ status = AE_CTRL_PENDING;
+ }
+
+ else {
+ /* Segment started with one or more valid characters, but fewer than 4 */
+
+ status = AE_AML_BAD_NAME;
+ }
+
+ *in_aml_address = aml_address;
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_get_name_string
+ *
+ * PARAMETERS: Data_type - Data type to be associated with this name
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get a name, including any prefixes.
+ *
+ ******************************************************************************/
+
+
+ACPI_STATUS
+acpi_aml_get_name_string (
+ OBJECT_TYPE_INTERNAL data_type,
+ u8 *in_aml_address,
+ char **out_name_string,
+ u32 *out_name_length)
+{
+ ACPI_STATUS status = AE_OK;
+ u8 *aml_address = in_aml_address;
+ char *name_string = NULL;
+ s32 num_segments;
+ s32 prefix_count = 0;
+ u8 prefix = 0;
+
+
+ if (INTERNAL_TYPE_DEF_FIELD == data_type ||
+ INTERNAL_TYPE_BANK_FIELD == data_type ||
+ INTERNAL_TYPE_INDEX_FIELD == data_type)
+ {
+ /* Disallow prefixes for types associated with field names */
+
+ name_string = acpi_aml_allocate_name_string (0, 1);
+ if (!name_string) {
+ status = AE_NO_MEMORY;
+ }
+ else {
+ status = acpi_aml_exec_name_segment (&aml_address, name_string);
+ }
+ }
+
+ else {
+ /*
+ * Data_type is not a field name.
+ * Examine first character of name for root or parent prefix operators
+ */
+
+ switch (*aml_address)
+ {
+
+ case AML_ROOT_PREFIX:
+
+ prefix = *aml_address++;
+ /*
+ * Remember that we have a Root_prefix --
+ * see comment in Acpi_aml_allocate_name_string()
+ */
+ prefix_count = -1;
+ break;
+
+
+ case AML_PARENT_PREFIX:
+
+ /* Increment past possibly multiple parent prefixes */
+
+ do
+ {
+ prefix = *aml_address++;
+ ++prefix_count;
+
+ } while (*aml_address == AML_PARENT_PREFIX);
+
+ break;
+
+
+ default:
+
+ break;
+ }
+
+
+ /* Examine first character of name for name segment prefix operator */
+
+ switch (*aml_address)
+ {
+
+ case AML_DUAL_NAME_PREFIX:
+
+ prefix = *aml_address++;
+ name_string = acpi_aml_allocate_name_string (prefix_count, 2);
+ if (!name_string) {
+ status = AE_NO_MEMORY;
+ break;
+ }
+
+ /* Ensure Prefix_count != 0 to remember processing a prefix */
+
+ prefix_count += 2;
+
+ status = acpi_aml_exec_name_segment (&aml_address, name_string);
+ if (ACPI_SUCCESS (status)) {
+ status = acpi_aml_exec_name_segment (&aml_address, name_string);
+ }
+ break;
+
+
+ case AML_MULTI_NAME_PREFIX_OP:
+
+ prefix = *aml_address++;
+ /* Fetch count of segments remaining in name path */
+
+ num_segments = *aml_address++;
+
+ name_string = acpi_aml_allocate_name_string (prefix_count, num_segments);
+ if (!name_string) {
+ status = AE_NO_MEMORY;
+ break;
+ }
+
+ /* Ensure Prefix_count != 0 to remember processing a prefix */
+
+ prefix_count += 2;
+
+ while (num_segments &&
+ (status = acpi_aml_exec_name_segment (&aml_address, name_string)) == AE_OK)
+ {
+ --num_segments;
+ }
+
+ break;
+
+
+ case 0:
+
+ /* Null_name valid as of 8-12-98 ASL/AML Grammar Update */
+
+
+ /* Consume the NULL byte */
+
+ aml_address++;
+ name_string = acpi_aml_allocate_name_string (prefix_count, 0);
+ if (!name_string) {
+ status = AE_NO_MEMORY;
+ break;
+ }
+
+ break;
+
+
+ default:
+
+ /* Name segment string */
+
+ name_string = acpi_aml_allocate_name_string (prefix_count, 1);
+ if (!name_string) {
+ status = AE_NO_MEMORY;
+ break;
+ }
+
+ status = acpi_aml_exec_name_segment (&aml_address, name_string);
+ break;
+
+ } /* Switch (Peek_op ()) */
+ }
+
+
+ if (AE_CTRL_PENDING == status && prefix_count != 0) {
+ /* Ran out of segments after processing a prefix */
+
+ REPORT_ERROR ("Ran out of segments after processing a prefix");
+
+ status = AE_AML_BAD_NAME;
+ }
+
+
+ *out_name_string = name_string;
+ *out_name_length = (u32) (aml_address - in_aml_address);
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/interpreter/amprep.c b/drivers/acpi/interpreter/amprep.c
new file mode 100644
index 000000000..9a5ef1706
--- /dev/null
+++ b/drivers/acpi/interpreter/amprep.c
@@ -0,0 +1,392 @@
+
+/******************************************************************************
+ *
+ * Module Name: amprep - ACPI AML (p-code) execution - field prep utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "interp.h"
+#include "amlcode.h"
+#include "namesp.h"
+#include "parser.h"
+
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("amprep");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_decode_field_access_type
+ *
+ * PARAMETERS: Access - Encoded field access bits
+ *
+ * RETURN: Field granularity (8, 16, or 32)
+ *
+ * DESCRIPTION: Decode the Access_type bits of a field definition.
+ *
+ ******************************************************************************/
+
+u32
+acpi_aml_decode_field_access_type (
+ u32 access)
+{
+
+ switch (access)
+ {
+ case ACCESS_ANY_ACC:
+ return 8;
+ break;
+
+ case ACCESS_BYTE_ACC:
+ return 8;
+ break;
+
+ case ACCESS_WORD_ACC:
+ return 16;
+ break;
+
+ case ACCESS_DWORD_ACC:
+ return 32;
+ break;
+
+ default:
+ /* Invalid field access type */
+
+ return 0;
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_prep_common_field_objec
+ *
+ * PARAMETERS: Obj_desc - The field object
+ * Field_flags - Access, Lock_rule, or Update_rule.
+ * The format of a Field_flag is described
+ * in the ACPI specification
+ * Field_position - Field position
+ * Field_length - Field length
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize the areas of the field object that are common
+ * to the various types of fields.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_prep_common_field_object (
+ ACPI_OBJECT_INTERNAL *obj_desc,
+ u8 field_flags,
+ u8 field_attribute,
+ u32 field_position,
+ u32 field_length)
+{
+ u32 granularity;
+
+
+ /*
+ * Note: the structure being initialized is the
+ * ACPI_COMMON_FIELD_INFO; Therefore, we can just use the Field union to
+ * access this common area. No structure fields outside of the common area
+ * are initialized by this procedure.
+ */
+
+ /* Decode the Field_flags */
+
+ obj_desc->field.access = (u8) ((field_flags & ACCESS_TYPE_MASK)
+ >> ACCESS_TYPE_SHIFT);
+ obj_desc->field.lock_rule = (u8) ((field_flags & LOCK_RULE_MASK)
+ >> LOCK_RULE_SHIFT);
+ obj_desc->field.update_rule = (u8) ((field_flags & UPDATE_RULE_MASK)
+ >> UPDATE_RULE_SHIFT);
+
+ /* Other misc fields */
+
+ obj_desc->field.length = (u16) field_length;
+ obj_desc->field.access_attribute = field_attribute;
+
+ /* Decode the access type so we can compute offsets */
+
+ granularity = acpi_aml_decode_field_access_type (obj_desc->field.access);
+ if (!granularity) {
+ return (AE_AML_OPERAND_VALUE);
+ }
+
+ /* Access granularity based fields */
+
+ obj_desc->field.granularity = (u8) granularity;
+ obj_desc->field.bit_offset = (u8) (field_position % granularity);
+ obj_desc->field.offset = (u32) field_position / granularity;
+
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_prep_def_field_value
+ *
+ * PARAMETERS: This_entry - Owning NTE
+ * Region - Region in which field is being defined
+ * Field_flags - Access, Lock_rule, or Update_rule.
+ * The format of a Field_flag is described
+ * in the ACPI specification
+ * Field_position - Field position
+ * Field_length - Field length
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Construct an ACPI_OBJECT_INTERNAL of type Def_field and
+ * connect it to the parent NTE.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_prep_def_field_value (
+ ACPI_NAMED_OBJECT *this_entry,
+ ACPI_HANDLE region,
+ u8 field_flags,
+ u8 field_attribute,
+ u32 field_position,
+ u32 field_length)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ s32 type;
+ ACPI_STATUS status;
+
+
+ /* Parameter validation */
+
+ if (!region) {
+ return (AE_AML_NO_OPERAND);
+ }
+
+ type = acpi_ns_get_type (region);
+ if (type != ACPI_TYPE_REGION) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ /* Allocate a new object */
+
+ obj_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_DEF_FIELD);
+ if (!obj_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+
+ /* Obj_desc and Region valid */
+
+ /* Initialize areas of the object that are common to all fields */
+
+ status = acpi_aml_prep_common_field_object (obj_desc, field_flags, field_attribute,
+ field_position, field_length);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Initialize areas of the object that are specific to this field type */
+
+ obj_desc->field.container = acpi_ns_get_attached_object (region);
+
+ /* An additional reference for the container */
+
+ acpi_cm_add_reference (obj_desc->field.container);
+
+
+ /* Debug info */
+
+ /*
+ * Store the constructed descriptor (Obj_desc) into the nte whose
+ * handle is on TOS, preserving the current type of that nte.
+ */
+ status = acpi_ns_attach_object ((ACPI_HANDLE) this_entry, obj_desc,
+ (u8) acpi_ns_get_type ((ACPI_HANDLE) this_entry));
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_prep_bank_field_value
+ *
+ * PARAMETERS: This_entry - Owning NTE
+ * Region - Region in which field is being defined
+ * Bank_reg - Bank selection register
+ * Bank_val - Value to store in selection register
+ * Field_flags - Access, Lock_rule, or Update_rule
+ * Field_position - Field position
+ * Field_length - Field length
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Construct an ACPI_OBJECT_INTERNAL of type Bank_field and
+ * connect it to the parent NTE.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_prep_bank_field_value (
+ ACPI_NAMED_OBJECT *this_entry,
+ ACPI_HANDLE region,
+ ACPI_HANDLE bank_reg,
+ u32 bank_val,
+ u8 field_flags,
+ u8 field_attribute,
+ u32 field_position,
+ u32 field_length)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ s32 type;
+ ACPI_STATUS status;
+
+
+ /* Parameter validation */
+
+ if (!region) {
+ return (AE_AML_NO_OPERAND);
+ }
+
+ type = acpi_ns_get_type (region);
+ if (type != ACPI_TYPE_REGION) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ /* Allocate a new object */
+
+ obj_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_BANK_FIELD);
+ if (!obj_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Obj_desc and Region valid */
+
+ /* Initialize areas of the object that are common to all fields */
+
+ status = acpi_aml_prep_common_field_object (obj_desc, field_flags, field_attribute,
+ field_position, field_length);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Initialize areas of the object that are specific to this field type */
+
+ obj_desc->bank_field.value = bank_val;
+ obj_desc->bank_field.container = acpi_ns_get_attached_object (region);
+ obj_desc->bank_field.bank_select = acpi_ns_get_attached_object (bank_reg);
+
+ /* An additional reference for the container and bank select */
+ /* TBD: [Restructure] is "Bank_select" ever a real internal object?? */
+
+ acpi_cm_add_reference (obj_desc->bank_field.container);
+ acpi_cm_add_reference (obj_desc->bank_field.bank_select);
+
+ /* Debug info */
+
+ /*
+ * Store the constructed descriptor (Obj_desc) into the nte whose
+ * handle is on TOS, preserving the current type of that nte.
+ */
+ status = acpi_ns_attach_object ((ACPI_HANDLE) this_entry, obj_desc,
+ (u8) acpi_ns_get_type ((ACPI_HANDLE) this_entry));
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_prep_index_field_value
+ *
+ * PARAMETERS: This_entry - Owning NTE
+ * Index_reg - Index register
+ * Data_reg - Data register
+ * Field_flags - Access, Lock_rule, or Update_rule
+ * Field_position - Field position
+ * Field_length - Field length
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Construct an ACPI_OBJECT_INTERNAL of type Index_field and
+ * connect it to the parent NTE.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_prep_index_field_value (
+ ACPI_NAMED_OBJECT *this_entry,
+ ACPI_HANDLE index_reg,
+ ACPI_HANDLE data_reg,
+ u8 field_flags,
+ u8 field_attribute,
+ u32 field_position,
+ u32 field_length)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_STATUS status;
+
+
+ /* Parameter validation */
+
+ if (!index_reg || !data_reg) {
+ return (AE_AML_NO_OPERAND);
+ }
+
+ /* Allocate a new object descriptor */
+
+ obj_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_INDEX_FIELD);
+ if (!obj_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Initialize areas of the object that are common to all fields */
+
+ status = acpi_aml_prep_common_field_object (obj_desc, field_flags, field_attribute,
+ field_position, field_length);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Initialize areas of the object that are specific to this field type */
+
+ obj_desc->index_field.value = (u32) (field_position /
+ obj_desc->field.granularity);
+ obj_desc->index_field.index = index_reg;
+ obj_desc->index_field.data = data_reg;
+
+ /* Debug info */
+
+ /*
+ * Store the constructed descriptor (Obj_desc) into the nte whose
+ * handle is on TOS, preserving the current type of that nte.
+ */
+ status = acpi_ns_attach_object ((ACPI_HANDLE) this_entry, obj_desc,
+ (u8) acpi_ns_get_type ((ACPI_HANDLE) this_entry));
+
+ return (status);
+}
+
diff --git a/drivers/acpi/interpreter/amregion.c b/drivers/acpi/interpreter/amregion.c
new file mode 100644
index 000000000..9a44daab2
--- /dev/null
+++ b/drivers/acpi/interpreter/amregion.c
@@ -0,0 +1,406 @@
+/******************************************************************************
+ *
+ * Module Name: amregion - ACPI default Op_region (address space) handlers
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "interp.h"
+#include "amlcode.h"
+#include "namesp.h"
+#include "hardware.h"
+#include "events.h"
+
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("amregion");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_system_memory_space_handler
+ *
+ * PARAMETERS: Function - Read or Write operation
+ * Address - Where in the space to read or write
+ * Bit_width - Field width in bits (8, 16, or 32)
+ * Value - Pointer to in or out value
+ * Context - Context pointer
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Handler for the System Memory address space (Op Region)
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_system_memory_space_handler (
+ u32 function,
+ u32 address, /* TBD: [Future] Should this be A POINTER for 64-bit support? */
+ u32 bit_width,
+ u32 *value,
+ void *context)
+{
+ ACPI_STATUS status = AE_OK;
+ void *logical_addr_ptr = NULL;
+ MEM_HANDLER_CONTEXT *mem_info = context;
+ u32 length;
+
+
+ /* Validate and translate the bit width */
+
+ switch (bit_width)
+ {
+ case 8:
+ length = 1;
+ break;
+
+ case 16:
+ length = 2;
+ break;
+
+ case 32:
+ length = 4;
+ break;
+
+ default:
+ return (AE_AML_OPERAND_VALUE);
+ break;
+ }
+
+
+ /*
+ * Does the request fit into the cached memory mapping?
+ * Is 1) Address below the current mapping? OR
+ * 2) Address beyond the current mapping?
+ */
+
+ if (((char *) address < mem_info->mapped_physical_address) ||
+ (((char *) address + length) >
+ (mem_info->mapped_physical_address + mem_info->mapped_length)))
+ {
+ /*
+ * The request cannot be resolved by the current memory mapping;
+ * Delete the existing mapping and create a new one.
+ */
+
+ if (mem_info->mapped_length) {
+ /* Valid mapping, delete it */
+
+ acpi_os_unmap_memory (mem_info->mapped_logical_address,
+ mem_info->mapped_length);
+ }
+
+ mem_info->mapped_length = 0; /* In case of failure below */
+
+ /* Create a new mapping starting at the address given */
+
+ status = acpi_os_map_memory ((void *) address, SYSMEM_REGION_WINDOW_SIZE,
+ (void **) &mem_info->mapped_logical_address);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ mem_info->mapped_physical_address = (char *) address;
+ mem_info->mapped_length = SYSMEM_REGION_WINDOW_SIZE;
+ }
+
+
+ /*
+ * Generate a logical pointer corresponding to the address we want to
+ * access
+ */
+
+ logical_addr_ptr = mem_info->mapped_logical_address +
+ ((char *) address - mem_info->mapped_physical_address);
+
+ /* Perform the memory read or write */
+
+ switch (function)
+ {
+
+ case ADDRESS_SPACE_READ:
+
+ switch (bit_width)
+ {
+ case 8:
+ *value = (u32)* (u8 *) logical_addr_ptr;
+ break;
+
+ case 16:
+ MOVE_UNALIGNED16_TO_32 (value, logical_addr_ptr);
+ break;
+
+ case 32:
+ MOVE_UNALIGNED32_TO_32 (value, logical_addr_ptr);
+ break;
+ }
+
+ break;
+
+
+ case ADDRESS_SPACE_WRITE:
+
+ switch (bit_width)
+ {
+ case 8:
+ *(u8 *) logical_addr_ptr = (u8) *value;
+ break;
+
+ case 16:
+ MOVE_UNALIGNED16_TO_16 (logical_addr_ptr, value);
+ break;
+
+ case 32:
+ MOVE_UNALIGNED32_TO_32 (logical_addr_ptr, value);
+ break;
+ }
+
+ break;
+
+
+ default:
+ status = AE_BAD_PARAMETER;
+ break;
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_system_io_space_handler
+ *
+ * PARAMETERS: Function - Read or Write operation
+ * Address - Where in the space to read or write
+ * Bit_width - Field width in bits (8, 16, or 32)
+ * Value - Pointer to in or out value
+ * Context - Context pointer
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Handler for the System IO address space (Op Region)
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_system_io_space_handler (
+ u32 function,
+ u32 address,
+ u32 bit_width,
+ u32 *value,
+ void *context)
+{
+ ACPI_STATUS status = AE_OK;
+
+
+ /* Decode the function parameter */
+
+ switch (function)
+ {
+
+ case ADDRESS_SPACE_READ:
+
+ switch (bit_width)
+ {
+ /* I/O Port width */
+
+ case 8:
+ *value = (u32) acpi_os_in8 ((ACPI_IO_ADDRESS) address);
+ break;
+
+ case 16:
+ *value = (u32) acpi_os_in16 ((ACPI_IO_ADDRESS) address);
+ break;
+
+ case 32:
+ *value = acpi_os_in32 ((ACPI_IO_ADDRESS) address);
+ break;
+
+ default:
+ status = AE_AML_OPERAND_VALUE;
+ }
+
+ break;
+
+
+ case ADDRESS_SPACE_WRITE:
+
+ switch (bit_width)
+ {
+ /* I/O Port width */
+ case 8:
+ acpi_os_out8 ((ACPI_IO_ADDRESS) address, (u8) *value);
+ break;
+
+ case 16:
+ acpi_os_out16 ((ACPI_IO_ADDRESS) address, (u16) *value);
+ break;
+
+ case 32:
+ acpi_os_out32 ((ACPI_IO_ADDRESS) address, *value);
+ break;
+
+ default:
+ status = AE_AML_OPERAND_VALUE;
+ }
+
+ break;
+
+
+ default:
+ status = AE_BAD_PARAMETER;
+ break;
+ }
+
+ return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_pci_config_space_handler
+ *
+ * PARAMETERS: Function - Read or Write operation
+ * Address - Where in the space to read or write
+ * Bit_width - Field width in bits (8, 16, or 32)
+ * Value - Pointer to in or out value
+ * Context - Context pointer
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Handler for the PCI Config address space (Op Region)
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_pci_config_space_handler (
+ u32 function,
+ u32 address,
+ u32 bit_width,
+ u32 *value,
+ void *context)
+{
+ ACPI_STATUS status = AE_OK;
+ u32 pci_bus;
+ u32 dev_func;
+ u8 pci_reg;
+ PCI_HANDLER_CONTEXT *PCIcontext;
+
+
+ /*
+ * The arguments to Acpi_os(Read|Write)Pci_cfg(Byte|Word|Dword) are:
+ *
+ * Seg_bus - 0xSSSSBBBB - SSSS is the PCI bus segment
+ * BBBB is the PCI bus number
+ *
+ * Dev_func - 0xDDDDFFFF - DDDD is the PCI device number
+ * FFFF is the PCI device function number
+ *
+ * Reg_num - Config space register must be < 40h
+ *
+ * Value - input value for write, output for read
+ *
+ */
+
+ PCIcontext = (PCI_HANDLER_CONTEXT *) context;
+
+ pci_bus = LOWORD(PCIcontext->seg) << 16;
+ pci_bus |= LOWORD(PCIcontext->bus);
+
+ dev_func = PCIcontext->dev_func;
+
+ pci_reg = (u8) address;
+
+ switch (function)
+ {
+
+ case ADDRESS_SPACE_READ:
+
+ *value = 0;
+
+ switch (bit_width)
+ {
+ /* PCI Register width */
+
+ case 8:
+ status = acpi_os_read_pci_cfg_byte (pci_bus, dev_func, pci_reg,
+ (u8 *) value);
+ break;
+
+ case 16:
+ status = acpi_os_read_pci_cfg_word (pci_bus, dev_func, pci_reg,
+ (u16 *) value);
+ break;
+
+ case 32:
+ status = acpi_os_read_pci_cfg_dword (pci_bus, dev_func, pci_reg,
+ value);
+ break;
+
+ default:
+ status = AE_AML_OPERAND_VALUE;
+
+ } /* Switch bit_width */
+
+ break;
+
+
+ case ADDRESS_SPACE_WRITE:
+
+
+ switch (bit_width)
+ {
+ /* PCI Register width */
+
+ case 8:
+ status = acpi_os_write_pci_cfg_byte (pci_bus, dev_func, pci_reg,
+ *(u8 *) value);
+ break;
+
+ case 16:
+ status = acpi_os_write_pci_cfg_word (pci_bus, dev_func, pci_reg,
+ *(u16 *) value);
+ break;
+
+ case 32:
+ status = acpi_os_write_pci_cfg_dword (pci_bus, dev_func, pci_reg,
+ *value);
+ break;
+
+ default:
+ status = AE_AML_OPERAND_VALUE;
+
+ } /* Switch bit_width */
+
+ break;
+
+
+ default:
+
+ status = AE_BAD_PARAMETER;
+ break;
+
+ }
+
+ return (status);
+}
+
diff --git a/drivers/acpi/interpreter/amresnte.c b/drivers/acpi/interpreter/amresnte.c
new file mode 100644
index 000000000..1f8db8b3d
--- /dev/null
+++ b/drivers/acpi/interpreter/amresnte.c
@@ -0,0 +1,555 @@
+
+/******************************************************************************
+ *
+ * Module Name: amresnte - AML Interpreter object resolution
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "amlcode.h"
+#include "parser.h"
+#include "dispatch.h"
+#include "interp.h"
+#include "namesp.h"
+#include "tables.h"
+#include "events.h"
+
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("amresnte");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_resolve_entry_to_value
+ *
+ * PARAMETERS: Stack_ptr - Pointer to a location on a stack that contains
+ * a ptr to an NTE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Resolve a ACPI_NAMED_OBJECT(nte, A.K.A. a "direct name pointer")
+ *
+ * Note: for some of the data types, the pointer attached to the NTE can be
+ * either a pointer to an actual internal object or a pointer into the AML
+ * stream itself. These types are currently:
+ *
+ * ACPI_TYPE_NUMBER
+ * ACPI_TYPE_STRING
+ * ACPI_TYPE_BUFFER
+ * ACPI_TYPE_MUTEX
+ * ACPI_TYPE_PACKAGE
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_resolve_entry_to_value (
+ ACPI_NAMED_OBJECT **stack_ptr)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_OBJECT_INTERNAL *val_desc = NULL;
+ ACPI_OBJECT_INTERNAL *obj_desc = NULL;
+ ACPI_NAMED_OBJECT *stack_entry;
+ u8 *aml_pointer = NULL;
+ OBJECT_TYPE_INTERNAL entry_type;
+ u8 locked;
+ u8 attached_aml_pointer = FALSE;
+ u8 aml_opcode = 0;
+ u32 temp_val;
+ OBJECT_TYPE_INTERNAL object_type;
+
+
+ stack_entry = *stack_ptr;
+
+
+ /*
+ * The stack pointer is a "Direct name ptr", and points to a
+ * a ACPI_NAMED_OBJECT(nte). Get the pointer that is attached to
+ * the nte.
+ */
+
+ val_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) stack_entry);
+ entry_type = acpi_ns_get_type ((ACPI_HANDLE) stack_entry);
+
+ /*
+ * The Val_desc attached to the NTE can be either:
+ * 1) An internal ACPI object
+ * 2) A pointer into the AML stream (into one of the ACPI system tables)
+ */
+
+ if (acpi_tb_system_table_pointer (val_desc)) {
+ attached_aml_pointer = TRUE;
+ aml_opcode = *((u8 *) val_desc);
+ aml_pointer = ((u8 *) val_desc) + 1;
+
+ }
+
+
+ /*
+ * Action is based on the type of the NTE, which indicates the type
+ * of the attached object or pointer
+ */
+ switch (entry_type)
+ {
+
+ case ACPI_TYPE_PACKAGE:
+
+ /*
+ * Val_desc should point to either an ACPI_OBJECT_INTERNAL of
+ * type Package, or an initialization in the AML stream.
+ */
+ if (!val_desc) {
+ return (AE_AML_NO_OPERAND);
+ }
+
+
+ if (attached_aml_pointer) {
+ /*
+ * This means that the package initialization is not parsed
+ * -- should not happen
+ */
+ return (AE_NOT_IMPLEMENTED);
+ }
+
+ /* Val_desc is an internal object in all cases by the time we get here */
+
+ if (!val_desc || (ACPI_TYPE_PACKAGE != val_desc->common.type)) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ /* Return an additional reference to the object */
+
+ obj_desc = val_desc;
+ acpi_cm_add_reference (obj_desc);
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ if (!val_desc) {
+ return (AE_AML_NO_OPERAND);
+ }
+
+ if (attached_aml_pointer) {
+ /*
+ * This means that the buffer initialization is not parsed
+ * -- should not happen
+ */
+ return (AE_NOT_IMPLEMENTED);
+ }
+
+ /* Val_desc is an internal object in all cases by the time we get here */
+
+ if (!val_desc || (ACPI_TYPE_BUFFER != val_desc->common.type)) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ /* Return an additional reference to the object */
+
+ obj_desc = val_desc;
+ acpi_cm_add_reference (obj_desc);
+
+ break;
+
+
+ case ACPI_TYPE_STRING:
+
+ if (attached_aml_pointer) {
+ /* Allocate a new string object */
+
+ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_STRING);
+ if (!obj_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Init the internal object */
+
+ obj_desc->string.pointer = (char *) aml_pointer;
+ obj_desc->string.length = STRLEN (aml_pointer);
+ }
+
+ else {
+ if (ACPI_TYPE_STRING != val_desc->common.type) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ /* Return an additional reference to the object */
+
+ obj_desc = val_desc;
+ acpi_cm_add_reference (obj_desc);
+ }
+
+ break;
+
+
+ case ACPI_TYPE_NUMBER:
+
+ if (!val_desc) {
+ return (AE_AML_NO_OPERAND);
+ }
+
+
+ /*
+ * An ACPI_TYPE_NUMBER can be either an object or an AML pointer
+ */
+
+ if (attached_aml_pointer) {
+ /*
+ * The attachment points into the AML stream, get the number from
+ * there. The actual number is based upon the AML opcode
+ *
+ * Note: Word_op and DWord_op will not work properly if the
+ * processor's endianness does not match the AML's.
+ */
+
+ switch (aml_opcode)
+ {
+
+ case AML_ZERO_OP:
+
+ temp_val = 0;
+ break;
+
+
+ case AML_ONE_OP:
+
+ temp_val = 1;
+ break;
+
+
+ case AML_ONES_OP:
+
+ temp_val = 0xFFFFFFFF;
+ break;
+
+
+ case AML_BYTE_OP:
+
+ temp_val = (u32) ((u8 *) val_desc)[1];
+ break;
+
+
+ case AML_WORD_OP:
+
+ MOVE_UNALIGNED16_TO_32 (&temp_val, &((u8 *) val_desc)[1]);
+ break;
+
+
+ case AML_DWORD_OP:
+
+ MOVE_UNALIGNED32_TO_32 (&temp_val, &((u8 *) val_desc)[1]);
+ break;
+
+
+ default:
+
+ return (AE_AML_BAD_OPCODE);
+
+ } /* switch */
+
+
+ /* Create and initialize a new object */
+
+ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER);
+ if (!obj_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+ obj_desc->number.value = temp_val;
+ }
+
+ else {
+ /*
+ * The NTE has an attached internal object, make sure that it's a
+ * number
+ */
+
+ if (ACPI_TYPE_NUMBER != val_desc->common.type) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ /* Return an additional reference to the object */
+
+ obj_desc = val_desc;
+ acpi_cm_add_reference (obj_desc);
+ }
+
+ break;
+
+
+ case INTERNAL_TYPE_DEF_FIELD:
+
+ /*
+ * TBD: [Investigate] Is this the correct solution?
+ *
+ * This section was extended to convert to generic buffer if
+ * the return length is greater than 32 bits, but still allows
+ * for returning a type Number for smaller values because the
+ * caller can then apply arithmetic operators on those fields.
+ *
+ * XXX - Implementation limitation: Fields are implemented as type
+ * XXX - Number, but they really are supposed to be type Buffer.
+ * XXX - The two are interchangeable only for lengths <= 32 bits.
+ */
+ if(val_desc->field.length > 32) {
+ object_type = ACPI_TYPE_BUFFER;
+ }
+ else {
+ object_type = ACPI_TYPE_NUMBER;
+ }
+
+ /*
+ * Create the destination buffer object and the buffer space.
+ */
+ obj_desc = acpi_cm_create_internal_object (object_type);
+ if (!obj_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+ /*
+ * Fill in the object specific details
+ */
+ if (ACPI_TYPE_BUFFER == object_type) {
+ obj_desc->buffer.pointer = acpi_cm_callocate(val_desc->field.length);
+ if (!obj_desc->buffer.pointer) {
+ acpi_cm_remove_reference(obj_desc);
+ return (AE_NO_MEMORY);
+ }
+
+ obj_desc->buffer.length = val_desc->field.length;
+
+ status = acpi_aml_get_named_field_value ((ACPI_HANDLE) stack_entry,
+ obj_desc->buffer.pointer, obj_desc->buffer.length);
+
+ if (AE_OK != status) {
+ return (status);
+ }
+ }
+ else {
+ status = acpi_aml_get_named_field_value ((ACPI_HANDLE) stack_entry,
+ &temp_val, sizeof (temp_val));
+
+ if (AE_OK != status) {
+ return (status);
+ }
+
+ obj_desc->number.value = temp_val;
+ }
+
+
+ break;
+
+
+ case INTERNAL_TYPE_BANK_FIELD:
+
+ if (!val_desc) {
+ return (AE_AML_NO_OPERAND);
+ }
+
+ if (attached_aml_pointer) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ if (INTERNAL_TYPE_BANK_FIELD != val_desc->common.type) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+
+ /* Get the global lock if needed */
+
+ obj_desc = (ACPI_OBJECT_INTERNAL *) *stack_ptr;
+ locked = acpi_aml_acquire_global_lock (obj_desc->field_unit.lock_rule);
+ {
+
+ /* Set Index value to select proper Data register */
+ /* perform the update */
+
+ status = acpi_aml_set_named_field_value (val_desc->bank_field.bank_select,
+ &val_desc->bank_field.value,
+ sizeof (val_desc->bank_field.value));
+ }
+ acpi_aml_release_global_lock (locked);
+
+
+ if (AE_OK != status) {
+ return (status);
+ }
+
+ /* Read Data value */
+
+ status = acpi_aml_get_named_field_value (
+ (ACPI_HANDLE) val_desc->bank_field.container,
+ &temp_val, sizeof (temp_val));
+ if (AE_OK != status) {
+ return (status);
+ }
+
+ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER);
+ if (!obj_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+ obj_desc->number.value = temp_val;
+ break;
+
+
+ case INTERNAL_TYPE_INDEX_FIELD:
+
+ if (!val_desc) {
+ return (AE_AML_NO_OPERAND);
+ }
+
+ if (attached_aml_pointer) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ if (INTERNAL_TYPE_INDEX_FIELD != val_desc->common.type) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+
+ /* Set Index value to select proper Data register */
+ /* Get the global lock if needed */
+
+ obj_desc = (ACPI_OBJECT_INTERNAL *) *stack_ptr;
+ locked = acpi_aml_acquire_global_lock (obj_desc->field_unit.lock_rule);
+ {
+ /* Perform the update */
+
+ status = acpi_aml_set_named_field_value (val_desc->index_field.index,
+ &val_desc->index_field.value,
+ sizeof (val_desc->index_field.value));
+ }
+ acpi_aml_release_global_lock (locked);
+
+ if (AE_OK != status) {
+ return (status);
+ }
+
+ /* Read Data value */
+
+ status = acpi_aml_get_named_field_value (val_desc->index_field.data, &temp_val, sizeof (temp_val));
+ if (AE_OK != status) {
+ return (status);
+ }
+
+ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER);
+ if (!obj_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+ obj_desc->number.value = temp_val;
+ break;
+
+
+ case ACPI_TYPE_FIELD_UNIT:
+
+ if (!val_desc) {
+ return (AE_AML_NO_OPERAND);
+ }
+
+ if (attached_aml_pointer) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ if (val_desc->common.type != (u8) entry_type) {
+ return (AE_AML_OPERAND_TYPE);
+ break;
+ }
+
+ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_ANY);
+ if (!obj_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+ if ((status = acpi_aml_get_field_unit_value (val_desc, obj_desc)) != AE_OK) {
+ acpi_cm_remove_reference (obj_desc);
+ return (status);
+ }
+
+ break;
+
+
+ /*
+ * For these objects, just return the object attached to the NTE
+ */
+
+ case ACPI_TYPE_MUTEX:
+ case ACPI_TYPE_METHOD:
+ case ACPI_TYPE_POWER:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_THERMAL:
+ case ACPI_TYPE_EVENT:
+ case ACPI_TYPE_REGION:
+
+
+ /* There must be an object attached to this NTE */
+
+ if (!val_desc) {
+ return (AE_AML_INTERNAL);
+ }
+
+ /* Return an additional reference to the object */
+
+ obj_desc = val_desc;
+ acpi_cm_add_reference (obj_desc);
+ break;
+
+
+ /* Devices rarely have an attached object, return the NTE */
+
+ case ACPI_TYPE_DEVICE:
+
+
+ /* Method locals and arguments have a pseudo-NTE, just return it */
+
+ case INTERNAL_TYPE_METHOD_ARGUMENT:
+ case INTERNAL_TYPE_METHOD_LOCAL_VAR:
+
+ return (AE_OK);
+ break;
+
+
+ /* TYPE_Any is untyped, and thus there is no object associated with it */
+
+ case ACPI_TYPE_ANY:
+
+ return (AE_AML_OPERAND_TYPE); /* Cannot be AE_TYPE */
+
+
+ /* Default case is for unknown types */
+
+ default:
+
+ return (AE_AML_OPERAND_TYPE);
+
+ } /* switch (Entry_type) */
+
+
+ /* Put the object descriptor on the stack */
+
+ *stack_ptr = (void *) obj_desc;
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/interpreter/amresolv.c b/drivers/acpi/interpreter/amresolv.c
new file mode 100644
index 000000000..886ebb7fc
--- /dev/null
+++ b/drivers/acpi/interpreter/amresolv.c
@@ -0,0 +1,452 @@
+
+/******************************************************************************
+ *
+ * Module Name: amresolv - AML Interpreter object resolution
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "amlcode.h"
+#include "parser.h"
+#include "dispatch.h"
+#include "interp.h"
+#include "namesp.h"
+#include "tables.h"
+#include "events.h"
+
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("amresolv");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_get_field_unit_value
+ *
+ * PARAMETERS: *Field_desc - Pointer to a Field_unit
+ * *Result_desc - Pointer to an empty descriptor
+ * which will become a Number
+ * containing the field's value.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieve the value from a Field_unit
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_get_field_unit_value (
+ ACPI_OBJECT_INTERNAL *field_desc,
+ ACPI_OBJECT_INTERNAL *result_desc)
+{
+ ACPI_STATUS status = AE_OK;
+ u32 mask;
+ u8 *location = NULL;
+ u8 locked = FALSE;
+
+
+ if (!field_desc) {
+ status = AE_AML_NO_OPERAND;
+ }
+
+ else if (!field_desc->field_unit.container) {
+ status = AE_AML_INTERNAL;
+ }
+
+ else if (ACPI_TYPE_BUFFER != field_desc->field_unit.container->common.type) {
+ status = AE_AML_OPERAND_TYPE;
+ }
+
+ else if (field_desc->field_unit.sequence
+ != field_desc->field_unit.container->buffer.sequence)
+ {
+ status = AE_AML_INTERNAL;
+ }
+
+ else if (!result_desc) {
+ status = AE_AML_INTERNAL;
+ }
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+
+ /* Get the global lock if needed */
+
+ locked = acpi_aml_acquire_global_lock (field_desc->field_unit.lock_rule);
+
+ /* Field location is (base of buffer) + (byte offset) */
+
+ location = field_desc->field_unit.container->buffer.pointer
+ + field_desc->field_unit.offset;
+
+ /*
+ * Construct Mask with as many 1 bits as the field width
+ *
+ * NOTE: Only the bottom 5 bits are valid for a shift operation, so
+ * special care must be taken for any shift greater than 31 bits.
+ *
+ * TBD: [Unhandled] Fields greater than 32-bits will not work.
+ */
+
+ if (field_desc->field_unit.length < 32) {
+ mask = ((u32) 1 << field_desc->field_unit.length) - (u32) 1;
+ }
+ else {
+ mask = 0xFFFFFFFF;
+ }
+
+ result_desc->number.type = (u8) ACPI_TYPE_NUMBER;
+
+ /* Get the 32 bit value at the location */
+
+ MOVE_UNALIGNED32_TO_32 (&result_desc->number.value, location);
+
+ /*
+ * Shift the 32-bit word containing the field, and mask off the
+ * resulting value
+ */
+
+ result_desc->number.value =
+ (result_desc->number.value >> field_desc->field_unit.bit_offset) & mask;
+
+ /* Release global lock if we acquired it earlier */
+
+ acpi_aml_release_global_lock (locked);
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_resolve_to_value
+ *
+ * PARAMETERS: **Stack_ptr - Points to entry on Obj_stack, which can
+ * be either an (ACPI_OBJECT_INTERNAL *)
+ * or an ACPI_HANDLE.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Convert Reference entries on Obj_stack to Rvalues
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_resolve_to_value (
+ ACPI_OBJECT_INTERNAL **stack_ptr)
+{
+ ACPI_STATUS status = AE_OK;
+
+
+ if (!stack_ptr || !*stack_ptr) {
+ return (AE_AML_NO_OPERAND);
+ }
+
+
+ /*
+ * The entity pointed to by the Stack_ptr can be either
+ * 1) A valid ACPI_OBJECT_INTERNAL, or
+ * 2) A ACPI_NAMED_OBJECT(nte)
+ */
+
+ if (VALID_DESCRIPTOR_TYPE (*stack_ptr, ACPI_DESC_TYPE_INTERNAL)) {
+
+ status = acpi_aml_resolve_object_to_value (stack_ptr);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+ /*
+ * Object on the stack may have changed if Acpi_aml_resolve_object_to_value()
+ * was called (i.e., we can't use an _else_ here.)
+ */
+
+ if (VALID_DESCRIPTOR_TYPE (*stack_ptr, ACPI_DESC_TYPE_NAMED)) {
+ status = acpi_aml_resolve_entry_to_value ((ACPI_NAMED_OBJECT**) stack_ptr);
+ }
+
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_resolve_object_to_value
+ *
+ * PARAMETERS: Stack_ptr - Pointer to a stack location that contains a
+ * ptr to an internal object.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieve the value from an internal object. The Reference type
+ * uses the associated AML opcode to determine the value.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_resolve_object_to_value (
+ ACPI_OBJECT_INTERNAL **stack_ptr)
+{
+ ACPI_OBJECT_INTERNAL *stack_desc;
+ ACPI_STATUS status = AE_OK;
+ ACPI_HANDLE temp_handle = NULL;
+ ACPI_OBJECT_INTERNAL *obj_desc = NULL;
+ u32 index = 0;
+ u16 opcode;
+
+
+ stack_desc = *stack_ptr;
+
+ /* This is an ACPI_OBJECT_INTERNAL */
+
+ switch (stack_desc->common.type)
+ {
+
+ case INTERNAL_TYPE_REFERENCE:
+
+ opcode = stack_desc->reference.op_code;
+
+ switch (opcode)
+ {
+
+ case AML_NAME_OP:
+
+ /*
+ * Convert indirect name ptr to a direct name ptr.
+ * Then, Acpi_aml_resolve_entry_to_value can be used to get the value
+ */
+
+ temp_handle = stack_desc->reference.object;
+
+ /* Delete the Reference Object */
+
+ acpi_cm_remove_reference (stack_desc);
+
+ /* Put direct name pointer onto stack and exit */
+
+ (*stack_ptr) = temp_handle;
+ status = AE_OK;
+ break;
+
+
+ case AML_LOCAL_OP:
+
+ index = stack_desc->reference.offset;
+
+ /* Delete the Reference Object */
+
+ acpi_cm_remove_reference (stack_desc);
+
+ /*
+ * Get the local from the method's state info
+ * Note: this increments the object reference count
+ */
+
+ status = acpi_ds_method_data_get_value (MTH_TYPE_LOCAL, index,
+ stack_ptr);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ stack_desc = *stack_ptr;
+
+ if (ACPI_TYPE_NUMBER == stack_desc->common.type) {
+ /* Value is a Number */
+
+ }
+
+ break;
+
+
+ case AML_ARG_OP:
+
+ index = stack_desc->reference.offset;
+
+ /* Delete the Reference Object*/
+
+ acpi_cm_remove_reference (stack_desc);
+
+ /*
+ * Get the argument from the method's state info
+ * Note: this increments the object reference count
+ */
+
+ status = acpi_ds_method_data_get_value (MTH_TYPE_ARG, index,
+ stack_ptr);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ stack_desc = *stack_ptr;
+
+ if (ACPI_TYPE_NUMBER == stack_desc->common.type) {
+ /* Value is a Number */
+
+ }
+
+ break;
+
+
+ /*
+ * TBD: [Restructure] These next three opcodes change the type of
+ * the object, which is actually a no-no.
+ */
+
+ case AML_ZERO_OP:
+
+ stack_desc->common.type = (u8) ACPI_TYPE_NUMBER;
+ stack_desc->number.value = 0;
+ break;
+
+
+ case AML_ONE_OP:
+
+ stack_desc->common.type = (u8) ACPI_TYPE_NUMBER;
+ stack_desc->number.value = 1;
+ break;
+
+
+ case AML_ONES_OP:
+
+ stack_desc->common.type = (u8) ACPI_TYPE_NUMBER;
+ stack_desc->number.value = 0xFFFFFFFF;
+ break;
+
+
+ case AML_INDEX_OP:
+
+ switch (stack_desc->reference.target_type)
+ {
+ case ACPI_TYPE_BUFFER_FIELD:
+
+ /* Just return - leave the Reference on the stack */
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+ obj_desc = *stack_desc->reference.where;
+ if (obj_desc) {
+ /*
+ * Valid obj descriptor, copy pointer to return value
+ * (i.e., dereference the package index)
+ * Delete the ref object, increment the returned object
+ */
+ acpi_cm_remove_reference (stack_desc);
+ acpi_cm_add_reference (obj_desc);
+ *stack_ptr = obj_desc;
+ }
+
+ else {
+ /*
+ * A NULL object descriptor means an unitialized element of
+ * the package, can't deref it
+ */
+
+ status = AE_AML_UNINITIALIZED_ELEMENT;
+ }
+ break;
+
+ default:
+ /* Invalid reference OBJ*/
+
+ status = AE_AML_INTERNAL;
+ break;
+ }
+
+ break;
+
+
+ case AML_DEBUG_OP:
+
+ /* Just leave the object as-is */
+ break;
+
+
+ default:
+
+ status = AE_AML_INTERNAL;
+
+ } /* switch (Opcode) */
+
+
+ if (AE_OK != status) {
+ return (status);
+ }
+
+ break; /* case INTERNAL_TYPE_REFERENCE */
+
+
+ case ACPI_TYPE_FIELD_UNIT:
+
+ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_ANY);
+ if (!obj_desc) {
+ /* Descriptor allocation failure */
+
+ return (AE_NO_MEMORY);
+ }
+
+ status = acpi_aml_get_field_unit_value (stack_desc, obj_desc);
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_remove_reference (obj_desc);
+ obj_desc = NULL;
+ }
+
+ *stack_ptr = (void *) obj_desc;
+ break;
+
+
+ case INTERNAL_TYPE_BANK_FIELD:
+
+ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_ANY);
+ if (!obj_desc) {
+ /* Descriptor allocation failure */
+
+ return (AE_NO_MEMORY);
+ }
+
+ status = acpi_aml_get_field_unit_value (stack_desc, obj_desc);
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_remove_reference (obj_desc);
+ obj_desc = NULL;
+ }
+
+ *stack_ptr = (void *) obj_desc;
+ break;
+
+
+ /* TBD: [Future] - may need to handle Index_field, and Def_field someday */
+
+ default:
+
+ break;
+
+ } /* switch (Stack_desc->Common.Type) */
+
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/interpreter/amresop.c b/drivers/acpi/interpreter/amresop.c
new file mode 100644
index 000000000..a579d94ca
--- /dev/null
+++ b/drivers/acpi/interpreter/amresop.c
@@ -0,0 +1,429 @@
+
+/******************************************************************************
+ *
+ * Module Name: amresop - AML Interpreter operand/object resolution
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "amlcode.h"
+#include "parser.h"
+#include "dispatch.h"
+#include "interp.h"
+#include "namesp.h"
+#include "tables.h"
+#include "events.h"
+
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("amresop");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_resolve_operands
+ *
+ * PARAMETERS: Opcode Opcode being interpreted
+ * Stack_ptr Top of operand stack
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Convert stack entries to required types
+ *
+ * Each nibble in Arg_types represents one required operand
+ * and indicates the required Type:
+ *
+ * The corresponding stack entry will be converted to the
+ * required type if possible, else return an exception
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_resolve_operands (
+ u16 opcode,
+ ACPI_OBJECT_INTERNAL **stack_ptr)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_STATUS status = AE_OK;
+ u8 object_type;
+ ACPI_HANDLE temp_handle;
+ u32 arg_types;
+ ACPI_OP_INFO *op_info;
+ u32 this_arg_type;
+
+
+ op_info = acpi_ps_get_opcode_info (opcode);
+ if (!op_info) {
+ return (AE_AML_BAD_OPCODE);
+ }
+
+
+ arg_types = op_info->runtime_args;
+ if (arg_types == ARGI_INVALID_OPCODE) {
+ status = AE_AML_INTERNAL;
+ goto cleanup;
+ }
+
+
+ /*
+ * Normal exit is with *Types == '\0' at end of string.
+ * Function will return an exception from within the loop upon
+ * finding an entry which is not, and cannot be converted
+ * to, the required type; if stack underflows; or upon
+ * finding a NULL stack entry (which "should never happen").
+ */
+
+ while (GET_CURRENT_ARG_TYPE (arg_types)) {
+ if (!stack_ptr || !*stack_ptr) {
+ status = AE_AML_INTERNAL;
+ goto cleanup;
+ }
+
+ /* Extract useful items */
+
+ obj_desc = *stack_ptr;
+
+ /* Decode the descriptor type */
+
+ if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) {
+ /* NTE */
+
+ object_type = ((ACPI_NAMED_OBJECT*) obj_desc)->type;
+ }
+
+ else if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_INTERNAL)) {
+ /* ACPI internal object */
+
+ object_type = obj_desc->common.type;
+
+ /* Check for bad ACPI_OBJECT_TYPE */
+
+ if (!acpi_aml_validate_object_type (object_type)) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+ if (object_type == (u8) INTERNAL_TYPE_REFERENCE) {
+ /*
+ * Decode the Reference
+ */
+
+ op_info = acpi_ps_get_opcode_info (opcode);
+ if (!op_info) {
+ return (AE_AML_BAD_OPCODE);
+ }
+
+
+ switch (obj_desc->reference.op_code)
+ {
+ case AML_ZERO_OP:
+ case AML_ONE_OP:
+ case AML_ONES_OP:
+ case AML_DEBUG_OP:
+ case AML_NAME_OP:
+ case AML_INDEX_OP:
+ case AML_ARG_OP:
+ case AML_LOCAL_OP:
+
+ break;
+
+ default:
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ break;
+ }
+ }
+
+ }
+
+ else {
+ /* Invalid descriptor */
+
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+
+ /*
+ * Decode a character from the type string
+ */
+
+ this_arg_type = GET_CURRENT_ARG_TYPE (arg_types);
+ INCREMENT_ARG_LIST (arg_types);
+
+
+ switch (this_arg_type)
+ {
+
+ case ARGI_REFERENCE: /* Reference */
+ case ARGI_TARGETREF:
+
+ /* Need an operand of type INTERNAL_TYPE_REFERENCE */
+
+ if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) /* direct name ptr OK as-is */ {
+ break;
+ }
+
+ if (INTERNAL_TYPE_REFERENCE != object_type) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+ if (AML_NAME_OP == obj_desc->reference.op_code) {
+ /*
+ * Convert an indirect name ptr to direct name ptr and put
+ * it on the stack
+ */
+
+ temp_handle = obj_desc->reference.object;
+ acpi_cm_remove_reference (obj_desc);
+ (*stack_ptr) = temp_handle;
+ }
+ break;
+
+
+ case ARGI_NUMBER: /* Number */
+
+ /* Need an operand of type ACPI_TYPE_NUMBER */
+
+ if ((status = acpi_aml_resolve_to_value (stack_ptr)) != AE_OK) {
+ goto cleanup;
+ }
+
+ if (ACPI_TYPE_NUMBER != (*stack_ptr)->common.type) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+ break;
+
+
+ case ARGI_STRING:
+
+ /* Need an operand of type ACPI_TYPE_STRING or ACPI_TYPE_BUFFER */
+
+ if ((status = acpi_aml_resolve_to_value (stack_ptr)) != AE_OK) {
+ goto cleanup;
+ }
+
+ if ((ACPI_TYPE_STRING != (*stack_ptr)->common.type) &&
+ (ACPI_TYPE_BUFFER != (*stack_ptr)->common.type))
+ {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+ break;
+
+
+ case ARGI_BUFFER:
+
+ /* Need an operand of type ACPI_TYPE_BUFFER */
+
+ if ((status = acpi_aml_resolve_to_value(stack_ptr)) != AE_OK) {
+ goto cleanup;
+ }
+
+ if (ACPI_TYPE_BUFFER != (*stack_ptr)->common.type) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+ break;
+
+
+ case ARGI_MUTEX:
+
+ /* Need an operand of type ACPI_TYPE_MUTEX */
+
+ if ((status = acpi_aml_resolve_to_value(stack_ptr)) != AE_OK) {
+ goto cleanup;
+ }
+
+ if (ACPI_TYPE_MUTEX != (*stack_ptr)->common.type) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+ break;
+
+
+ case ARGI_EVENT:
+
+ /* Need an operand of type ACPI_TYPE_EVENT */
+
+ if ((status = acpi_aml_resolve_to_value(stack_ptr)) != AE_OK) {
+ goto cleanup;
+ }
+
+ if (ACPI_TYPE_EVENT != (*stack_ptr)->common.type) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+ break;
+
+
+ case ARGI_REGION:
+
+ /* Need an operand of type ACPI_TYPE_REGION */
+
+ if ((status = acpi_aml_resolve_to_value(stack_ptr)) != AE_OK) {
+ goto cleanup;
+ }
+
+ if (ACPI_TYPE_REGION != (*stack_ptr)->common.type) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+ break;
+
+
+ case ARGI_IF: /* If */
+
+ /* Need an operand of type INTERNAL_TYPE_IF */
+
+ if (INTERNAL_TYPE_IF != (*stack_ptr)->common.type) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+ break;
+
+
+ case ARGI_PACKAGE: /* Package */
+
+ /* Need an operand of type ACPI_TYPE_PACKAGE */
+
+ if ((status = acpi_aml_resolve_to_value (stack_ptr)) != AE_OK) {
+ goto cleanup;
+ }
+
+ if (ACPI_TYPE_PACKAGE != (*stack_ptr)->common.type) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+ break;
+
+
+ case ARGI_ANYTYPE:
+
+
+ /*
+ * We don't want to resolve Index_op reference objects during
+ * a store because this would be an implicit De_ref_of operation.
+ * Instead, we just want to store the reference object.
+ */
+
+ if ((opcode == AML_STORE_OP) &&
+ ((*stack_ptr)->common.type == INTERNAL_TYPE_REFERENCE) &&
+ ((*stack_ptr)->reference.op_code == AML_INDEX_OP))
+ {
+ break;
+ }
+
+ /* All others must be resolved */
+
+ if ((status = acpi_aml_resolve_to_value (stack_ptr)) != AE_OK) {
+ goto cleanup;
+ }
+
+ /* All types OK, so we don't perform any typechecks */
+
+ break;
+
+
+ case ARGI_DATAOBJECT:
+ /*
+ * ARGI_DATAOBJECT is only used by the Size_of operator.
+ *
+ * The ACPI specification allows Size_of to return the size of
+ * a Buffer, String or Package. However, the MS ACPI.SYS AML
+ * Interpreter also allows an NTE reference to return without
+ * error with a size of 4.
+ */
+
+ if ((status = acpi_aml_resolve_to_value (stack_ptr)) != AE_OK) {
+ goto cleanup;
+ }
+
+ /* Need a buffer, string, package or NTE reference */
+
+ if (((*stack_ptr)->common.type != ACPI_TYPE_BUFFER) &&
+ ((*stack_ptr)->common.type != ACPI_TYPE_STRING) &&
+ ((*stack_ptr)->common.type != ACPI_TYPE_PACKAGE) &&
+ ((*stack_ptr)->common.type != INTERNAL_TYPE_REFERENCE))
+ {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+ /*
+ * If this is a reference, only allow a reference to an NTE.
+ */
+ if ((*stack_ptr)->common.type == INTERNAL_TYPE_REFERENCE) {
+ if (!(*stack_ptr)->reference.nte) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+ }
+
+ break;
+
+
+ case ARGI_COMPLEXOBJ:
+
+ if ((status = acpi_aml_resolve_to_value (stack_ptr)) != AE_OK) {
+ goto cleanup;
+ }
+
+ /* Need a buffer or package */
+
+ if (((*stack_ptr)->common.type != ACPI_TYPE_BUFFER) &&
+ ((*stack_ptr)->common.type != ACPI_TYPE_PACKAGE))
+ {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+ break;
+
+
+ /* Unknown abbreviation passed in */
+
+ default:
+ status = AE_BAD_PARAMETER;
+ goto cleanup;
+
+ } /* switch (*Types++) */
+
+
+ /*
+ * If more operands needed, decrement Stack_ptr to point
+ * to next operand on stack (after checking for underflow).
+ */
+ if (GET_CURRENT_ARG_TYPE (arg_types)) {
+ stack_ptr--;
+ }
+
+ } /* while (*Types) */
+
+
+cleanup:
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/interpreter/amstore.c b/drivers/acpi/interpreter/amstore.c
new file mode 100644
index 000000000..9f9ec96d8
--- /dev/null
+++ b/drivers/acpi/interpreter/amstore.c
@@ -0,0 +1,374 @@
+
+/******************************************************************************
+ *
+ * Module Name: amstore - AML Interpreter object store support
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "dispatch.h"
+#include "interp.h"
+#include "amlcode.h"
+#include "namesp.h"
+#include "tables.h"
+
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("amstore");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exec_store
+ *
+ * PARAMETERS: *Val_desc - Value to be stored
+ * *Dest_desc - Where to store it 0 Must be (ACPI_HANDLE)
+ * or an ACPI_OBJECT_INTERNAL of type
+ * Reference; if the latter the descriptor
+ * will be either reused or deleted.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Store the value described by Val_desc into the location
+ * described by Dest_desc. Called by various interpreter
+ * functions to store the result of an operation into
+ * the destination operand.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_exec_store (
+ ACPI_OBJECT_INTERNAL *val_desc,
+ ACPI_OBJECT_INTERNAL *dest_desc)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_OBJECT_INTERNAL *delete_dest_desc = NULL;
+ ACPI_OBJECT_INTERNAL *tmp_desc;
+ ACPI_NAMED_OBJECT *entry = NULL;
+ u8 value = 0;
+ u32 length;
+ u32 i;
+
+
+ /* Validate parameters */
+
+ if (!val_desc || !dest_desc) {
+ return (AE_AML_NO_OPERAND);
+ }
+
+ /* Examine the datatype of the Dest_desc */
+
+ if (VALID_DESCRIPTOR_TYPE (dest_desc, ACPI_DESC_TYPE_NAMED)) {
+ /* Dest is an ACPI_HANDLE, create a new object */
+
+ entry = (ACPI_NAMED_OBJECT*) dest_desc;
+ dest_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REFERENCE);
+ if (!dest_desc) {
+ /* Allocation failure */
+
+ return (AE_NO_MEMORY);
+ }
+
+ /* Build a new Reference wrapper around the handle */
+
+ dest_desc->reference.op_code = AML_NAME_OP;
+ dest_desc->reference.object = entry;
+ }
+
+
+ /* Destination object must be of type Reference */
+
+ if (dest_desc->common.type != INTERNAL_TYPE_REFERENCE) {
+ /* Destination is not an Reference */
+
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ /* Examine the Reference opcode */
+
+ switch (dest_desc->reference.op_code)
+ {
+
+ case AML_NAME_OP:
+
+ /*
+ * Storing into a Name
+ */
+ delete_dest_desc = dest_desc;
+ status = acpi_aml_store_object_to_nte (val_desc, dest_desc->reference.object);
+
+ break; /* Case Name_op */
+
+
+ case AML_INDEX_OP:
+
+ delete_dest_desc = dest_desc;
+
+ /*
+ * Valid source value and destination reference pointer.
+ *
+ * ACPI Specification 1.0B section 15.2.3.4.2.13:
+ * Destination should point to either a buffer or a package
+ */
+
+ /*
+ * Actually, storing to a package is not so simple. The source must be
+ * evaluated and converted to the type of the destination and then the
+ * source is copied into the destination - we can't just point to the
+ * source object.
+ */
+ if (dest_desc->reference.target_type == ACPI_TYPE_PACKAGE) {
+ /*
+ * The object at *(Dest_desc->Reference.Where) is the
+ * element within the package that is to be modified.
+ */
+ tmp_desc = *(dest_desc->reference.where);
+ if (tmp_desc) {
+ /*
+ * If the Destination element is a package, we will delete
+ * that object and construct a new one.
+ *
+ * TBD: [Investigate] Should both the src and dest be required
+ * to be packages?
+ * && (Val_desc->Common.Type == ACPI_TYPE_PACKAGE)
+ */
+ if (tmp_desc->common.type == ACPI_TYPE_PACKAGE) {
+ /*
+ * Take away the reference for being part of a package and
+ * delete
+ */
+ acpi_cm_remove_reference (tmp_desc);
+ acpi_cm_remove_reference (tmp_desc);
+
+ tmp_desc = NULL;
+ }
+ }
+
+ if (!tmp_desc) {
+ /*
+ * If the Tmp_desc is NULL, that means an uninitialized package
+ * has been used as a destination, therefore, we must create
+ * the destination element to match the type of the source
+ * element NOTE: Val_desc can be of any type.
+ */
+ tmp_desc = acpi_cm_create_internal_object (val_desc->common.type);
+ if (!tmp_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * If the source is a package, copy the source to the new dest
+ */
+ if (ACPI_TYPE_PACKAGE == tmp_desc->common.type) {
+ status = acpi_aml_build_copy_internal_package_object (
+ val_desc, tmp_desc);
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_remove_reference (tmp_desc);
+ tmp_desc = NULL;
+ goto cleanup;
+ }
+ }
+
+ /*
+ * Install the new descriptor into the package and add a
+ * reference to the newly created descriptor for now being
+ * part of the parent package
+ */
+
+ *(dest_desc->reference.where) = tmp_desc;
+ acpi_cm_add_reference (tmp_desc);
+ }
+
+ if (ACPI_TYPE_PACKAGE != tmp_desc->common.type) {
+ /*
+ * The destination element is not a package, so we need to
+ * convert the contents of the source (Val_desc) and copy into
+ * the destination (Tmp_desc)
+ */
+ status = acpi_aml_store_object_to_object(val_desc, tmp_desc);
+ if (ACPI_FAILURE (status)) {
+ /*
+ * An error occurrered when copying the internal object
+ * so delete the reference.
+ */
+ status = AE_AML_OPERAND_TYPE;
+ }
+ }
+
+ break;
+ }
+
+ /*
+ * Check that the destination is a Buffer Field type
+ */
+ if (dest_desc->reference.target_type != ACPI_TYPE_BUFFER_FIELD) {
+ status = AE_AML_OPERAND_TYPE;
+ break;
+ }
+
+ /*
+ * Storing into a buffer at a location defined by an Index.
+ *
+ * Each 8-bit element of the source object is written to the
+ * 8-bit Buffer Field of the Index destination object.
+ */
+
+ /*
+ * Set the Tmp_desc to the destination object and type check.
+ */
+ tmp_desc = dest_desc->reference.object;
+
+ if (tmp_desc->common.type != ACPI_TYPE_BUFFER) {
+ status = AE_AML_OPERAND_TYPE;
+ break;
+ }
+
+ /*
+ * The assignment of the individual elements will be slightly
+ * different for each source type.
+ */
+
+ switch (val_desc->common.type)
+ {
+ /*
+ * If the type is Integer, the Length is 4.
+ * This loop to assign each of the elements is somewhat
+ * backward because of the Big Endian-ness of IA-64
+ */
+ case ACPI_TYPE_NUMBER:
+ length = 4;
+ for (i = length; i != 0; i--) {
+ value = (u8)(val_desc->number.value >> (MUL_8 (i - 1)));
+ tmp_desc->buffer.pointer[dest_desc->reference.offset] = value;
+ }
+ break;
+
+ /*
+ * If the type is Buffer, the Length is in the structure.
+ * Just loop through the elements and assign each one in turn.
+ */
+ case ACPI_TYPE_BUFFER:
+ length = val_desc->buffer.length;
+ for (i = 0; i < length; i++) {
+ value = *(val_desc->buffer.pointer + i);
+ tmp_desc->buffer.pointer[dest_desc->reference.offset] = value;
+ }
+ break;
+
+ /*
+ * If the type is String, the Length is in the structure.
+ * Just loop through the elements and assign each one in turn.
+ */
+ case ACPI_TYPE_STRING:
+ length = val_desc->string.length;
+ for (i = 0; i < length; i++) {
+ value = *(val_desc->string.pointer + i);
+ tmp_desc->buffer.pointer[dest_desc->reference.offset] = value;
+ }
+ break;
+
+ /*
+ * If source is not a valid type so return an error.
+ */
+ default:
+ status = AE_AML_OPERAND_TYPE;
+ break;
+ }
+
+ /*
+ * If we had an error, break out of this case statement.
+ */
+ if(AE_OK != status) {
+ break;
+ }
+
+ /*
+ * Set the return pointer
+ */
+ dest_desc = tmp_desc;
+
+ break;
+
+ case AML_ZERO_OP:
+ case AML_ONE_OP:
+ case AML_ONES_OP:
+
+ /*
+ * Storing to a constant is a no-op -- see spec sec 15.2.3.3.1.
+ * Delete the result descriptor.
+ */
+
+ delete_dest_desc = dest_desc;
+ break;
+
+
+ case AML_LOCAL_OP:
+
+ status = acpi_ds_method_data_set_value (MTH_TYPE_LOCAL,
+ (dest_desc->reference.offset), val_desc);
+ delete_dest_desc = dest_desc;
+ break;
+
+
+ case AML_ARG_OP:
+
+ status = acpi_ds_method_data_set_value (MTH_TYPE_ARG,
+ (dest_desc->reference.offset), val_desc);
+ delete_dest_desc = dest_desc;
+ break;
+
+
+ case AML_DEBUG_OP:
+
+ /*
+ * Storing to the Debug object causes the value stored to be
+ * displayed and otherwise has no effect -- see sec. 15.2.3.3.3.
+ */
+
+ delete_dest_desc = dest_desc;
+ break;
+
+
+ default:
+
+ /* TBD: [Restructure] use object dump routine !! */
+
+ delete_dest_desc = dest_desc;
+ status = AE_AML_INTERNAL;
+
+ } /* switch(Dest_desc->Reference.Op_code) */
+
+
+cleanup:
+
+ /* Cleanup and exit*/
+
+ if (delete_dest_desc) {
+ acpi_cm_remove_reference (delete_dest_desc);
+ }
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/interpreter/amstoren.c b/drivers/acpi/interpreter/amstoren.c
new file mode 100644
index 000000000..4d35d0c54
--- /dev/null
+++ b/drivers/acpi/interpreter/amstoren.c
@@ -0,0 +1,518 @@
+
+/******************************************************************************
+ *
+ * Module Name: amstoren - AML Interpreter object store support, store to NTE
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "dispatch.h"
+#include "interp.h"
+#include "amlcode.h"
+#include "namesp.h"
+#include "tables.h"
+
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("amstoren");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_store_object_to_nte
+ *
+ * PARAMETERS: *Val_desc - Value to be stored
+ * *Entry - Named object to recieve the value
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Store the object to the named object.
+ *
+ * The Assignment of an object to a named object is handled here
+ * The val passed in will replace the current value (if any)
+ * with the input value.
+ *
+ * When storing into an object the data is converted to the
+ * target object type then stored in the object. This means
+ * that the target object type (for an initialized target) will
+ * not be changed by a store operation.
+ *
+ * NOTE: the global lock is acquired early. This will result
+ * in the global lock being held a bit longer. Also, if the
+ * function fails during set up we may get the lock when we
+ * don't really need it. I don't think we care.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_store_object_to_nte (
+ ACPI_OBJECT_INTERNAL *val_desc,
+ ACPI_NAMED_OBJECT *entry)
+{
+ ACPI_STATUS status = AE_OK;
+ u8 *buffer = NULL;
+ u32 length = 0;
+ u32 mask;
+ u32 new_value;
+ u8 locked = FALSE;
+ u8 *location=NULL;
+ ACPI_OBJECT_INTERNAL *dest_desc;
+ OBJECT_TYPE_INTERNAL destination_type = ACPI_TYPE_ANY;
+
+
+ /*
+ * Assuming the parameters are valid!!!
+ */
+ ACPI_ASSERT((entry) && (val_desc));
+
+ destination_type = acpi_ns_get_type (entry);
+
+ /*
+ * First ensure we have a value that can be stored in the target
+ */
+ switch (destination_type)
+ {
+ /* Type of Name's existing value */
+
+ case INTERNAL_TYPE_ALIAS:
+
+ /*
+ * Aliases are resolved by Acpi_aml_prep_operands
+ */
+
+ status = AE_AML_INTERNAL;
+ break;
+
+
+ case INTERNAL_TYPE_BANK_FIELD:
+ case INTERNAL_TYPE_INDEX_FIELD:
+ case ACPI_TYPE_FIELD_UNIT:
+ case ACPI_TYPE_NUMBER:
+
+ /*
+ * These cases all require only number values or values that
+ * can be converted to numbers.
+ *
+ * If value is not a Number, try to resolve it to one.
+ */
+
+ if (val_desc->common.type != ACPI_TYPE_NUMBER) {
+ /*
+ * Initially not a number, convert
+ */
+ status = acpi_aml_resolve_to_value (&val_desc);
+ if ((status == AE_OK) &&
+ (val_desc->common.type != ACPI_TYPE_NUMBER))
+ {
+ /*
+ * Conversion successful but still not a number
+ */
+ status = AE_AML_OPERAND_TYPE;
+ }
+ }
+
+ break;
+
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+ case INTERNAL_TYPE_DEF_FIELD:
+
+ /*
+ * Storing into a Field in a region or into a buffer or into
+ * a string all is essentially the same.
+ *
+ * If value is not a valid type, try to resolve it to one.
+ */
+
+ if ((val_desc->common.type != ACPI_TYPE_NUMBER) &&
+ (val_desc->common.type != ACPI_TYPE_BUFFER) &&
+ (val_desc->common.type != ACPI_TYPE_STRING))
+ {
+ /*
+ * Initially not a valid type, convert
+ */
+ status = acpi_aml_resolve_to_value (&val_desc);
+ if ((status == AE_OK) &&
+ (val_desc->common.type != ACPI_TYPE_NUMBER) &&
+ (val_desc->common.type != ACPI_TYPE_BUFFER) &&
+ (val_desc->common.type != ACPI_TYPE_STRING))
+ {
+ /*
+ * Conversion successful but still not a valid type
+ */
+ status = AE_AML_OPERAND_TYPE;
+ }
+ }
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+
+ /*
+ * TBD: [Unhandled] Not real sure what to do here
+ */
+ status = AE_NOT_IMPLEMENTED;
+ break;
+
+
+ default:
+
+ /*
+ * All other types than Alias and the various Fields come here.
+ * Store Val_desc as the new value of the Name, and set
+ * the Name's type to that of the value being stored in it.
+ * Val_desc reference count is incremented by Attach_object.
+ */
+
+ status = acpi_ns_attach_object (entry, val_desc, val_desc->common.type);
+
+ goto clean_up_and_bail_out;
+ break;
+ }
+
+ /* Exit now if failure above */
+
+ if (status != AE_OK) {
+ goto clean_up_and_bail_out;
+ }
+
+ /*
+ * Get descriptor for object attached to NTE
+ */
+ dest_desc = acpi_ns_get_attached_object (entry);
+ if (!dest_desc) {
+ /*
+ * There is no existing object attached to this NTE
+ */
+ status = AE_AML_INTERNAL;
+ goto clean_up_and_bail_out;
+ }
+
+ /*
+ * Make sure the destination Object is the same as the NTE
+ */
+ if (dest_desc->common.type != (u8) destination_type) {
+ status = AE_AML_INTERNAL;
+ goto clean_up_and_bail_out;
+ }
+
+ /*
+ * Acpi_everything is ready to execute now, We have
+ * a value we can handle, just perform the update
+ */
+
+ switch (destination_type)
+ {
+ /* Type of Name's existing value */
+
+ case INTERNAL_TYPE_BANK_FIELD:
+
+ /*
+ * Get the global lock if needed
+ */
+ locked = acpi_aml_acquire_global_lock (dest_desc->bank_field.lock_rule);
+
+ /*
+ * Set Bank value to select proper Bank
+ * Perform the update (Set Bank Select)
+ */
+
+ status = acpi_aml_set_named_field_value (dest_desc->bank_field.bank_select,
+ &dest_desc->bank_field.value,
+ sizeof (dest_desc->bank_field.value));
+ if (status == AE_OK) {
+ /* Set bank select successful, set data value */
+
+ status = acpi_aml_set_named_field_value (dest_desc->bank_field.bank_select,
+ &val_desc->bank_field.value,
+ sizeof (val_desc->bank_field.value));
+ }
+
+ break;
+
+
+ case INTERNAL_TYPE_DEF_FIELD:
+
+ /*
+ * Get the global lock if needed
+ */
+ locked = acpi_aml_acquire_global_lock (val_desc->field.lock_rule);
+
+ /*
+ * Perform the update
+ */
+
+ switch (val_desc->common.type)
+ {
+ case ACPI_TYPE_NUMBER:
+ buffer = (u8 *) &val_desc->number.value;
+ length = sizeof (val_desc->number.value);
+ break;
+
+ case ACPI_TYPE_BUFFER:
+ buffer = (u8 *) val_desc->buffer.pointer;
+ length = val_desc->buffer.length;
+ break;
+
+ case ACPI_TYPE_STRING:
+ buffer = (u8 *) val_desc->string.pointer;
+ length = val_desc->string.length;
+ break;
+ }
+
+ status = acpi_aml_set_named_field_value (entry, buffer, length);
+ break; /* Global Lock released below */
+
+
+ case ACPI_TYPE_STRING:
+
+ /*
+ * Perform the update
+ */
+
+ switch (val_desc->common.type)
+ {
+ case ACPI_TYPE_NUMBER:
+ buffer = (u8 *) &val_desc->number.value;
+ length = sizeof (val_desc->number.value);
+ break;
+
+ case ACPI_TYPE_BUFFER:
+ buffer = (u8 *) val_desc->buffer.pointer;
+ length = val_desc->buffer.length;
+ break;
+
+ case ACPI_TYPE_STRING:
+ buffer = (u8 *) val_desc->string.pointer;
+ length = val_desc->string.length;
+ break;
+ }
+
+ /*
+ * Setting a string value replaces the old string
+ */
+
+ if (length < dest_desc->string.length) {
+ /*
+ * Zero fill, not willing to do pointer arithmetic for
+ * archetecture independance. Just clear the whole thing
+ */
+ MEMSET(dest_desc->string.pointer, 0, dest_desc->string.length);
+ MEMCPY(dest_desc->string.pointer, buffer, length);
+ }
+ else {
+ /*
+ * Free the current buffer, then allocate a buffer
+ * large enough to hold the value
+ */
+ if ( dest_desc->string.pointer &&
+ !acpi_tb_system_table_pointer (dest_desc->string.pointer))
+ {
+ /*
+ * Only free if not a pointer into the DSDT
+ */
+
+ acpi_cm_free(dest_desc->string.pointer);
+ }
+
+ dest_desc->string.pointer = acpi_cm_allocate (length + 1);
+ dest_desc->string.length = length;
+
+ if (!dest_desc->string.pointer) {
+ status = AE_NO_MEMORY;
+ goto clean_up_and_bail_out;
+ }
+
+ MEMCPY(dest_desc->string.pointer, buffer, length);
+ }
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ /*
+ * Perform the update to the buffer
+ */
+
+ switch (val_desc->common.type)
+ {
+ case ACPI_TYPE_NUMBER:
+ buffer = (u8 *) &val_desc->number.value;
+ length = sizeof (val_desc->number.value);
+ break;
+
+ case ACPI_TYPE_BUFFER:
+ buffer = (u8 *) val_desc->buffer.pointer;
+ length = val_desc->buffer.length;
+ break;
+
+ case ACPI_TYPE_STRING:
+ buffer = (u8 *) val_desc->string.pointer;
+ length = val_desc->string.length;
+ break;
+ }
+
+ /*
+ * Buffer is a static allocation,
+ * only place what will fit in the buffer.
+ */
+ if (length <= dest_desc->buffer.length) {
+ /*
+ * Zero fill first, not willing to do pointer arithmetic for
+ * archetecture independence. Just clear the whole thing
+ */
+ MEMSET(dest_desc->buffer.pointer, 0, dest_desc->buffer.length);
+ MEMCPY(dest_desc->buffer.pointer, buffer, length);
+ }
+ else {
+ /*
+ * truncate, copy only what will fit
+ */
+ MEMCPY(dest_desc->buffer.pointer, buffer, dest_desc->buffer.length);
+ }
+ break;
+
+
+ case INTERNAL_TYPE_INDEX_FIELD:
+
+ /*
+ * Get the global lock if needed
+ */
+ locked = acpi_aml_acquire_global_lock (dest_desc->index_field.lock_rule);
+
+ /*
+ * Set Index value to select proper Data register
+ * perform the update (Set index)
+ */
+
+ status = acpi_aml_set_named_field_value (dest_desc->index_field.index,
+ &dest_desc->index_field.value,
+ sizeof (dest_desc->index_field.value));
+
+ if (AE_OK == status) {
+ /* set index successful, next set Data value */
+
+ status = acpi_aml_set_named_field_value (dest_desc->index_field.data,
+ &val_desc->number.value,
+ sizeof (val_desc->number.value));
+ }
+ break;
+
+
+ case ACPI_TYPE_FIELD_UNIT:
+
+ if ((!dest_desc->field_unit.container ||
+ ACPI_TYPE_BUFFER != dest_desc->field_unit.container->common.type ||
+ dest_desc->field_unit.sequence !=
+ dest_desc->field_unit.container->buffer.sequence))
+ {
+ status = AE_AML_INTERNAL;
+ goto clean_up_and_bail_out;
+ }
+
+ /*
+ * Get the global lock if needed
+ */
+ locked = acpi_aml_acquire_global_lock (dest_desc->field_unit.lock_rule);
+
+ /*
+ * TBD: [Unhandled] REMOVE this limitation
+ * Make sure the operation is within the limits of our implementation
+ * this is not a Spec limitation!!
+ */
+ if (dest_desc->field_unit.length + dest_desc->field_unit.bit_offset > 32) {
+ status = AE_NOT_IMPLEMENTED;
+ goto clean_up_and_bail_out;
+ }
+
+ /* Field location is (base of buffer) + (byte offset) */
+
+ location = dest_desc->field_unit.container->buffer.pointer
+ + dest_desc->field_unit.offset;
+
+ /*
+ * Construct Mask with 1 bits where the field is,
+ * 0 bits elsewhere
+ */
+ mask = ((u32) 1 << dest_desc->field_unit.length) - ((u32)1
+ << dest_desc->field_unit.bit_offset);
+
+ /* Zero out the field in the buffer */
+
+ MOVE_UNALIGNED32_TO_32 (&new_value, location);
+ new_value &= ~mask;
+
+ /*
+ * Shift and mask the new value into position,
+ * and or it into the buffer.
+ */
+ new_value |= (val_desc->number.value << dest_desc->field_unit.bit_offset) &
+ mask;
+
+ /* Store back the value */
+
+ MOVE_UNALIGNED32_TO_32 (location, &new_value);
+
+ break;
+
+
+ case ACPI_TYPE_NUMBER:
+
+ dest_desc->number.value = val_desc->number.value;
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+
+ /*
+ * TBD: [Unhandled] Not real sure what to do here
+ */
+ status = AE_NOT_IMPLEMENTED;
+ break;
+
+
+ default:
+
+ /*
+ * All other types than Alias and the various Fields come here.
+ * Store Val_desc as the new value of the Name, and set
+ * the Name's type to that of the value being stored in it.
+ * Val_desc reference count is incremented by Attach_object.
+ */
+
+ status = AE_NOT_IMPLEMENTED;
+ break;
+ }
+
+
+clean_up_and_bail_out:
+
+ /*
+ * Release global lock if we acquired it earlier
+ */
+ acpi_aml_release_global_lock (locked);
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/interpreter/amstorob.c b/drivers/acpi/interpreter/amstorob.c
new file mode 100644
index 000000000..6b63108d4
--- /dev/null
+++ b/drivers/acpi/interpreter/amstorob.c
@@ -0,0 +1,314 @@
+
+/******************************************************************************
+ *
+ * Module Name: amstorob - AML Interpreter object store support, store to object
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "dispatch.h"
+#include "interp.h"
+#include "amlcode.h"
+#include "namesp.h"
+#include "tables.h"
+
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("amstorob");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_store_object_to_object
+ *
+ * PARAMETERS: *Val_desc - Value to be stored
+ * *Dest_desc - Object to receive the value
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Store an object to another object.
+ *
+ * The Assignment of an object to another (not named) object
+ * is handled here.
+ * The val passed in will replace the current value (if any)
+ * with the input value.
+ *
+ * When storing into an object the data is converted to the
+ * target object type then stored in the object. This means
+ * that the target object type (for an initialized target) will
+ * not be changed by a store operation.
+ *
+ * This module allows destination types of Number, String,
+ * and Buffer.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_store_object_to_object (
+ ACPI_OBJECT_INTERNAL *val_desc,
+ ACPI_OBJECT_INTERNAL *dest_desc)
+{
+ ACPI_STATUS status = AE_OK;
+ u8 *buffer = NULL;
+ u32 length = 0;
+ OBJECT_TYPE_INTERNAL destination_type = dest_desc->common.type;
+
+
+ /*
+ * Assuming the parameters are valid!!!
+ */
+ ACPI_ASSERT((dest_desc) && (val_desc));
+
+ /*
+ * First ensure we have a value that can be stored in the target
+ */
+ switch (destination_type)
+ {
+ /* Type of Name's existing value */
+
+ case ACPI_TYPE_NUMBER:
+
+ /*
+ * These cases all require only number values or values that
+ * can be converted to numbers.
+ *
+ * If value is not a Number, try to resolve it to one.
+ */
+
+ if (val_desc->common.type != ACPI_TYPE_NUMBER) {
+ /*
+ * Initially not a number, convert
+ */
+ status = acpi_aml_resolve_to_value (&val_desc);
+ if ((status == AE_OK) &&
+ (val_desc->common.type != ACPI_TYPE_NUMBER))
+ {
+ /*
+ * Conversion successful but still not a number
+ */
+ status = AE_AML_OPERAND_TYPE;
+ }
+ }
+
+ break;
+
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+
+ /*
+ * Storing into a Field in a region or into a buffer or into
+ * a string all is essentially the same.
+ *
+ * If value is not a valid type, try to resolve it to one.
+ */
+
+ if ((val_desc->common.type != ACPI_TYPE_NUMBER) &&
+ (val_desc->common.type != ACPI_TYPE_BUFFER) &&
+ (val_desc->common.type != ACPI_TYPE_STRING))
+ {
+ /*
+ * Initially not a valid type, convert
+ */
+ status = acpi_aml_resolve_to_value (&val_desc);
+ if ((status == AE_OK) &&
+ (val_desc->common.type != ACPI_TYPE_NUMBER) &&
+ (val_desc->common.type != ACPI_TYPE_BUFFER) &&
+ (val_desc->common.type != ACPI_TYPE_STRING))
+ {
+ /*
+ * Conversion successful but still not a valid type
+ */
+ status = AE_AML_OPERAND_TYPE;
+ }
+ }
+ break;
+
+
+ default:
+
+ /*
+ * TBD: [Unhandled] What other combinations must be implemented?
+ */
+ status = AE_NOT_IMPLEMENTED;
+ break;
+ }
+
+ /* Exit now if failure above */
+
+ if (status != AE_OK) {
+ goto clean_up_and_bail_out;
+ }
+
+ /*
+ * Acpi_everything is ready to execute now, We have
+ * a value we can handle, just perform the update
+ */
+
+ switch (destination_type)
+ {
+
+ case ACPI_TYPE_STRING:
+
+ /*
+ * Perform the update
+ */
+
+ switch (val_desc->common.type)
+ {
+ case ACPI_TYPE_NUMBER:
+ buffer = (u8 *) &val_desc->number.value;
+ length = sizeof (val_desc->number.value);
+ break;
+
+ case ACPI_TYPE_BUFFER:
+ buffer = (u8 *) val_desc->buffer.pointer;
+ length = val_desc->buffer.length;
+ break;
+
+ case ACPI_TYPE_STRING:
+ buffer = (u8 *) val_desc->string.pointer;
+ length = val_desc->string.length;
+ break;
+ }
+
+ /*
+ * Setting a string value replaces the old string
+ */
+
+ if (length < dest_desc->string.length) {
+ /*
+ * Zero fill, not willing to do pointer arithmetic for
+ * architecture independence. Just clear the whole thing
+ */
+ MEMSET(dest_desc->string.pointer, 0, dest_desc->string.length);
+ MEMCPY(dest_desc->string.pointer, buffer, length);
+ }
+ else {
+ /*
+ * Free the current buffer, then allocate a buffer
+ * large enough to hold the value
+ */
+ if ( dest_desc->string.pointer &&
+ !acpi_tb_system_table_pointer (dest_desc->string.pointer))
+ {
+ /*
+ * Only free if not a pointer into the DSDT
+ */
+
+ acpi_cm_free(dest_desc->string.pointer);
+ }
+
+ dest_desc->string.pointer = acpi_cm_allocate (length + 1);
+ dest_desc->string.length = length;
+
+ if (!dest_desc->string.pointer) {
+ status = AE_NO_MEMORY;
+ goto clean_up_and_bail_out;
+ }
+
+ MEMCPY(dest_desc->string.pointer, buffer, length);
+ }
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ /*
+ * Perform the update to the buffer
+ */
+
+ switch (val_desc->common.type)
+ {
+ case ACPI_TYPE_NUMBER:
+ buffer = (u8 *) &val_desc->number.value;
+ length = sizeof (val_desc->number.value);
+ break;
+
+ case ACPI_TYPE_BUFFER:
+ buffer = (u8 *) val_desc->buffer.pointer;
+ length = val_desc->buffer.length;
+ break;
+
+ case ACPI_TYPE_STRING:
+ buffer = (u8 *) val_desc->string.pointer;
+ length = val_desc->string.length;
+ break;
+ }
+
+ /*
+ * If the buffer is uninitialized,
+ * memory needs to be allocated for the copy.
+ */
+ if(0 == dest_desc->buffer.length) {
+ dest_desc->buffer.pointer = acpi_cm_callocate(length);
+ dest_desc->buffer.length = length;
+
+ if (!dest_desc->buffer.pointer) {
+ status = AE_NO_MEMORY;
+ goto clean_up_and_bail_out;
+ }
+ }
+
+ /*
+ * Buffer is a static allocation,
+ * only place what will fit in the buffer.
+ */
+ if (length <= dest_desc->buffer.length) {
+ /*
+ * Zero fill first, not willing to do pointer arithmetic for
+ * architecture independence. Just clear the whole thing
+ */
+ MEMSET(dest_desc->buffer.pointer, 0, dest_desc->buffer.length);
+ MEMCPY(dest_desc->buffer.pointer, buffer, length);
+ }
+ else {
+ /*
+ * truncate, copy only what will fit
+ */
+ MEMCPY(dest_desc->buffer.pointer, buffer, dest_desc->buffer.length);
+ }
+ break;
+
+ case ACPI_TYPE_NUMBER:
+
+ dest_desc->number.value = val_desc->number.value;
+ break;
+
+ default:
+
+ /*
+ * All other types than Alias and the various Fields come here.
+ * Store Val_desc as the new value of the Name, and set
+ * the Name's type to that of the value being stored in it.
+ * Val_desc reference count is incremented by Attach_object.
+ */
+
+ status = AE_NOT_IMPLEMENTED;
+ break;
+ }
+
+clean_up_and_bail_out:
+
+ return (status);
+}
+
diff --git a/drivers/acpi/interpreter/amsystem.c b/drivers/acpi/interpreter/amsystem.c
new file mode 100644
index 000000000..9207a2e72
--- /dev/null
+++ b/drivers/acpi/interpreter/amsystem.c
@@ -0,0 +1,343 @@
+
+/******************************************************************************
+ *
+ * Module Name: amsystem - Interface to OS services
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "interp.h"
+#include "namesp.h"
+#include "hardware.h"
+#include "events.h"
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("amsystem");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_system_thread_id
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Current Thread ID (for this implementation a 1 is returned)
+ *
+ * DESCRIPTION: An invocation is identified by its Thread ID. In a single
+ * threaded OS the Thread ID is undefined so a 1 will be
+ * returned.
+ *
+ ******************************************************************************/
+
+u16
+acpi_aml_system_thread_id (void)
+{
+ return (1);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_system_wait_semaphore
+ *
+ * PARAMETERS: Semaphore - OSD semaphore to wait on
+ * Timeout - Max time to wait
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Implements a semaphore wait with a check to see if the
+ * semaphore is available immediately. If it is not, the
+ * interpreter is released.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_system_wait_semaphore (
+ ACPI_HANDLE semaphore,
+ u32 timeout)
+{
+ ACPI_STATUS status;
+
+
+ status = acpi_os_wait_semaphore (semaphore, 1, 0);
+ if (ACPI_SUCCESS (status)) {
+ return (status);
+ }
+
+ if (status == AE_TIME) {
+ /* We must wait, so unlock the interpreter */
+
+ acpi_aml_exit_interpreter ();
+
+ status = acpi_os_wait_semaphore (semaphore, 1, timeout);
+
+ /* Reacquire the interpreter */
+
+ acpi_aml_enter_interpreter ();
+
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_system_do_stall
+ *
+ * PARAMETERS: How_long - The amount of time to stall
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Suspend running thread for specified amount of time.
+ *
+ ******************************************************************************/
+
+void
+acpi_aml_system_do_stall (
+ u32 how_long)
+{
+
+ if (how_long > 1000) /* 1 millisecond */ {
+ /* Since this thread will sleep, we must release the interpreter */
+
+ acpi_aml_exit_interpreter ();
+
+ acpi_os_sleep_usec (how_long);
+
+ /* And now we must get the interpreter again */
+
+ acpi_aml_enter_interpreter ();
+ }
+
+ else {
+ acpi_os_sleep_usec (how_long);
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_system_do_suspend
+ *
+ * PARAMETERS: How_long - The amount of time to suspend
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Suspend running thread for specified amount of time.
+ *
+ ******************************************************************************/
+
+void
+acpi_aml_system_do_suspend (
+ u32 how_long)
+{
+ /* Since this thread will sleep, we must release the interpreter */
+
+ acpi_aml_exit_interpreter ();
+
+ acpi_os_sleep ((u16) (how_long / (u32) 1000),
+ (u16) (how_long % (u32) 1000));
+
+ /* And now we must get the interpreter again */
+
+ acpi_aml_enter_interpreter ();
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_system_acquire_mutex
+ *
+ * PARAMETERS: *Time_desc - The 'time to delay' object descriptor
+ * *Obj_desc - The object descriptor for this op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Provides an access point to perform synchronization operations
+ * within the AML. This function will cause a lock to be generated
+ * for the Mutex pointed to by Obj_desc.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_system_acquire_mutex (
+ ACPI_OBJECT_INTERNAL *time_desc,
+ ACPI_OBJECT_INTERNAL *obj_desc)
+{
+ ACPI_STATUS status = AE_OK;
+
+
+ if (!obj_desc) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Support for the _GL_ Mutex object -- go get the global lock
+ */
+
+ if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) {
+ status = acpi_ev_acquire_global_lock ();
+ return (status);
+ }
+
+ status = acpi_aml_system_wait_semaphore (obj_desc->mutex.semaphore,
+ time_desc->number.value);
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_system_release_mutex
+ *
+ * PARAMETERS: *Obj_desc - The object descriptor for this op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Provides an access point to perform synchronization operations
+ * within the AML. This operation is a request to release a
+ * previously acquired Mutex. If the Mutex variable is set then
+ * it will be decremented.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_system_release_mutex (
+ ACPI_OBJECT_INTERNAL *obj_desc)
+{
+ ACPI_STATUS status = AE_OK;
+
+
+ if (!obj_desc) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Support for the _GL_ Mutex object -- release the global lock
+ */
+ if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) {
+ acpi_ev_release_global_lock ();
+ return (AE_OK);
+ }
+
+ status = acpi_os_signal_semaphore (obj_desc->mutex.semaphore, 1);
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_system_signal_event
+ *
+ * PARAMETERS: *Obj_desc - The object descriptor for this op
+ *
+ * RETURN: AE_OK
+ *
+ * DESCRIPTION: Provides an access point to perform synchronization operations
+ * within the AML.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_system_signal_event (
+ ACPI_OBJECT_INTERNAL *obj_desc)
+{
+ ACPI_STATUS status = AE_OK;
+
+
+ if (obj_desc) {
+ status = acpi_os_signal_semaphore (obj_desc->event.semaphore, 1);
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_system_wait_event
+ *
+ * PARAMETERS: *Time_desc - The 'time to delay' object descriptor
+ * *Obj_desc - The object descriptor for this op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Provides an access point to perform synchronization operations
+ * within the AML. This operation is a request to wait for an
+ * event.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_system_wait_event (
+ ACPI_OBJECT_INTERNAL *time_desc,
+ ACPI_OBJECT_INTERNAL *obj_desc)
+{
+ ACPI_STATUS status = AE_OK;
+
+
+ if (obj_desc) {
+ status = acpi_aml_system_wait_semaphore (obj_desc->event.semaphore,
+ time_desc->number.value);
+ }
+
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_system_reset_event
+ *
+ * PARAMETERS: *Obj_desc - The object descriptor for this op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Provides an access point to perform synchronization operations
+ * within the AML.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_system_reset_event (
+ ACPI_OBJECT_INTERNAL *obj_desc)
+{
+ ACPI_STATUS status = AE_OK;
+ void *temp_semaphore;
+
+
+ /*
+ * We are going to simply delete the existing semaphore and
+ * create a new one!
+ */
+
+ status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 0, &temp_semaphore);
+ if (ACPI_SUCCESS (status)) {
+ acpi_os_delete_semaphore (obj_desc->mutex.semaphore);
+ obj_desc->mutex.semaphore = temp_semaphore;
+ }
+
+ return (status);
+}
+
diff --git a/drivers/acpi/interpreter/amutils.c b/drivers/acpi/interpreter/amutils.c
new file mode 100644
index 000000000..1e10e28cb
--- /dev/null
+++ b/drivers/acpi/interpreter/amutils.c
@@ -0,0 +1,522 @@
+
+/******************************************************************************
+ *
+ * Module Name: amutils - interpreter/scanner utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "interp.h"
+#include "amlcode.h"
+#include "namesp.h"
+#include "events.h"
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("amutils");
+
+
+typedef struct internal_search_st
+{
+ ACPI_OBJECT_INTERNAL *dest_obj;
+ u32 index;
+ ACPI_OBJECT_INTERNAL *source_obj;
+
+} INTERNAL_PKG_SEARCH_INFO;
+
+
+/* Used to traverse nested packages when copying*/
+
+INTERNAL_PKG_SEARCH_INFO copy_level[MAX_PACKAGE_DEPTH];
+
+
+static char hex[] =
+ {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_enter_interpreter
+ *
+ * PARAMETERS: None
+ *
+ * DESCRIPTION: Enter the interpreter execution region
+ *
+ ******************************************************************************/
+
+void
+acpi_aml_enter_interpreter (void)
+{
+
+ acpi_cm_acquire_mutex (ACPI_MTX_EXECUTE);
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_exit_interpreter
+ *
+ * PARAMETERS: None
+ *
+ * DESCRIPTION: Exit the interpreter execution region
+ *
+ * Cases where the interpreter is unlocked:
+ * 1) Completion of the execution of a control method
+ * 2) Method blocked on a Sleep() AML opcode
+ * 3) Method blocked on an Acquire() AML opcode
+ * 4) Method blocked on a Wait() AML opcode
+ * 5) Method blocked to acquire the global lock
+ * 6) Method blocked to execute a serialized control method that is
+ * already executing
+ * 7) About to invoke a user-installed opregion handler
+ *
+ ******************************************************************************/
+
+void
+acpi_aml_exit_interpreter (void)
+{
+
+ acpi_cm_release_mutex (ACPI_MTX_EXECUTE);
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_validate_object_type
+ *
+ * PARAMETERS: Type Object type to validate
+ *
+ * DESCRIPTION: Determine if a type is a valid ACPI object type
+ *
+ ******************************************************************************/
+
+u8
+acpi_aml_validate_object_type (
+ ACPI_OBJECT_TYPE type)
+{
+
+ if ((type > ACPI_TYPE_MAX && type < INTERNAL_TYPE_BEGIN) ||
+ (type > INTERNAL_TYPE_MAX))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_append_operand_diag
+ *
+ * PARAMETERS: *File_name - Name of source file
+ * Line_num - Line Number in file
+ * Op_code - Op_code being executed
+ * Num_operands - Number of operands Prep_stack tried to check
+ *
+ * DESCRIPTION: Print diagnostic information about operands.
+ * This function is intended to be called after Prep_stack
+ * has returned S_ERROR.
+ *
+ ******************************************************************************/
+
+void
+acpi_aml_append_operand_diag (
+ char *file_name,
+ s32 line_num,
+ u16 op_code,
+ ACPI_OBJECT_INTERNAL **operands,
+ s32 num_operands)
+{
+
+ /*
+ * This function outputs debug information only
+ */
+
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_buf_seq
+ *
+ * RETURN: The next buffer descriptor sequence number
+ *
+ * DESCRIPTION: Provide a unique sequence number for each Buffer descriptor
+ * allocated during the interpreter's existence. These numbers
+ * are used to relate Field_unit descriptors to the Buffers
+ * within which the fields are defined.
+ *
+ * Just increment the global counter and return it.
+ *
+ ******************************************************************************/
+
+u32
+acpi_aml_buf_seq (void)
+{
+
+ return ++acpi_gbl_buf_seq;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_acquire_global_lock
+ *
+ * PARAMETERS: Rule - Lock rule: Always_lock, Never_lock
+ *
+ * RETURN: TRUE/FALSE indicating whether the lock was actually acquired
+ *
+ * DESCRIPTION: Obtain the global lock and keep track of this fact via two
+ * methods. A global variable keeps the state of the lock, and
+ * the state is returned to the caller.
+ *
+ ******************************************************************************/
+
+u8
+acpi_aml_acquire_global_lock (
+ u32 rule)
+{
+ u8 locked = FALSE;
+ ACPI_STATUS status;
+
+
+ /* Only attempt lock if the Rule says so */
+
+ if (rule == (u32) GLOCK_ALWAYS_LOCK) {
+ /* OK to get the lock */
+
+ status = acpi_ev_acquire_global_lock ();
+
+ if (ACPI_SUCCESS (status)) {
+ acpi_gbl_global_lock_set = TRUE;
+ locked = TRUE;
+ }
+ }
+
+ return (locked);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_release_global_lock
+ *
+ * PARAMETERS: Locked_by_me - Return value from corresponding call to
+ * Acquire_global_lock.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Release the global lock if it is locked.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_release_global_lock (
+ u8 locked_by_me)
+{
+
+
+ /* Only attempt unlock if the caller locked it */
+
+ if (locked_by_me) {
+ /* Double check against the global flag */
+
+ if (acpi_gbl_global_lock_set) {
+ /* OK, now release the lock */
+
+ acpi_ev_release_global_lock ();
+ acpi_gbl_global_lock_set = FALSE;
+ }
+
+ }
+
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_digits_needed
+ *
+ * PARAMETERS: val - Value to be represented
+ * base - Base of representation
+ *
+ * RETURN: the number of digits needed to represent val in base
+ *
+ ******************************************************************************/
+
+s32
+acpi_aml_digits_needed (
+ s32 val,
+ s32 base)
+{
+ s32 num_digits = 0;
+
+
+ if (base < 1) {
+ /* impossible base */
+
+ REPORT_ERROR ("Aml_digits_needed: Impossible base");
+ }
+
+ else {
+ for (num_digits = 1 + (val < 0) ; val /= base ; ++num_digits) { ; }
+ }
+
+ return (num_digits);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: ntohl
+ *
+ * PARAMETERS: Value - Value to be converted
+ *
+ * RETURN: Convert a 32-bit value to big-endian (swap the bytes)
+ *
+ ******************************************************************************/
+
+u32
+_ntohl (
+ u32 value)
+{
+ union
+ {
+ u32 value;
+ char bytes[4];
+ } out;
+
+ union
+ {
+ u32 value;
+ char bytes[4];
+ } in;
+
+
+ in.value = value;
+
+ out.bytes[0] = in.bytes[3];
+ out.bytes[1] = in.bytes[2];
+ out.bytes[2] = in.bytes[1];
+ out.bytes[3] = in.bytes[0];
+
+ return out.value;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_eisa_id_to_string
+ *
+ * PARAMETERS: Numeric_id - EISA ID to be converted
+ * Out_string - Where to put the converted string (8 bytes)
+ *
+ * RETURN: Convert a numeric EISA ID to string representation
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_eisa_id_to_string (
+ u32 numeric_id,
+ char *out_string)
+{
+ u32 id;
+
+ /* swap to big-endian to get contiguous bits */
+
+ id = _ntohl (numeric_id);
+
+ out_string[0] = (char) ('@' + ((id >> 26) & 0x1f));
+ out_string[1] = (char) ('@' + ((id >> 21) & 0x1f));
+ out_string[2] = (char) ('@' + ((id >> 16) & 0x1f));
+ out_string[3] = hex[(id >> 12) & 0xf];
+ out_string[4] = hex[(id >> 8) & 0xf];
+ out_string[5] = hex[(id >> 4) & 0xf];
+ out_string[6] = hex[id & 0xf];
+ out_string[7] = 0;
+
+ return AE_OK;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_build_copy_internal_package_object
+ *
+ * PARAMETERS: *Source_obj - Pointer to the source package object
+ * *Dest_obj - Where the internal object is returned
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to copy an internal package object
+ * into another internal package object.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_build_copy_internal_package_object (
+ ACPI_OBJECT_INTERNAL *source_obj,
+ ACPI_OBJECT_INTERNAL *dest_obj)
+{
+ u32 current_depth = 0;
+ ACPI_STATUS status = AE_OK;
+ u32 length = 0;
+ u32 this_index;
+ u32 object_space = 0;
+ ACPI_OBJECT_INTERNAL *this_dest_obj;
+ ACPI_OBJECT_INTERNAL *this_source_obj;
+ INTERNAL_PKG_SEARCH_INFO *level_ptr;
+
+
+ /*
+ * Initialize the working variables
+ */
+
+ MEMSET ((void *) copy_level, 0, sizeof(copy_level));
+
+ copy_level[0].dest_obj = dest_obj;
+ copy_level[0].source_obj = source_obj;
+ level_ptr = &copy_level[0];
+ current_depth = 0;
+
+ dest_obj->common.type = source_obj->common.type;
+ dest_obj->package.count = source_obj->package.count;
+
+
+ /*
+ * Build an array of ACPI_OBJECTS in the buffer
+ * and move the free space past it
+ */
+
+ dest_obj->package.elements = acpi_cm_callocate (
+ (dest_obj->package.count + 1) *
+ sizeof (void *));
+ if (!dest_obj->package.elements) {
+ /* Package vector allocation failure */
+
+ REPORT_ERROR ("Aml_build_copy_internal_package_object: Package vector allocation failure");
+ return (AE_NO_MEMORY);
+ }
+
+ dest_obj->package.next_element = dest_obj->package.elements;
+
+
+ while (1) {
+ this_index = level_ptr->index;
+ this_dest_obj = (ACPI_OBJECT_INTERNAL *) level_ptr->dest_obj->package.elements[this_index];
+ this_source_obj = (ACPI_OBJECT_INTERNAL *) level_ptr->source_obj->package.elements[this_index];
+
+ if (IS_THIS_OBJECT_TYPE (this_source_obj, ACPI_TYPE_PACKAGE)) {
+ /*
+ * If this object is a package then we go one deeper
+ */
+ if (current_depth >= MAX_PACKAGE_DEPTH-1) {
+ /*
+ * Too many nested levels of packages for us to handle
+ */
+ return (AE_LIMIT);
+ }
+
+ /*
+ * Build the package object
+ */
+ this_dest_obj = acpi_cm_create_internal_object (ACPI_TYPE_PACKAGE);
+ level_ptr->dest_obj->package.elements[this_index] = this_dest_obj;
+
+
+ this_dest_obj->common.type = ACPI_TYPE_PACKAGE;
+ this_dest_obj->package.count = this_dest_obj->package.count;
+
+ /*
+ * Save space for the array of objects (Package elements)
+ * update the buffer length counter
+ */
+ object_space = this_dest_obj->package.count *
+ sizeof (ACPI_OBJECT_INTERNAL);
+ length += object_space;
+ current_depth++;
+ level_ptr = &copy_level[current_depth];
+ level_ptr->dest_obj = this_dest_obj;
+ level_ptr->source_obj = this_source_obj;
+ level_ptr->index = 0;
+
+ } /* if object is a package */
+
+ else {
+
+ this_dest_obj = acpi_cm_create_internal_object (
+ this_source_obj->common.type);
+ level_ptr->dest_obj->package.elements[this_index] = this_dest_obj;
+
+ status = acpi_aml_store_object_to_object(this_source_obj, this_dest_obj);
+
+ if (status != AE_OK) {
+ /*
+ * Failure get out
+ */
+ return (status);
+ }
+
+ length +=object_space;
+
+ level_ptr->index++;
+ while (level_ptr->index >= level_ptr->dest_obj->package.count) {
+ /*
+ * We've handled all of the objects at this level, This means
+ * that we have just completed a package. That package may
+ * have contained one or more packages itself
+ */
+ if (current_depth == 0) {
+ /*
+ * We have handled all of the objects in the top level
+ * package just add the length of the package objects
+ * and exit
+ */
+ return (AE_OK);
+ }
+
+ /*
+ * Go back up a level and move the index past the just
+ * completed package object.
+ */
+ current_depth--;
+ level_ptr = &copy_level[current_depth];
+ level_ptr->index++;
+ }
+ } /* else object is NOT a package */
+ } /* while (1) */
+
+
+ /*
+ * We'll never get here, but the compiler whines about return value
+ */
+ return (AE_OK);
+}
+
+
diff --git a/drivers/acpi/interpreter/amxface.c b/drivers/acpi/interpreter/amxface.c
new file mode 100644
index 000000000..74a92e813
--- /dev/null
+++ b/drivers/acpi/interpreter/amxface.c
@@ -0,0 +1,94 @@
+
+/******************************************************************************
+ *
+ * Module Name: ixface - External interpreter interfaces
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "interp.h"
+
+
+#define _COMPONENT INTERPRETER
+ MODULE_NAME ("amxface");
+
+
+/*
+ * DEFINE_AML_GLOBALS is tested in amlcode.h
+ * to determine whether certain global names should be "defined" or only
+ * "declared" in the current compilation. This enhances maintainability
+ * by enabling a single header file to embody all knowledge of the names
+ * in question.
+ *
+ * Exactly one module of any executable should #define DEFINE_GLOBALS
+ * before #including the header files which use this convention. The
+ * names in question will be defined and initialized in that module,
+ * and declared as extern in all other modules which #include those
+ * header files.
+ */
+
+#define DEFINE_AML_GLOBALS
+#include "amlcode.h"
+#include "parser.h"
+#include "namesp.h"
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_aml_execute_method
+ *
+ * PARAMETERS: Pcode - Pointer to the pcode stream
+ * Pcode_length - Length of pcode that comprises the method
+ * **Params - List of parameters to pass to method,
+ * terminated by NULL. Params itself may be
+ * NULL if no parameters are being passed.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute a control method
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_aml_execute_method (
+ ACPI_NAMED_OBJECT *method_entry,
+ ACPI_OBJECT_INTERNAL **params,
+ ACPI_OBJECT_INTERNAL **return_obj_desc)
+{
+ ACPI_STATUS status;
+
+
+ /*
+ * The point here is to lock the interpreter and call the low
+ * level execute.
+ */
+
+ acpi_aml_enter_interpreter ();
+
+ status = acpi_psx_execute (method_entry, params, return_obj_desc);
+
+ acpi_aml_exit_interpreter ();
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c
new file mode 100644
index 000000000..7cb9ac409
--- /dev/null
+++ b/drivers/acpi/namespace/nsaccess.c
@@ -0,0 +1,647 @@
+
+/******************************************************************************
+ *
+ * Module Name: nsaccess - Top-level functions for accessing ACPI namespace
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "amlcode.h"
+#include "interp.h"
+#include "namesp.h"
+#include "dispatch.h"
+
+
+#define _COMPONENT NAMESPACE
+ MODULE_NAME ("nsaccess");
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_root_create_scope
+ *
+ * PARAMETERS: Entry - NTE for which a scope will be created
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a scope table for the given name table entry
+ *
+ * MUTEX: Expects namespace to be locked
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ns_root_create_scope (
+ ACPI_NAMED_OBJECT *entry)
+{
+
+ /* Allocate a scope table */
+
+ if (entry->child_table) {
+ return (AE_EXIST);
+ }
+
+ entry->child_table = acpi_ns_allocate_name_table (NS_TABLE_SIZE);
+ if (!entry->child_table) {
+ /* root name table allocation failure */
+
+ REPORT_ERROR ("Root name table allocation failure");
+ return (AE_NO_MEMORY);
+ }
+
+ /*
+ * Init the scope first entry -- since it is the exemplar of
+ * the scope (Some fields are duplicated to new entries!)
+ */
+ acpi_ns_initialize_table (entry->child_table, NULL, entry);
+ return (AE_OK);
+
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_root_initialize
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Allocate and initialize the root name table
+ *
+ * MUTEX: Locks namespace for entire execution
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ns_root_initialize (void)
+{
+ ACPI_STATUS status = AE_OK;
+ PREDEFINED_NAMES *init_val = NULL;
+ ACPI_NAMED_OBJECT *new_entry;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+ /*
+ * Root is initially NULL, so a non-NULL value indicates
+ * that Acpi_ns_root_initialize() has already been called; just return.
+ */
+
+ if (acpi_gbl_root_object->child_table) {
+ status = AE_OK;
+ goto unlock_and_exit;
+ }
+
+
+ /* Create the root scope */
+
+ status = acpi_ns_root_create_scope (acpi_gbl_root_object);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ /* Enter the pre-defined names in the name table */
+
+ for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) {
+ status = acpi_ns_lookup (NULL, init_val->name,
+ (OBJECT_TYPE_INTERNAL) init_val->type,
+ IMODE_LOAD_PASS2, NS_NO_UPSEARCH,
+ NULL, &new_entry);
+
+ /*
+ * if name entered successfully
+ * && its entry in Pre_defined_names[] specifies an
+ * initial value
+ */
+
+ if ((status == AE_OK) &&
+ new_entry && init_val->val)
+ {
+ /*
+ * Entry requests an initial value, allocate a
+ * descriptor for it.
+ */
+
+ obj_desc =
+ acpi_cm_create_internal_object (
+ (OBJECT_TYPE_INTERNAL) init_val->type);
+
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ /*
+ * Convert value string from table entry to
+ * internal representation. Only types actually
+ * used for initial values are implemented here.
+ */
+
+ switch (init_val->type)
+ {
+
+ case ACPI_TYPE_NUMBER:
+
+ obj_desc->number.value =
+ (u32) STRTOUL (init_val->val, NULL, 10);
+ break;
+
+
+ case ACPI_TYPE_STRING:
+
+ obj_desc->string.length =
+ (u16) STRLEN (init_val->val);
+
+ /*
+ * Allocate a buffer for the string. All
+ * String.Pointers must be allocated buffers!
+ * (makes deletion simpler)
+ */
+ obj_desc->string.pointer =
+ acpi_cm_allocate ((ACPI_SIZE)
+ (obj_desc->string.length + 1));
+
+ if (!obj_desc->string.pointer) {
+ REPORT_ERROR ("Initial value string"
+ "allocation failure");
+
+ acpi_cm_remove_reference (obj_desc);
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ STRCPY ((char *) obj_desc->string.pointer,
+ init_val->val);
+ break;
+
+
+ case ACPI_TYPE_MUTEX:
+
+ obj_desc->mutex.sync_level =
+ (u16) STRTOUL (init_val->val, NULL, 10);
+
+ if (STRCMP (init_val->name, "_GL_") == 0) {
+ /*
+ * Create a counting semaphore for the
+ * global lock
+ */
+ status =
+ acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT,
+ 1, &obj_desc->mutex.semaphore);
+
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+ /*
+ * We just created the mutex for the
+ * global lock, save it
+ */
+
+ acpi_gbl_global_lock_semaphore =
+ obj_desc->mutex.semaphore;
+ }
+
+ else {
+ /* Create a mutex */
+
+ status = acpi_os_create_semaphore (1, 1,
+ &obj_desc->mutex.semaphore);
+
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+ }
+
+ /* TBD: [Restructure] These fields may be obsolete */
+
+ obj_desc->mutex.lock_count = 0;
+ obj_desc->mutex.thread_id = 0;
+ break;
+
+
+ default:
+ REPORT_ERROR ("Unsupported initial type value");
+ acpi_cm_remove_reference (obj_desc);
+ obj_desc = NULL;
+ continue;
+ }
+
+ /* Store pointer to value descriptor in nte */
+
+ acpi_ns_attach_object (new_entry, obj_desc,
+ obj_desc->common.type);
+ }
+ }
+
+
+unlock_and_exit:
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ return (status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_lookup
+ *
+ * PARAMETERS: Prefix_scope - Search scope if name is not fully qualified
+ * Pathname - Search pathname, in internal format
+ * (as represented in the AML stream)
+ * Type - Type associated with name
+ * Interpreter_mode - IMODE_LOAD_PASS2 => add name if not found
+ * Ret_entry - Where the new entry (NTE) is placed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Find or enter the passed name in the name space.
+ * Log an error if name not found in Exec mode.
+ *
+ * MUTEX: Assumes namespace is locked.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ns_lookup (
+ ACPI_GENERIC_STATE *scope_info,
+ char *pathname,
+ OBJECT_TYPE_INTERNAL type,
+ OPERATING_MODE interpreter_mode,
+ u32 flags,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_NAMED_OBJECT **ret_entry)
+{
+ ACPI_STATUS status;
+ ACPI_NAME_TABLE *prefix_scope;
+ ACPI_NAME_TABLE *table_to_search = NULL;
+ ACPI_NAME_TABLE *scope_to_push = NULL;
+ ACPI_NAMED_OBJECT *this_entry = NULL;
+ u32 num_segments;
+ ACPI_NAME simple_name;
+ u8 null_name_path = FALSE;
+ OBJECT_TYPE_INTERNAL type_to_check_for;
+ OBJECT_TYPE_INTERNAL this_search_type;
+
+ if (!ret_entry) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ acpi_gbl_ns_lookup_count++;
+
+ *ret_entry = ENTRY_NOT_FOUND;
+ if (!acpi_gbl_root_object->child_table) {
+ /*
+ * If the name space has not been initialized:
+ * - In Pass1 of Load mode, we need to initialize it
+ * before trying to define a name.
+ * - In Exec mode, there are no names to be found.
+ */
+
+ if (IMODE_LOAD_PASS1 == interpreter_mode) {
+ if ((status = acpi_ns_root_initialize ()) != AE_OK) {
+ return (status);
+ }
+ }
+ else {
+ return (AE_NOT_FOUND);
+ }
+ }
+
+
+ /*
+ * Get the prefix scope.
+ * A null scope means use the root scope
+ */
+
+ if ((!scope_info) ||
+ (!scope_info->scope.name_table))
+ {
+ prefix_scope = acpi_gbl_root_object->child_table;
+ }
+ else {
+ prefix_scope = scope_info->scope.name_table;
+ }
+
+
+ /*
+ * This check is explicitly split provide relax the Type_to_check_for
+ * conditions for Bank_field_defn. Originally, both Bank_field_defn and
+ * Def_field_defn caused Type_to_check_for to be set to ACPI_TYPE_REGION,
+ * but the Bank_field_defn may also check for a Field definition as well
+ * as an Operation_region.
+ */
+
+ if (INTERNAL_TYPE_DEF_FIELD_DEFN == type) {
+ /* Def_field_defn defines fields in a Region */
+
+ type_to_check_for = ACPI_TYPE_REGION;
+ }
+
+ else if (INTERNAL_TYPE_BANK_FIELD_DEFN == type) {
+ /* Bank_field_defn defines data fields in a Field Object */
+
+ type_to_check_for = ACPI_TYPE_ANY;
+ }
+
+ else {
+ type_to_check_for = type;
+ }
+
+
+ /* Examine the name pointer */
+
+ if (!pathname) {
+ /* 8-12-98 ASL Grammar Update supports null Name_path */
+
+ null_name_path = TRUE;
+ num_segments = 0;
+ this_entry = acpi_gbl_root_object;
+
+ }
+
+ else {
+ /*
+ * Valid name pointer (Internal name format)
+ *
+ * Check for prefixes. As represented in the AML stream, a
+ * Pathname consists of an optional scope prefix followed by
+ * a segment part.
+ *
+ * If present, the scope prefix is either a Root_prefix (in
+ * which case the name is fully qualified), or zero or more
+ * Parent_prefixes (in which case the name's scope is relative
+ * to the current scope).
+ *
+ * The segment part consists of either:
+ * - A single 4-byte name segment, or
+ * - A Dual_name_prefix followed by two 4-byte name segments, or
+ * - A Multi_name_prefix_op, followed by a byte indicating the
+ * number of segments and the segments themselves.
+ */
+
+ if (*pathname == AML_ROOT_PREFIX) {
+ /* Pathname is fully qualified, look in root name table */
+
+ table_to_search = acpi_gbl_root_object->child_table;
+ /* point to segment part */
+ pathname++;
+
+ /* Direct reference to root, "\" */
+
+ if (!(*pathname)) {
+ this_entry = acpi_gbl_root_object;
+ goto check_for_new_scope_and_exit;
+ }
+ }
+
+ else {
+ /* Pathname is relative to current scope, start there */
+
+ table_to_search = prefix_scope;
+
+ /*
+ * Handle up-prefix (carat). More than one prefix
+ * is supported
+ */
+
+ while (*pathname == AML_PARENT_PREFIX) {
+
+ /* Point to segment part or next Parent_prefix */
+
+ pathname++;
+
+ /* Backup to the parent's scope */
+
+ table_to_search = table_to_search->parent_table;
+ if (!table_to_search) {
+ /* Current scope has no parent scope */
+
+ REPORT_ERROR ("Ns_lookup: Too many parent"
+ "prefixes or scope has no parent");
+
+
+ return (AE_NOT_FOUND);
+ }
+ }
+ }
+
+
+ /*
+ * Examine the name prefix opcode, if any,
+ * to determine the number of segments
+ */
+
+ if (*pathname == AML_DUAL_NAME_PREFIX) {
+ num_segments = 2;
+ /* point to first segment */
+ pathname++;
+
+ }
+
+ else if (*pathname == AML_MULTI_NAME_PREFIX_OP) {
+ num_segments = (s32)* (u8 *) ++pathname;
+ /* point to first segment */
+ pathname++;
+
+ }
+
+ else {
+ /*
+ * No Dual or Multi prefix, hence there is only one
+ * segment and Pathname is already pointing to it.
+ */
+ num_segments = 1;
+
+ }
+
+ }
+
+
+ /*
+ * Search namespace for each segment of the name.
+ * Loop through and verify/add each name segment.
+ */
+
+
+ while (num_segments-- && table_to_search) {
+ /*
+ * Search for the current segment in the table where
+ * it should be.
+ * Type is significant only at the last (topmost) level.
+ */
+ this_search_type = ACPI_TYPE_ANY;
+ if (!num_segments) {
+ this_search_type = type;
+ }
+
+ MOVE_UNALIGNED32_TO_32 (&simple_name, pathname);
+ status = acpi_ns_search_and_enter (simple_name, walk_state,
+ table_to_search, interpreter_mode,
+ this_search_type, flags,
+ &this_entry);
+
+ if (status != AE_OK) {
+ if (status == AE_NOT_FOUND) {
+ /* Name not in ACPI namespace */
+
+ if (IMODE_LOAD_PASS1 == interpreter_mode ||
+ IMODE_LOAD_PASS2 == interpreter_mode)
+ {
+ REPORT_ERROR ("Name table overflow");
+ }
+
+ }
+
+ return (status);
+ }
+
+
+ /*
+ * If 1) last segment (Num_segments == 0)
+ * 2) and looking for a specific type
+ * (Not checking for TYPE_ANY)
+ * 3) which is not a local type (TYPE_DEF_ANY)
+ * 4) which is not a local type (TYPE_SCOPE)
+ * 5) which is not a local type (TYPE_INDEX_FIELD_DEFN)
+ * 6) and type of entry is known (not TYPE_ANY)
+ * 7) and entry does not match request
+ *
+ * Then we have a type mismatch. Just warn and ignore it.
+ */
+ if ((num_segments == 0) &&
+ (type_to_check_for != ACPI_TYPE_ANY) &&
+ (type_to_check_for != INTERNAL_TYPE_DEF_ANY) &&
+ (type_to_check_for != INTERNAL_TYPE_SCOPE) &&
+ (type_to_check_for != INTERNAL_TYPE_INDEX_FIELD_DEFN) &&
+ (this_entry->type != ACPI_TYPE_ANY) &&
+ (this_entry->type != type_to_check_for))
+ {
+ /* Complain about type mismatch */
+
+ REPORT_WARNING ("Type mismatch");
+ }
+
+ /*
+ * If last segment and not looking for a specific type, but type of
+ * found entry is known, use that type to see if it opens a scope.
+ */
+
+ if ((0 == num_segments) && (ACPI_TYPE_ANY == type)) {
+ type = this_entry->type;
+ }
+
+ if ((num_segments || acpi_ns_opens_scope (type)) &&
+ (this_entry->child_table == NULL))
+ {
+ /*
+ * More segments or the type implies enclosed scope,
+ * and the next scope has not been allocated.
+ */
+
+ if ((IMODE_LOAD_PASS1 == interpreter_mode) ||
+ (IMODE_LOAD_PASS2 == interpreter_mode))
+ {
+ /*
+ * First or second pass load mode
+ * ==> locate the next scope
+ */
+
+ this_entry->child_table =
+ acpi_ns_allocate_name_table (NS_TABLE_SIZE);
+
+ if (!this_entry->child_table) {
+ return (AE_NO_MEMORY);
+ }
+ }
+
+ /* Now complain if there is no next scope */
+
+ if (this_entry->child_table == NULL) {
+ if (IMODE_LOAD_PASS1 == interpreter_mode ||
+ IMODE_LOAD_PASS2 == interpreter_mode)
+ {
+ REPORT_ERROR ("Name Table allocation failure");
+ return (AE_NOT_FOUND);
+ }
+
+ return (AE_NOT_FOUND);
+ }
+
+
+ /* Scope table initialization */
+
+ if (IMODE_LOAD_PASS1 == interpreter_mode ||
+ IMODE_LOAD_PASS2 == interpreter_mode)
+ {
+ /* Initialize the new table */
+
+ acpi_ns_initialize_table (this_entry->child_table,
+ table_to_search,
+ this_entry);
+ }
+ }
+
+ table_to_search = this_entry->child_table;
+ /* point to next name segment */
+ pathname += ACPI_NAME_SIZE;
+ }
+
+
+ /*
+ * Always check if we need to open a new scope
+ */
+
+check_for_new_scope_and_exit:
+
+ if (!(flags & NS_DONT_OPEN_SCOPE) && (walk_state)) {
+ /*
+ * If entry is a type which opens a scope,
+ * push the new scope on the scope stack.
+ */
+
+ if (acpi_ns_opens_scope (type_to_check_for)) {
+ /* 8-12-98 ASL Grammar Update supports null Name_path */
+
+ if (null_name_path) {
+ /* TBD: [Investigate] - is this the correct thing to do? */
+
+ scope_to_push = NULL;
+ }
+ else {
+ scope_to_push = this_entry->child_table;
+ }
+
+ status = acpi_ds_scope_stack_push (scope_to_push, type,
+ walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ }
+ }
+
+ *ret_entry = this_entry;
+ return (AE_OK);
+}
+
diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c
new file mode 100644
index 000000000..414f3791a
--- /dev/null
+++ b/drivers/acpi/namespace/nsalloc.c
@@ -0,0 +1,411 @@
+
+/******************************************************************************
+ *
+ * Module Name: nsalloc - Namespace allocation and deletion utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "namesp.h"
+#include "interp.h"
+
+
+#define _COMPONENT NAMESPACE
+ MODULE_NAME ("nsalloc");
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_allocate_name_table
+ *
+ * PARAMETERS: Nte_count - Count of NTEs to allocate
+ *
+ * RETURN: The address of the first nte in the array, or NULL
+ *
+ * DESCRIPTION: Allocate an array of nte, including prepended link space
+ * Array is set to all zeros via Acpi_os_callcate().
+ *
+ ***************************************************************************/
+
+ACPI_NAME_TABLE *
+acpi_ns_allocate_name_table (
+ u32 num_entries)
+{
+ ACPI_NAME_TABLE *name_table = NULL;
+ ACPI_SIZE alloc_size;
+
+
+ alloc_size = sizeof (ACPI_NAME_TABLE) + ((num_entries - 1) *
+ sizeof (ACPI_NAMED_OBJECT));
+
+ name_table = acpi_cm_callocate (alloc_size);
+
+
+ return (name_table);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_delete_namespace_subtree
+ *
+ * PARAMETERS: None.
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Delete a subtree of the namespace. This includes all objects stored
+ * within the subtree. Scope tables are deleted also
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ns_delete_namespace_subtree (
+ ACPI_NAMED_OBJECT *parent_entry)
+{
+ ACPI_NAMED_OBJECT *child_entry;
+ u32 level;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+
+
+ child_entry = 0;
+ level = 1;
+
+ /*
+ * Traverse the tree of objects until we bubble back up
+ * to where we started.
+ */
+
+ while (level > 0) {
+ /*
+ * Get the next typed object in this scope.
+ * Null returned if not found
+ */
+
+ child_entry = acpi_ns_get_next_object (ACPI_TYPE_ANY,
+ parent_entry,
+ child_entry);
+
+ if (child_entry) {
+ /*
+ * Found an object - delete the object within
+ * the Value field
+ */
+
+ obj_desc = acpi_ns_get_attached_object (child_entry);
+ if (obj_desc) {
+ acpi_ns_detach_object (child_entry);
+ acpi_cm_remove_reference (obj_desc);
+ }
+
+
+ /*
+ * Clear the NTE in case this scope is reused
+ * (e.g., a control method scope)
+ */
+
+ child_entry->type = ACPI_TYPE_ANY;
+ child_entry->name = 0;
+
+ /* Check if this object has any children */
+
+ if (acpi_ns_get_next_object (ACPI_TYPE_ANY, child_entry, 0)) {
+ /*
+ * There is at least one child of this object,
+ * visit the object
+ */
+
+ level++;
+ parent_entry = child_entry;
+ child_entry = 0;
+ }
+
+ else {
+ /*
+ * There may be a name table even if there are
+ * no children
+ */
+
+ acpi_ns_delete_name_table (child_entry->child_table);
+ child_entry->child_table = NULL;
+
+ }
+ }
+
+ else {
+ /*
+ * No more children in this object.
+ * We will move up to the grandparent.
+ */
+ level--;
+
+ /*
+ * Delete the scope (Name Table) associated with
+ * the parent object
+ */
+ /* Don't delete the top level scope, this allows
+ * the dynamic deletion of objects created underneath
+ * control methods!
+ */
+
+ if (level != 0) {
+ acpi_ns_delete_name_table (parent_entry->child_table);
+ parent_entry->child_table = NULL;
+ }
+
+ /* New "last child" is this parent object */
+
+ child_entry = parent_entry;
+
+ /* Now we can move up the tree to the grandparent */
+
+ parent_entry = acpi_ns_get_parent_entry (parent_entry);
+ }
+ }
+
+
+ return (AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_remove_reference
+ *
+ * PARAMETERS: Entry - NTE whose reference count is to be decremented
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Remove an NTE reference. Decrements the reference count of
+ * all parent NTEs up to the root. Any NTE along the way that
+ * reaches zero references is freed.
+ *
+ ***************************************************************************/
+
+void
+acpi_ns_remove_reference (
+ ACPI_NAMED_OBJECT *entry)
+{
+ ACPI_NAMED_OBJECT *this_entry;
+
+
+ /* There may be a name table even if there are no children */
+
+ acpi_ns_delete_name_table (entry->child_table);
+ entry->child_table = NULL;
+
+
+ /*
+ * Decrement the reference count(s) of all parents up to the root,
+ * And delete anything with zero remaining references.
+ */
+ this_entry = entry;
+ while (this_entry) {
+ /* Decrement the reference */
+
+ this_entry->reference_count--;
+
+ /* Delete entry if no more references */
+
+ if (!this_entry->reference_count) {
+ /* Delete the scope if present */
+
+ if (this_entry->child_table) {
+ acpi_ns_delete_name_table (this_entry->child_table);
+ this_entry->child_table = NULL;
+ }
+
+ /*
+ * Mark the entry free
+ * (This doesn't deallocate anything)
+ */
+
+ acpi_ns_free_table_entry (this_entry);
+
+ }
+
+ /* Move up to parent */
+
+ this_entry = acpi_ns_get_parent_entry (this_entry);
+ }
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_delete_namespace_by_owner
+ *
+ * PARAMETERS: None.
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Delete entries within the namespace that are owned by a
+ * specific ID. Used to delete entire ACPI tables. All
+ * reference counts are updated.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ns_delete_namespace_by_owner (
+ u16 owner_id)
+{
+ ACPI_NAMED_OBJECT *child_entry;
+ u32 level;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_NAMED_OBJECT *parent_entry;
+
+
+ parent_entry = acpi_gbl_root_object;
+ child_entry = 0;
+ level = 1;
+
+ /*
+ * Traverse the tree of objects until we bubble back up
+ * to where we started.
+ */
+
+ while (level > 0) {
+ /*
+ * Get the next typed object in this scope.
+ * Null returned if not found
+ */
+
+ child_entry = acpi_ns_get_next_object (ACPI_TYPE_ANY,
+ parent_entry,
+ child_entry);
+
+ if (child_entry) {
+ if (child_entry->owner_id == owner_id) {
+ /*
+ * Found an object - delete the object within
+ * the Value field
+ */
+
+ obj_desc = acpi_ns_get_attached_object (child_entry);
+ if (obj_desc) {
+ acpi_ns_detach_object (child_entry);
+ acpi_cm_remove_reference (obj_desc);
+ }
+ }
+
+ /* Check if this object has any children */
+
+ if (acpi_ns_get_next_object (ACPI_TYPE_ANY, child_entry, 0)) {
+ /*
+ * There is at least one child of this object,
+ * visit the object
+ */
+
+ level++;
+ parent_entry = child_entry;
+ child_entry = 0;
+ }
+
+ else if (child_entry->owner_id == owner_id) {
+ acpi_ns_remove_reference (child_entry);
+ }
+ }
+
+ else {
+ /*
+ * No more children in this object.
+ * We will move up to the grandparent.
+ */
+ level--;
+
+ /*
+ * Delete the scope (Name Table) associated with
+ * the parent object
+ */
+ /* Don't delete the top level scope, this allows
+ * the dynamic deletion of objects created underneath
+ * control methods!
+ */
+
+
+ if (level != 0) {
+ if (parent_entry->owner_id == owner_id) {
+ acpi_ns_remove_reference (parent_entry);
+ }
+ }
+
+
+ /* New "last child" is this parent object */
+
+ child_entry = parent_entry;
+
+ /* Now we can move up the tree to the grandparent */
+
+ parent_entry = acpi_ns_get_parent_entry (parent_entry);
+ }
+ }
+
+
+ return (AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_delete_name_table
+ *
+ * PARAMETERS: Scope - A handle to the scope to be deleted
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Delete a namespace Name Table with zero or
+ * more appendages. The table and all appendages are deleted.
+ *
+ ***************************************************************************/
+
+void
+acpi_ns_delete_name_table (
+ ACPI_NAME_TABLE *name_table)
+{
+ ACPI_NAME_TABLE *this_table;
+ ACPI_NAME_TABLE *next_table;
+
+
+ if (!name_table) {
+ return;
+ }
+
+ this_table = name_table;
+
+
+ /*
+ * Deallocate the name table and all appendages
+ */
+ do
+ {
+ next_table = this_table->next_table;
+
+ /* Now we can free the table */
+
+ acpi_cm_free (this_table);
+ this_table = next_table;
+
+ } while (this_table);
+
+ return;
+}
+
+
diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c
new file mode 100644
index 000000000..ea3e15621
--- /dev/null
+++ b/drivers/acpi/namespace/nseval.c
@@ -0,0 +1,507 @@
+
+/******************************************************************************
+ *
+ * Module Name: nseval - Object evaluation interfaces -- includes control
+ * method lookup and execution.
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "amlcode.h"
+#include "parser.h"
+#include "interp.h"
+#include "namesp.h"
+
+
+#define _COMPONENT NAMESPACE
+ MODULE_NAME ("nseval");
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_evaluate_relative
+ *
+ * PARAMETERS: Rel_obj_entry - NTE of the relative containing object
+ * *Pathname - Name of method to execute, If NULL, the
+ * handle is the object to execute
+ * **Params - List of parameters to pass to the method,
+ * terminated by NULL. Params itself may be
+ * NULL if no parameters are being passed.
+ * *Return_object - Where to put method's return value (if
+ * any). If NULL, no value is returned.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Find and execute the requested method using the handle as a
+ * scope
+ *
+ * MUTEX: Locks Namespace
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ns_evaluate_relative (
+ ACPI_NAMED_OBJECT *handle,
+ char *pathname,
+ ACPI_OBJECT_INTERNAL **params,
+ ACPI_OBJECT_INTERNAL **return_object)
+{
+ ACPI_NAMED_OBJECT *rel_obj_entry;
+ ACPI_STATUS status;
+ ACPI_NAMED_OBJECT *obj_entry = NULL;
+ char *internal_path = NULL;
+ ACPI_GENERIC_STATE scope_info;
+
+
+ /*
+ * Must have a valid object handle
+ */
+ if (!handle) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Build an internal name string for the method */
+
+ status = acpi_ns_internalize_name (pathname, &internal_path);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Get the prefix handle and NTE */
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+ rel_obj_entry = acpi_ns_convert_handle_to_entry (handle);
+ if (!rel_obj_entry) {
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ status = AE_BAD_PARAMETER;
+ goto cleanup;
+ }
+
+ /* Lookup the name in the namespace */
+
+ scope_info.scope.name_table = rel_obj_entry->child_table;
+ status = acpi_ns_lookup (&scope_info, internal_path, ACPI_TYPE_ANY,
+ IMODE_EXECUTE,
+ NS_NO_UPSEARCH, NULL,
+ &obj_entry);
+
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+
+ if (status != AE_OK) {
+ goto cleanup;
+ }
+
+ /*
+ * Now that we have a handle to the object, we can attempt
+ * to evaluate it.
+ */
+
+ status = acpi_ns_evaluate_by_handle (obj_entry, params, return_object);
+
+cleanup:
+
+ /* Cleanup */
+
+ acpi_cm_free (internal_path);
+
+ return (status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_evaluate_by_name
+ *
+ * PARAMETERS: Pathname - Fully qualified pathname to the object
+ * *Return_object - Where to put method's return value (if
+ * any). If NULL, no value is returned.
+ * **Params - List of parameters to pass to the method,
+ * terminated by NULL. Params itself may be
+ * NULL if no parameters are being passed.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Find and execute the requested method passing the given
+ * parameters
+ *
+ * MUTEX: Locks Namespace
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ns_evaluate_by_name (
+ char *pathname,
+ ACPI_OBJECT_INTERNAL **params,
+ ACPI_OBJECT_INTERNAL **return_object)
+{
+ ACPI_STATUS status;
+ ACPI_NAMED_OBJECT *obj_entry = NULL;
+ char *internal_path = NULL;
+
+
+ /* Build an internal name string for the method */
+
+ if (pathname[0] != '\\' || pathname[1] != '/') {
+ status = acpi_ns_internalize_name (pathname, &internal_path);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+ /* Lookup the name in the namespace */
+
+ status = acpi_ns_lookup (NULL, internal_path, ACPI_TYPE_ANY,
+ IMODE_EXECUTE,
+ NS_NO_UPSEARCH, NULL,
+ &obj_entry);
+
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+
+ if (status != AE_OK) {
+ goto cleanup;
+ }
+
+ /*
+ * Now that we have a handle to the object, we can attempt
+ * to evaluate it.
+ */
+
+ status = acpi_ns_evaluate_by_handle (obj_entry, params, return_object);
+
+
+cleanup:
+
+ /* Cleanup */
+
+ if (internal_path) {
+ acpi_cm_free (internal_path);
+ }
+
+ return (status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_evaluate_by_handle
+ *
+ * PARAMETERS: Obj_entry - NTE of method to execute
+ * *Return_object - Where to put method's return value (if
+ * any). If NULL, no value is returned.
+ * **Params - List of parameters to pass to the method,
+ * terminated by NULL. Params itself may be
+ * NULL if no parameters are being passed.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute the requested method passing the given parameters
+ *
+ * MUTEX: Locks Namespace
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ns_evaluate_by_handle (
+ ACPI_NAMED_OBJECT *handle,
+ ACPI_OBJECT_INTERNAL **params,
+ ACPI_OBJECT_INTERNAL **return_object)
+{
+ ACPI_NAMED_OBJECT *obj_entry;
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL *local_return_object;
+
+
+ /* Check if namespace has been initialized */
+
+ if (!acpi_gbl_root_object->child_table) {
+ return (AE_NO_NAMESPACE);
+ }
+
+ /* Parameter Validation */
+
+ if (!handle) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ if (return_object) {
+ /* Initialize the return value to an invalid object */
+
+ *return_object = NULL;
+ }
+
+ /* Get the prefix handle and NTE */
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+ obj_entry = acpi_ns_convert_handle_to_entry (handle);
+ if (!obj_entry) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+
+ /*
+ * Two major cases here:
+ * 1) The object is an actual control method -- execute it.
+ * 2) The object is not a method -- just return it's current
+ * value
+ *
+ * In both cases, the namespace is unlocked by the
+ * Acpi_ns* procedure
+ */
+
+ if (acpi_ns_get_type (obj_entry) == ACPI_TYPE_METHOD) {
+ /*
+ * Case 1) We have an actual control method to execute
+ */
+
+ status = acpi_ns_execute_control_method (obj_entry,
+ params,
+ &local_return_object);
+ }
+
+ else {
+ /*
+ * Case 2) Object is NOT a method, just return its
+ * current value
+ */
+
+ status = acpi_ns_get_object_value (obj_entry,
+ &local_return_object);
+ }
+
+
+ /*
+ * Check if there is a return value on the stack that must
+ * be dealt with
+ */
+
+ if (status == AE_CTRL_RETURN_VALUE) {
+ /*
+ * If the Method returned a value and the caller
+ * provided a place to store a returned value, Copy
+ * the returned value to the object descriptor provided
+ * by the caller.
+ */
+
+ if (return_object) {
+ /*
+ * Valid return object, copy the pointer to
+ * the returned object
+ */
+
+ *return_object = local_return_object;
+ }
+
+
+ /* Map AE_RETURN_VALUE to AE_OK, we are done with it */
+
+ if (status == AE_CTRL_RETURN_VALUE) {
+ status = AE_OK;
+ }
+ }
+
+ /*
+ * Namespace was unlocked by the handling Acpi_ns* function,
+ * so we just return
+ */
+
+ return (status);
+
+
+unlock_and_exit:
+
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ return (status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_execute_control_method
+ *
+ * PARAMETERS: Method_entry - The Nte of the object/method
+ * **Params - List of parameters to pass to the method,
+ * terminated by NULL. Params itself may be
+ * NULL if no parameters are being passed.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute the requested method passing the given parameters
+ *
+ * MUTEX: Assumes namespace is locked
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ns_execute_control_method (
+ ACPI_NAMED_OBJECT *method_entry,
+ ACPI_OBJECT_INTERNAL **params,
+ ACPI_OBJECT_INTERNAL **return_obj_desc)
+{
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+
+
+ /* Verify that there is a method associated with this object */
+
+ obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) method_entry);
+ if (!obj_desc) {
+ return (AE_ERROR);
+ }
+
+ /*
+ * Valid method, Set the current scope to that of the Method,
+ * and execute it.
+ */
+
+
+ /*
+ * Unlock the namespace before execution. This allows namespace access
+ * via the external Acpi* interfaces while a method is being executed.
+ * However, any namespace deletion must acquire both the namespace and
+ * interpter locks to ensure that no thread is using the portion of the
+ * namespace that is being deleted.
+ */
+
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+
+ /*
+ * Excecute the method via the interpreter
+ */
+ status = acpi_aml_execute_method (method_entry, params, return_obj_desc);
+
+ return (status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_get_object_value
+ *
+ * PARAMETERS: Object_entry - The Nte of the object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Return the current value of the object
+ *
+ * MUTEX: Assumes namespace is locked
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ns_get_object_value (
+ ACPI_NAMED_OBJECT *object_entry,
+ ACPI_OBJECT_INTERNAL **return_obj_desc)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_OBJECT_INTERNAL *val_desc;
+
+
+ /*
+ * We take the value from certain objects directly
+ */
+
+ if ((object_entry->type == ACPI_TYPE_PROCESSOR) ||
+ (object_entry->type == ACPI_TYPE_POWER))
+ {
+
+ /*
+ * Create a Reference object to contain the object
+ */
+ obj_desc = acpi_cm_create_internal_object (object_entry->type);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ /*
+ * Get the attached object
+ */
+
+ val_desc = acpi_ns_get_attached_object (object_entry);
+ if (!val_desc) {
+ status = AE_NULL_OBJECT;
+ goto unlock_and_exit;
+ }
+
+ /*
+ * Just copy from the original to the return object
+ */
+
+ MEMCPY (&obj_desc->common.first_non_common_byte,
+ &val_desc->common.first_non_common_byte,
+ (sizeof(ACPI_OBJECT_COMMON) -
+ sizeof(obj_desc->common.first_non_common_byte)));
+ }
+
+
+ /*
+ * Other objects require a reference object wrapper which we
+ * then attempt to resolve.
+ */
+ else {
+ /* Create an Reference object to contain the object */
+
+ obj_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REFERENCE);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ /* Construct a descriptor pointing to the name */
+
+ obj_desc->reference.op_code = (u8) AML_NAME_OP;
+ obj_desc->reference.object = (void *) object_entry;
+
+ /*
+ * Use Acpi_aml_resolve_to_value() to get the associated value.
+ * The call to Acpi_aml_resolve_to_value causes
+ * Obj_desc (allocated above) to always be deleted.
+ */
+
+ status = acpi_aml_resolve_to_value (&obj_desc);
+ }
+
+ /*
+ * If Acpi_aml_resolve_to_value() succeeded, the return value was
+ * placed in Obj_desc.
+ */
+
+ if (status == AE_OK) {
+ status = AE_CTRL_RETURN_VALUE;
+
+ *return_obj_desc = obj_desc;
+ }
+
+
+unlock_and_exit:
+
+ /* Unlock the namespace */
+
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ return (status);
+}
diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c
new file mode 100644
index 000000000..4b6b3f309
--- /dev/null
+++ b/drivers/acpi/namespace/nsload.c
@@ -0,0 +1,488 @@
+
+/******************************************************************************
+ *
+ * Module Name: nsload - namespace loading/expanding/contracting procedures
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "interp.h"
+#include "namesp.h"
+#include "amlcode.h"
+#include "parser.h"
+#include "dispatch.h"
+#include "debugger.h"
+
+
+#define _COMPONENT NAMESPACE
+ MODULE_NAME ("nsload");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ns_parse_table
+ *
+ * PARAMETERS: Table_desc - An ACPI table descriptor for table to parse
+ * Scope - Where to enter the table into the namespace
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Parse AML within an ACPI table and return a tree of ops
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ns_parse_table (
+ ACPI_TABLE_DESC *table_desc,
+ ACPI_NAME_TABLE *scope)
+{
+ ACPI_STATUS status;
+
+
+ /* Create the root object */
+
+ acpi_gbl_parsed_namespace_root = acpi_ps_alloc_op (AML_SCOPE_OP);
+ if (!acpi_gbl_parsed_namespace_root) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Initialize the root object */
+
+ ((ACPI_NAMED_OP *) acpi_gbl_parsed_namespace_root)->name = ACPI_ROOT_NAME;
+
+ /* Pass 1: Parse everything except control method bodies */
+
+ status = acpi_ps_parse_aml (acpi_gbl_parsed_namespace_root,
+ table_desc->aml_pointer,
+ table_desc->aml_length, 0);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+
+#ifndef PARSER_ONLY
+ status = acpi_ps_walk_parsed_aml (acpi_ps_get_child (acpi_gbl_parsed_namespace_root),
+ acpi_gbl_parsed_namespace_root, NULL,
+ scope, NULL, NULL,
+ table_desc->table_id,
+ acpi_ds_load2_begin_op,
+ acpi_ds_load2_end_op);
+
+
+ /*
+ * Now that the internal namespace has been constructed, we can delete the
+ * parsed namespace, since it is no longer needed
+ */
+
+ acpi_ps_delete_parse_tree (acpi_gbl_parsed_namespace_root);
+ acpi_gbl_parsed_namespace_root = NULL;
+#endif
+
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_load_table
+ *
+ * PARAMETERS: *Pcode_addr - Address of pcode block
+ * Pcode_length - Length of pcode block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Mainline of the AML load/dump subsystem. Sets up the
+ * input engine, calls handler for outermost object type.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ns_load_table (
+ ACPI_TABLE_DESC *table_desc,
+ ACPI_NAMED_OBJECT *entry)
+{
+ ACPI_STATUS status;
+
+
+ if (!table_desc->aml_pointer) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ if (!table_desc->aml_length) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /*
+ * Parse the table and load the namespace with all named
+ * objects found within. Control methods are NOT parsed
+ * at this time. In fact, the control methods cannot be
+ * parsed until the entire namespace is loaded, because
+ * if a control method makes a forward reference (call)
+ * to another control method, we can't continue parsing
+ * because we don't know how many arguments to parse next!
+ */
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+ status = acpi_ns_parse_table (table_desc, entry->child_table);
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /*
+ * Now we can parse the control methods. We always parse
+ * them here for a sanity check, and if configured for
+ * just-in-time parsing, we delete the control method
+ * parse trees.
+ */
+
+ status = acpi_ds_initialize_objects (table_desc, entry);
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ns_load_table_by_type
+ *
+ * PARAMETERS: Table_type - Id of the table type to load
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Load an ACPI table or tables into the namespace. All tables
+ * of the given type are loaded. The mechanism allows this
+ * routine to be called repeatedly.
+ *
+ *****************************************************************************/
+
+ACPI_STATUS
+acpi_ns_load_table_by_type (
+ ACPI_TABLE_TYPE table_type)
+{
+ u32 i;
+ ACPI_STATUS status = AE_OK;
+ ACPI_TABLE_HEADER *table_ptr;
+ ACPI_TABLE_DESC *table_desc;
+
+
+ acpi_cm_acquire_mutex (ACPI_MTX_TABLES);
+
+
+ /*
+ * Table types supported are:
+ * DSDT (one), SSDT/PSDT (multiple)
+ */
+
+ switch (table_type)
+ {
+
+ case ACPI_TABLE_DSDT:
+
+ table_desc = &acpi_gbl_acpi_tables[ACPI_TABLE_DSDT];
+
+ /* If table already loaded into namespace, just return */
+
+ if (table_desc->loaded_into_namespace) {
+ goto unlock_and_exit;
+ }
+
+ table_desc->table_id = TABLE_ID_DSDT;
+
+ /* Initialize the root of the namespace tree */
+
+ status = acpi_ns_root_initialize ();
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ /* Now load the single DSDT */
+
+ status = acpi_ns_load_table (table_desc, acpi_gbl_root_object);
+ if (ACPI_SUCCESS (status)) {
+ table_desc->loaded_into_namespace = TRUE;
+ }
+
+ break;
+
+
+ case ACPI_TABLE_SSDT:
+
+ /*
+ * Traverse list of SSDT tables
+ */
+
+ table_desc = &acpi_gbl_acpi_tables[ACPI_TABLE_SSDT];
+ for (i = 0; i < acpi_gbl_acpi_tables[ACPI_TABLE_SSDT].count; i++) {
+ table_ptr = table_desc->pointer;
+
+ /*
+ * Only attempt to load table if it is not
+ * already loaded!
+ */
+
+ if (!table_desc->loaded_into_namespace) {
+ status = acpi_ns_load_table (table_desc,
+ acpi_gbl_root_object);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ table_desc->loaded_into_namespace = TRUE;
+ }
+
+ table_desc = table_desc->next;
+ }
+
+ break;
+
+
+ case ACPI_TABLE_PSDT:
+
+ /*
+ * Traverse list of PSDT tables
+ */
+
+ table_desc = &acpi_gbl_acpi_tables[ACPI_TABLE_PSDT];
+
+ for (i = 0; i < acpi_gbl_acpi_tables[ACPI_TABLE_PSDT].count; i++) {
+ table_ptr = table_desc->pointer;
+
+ /* Only attempt to load table if it is not already loaded! */
+
+ if (!table_desc->loaded_into_namespace) {
+ status = acpi_ns_load_table (table_desc,
+ acpi_gbl_root_object);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ table_desc->loaded_into_namespace = TRUE;
+ }
+
+ table_desc = table_desc->next;
+ }
+
+ break;
+
+
+ default:
+ status = AE_SUPPORT;
+ }
+
+
+unlock_and_exit:
+
+ acpi_cm_release_mutex (ACPI_MTX_TABLES);
+
+ return (status);
+
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ns_free_table_entry
+ *
+ * PARAMETERS: Entry - The entry to be deleted
+ *
+ * RETURNS None
+ *
+ * DESCRIPTION: Free an entry in a namespace table. Delete any objects contained
+ * in the entry, unlink the entry, then mark it unused.
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_free_table_entry (
+ ACPI_NAMED_OBJECT *entry)
+{
+
+ if (!entry) {
+ return;
+ }
+
+ /*
+ * Need to delete
+ * 1) The scope, if any
+ * 2) An attached object, if any
+ */
+
+ if (entry->child_table) {
+ acpi_cm_free (entry->child_table);
+ entry->child_table = NULL;
+ }
+
+ if (entry->object) {
+ acpi_ns_detach_object (entry->object);
+ entry->object = NULL;
+ }
+
+ /* Mark the entry unallocated */
+
+ entry->name = 0;
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ns_delete_subtree
+ *
+ * PARAMETERS: Start_handle - Handle in namespace where search begins
+ *
+ * RETURNS Status
+ *
+ * DESCRIPTION: Walks the namespace starting at the given handle and deletes
+ * all objects, entries, and scopes in the entire subtree.
+ *
+ * TBD: [Investigate] What if any part of this subtree is in use?
+ * (i.e. on one of the object stacks?)
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ns_delete_subtree (
+ ACPI_HANDLE start_handle)
+{
+ ACPI_STATUS status;
+ ACPI_HANDLE child_handle;
+ ACPI_HANDLE parent_handle;
+ ACPI_HANDLE next_child_handle;
+ ACPI_HANDLE dummy;
+ u32 level;
+
+
+ parent_handle = start_handle;
+ child_handle = 0;
+ level = 1;
+
+ /*
+ * Traverse the tree of objects until we bubble back up
+ * to where we started.
+ */
+
+ while (level > 0) {
+ /* Attempt to get the next object in this scope */
+
+ status = acpi_get_next_object (ACPI_TYPE_ANY, parent_handle,
+ child_handle,
+ &next_child_handle);
+
+ /*
+ * Regardless of the success or failure of the
+ * previous operation, we are done with the previous
+ * object (if there was one), and any children it
+ * may have had. So we can now safely delete it (and
+ * its scope, if any)
+ */
+
+ acpi_ns_free_table_entry (child_handle);
+ child_handle = next_child_handle;
+
+
+ /* Did we get a new object? */
+
+ if (ACPI_SUCCESS (status)) {
+ /* Check if this object has any children */
+
+ if (ACPI_SUCCESS (acpi_get_next_object (ACPI_TYPE_ANY,
+ child_handle, 0,
+ &dummy)))
+ {
+ /*
+ * There is at least one child of this object,
+ * visit the object
+ */
+
+ level++;
+ parent_handle = child_handle;
+ child_handle = 0;
+ }
+ }
+
+ else {
+ /*
+ * No more children in this object, go back up to
+ * the object's parent
+ */
+ level--;
+ child_handle = parent_handle;
+ acpi_get_parent (parent_handle, &parent_handle);
+ }
+ }
+
+ /* Now delete the starting object, and we are done */
+
+ acpi_ns_free_table_entry ((ACPI_NAMED_OBJECT*) child_handle);
+
+
+ return (AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_unload_name_space
+ *
+ * PARAMETERS: Handle - Root of namespace subtree to be deleted
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Shrinks the namespace, typically in response to an undocking
+ * event. Deletes an entire subtree starting from (and
+ * including) the given handle.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ns_unload_namespace (
+ ACPI_HANDLE handle)
+{
+ ACPI_STATUS status;
+
+
+ /* Parameter validation */
+
+ if (!acpi_gbl_root_object->child_table) {
+ return (AE_NO_NAMESPACE);
+ }
+
+ if (!handle) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /* This function does the real work */
+
+ status = acpi_ns_delete_subtree (handle);
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c
new file mode 100644
index 000000000..1c4ab7c0b
--- /dev/null
+++ b/drivers/acpi/namespace/nsnames.c
@@ -0,0 +1,503 @@
+
+/******************************************************************************
+ *
+ * Module Name: nsnames - Name manipulation and search
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "amlcode.h"
+#include "interp.h"
+#include "namesp.h"
+
+
+#define _COMPONENT NAMESPACE
+ MODULE_NAME ("nsnames");
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_name_of_scope
+ *
+ * PARAMETERS: Scope - Scope whose name is needed
+ *
+ * RETURN: Pointer to storage containing the fully qualified name of
+ * the scope, in Label format (all segments strung together
+ * with no separators)
+ *
+ * DESCRIPTION: Used via Acpi_ns_name_of_current_scope() and Acpi_ns_last_fQN()
+ * for label generation in the interpreter, and for debug
+ * printing in Acpi_ns_search_table().
+ *
+ ***************************************************************************/
+
+char *
+acpi_ns_name_of_scope (
+ ACPI_NAME_TABLE *scope)
+{
+ char *name_buffer;
+ ACPI_SIZE size;
+ ACPI_NAME name;
+ ACPI_NAMED_OBJECT *entry_to_search;
+ ACPI_NAMED_OBJECT *parent_entry;
+
+
+ if (!acpi_gbl_root_object->child_table || !scope) {
+ /*
+ * If the name space has not been initialized,
+ * this function should not have been called.
+ */
+ return (NULL);
+ }
+
+ entry_to_search = scope->entries;
+
+
+ /* Calculate required buffer size based on depth below root NT */
+
+ size = 1;
+ parent_entry = entry_to_search;
+ while (parent_entry) {
+ parent_entry = acpi_ns_get_parent_entry (parent_entry);
+ if (parent_entry) {
+ size += ACPI_NAME_SIZE;
+ }
+ }
+
+
+ /* Allocate the buffer */
+
+ name_buffer = acpi_cm_callocate (size + 1);
+ if (!name_buffer) {
+ REPORT_ERROR ("Ns_name_of_scope: allocation failure");
+ return (NULL);
+ }
+
+
+ /* Store terminator byte, then build name backwards */
+
+ name_buffer[size] = '\0';
+ while ((size > ACPI_NAME_SIZE) &&
+ acpi_ns_get_parent_entry (entry_to_search))
+ {
+ size -= ACPI_NAME_SIZE;
+ name = acpi_ns_find_parent_name (entry_to_search);
+
+ /* Put the name into the buffer */
+
+ MOVE_UNALIGNED32_TO_32 ((name_buffer + size), &name);
+ entry_to_search = acpi_ns_get_parent_entry (entry_to_search);
+ }
+
+ name_buffer[--size] = AML_ROOT_PREFIX;
+
+
+ return (name_buffer);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_name_of_current_scope
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: pointer to storage containing the name of the current scope
+ *
+ ***************************************************************************/
+
+char *
+acpi_ns_name_of_current_scope (
+ ACPI_WALK_STATE *walk_state)
+{
+ char *scope_name;
+
+
+ if (walk_state && walk_state->scope_info) {
+ scope_name =
+ acpi_ns_name_of_scope (walk_state->scope_info->scope.name_table);
+
+ return (scope_name);
+ }
+
+ REPORT_ERROR ("Current scope pointer is invalid");
+
+ return (NULL);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_handle_to_pathname
+ *
+ * PARAMETERS: Target_handle - Handle of nte whose name is to be found
+ * Buf_size - Size of the buffer provided
+ * User_buffer - Where the pathname is returned
+ *
+ * RETURN: Status, Buffer is filled with pathname if status == AE_OK
+ *
+ * DESCRIPTION: Build and return a full namespace pathname
+ *
+ * MUTEX: Locks Namespace
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ns_handle_to_pathname (
+ ACPI_HANDLE target_handle,
+ u32 *buf_size,
+ char *user_buffer)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_NAMED_OBJECT *entry_to_search = NULL;
+ ACPI_NAMED_OBJECT *temp = NULL;
+ ACPI_SIZE path_length = 0;
+ ACPI_SIZE size;
+ u32 user_buf_size;
+ ACPI_NAME name;
+ u8 namespace_was_locked;
+
+
+ if (!acpi_gbl_root_object->child_table || !target_handle) {
+ /*
+ * If the name space has not been initialized,
+ * this function should not have been called.
+ */
+
+ return (AE_NO_NAMESPACE);
+ }
+
+ namespace_was_locked = acpi_gbl_acpi_mutex_info[ACPI_MTX_NAMESPACE].locked;
+ if (!namespace_was_locked) {
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+ }
+
+ entry_to_search = acpi_ns_convert_handle_to_entry (target_handle);
+ if (!entry_to_search) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Compute length of pathname as 5 * number of name segments.
+ * Go back up the parent tree to the root
+ */
+ for (size = 0, temp = entry_to_search;
+ acpi_ns_get_parent_entry (temp);
+ temp = acpi_ns_get_parent_entry (temp))
+ {
+ size += PATH_SEGMENT_LENGTH;
+ }
+
+ /* Set return length to the required path length */
+
+ path_length = size + 1;
+ user_buf_size = *buf_size;
+ *buf_size = path_length;
+
+ /* Check if the user buffer is sufficiently large */
+
+ if (path_length > user_buf_size) {
+ status = AE_BUFFER_OVERFLOW;
+ goto unlock_and_exit;
+ }
+
+ /* Store null terminator */
+
+ user_buffer[size] = 0;
+ size -= ACPI_NAME_SIZE;
+
+ /* Put the original ACPI name at the end of the path */
+
+ MOVE_UNALIGNED32_TO_32 ((user_buffer + size),
+ &entry_to_search->name);
+
+ user_buffer[--size] = PATH_SEPARATOR;
+
+ /* Build name backwards, putting "." between segments */
+
+ while ((size > ACPI_NAME_SIZE) && entry_to_search) {
+ size -= ACPI_NAME_SIZE;
+ name = acpi_ns_find_parent_name (entry_to_search);
+ MOVE_UNALIGNED32_TO_32 ((user_buffer + size), &name);
+
+ user_buffer[--size] = PATH_SEPARATOR;
+ entry_to_search = acpi_ns_get_parent_entry (entry_to_search);
+ }
+
+ /*
+ * Overlay the "." preceding the first segment with
+ * the root name "\"
+ */
+
+ user_buffer[size] = '\\';
+
+
+unlock_and_exit:
+
+ if (!namespace_was_locked) {
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ }
+
+ return (status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_pattern_match
+ *
+ * PARAMETERS: Obj_entry - A namespace entry
+ * Search_for - Wildcard pattern string
+ *
+ * DESCRIPTION: Matches a namespace name against a wildcard pattern. Only
+ * a very simple pattern - 4 chars, either a valid char or a "?"
+ * to match any.
+ *
+ ***************************************************************************/
+
+u8
+acpi_ns_pattern_match (
+ ACPI_NAMED_OBJECT *obj_entry,
+ char *search_for)
+{
+ s32 i;
+
+
+ for (i = 0; i < ACPI_NAME_SIZE; i++) {
+ if (search_for[i] != '?' &&
+ search_for[i] != ((char *) &obj_entry->name)[i])
+ {
+ /* No match */
+
+ return FALSE;
+ }
+ }
+
+ /* name matches pattern */
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_name_compare
+ *
+ * PARAMETERS: Obj_handle - A namespace entry
+ * Level - Current nesting level
+ * Context - A FIND_CONTEXT structure
+ *
+ * DESCRIPTION: A User_function called by Acpi_ns_walk_namespace(). It performs
+ * a pattern match for Acpi_ns_low_find_names(), and updates the list
+ * and count as required.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ns_name_compare (
+ ACPI_HANDLE obj_handle,
+ u32 level,
+ void *context,
+ void **return_value)
+{
+ FIND_CONTEXT *find = context;
+
+
+ /* Match, yes or no? */
+
+ if (acpi_ns_pattern_match ((ACPI_NAMED_OBJECT*) obj_handle,
+ find->search_for))
+ {
+ /* Name matches pattern */
+
+ if (find->list) {
+ find->list[*(find->count)] = obj_handle;
+ }
+
+ ++*(find->count);
+ }
+
+ /* Don't terminate the walk */
+ return AE_OK;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_low_find_names
+ *
+ * PARAMETERS: *This_entry - Table to be searched
+ * *Search_for - Pattern to be found.
+ * 4 bytes, ? matches any character.
+ * *Count - Output count of matches found.
+ * Outermost caller should preset to 0
+ * List[] - Output array of handles. If
+ * null, only the count is obtained.
+ * Max_depth - Maximum depth of search. Use
+ * INT_MAX for an effectively
+ * unlimited depth.
+ *
+ * DESCRIPTION: Low-level find name.
+ * Traverse the name space finding names which match a search
+ * pattern, and return an array of handles in List[].
+ *
+ ***************************************************************************/
+
+void
+acpi_ns_low_find_names (
+ ACPI_NAMED_OBJECT *this_entry,
+ char *search_for,
+ s32 *count,
+ ACPI_HANDLE list[],
+ s32 max_depth)
+{
+ FIND_CONTEXT find;
+
+
+ if (0 == max_depth || !this_entry || !search_for || !count) {
+ /*
+ * Zero requested depth, nothing to search,
+ * nothing to search for, or count pointer bad
+ */
+
+ return;
+ }
+
+ /* Init the context structure used by compare routine */
+
+ find.list = list;
+ find.count = count;
+ find.search_for = search_for;
+
+ /* Walk the namespace and find all matches */
+
+ acpi_ns_walk_namespace (ACPI_TYPE_ANY, (ACPI_HANDLE) this_entry,
+ max_depth, NS_WALK_NO_UNLOCK,
+ acpi_ns_name_compare, &find, NULL);
+
+ if (list) {
+ /* null-terminate the output array */
+
+ list[*count] = (ACPI_HANDLE) 0;
+ }
+
+ return;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_find_names
+
+ *
+ * PARAMETERS: *Search_for - pattern to be found.
+ * 4 bytes, ? matches any character.
+ * If NULL, "????" will be used.
+ * Start_handle - Root of subtree to be searched, or
+ * NS_ALL to search the entire namespace
+ * Max_depth - Maximum depth of search. Use INT_MAX
+ * for an effectively unlimited depth.
+ *
+ * DESCRIPTION: Traverse the name space finding names which match a search
+ * pattern, and return an array of handles. The end of the
+ * array is marked by the value (ACPI_HANDLE)0. A return value
+ * of (ACPI_HANDLE *)0 indicates that no matching names were
+ * found or that space for the list could not be allocated.
+ * if Start_handle is NS_ALL (null) search from the root,
+ * else it is a handle whose children are to be searched.
+ *
+ ***************************************************************************/
+
+ACPI_HANDLE *
+acpi_ns_find_names (
+ char *search_for,
+ ACPI_HANDLE start_handle,
+ s32 max_depth)
+{
+ ACPI_HANDLE *list = NULL;
+ s32 count;
+
+
+ if (!acpi_gbl_root_object->child_table) {
+ /*
+ * If the name space has not been initialized,
+ * there surely are no matching names.
+ */
+ return (NULL);
+ }
+
+ if (NS_ALL == start_handle) {
+ /* base is root */
+
+ start_handle = acpi_gbl_root_object;
+ }
+
+ else if (((ACPI_NAMED_OBJECT *) start_handle)->child_table) {
+ /* base has children to search */
+
+ start_handle =
+ ((ACPI_NAMED_OBJECT *) start_handle)->child_table->entries;
+ }
+
+ else {
+ /*
+ * If base is not the root and has no children,
+ * there is nothing to search.
+ */
+ return (NULL);
+ }
+
+ if (!search_for) {
+ /* Search name not specified */
+
+ search_for = "????";
+ }
+
+
+ /* Pass 1. Get required buffer size, don't try to build list */
+
+ count = 0;
+ acpi_ns_low_find_names (start_handle, search_for, &count,
+ NULL, max_depth);
+
+ if (0 == count) {
+ return (NULL);
+ }
+
+ /* Allow for trailing null */
+ count++;
+
+ list = acpi_cm_callocate (count * sizeof(ACPI_HANDLE));
+ if (!list) {
+ REPORT_ERROR ("Ns_find_names: allocation failure");
+ return (NULL);
+ }
+
+ /* Pass 2. Fill buffer */
+
+ count = 0;
+ acpi_ns_low_find_names (start_handle, search_for, &count, list, max_depth);
+
+ return (list);
+}
+
+
diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c
new file mode 100644
index 000000000..56e497bb0
--- /dev/null
+++ b/drivers/acpi/namespace/nsobject.c
@@ -0,0 +1,556 @@
+
+/******************************************************************************
+ *
+ * Module Name: nsobject - Utilities for objects attached to namespace
+ * table entries
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "amlcode.h"
+#include "namesp.h"
+#include "interp.h"
+#include "tables.h"
+
+
+#define _COMPONENT NAMESPACE
+ MODULE_NAME ("nsobject");
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_attach_object
+ *
+ * PARAMETERS: Handle - Handle of nte
+ * Object - Object to be attached
+ * Type - Type of object, or ACPI_TYPE_ANY if not
+ * known
+ *
+ * DESCRIPTION: Record the given object as the value associated with the
+ * name whose ACPI_HANDLE is passed. If Object is NULL
+ * and Type is ACPI_TYPE_ANY, set the name as having no value.
+ *
+ * MUTEX: Assumes namespace is locked
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ns_attach_object (
+ ACPI_HANDLE handle,
+ ACPI_HANDLE object,
+ OBJECT_TYPE_INTERNAL type)
+{
+ ACPI_NAMED_OBJECT *this_entry = (ACPI_NAMED_OBJECT*) handle;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_OBJECT_INTERNAL *previous_obj_desc;
+ OBJECT_TYPE_INTERNAL obj_type = ACPI_TYPE_ANY;
+ u8 flags;
+ u16 opcode;
+
+
+ /*
+ * Parameter validation
+ */
+
+ if (!acpi_gbl_root_object->child_table) {
+ /* Name space not initialized */
+
+ REPORT_ERROR ("Ns_attach_object: Name space not initialized");
+ return (AE_NO_NAMESPACE);
+ }
+
+ if (!handle) {
+ /* Invalid handle */
+
+ REPORT_ERROR ("Ns_attach_object: Null name handle");
+ return (AE_BAD_PARAMETER);
+ }
+
+ if (!object && (ACPI_TYPE_ANY != type)) {
+ /* Null object */
+
+ REPORT_ERROR ("Ns_attach_object: Null object, but type"
+ "not ACPI_TYPE_ANY");
+ return (AE_BAD_PARAMETER);
+ }
+
+ if (!VALID_DESCRIPTOR_TYPE (handle, ACPI_DESC_TYPE_NAMED)) {
+ /* Not a name handle */
+
+ REPORT_ERROR ("Ns_attach_object: Invalid handle");
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Check if this object is already attached */
+
+ if (this_entry->object == object) {
+ return (AE_OK);
+ }
+
+
+ /* Get the current flags field of the NTE */
+
+ flags = this_entry->flags;
+ flags &= ~NTE_AML_ATTACHMENT;
+
+
+ /* If null object, we will just install it */
+
+ if (!object) {
+ obj_desc = NULL;
+ obj_type = ACPI_TYPE_ANY;
+ }
+
+ /*
+ * If the object is an NTE with an attached object,
+ * we will use that (attached) object
+ */
+
+ else if (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_NAMED) &&
+ ((ACPI_NAMED_OBJECT*) object)->object)
+ {
+ /*
+ * Value passed is a name handle and that name has a
+ * non-null value. Use that name's value and type.
+ */
+
+ obj_desc = ((ACPI_NAMED_OBJECT*) object)->object;
+ obj_type = ((ACPI_NAMED_OBJECT*) object)->type;
+
+ /*
+ * Copy appropriate flags
+ */
+
+ if (((ACPI_NAMED_OBJECT*) object)->flags & NTE_AML_ATTACHMENT) {
+ flags |= NTE_AML_ATTACHMENT;
+ }
+ }
+
+
+ /*
+ * Otherwise, we will use the parameter object, but we must type
+ * it first
+ */
+
+ else {
+ obj_desc = (ACPI_OBJECT_INTERNAL *) object;
+
+
+ /* If a valid type (non-ANY) was given, just use it */
+
+ if (ACPI_TYPE_ANY != type) {
+ obj_type = type;
+ }
+
+
+ /*
+ * Type is TYPE_Any, we must try to determinte the
+ * actual type of the object
+ */
+
+ /*
+ * Check if value points into the AML code
+ */
+ else if (acpi_tb_system_table_pointer (object)) {
+ /*
+ * Object points into the AML stream.
+ * Set a flag bit in the NTE to indicate this
+ */
+
+ flags |= NTE_AML_ATTACHMENT;
+
+ /*
+ * The next byte (perhaps the next two bytes)
+ * will be the AML opcode
+ */
+
+ MOVE_UNALIGNED16_TO_16 (&opcode, object);
+
+ /* Check for a recognized Op_code */
+
+ switch ((u8) opcode)
+ {
+
+ case AML_OP_PREFIX:
+
+ if (opcode != AML_REVISION_OP) {
+ /*
+ * Op_prefix is unrecognized unless part
+ * of Revision_op
+ */
+
+ break;
+ }
+
+ /* Else fall through to set type as Number */
+
+
+ case AML_ZERO_OP: case AML_ONES_OP: case AML_ONE_OP:
+ case AML_BYTE_OP: case AML_WORD_OP: case AML_DWORD_OP:
+
+ obj_type = ACPI_TYPE_NUMBER;
+ break;
+
+
+ case AML_STRING_OP:
+
+ obj_type = ACPI_TYPE_STRING;
+ break;
+
+
+ case AML_BUFFER_OP:
+
+ obj_type = ACPI_TYPE_BUFFER;
+ break;
+
+
+ case AML_MUTEX_OP:
+
+ obj_type = ACPI_TYPE_MUTEX;
+ break;
+
+
+ case AML_PACKAGE_OP:
+
+ obj_type = ACPI_TYPE_PACKAGE;
+ break;
+
+
+ default:
+
+ return (AE_TYPE);
+ break;
+ }
+ }
+
+ else {
+ /*
+ * Cannot figure out the type -- set to Def_any which
+ * will print as an error in the name table dump
+ */
+
+
+ obj_type = INTERNAL_TYPE_DEF_ANY;
+ }
+ }
+
+
+ /*
+ * Must increment the new value's reference count
+ * (if it is an internal object)
+ */
+
+ acpi_cm_add_reference (obj_desc);
+
+ /* Save the existing object (if any) for deletion later */
+
+ previous_obj_desc = this_entry->object;
+
+ /* Install the object and set the type, flags */
+
+ this_entry->object = obj_desc;
+ this_entry->type = (u8) obj_type;
+ this_entry->flags = flags;
+
+
+ /*
+ * Delete an existing attached object.
+ */
+
+ if (previous_obj_desc) {
+ /* One for the attach to the NTE */
+ acpi_cm_remove_reference (previous_obj_desc);
+ /* Now delete */
+ acpi_cm_remove_reference (previous_obj_desc);
+ }
+
+ return (AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_attach_method
+ *
+ * PARAMETERS: Handle - Handle of nte to be set
+ * Offset - Value to be set
+ * Length - Length associated with value
+ *
+ * DESCRIPTION: Record the given offset and p-code length of the method
+ * whose handle is passed
+ *
+ * MUTEX: Assumes namespace is locked
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ns_attach_method (
+ ACPI_HANDLE handle,
+ u8 *pcode_addr,
+ u32 pcode_length)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_OBJECT_INTERNAL *previous_obj_desc;
+ ACPI_NAMED_OBJECT *this_entry = (ACPI_NAMED_OBJECT*) handle;
+
+
+ /* Parameter validation */
+
+ if (!acpi_gbl_root_object->child_table) {
+ /* Name space uninitialized */
+
+ REPORT_ERROR ("Ns_attach_method: name space uninitialized");
+ return (AE_NO_NAMESPACE);
+ }
+
+ if (!handle) {
+ /* Null name handle */
+
+ REPORT_ERROR ("Ns_attach_method: null name handle");
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /* Allocate a method descriptor */
+
+ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_METHOD);
+ if (!obj_desc) {
+ /* Method allocation failure */
+
+ REPORT_ERROR ("Ns_attach_method: allocation failure");
+ return (AE_NO_MEMORY);
+ }
+
+ /* Init the method info */
+
+ obj_desc->method.pcode = pcode_addr;
+ obj_desc->method.pcode_length = pcode_length;
+
+ /* Update reference count and install */
+
+ acpi_cm_add_reference (obj_desc);
+
+ previous_obj_desc = this_entry->object;
+ this_entry->object = obj_desc;
+
+
+ /*
+ * Delete an existing object. Don't try to re-use in case it is shared
+ */
+ if (previous_obj_desc) {
+ acpi_cm_remove_reference (previous_obj_desc);
+ }
+
+ return (AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_detach_object
+ *
+ * PARAMETERS: Object - An object whose Value will be deleted
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Delete the Value associated with a namespace object. If the
+ * Value is an allocated object, it is freed. Otherwise, the
+ * field is simply cleared.
+ *
+ ***************************************************************************/
+
+void
+acpi_ns_detach_object (
+ ACPI_HANDLE object)
+{
+ ACPI_NAMED_OBJECT *entry = object;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+
+
+ obj_desc = entry->object;
+ if (!obj_desc) {
+ return;
+ }
+
+ /* Clear the entry in all cases */
+
+ entry->object = NULL;
+
+ /* Found a valid value */
+
+ /*
+ * Not every value is an object allocated via Acpi_cm_callocate,
+ * - must check
+ */
+
+ if (!acpi_tb_system_table_pointer (obj_desc)) {
+ /* Attempt to delete the object (and all subobjects) */
+
+ acpi_cm_remove_reference (obj_desc);
+ }
+
+ return;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_get_attached_object
+ *
+ * PARAMETERS: Handle - Handle of nte to be examined
+ *
+ * RETURN: Current value of the object field from nte whose handle is
+ * passed
+ *
+ ***************************************************************************/
+
+void *
+acpi_ns_get_attached_object (
+ ACPI_HANDLE handle)
+{
+
+ if (!handle) {
+ /* handle invalid */
+
+ REPORT_WARNING ("Ns_get_attached_object: Null handle");
+ return (NULL);
+ }
+
+ return (((ACPI_NAMED_OBJECT*) handle)->object);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_compare_object
+ *
+ * PARAMETERS: Obj_handle - A namespace entry
+ * Level - Current nesting level
+ * Obj_desc - The value to be compared
+ *
+ * DESCRIPTION: A User_function called by Acpi_ns_walk_namespace(). It performs
+ * a comparison for Acpi_ns_find_attached_object(). The comparison is against
+ * the value in the value field of the Obj_handle (an NTE).
+ * If a match is found, the handle is returned, which aborts
+ * Acpi_ns_walk_namespace.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ns_compare_object (
+ ACPI_HANDLE obj_handle,
+ u32 level,
+ void *obj_desc,
+ void **return_value)
+{
+
+ if (((ACPI_NAMED_OBJECT*) obj_handle)->object == obj_desc) {
+ if (return_value) {
+ *return_value = obj_handle;
+ }
+
+ /* Stop the walk */
+ return AE_CTRL_TERMINATE;
+ }
+
+ /* Not found, continue the walk */
+ return AE_OK;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_find_attached_object
+ *
+ * PARAMETERS: *Obj_desc - Value to be found in ptr_val field.
+ * Start_handle - Root of subtree to be searched, or
+ * NS_ALL to search the entire namespace
+ * Max_depth - Maximum depth of search. Use INT_MAX
+ * for an effectively unlimited depth.
+ *
+ * DESCRIPTION: Traverse the name space until finding a name whose Value field
+ * matches the Obj_desc parameter, and return a handle to that
+ * name, or (ACPI_HANDLE)0 if none exists.
+ * if Start_handle is NS_ALL (null) search from the root,
+ * else it is a handle whose children are to be searched.
+ *
+ ***************************************************************************/
+
+ACPI_HANDLE
+acpi_ns_find_attached_object (
+ ACPI_OBJECT_INTERNAL *obj_desc,
+ ACPI_HANDLE start_handle,
+ s32 max_depth)
+{
+ ACPI_HANDLE ret_object;
+ ACPI_STATUS status;
+
+
+ /* Parameter validation */
+
+ if (!obj_desc) {
+ return (NULL);
+ }
+
+ if (0 == max_depth) {
+ return (NULL);
+ }
+
+ if (!acpi_gbl_root_object->child_table) {
+ /*
+ * If the name space has not been initialized,
+ * there surely are no matching values.
+ */
+ return (NULL);
+ }
+
+ if (NS_ALL == start_handle) {
+ start_handle = acpi_gbl_root_object;
+ }
+
+ else {
+ /*
+ * If base is not the root and has no children,
+ * there is nothing to search.
+ */
+ return (NULL);
+ }
+
+
+ /*
+ * Walk namespace until a match is found.
+ * Either the matching object is returned, or NULL in case
+ * of no match.
+ */
+ status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, start_handle,
+ max_depth, NS_WALK_NO_UNLOCK,
+ acpi_ns_compare_object,
+ obj_desc, &ret_object);
+
+ if (ACPI_FAILURE (status)) {
+ ret_object = NULL;
+ }
+
+ return (ret_object);
+}
+
+
diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c
new file mode 100644
index 000000000..19fad8ad6
--- /dev/null
+++ b/drivers/acpi/namespace/nssearch.c
@@ -0,0 +1,646 @@
+
+/******************************************************************************
+ *
+ * Module Name: nssearch - Namespace search
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "amlcode.h"
+#include "interp.h"
+#include "namesp.h"
+
+
+#define _COMPONENT NAMESPACE
+ MODULE_NAME ("nssearch");
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_search_one_scope
+ *
+ * PARAMETERS: *Entry_name - Ascii ACPI name to search for
+ * *Name_table - Starting table where search will begin
+ * Type - Object type to match
+ * **Ret_entry - Where the matched NTE is returned
+ * *Ret_info - Where info about the search is returned
+ *
+ * RETURN: Status and return information via NS_SEARCH_DATA
+ *
+ * DESCRIPTION: Search a single namespace table. Performs a simple search,
+ * does not add entries or search parents.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ns_search_one_scope (
+ u32 entry_name,
+ ACPI_NAME_TABLE *name_table,
+ OBJECT_TYPE_INTERNAL type,
+ ACPI_NAMED_OBJECT **ret_entry,
+ NS_SEARCH_DATA *ret_info)
+{
+ u32 position;
+ ACPI_NAME_TABLE *this_table;
+ ACPI_NAME_TABLE *previous_table = name_table;
+ ACPI_NAMED_OBJECT *entries;
+ u8 table_full = TRUE;
+ ACPI_NAME_TABLE *table_with_empty_slots = NULL;
+ u32 empty_slot_position = 0;
+
+
+
+ /*
+ * Name tables are built (and subsequently dumped) in the
+ * order in which the names are encountered during the namespace load;
+ *
+ * All namespace searching will be linear; If a table overflows an
+ * additional segment will be allocated and added (chained).
+ *
+ * Start linear search at top of table
+ */
+ position = 0;
+ this_table = name_table;
+ entries = this_table->entries;
+
+
+ /* Init return data */
+
+ if (ret_info) {
+ ret_info->name_table = this_table;
+ }
+
+
+ /*
+ * Search entire name table, including all linked appendages
+ */
+
+ while (this_table) {
+ /*
+ * Search for name in table, starting at Position. Stop
+ * searching upon examining all entries in the table.
+ *
+ */
+
+ entries = this_table->entries;
+ while (position < NS_TABLE_SIZE) {
+ /* Check for a valid entry */
+
+ if (!entries[position].name) {
+ if (table_full) {
+ /*
+ * There is room in the table for more
+ * entries, if necessary
+ */
+
+ table_full = FALSE;
+ table_with_empty_slots = this_table;
+ empty_slot_position = position;
+ }
+ }
+
+ /* Search for name in table */
+
+ else if (entries[position].name == entry_name) {
+ /*
+ * Found matching entry. Capture type if
+ * appropriate before returning the entry.
+ */
+
+ /*
+ * The Def_field_defn and Bank_field_defn cases
+ * are actually looking up the Region in which
+ * the field will be defined
+ */
+
+ if ((INTERNAL_TYPE_DEF_FIELD_DEFN == type) ||
+ (INTERNAL_TYPE_BANK_FIELD_DEFN == type))
+ {
+ type = ACPI_TYPE_REGION;
+ }
+
+ /*
+ * Scope, Def_any, and Index_field_defn are bogus
+ * "types" which do not actually have anything
+ * to do with the type of the name being looked
+ * up. For any other value of Type, if the type
+ * stored in the entry is Any (i.e. unknown),
+ * save the actual type.
+ */
+
+ if (type != INTERNAL_TYPE_SCOPE &&
+ type != INTERNAL_TYPE_DEF_ANY &&
+ type != INTERNAL_TYPE_INDEX_FIELD_DEFN &&
+ entries[position].type == ACPI_TYPE_ANY)
+ {
+ entries[position].type = (u8) type;
+ }
+
+ *ret_entry = &entries[position];
+ return (AE_OK);
+ }
+
+
+ /* Didn't match name, move on to the next entry */
+
+ position++;
+ }
+
+
+ /*
+ * Just examined last slot in this table, move on
+ * to next appendate.
+ * All appendages, even to the root NT, contain
+ * NS_TABLE_SIZE entries.
+ */
+
+ previous_table = this_table;
+ this_table = this_table->next_table;
+
+ position = 0;
+ }
+
+
+ /* Searched entire table, not found */
+
+
+ if (ret_info) {
+ /*
+ * Save info on if/where a slot is available
+ * (name was not found)
+ */
+
+ ret_info->table_full = table_full;
+ if (table_full) {
+ ret_info->name_table = previous_table;
+ }
+
+ else {
+ ret_info->position = empty_slot_position;
+ ret_info->name_table = table_with_empty_slots;
+ }
+ }
+
+ return (AE_NOT_FOUND);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_search_parent_tree
+ *
+ * PARAMETERS: *Entry_name - Ascii ACPI name to search for
+ * *Name_table - Starting table where search will begin
+ * Type - Object type to match
+ * **Ret_entry - Where the matched NTE is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Called when a name has not been found in the current namespace
+ * table. Before adding it or giving up, ACPI scope rules require
+ * searching enclosing scopes in cases identified by Acpi_ns_local().
+ *
+ * "A name is located by finding the matching name in the current
+ * name space, and then in the parent name space. If the parent
+ * name space does not contain the name, the search continues
+ * recursively until either the name is found or the name space
+ * does not have a parent (the root of the name space). This
+ * indicates that the name is not found" (From ACPI Specification,
+ * section 5.3)
+ *
+ ***************************************************************************/
+
+
+ACPI_STATUS
+acpi_ns_search_parent_tree (
+ u32 entry_name,
+ ACPI_NAME_TABLE *name_table,
+ OBJECT_TYPE_INTERNAL type,
+ ACPI_NAMED_OBJECT **ret_entry)
+{
+ ACPI_STATUS status;
+ ACPI_NAMED_OBJECT *parent_entry;
+ ACPI_NAMED_OBJECT *entries;
+
+
+ entries = name_table->entries;
+
+ /*
+ * If no parent or type is "local", we won't be searching the
+ * parent tree.
+ */
+
+ if (!acpi_ns_local (type) &&
+ name_table->parent_entry)
+ {
+ parent_entry = name_table->parent_entry;
+ /*
+ * Search parents until found or we have backed up to
+ * the root
+ */
+
+ while (parent_entry) {
+ /* Search parent scope */
+ /* TBD: [Investigate] Why ACPI_TYPE_ANY? */
+
+ status = acpi_ns_search_one_scope (entry_name,
+ parent_entry->child_table,
+ ACPI_TYPE_ANY,
+ ret_entry, NULL);
+
+ if (status == AE_OK) {
+ return (status);
+ }
+
+ /*
+ * Not found here, go up another level
+ * (until we reach the root)
+ */
+
+ parent_entry = acpi_ns_get_parent_entry (parent_entry);
+ }
+
+ /* Not found in parent tree */
+ }
+
+
+ return (AE_NOT_FOUND);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_create_and_link_new_table
+ *
+ * PARAMETERS: *Name_table - The table that is to be "extended" by
+ * the creation of an appendage table.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Allocate a new namespace table, initialize it, and link it
+ * into the parent table.
+ *
+ * NOTE: We are in the first or second pass load mode, want to
+ * add a new table entry, and the current table is full.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ns_create_and_link_new_table (
+ ACPI_NAME_TABLE *name_table)
+{
+ ACPI_NAME_TABLE *new_table;
+ ACPI_NAMED_OBJECT *parent_entry;
+ ACPI_STATUS status = AE_OK;
+
+
+ /* Sanity check on the data structure */
+
+ if (name_table->next_table) {
+ /* We should never get here (an appendage already allocated) */
+
+ return (AE_AML_INTERNAL);
+ }
+
+
+ /*
+ * We can use the parent entries from the current table
+ * Since the parent information remains the same.
+ */
+ parent_entry = name_table->parent_entry;
+
+
+ /* Allocate and chain an appendage to the filled table */
+
+ new_table = acpi_ns_allocate_name_table (NS_TABLE_SIZE);
+ if (!new_table) {
+ REPORT_ERROR ("Name Table appendage allocation failure");
+ return (AE_NO_MEMORY);
+ }
+
+ /*
+ * Allocation successful. Init the new table.
+ */
+ name_table->next_table = new_table;
+ acpi_ns_initialize_table (new_table, parent_entry->child_table,
+ parent_entry);
+
+ return (status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_initialize_table
+ *
+ * PARAMETERS: New_table - The new table to be initialized
+ * Parent_table - The parent (owner) scope
+ * Parent_entry - The NTE for the parent
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Initialize a new namespace table. Simple, but called
+ * from several places -- code should be kept in one place.
+ *
+ ***************************************************************************/
+
+void
+acpi_ns_initialize_table (
+ ACPI_NAME_TABLE *new_table,
+ ACPI_NAME_TABLE *parent_table,
+ ACPI_NAMED_OBJECT *parent_entry)
+{
+ u8 i;
+
+
+ new_table->parent_entry = parent_entry;
+ new_table->parent_table = parent_table;
+
+
+ /* Init each named object entry in the table */
+
+ for (i = 0; i < NS_TABLE_SIZE; i++) {
+ new_table->entries[i].this_index = i;
+ new_table->entries[i].data_type = ACPI_DESC_TYPE_NAMED;
+ }
+
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_initialize_entry
+ *
+ * PARAMETERS: Name_table - The containing table for the new NTE
+ * Position - Position (index) of the new NTE in the table
+ * Entry_name - ACPI name of the new entry
+ * Type - ACPI object type of the new entry
+ * Previous_entry - Link back to the previous entry (can span
+ * multiple tables)
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Initialize a new entry within a namespace table.
+ *
+ ***************************************************************************/
+
+void
+acpi_ns_initialize_entry (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_NAME_TABLE *name_table,
+ u32 position,
+ u32 entry_name,
+ OBJECT_TYPE_INTERNAL type)
+{
+ ACPI_NAMED_OBJECT *new_entry;
+ u16 owner_id = TABLE_ID_DSDT;
+ ACPI_NAMED_OBJECT *entries;
+
+
+ /*
+ * Get the owner ID from the Walk state
+ * The owner ID is used to track table deletion and
+ * deletion of objects created by methods
+ */
+ if (walk_state) {
+ owner_id = walk_state->owner_id;
+ }
+
+ /* The new entry is given by two parameters */
+
+ entries = name_table->entries;
+ new_entry = &entries[position];
+
+ /* Init the new entry */
+
+ new_entry->data_type = ACPI_DESC_TYPE_NAMED;
+ new_entry->name = entry_name;
+ new_entry->owner_id = owner_id;
+ new_entry->reference_count = 1;
+
+
+ /*
+ * If adding a name with unknown type, or having to
+ * add the region in order to define fields in it, we
+ * have a forward reference.
+ */
+
+ if ((ACPI_TYPE_ANY == type) ||
+ (INTERNAL_TYPE_DEF_FIELD_DEFN == type) ||
+ (INTERNAL_TYPE_BANK_FIELD_DEFN == type))
+ {
+ /*
+ * We don't want to abort here, however!
+ * We will fill in the actual type when the
+ * real definition is found later.
+ */
+
+ }
+
+ /*
+ * The Def_field_defn and Bank_field_defn cases are actually
+ * looking up the Region in which the field will be defined
+ */
+
+ if ((INTERNAL_TYPE_DEF_FIELD_DEFN == type) ||
+ (INTERNAL_TYPE_BANK_FIELD_DEFN == type))
+ {
+ type = ACPI_TYPE_REGION;
+ }
+
+ /*
+ * Scope, Def_any, and Index_field_defn are bogus "types" which do
+ * not actually have anything to do with the type of the name
+ * being looked up. Save any other value of Type as the type of
+ * the entry.
+ */
+
+ if ((type != INTERNAL_TYPE_SCOPE) &&
+ (type != INTERNAL_TYPE_DEF_ANY) &&
+ (type != INTERNAL_TYPE_INDEX_FIELD_DEFN))
+ {
+ new_entry->type = (u8) type;
+ }
+
+ return;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_search_and_enter
+ *
+ * PARAMETERS: Entry_name - Ascii ACPI name to search for (4 chars)
+ * *Name_table - Starting table where search will begin
+ * Interpreter_mode - Add names only in MODE_Load_pass_x. Otherwise,
+ * search only.
+ * Type - Object type to match
+ * **Ret_entry - Where the matched NTE is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Search for a name segment in a single name table,
+ * optionally adding it if it is not found. If the passed
+ * Type is not Any and the type previously stored in the
+ * entry was Any (i.e. unknown), update the stored type.
+ *
+ * In IMODE_EXECUTE, search only.
+ * In other modes, search and add if not found.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ns_search_and_enter (
+ u32 entry_name,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_NAME_TABLE *name_table,
+ OPERATING_MODE interpreter_mode,
+ OBJECT_TYPE_INTERNAL type,
+ u32 flags,
+ ACPI_NAMED_OBJECT **ret_entry)
+{
+ u32 position; /* position in table */
+ ACPI_STATUS status;
+ NS_SEARCH_DATA search_info;
+ ACPI_NAMED_OBJECT *entry;
+ ACPI_NAMED_OBJECT *entries;
+
+
+ /* Parameter validation */
+
+ if (!name_table || !entry_name || !ret_entry) {
+ REPORT_ERROR ("Ns_search_and_enter: bad parameter");
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /* Name must consist of printable characters */
+
+ if (!acpi_cm_valid_acpi_name (entry_name)) {
+ return (AE_BAD_CHARACTER);
+ }
+
+
+ /* Try to find the name in the table specified by the caller */
+
+ *ret_entry = ENTRY_NOT_FOUND;
+ status = acpi_ns_search_one_scope (entry_name, name_table,
+ type, ret_entry, &search_info);
+ if (status != AE_NOT_FOUND) {
+ /*
+ * Either found it or there was an error
+ * -- finished either way
+ */
+
+ return (status);
+ }
+
+
+ /*
+ * Not found in the table. If we are NOT performing the
+ * first pass (name entry) of loading the namespace, search
+ * the parent tree (all the way to the root if necessary.)
+ * We don't want to perform the parent search when the
+ * namespace is actually being loaded. We want to perform
+ * the search when namespace references are being resolved
+ * (load pass 2) and during the execution phase.
+ */
+
+ if ((interpreter_mode != IMODE_LOAD_PASS1) &&
+ (flags & NS_SEARCH_PARENT))
+ {
+ /*
+ * Not found in table - search parent tree according
+ * to ACPI specification
+ */
+
+ status = acpi_ns_search_parent_tree (entry_name, name_table,
+ type, ret_entry);
+
+ if (status == AE_OK) {
+ return (status);
+ }
+ }
+
+
+ /*
+ * In execute mode, just search, never add names. Exit now.
+ */
+
+ if (interpreter_mode == IMODE_EXECUTE) {
+ return (AE_NOT_FOUND);
+ }
+
+
+ /*
+ * Extract the pertinent info from the search result struct.
+ * Name_table and position might now point to an appendage
+ */
+ name_table = search_info.name_table;
+ position = search_info.position;
+
+
+ /*
+ * This block handles the case where the existing table is full.
+ * we must allocate a new table before we can initialize a new entry
+ */
+
+ if (search_info.table_full) {
+ status = acpi_ns_create_and_link_new_table (name_table);
+ if (status != AE_OK) {
+ return (status);
+ }
+
+ /* Point to the first slot in the new table */
+
+ name_table = name_table->next_table;
+ position = 0;
+ }
+
+
+ /*
+ * There is room in the table (or we have just allocated a new one.)
+ * Initialize the new entry
+ */
+
+ acpi_ns_initialize_entry (walk_state, name_table, position,
+ entry_name, type);
+
+
+ entries = name_table->entries;
+ *ret_entry = &entries[position];
+ entry = &entries[position];
+
+ /*
+ * Increment the reference count(s) of all parents up to
+ * the root!
+ */
+
+ while (acpi_ns_get_parent_entry (entry)) {
+ entry = acpi_ns_get_parent_entry (entry);
+ entry->reference_count++;
+ }
+
+
+ return (AE_OK);
+}
+
diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c
new file mode 100644
index 000000000..c938ede93
--- /dev/null
+++ b/drivers/acpi/namespace/nsutils.c
@@ -0,0 +1,886 @@
+
+/******************************************************************************
+ *
+ * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing
+ * parents and siblings and Scope manipulation
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "namesp.h"
+#include "interp.h"
+#include "amlcode.h"
+#include "tables.h"
+
+#define _COMPONENT NAMESPACE
+ MODULE_NAME ("nsutils");
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_valid_root_prefix
+ *
+ * PARAMETERS: Prefix - Character to be checked
+ *
+ * RETURN: TRUE if a valid prefix
+ *
+ * DESCRIPTION: Check if a character is a valid ACPI Root prefix
+ *
+ ***************************************************************************/
+
+u8
+acpi_ns_valid_root_prefix (
+ char prefix)
+{
+
+ return ((u8) (prefix == '\\'));
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_valid_path_separator
+ *
+ * PARAMETERS: Sep - Character to be checked
+ *
+ * RETURN: TRUE if a valid path separator
+ *
+ * DESCRIPTION: Check if a character is a valid ACPI path separator
+ *
+ ***************************************************************************/
+
+u8
+acpi_ns_valid_path_separator (
+ char sep)
+{
+
+ return ((u8) (sep == '.'));
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_get_type
+ *
+ * PARAMETERS: Handle - Handle of nte to be examined
+ *
+ * RETURN: Type field from nte whose handle is passed
+ *
+ ***************************************************************************/
+
+OBJECT_TYPE_INTERNAL
+acpi_ns_get_type (
+ ACPI_HANDLE handle)
+{
+
+ if (!handle) {
+ /* Handle invalid */
+
+ REPORT_WARNING ("Ns_get_type: Null handle");
+ return (ACPI_TYPE_ANY);
+ }
+
+ return (((ACPI_NAMED_OBJECT*) handle)->type);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_local
+ *
+ * PARAMETERS: Type - A namespace object type
+ *
+ * RETURN: LOCAL if names must be found locally in objects of the
+ * passed type, 0 if enclosing scopes should be searched
+ *
+ ***************************************************************************/
+
+s32
+acpi_ns_local (
+ OBJECT_TYPE_INTERNAL type)
+{
+
+ if (!acpi_cm_valid_object_type (type)) {
+ /* type code out of range */
+
+ REPORT_WARNING ("Ns_local: Invalid Object Type");
+ return (NSP_NORMAL);
+ }
+
+ return ((s32) acpi_gbl_ns_properties[type] & NSP_LOCAL);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_internalize_name
+ *
+ * PARAMETERS: *External_name - External representation of name
+ * **Converted Name - Where to return the resulting
+ * internal represention of the name
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Convert an external representation (e.g. "\_PR_.CPU0")
+ * to internal form (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30)
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ns_internalize_name (
+ char *external_name,
+ char **converted_name)
+{
+ char *result = NULL;
+ char *internal_name;
+ ACPI_SIZE num_segments;
+ u8 fully_qualified = FALSE;
+ u32 i;
+
+
+ if ((!external_name) ||
+ (*external_name == 0) ||
+ (!converted_name))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /*
+ * For the internal name, the required length is 4 bytes
+ * per segment, plus 1 each for Root_prefix, Multi_name_prefix_op,
+ * segment count, trailing null (which is not really needed,
+ * but no there's harm in putting it there)
+ *
+ * strlen() + 1 covers the first Name_seg, which has no
+ * path separator
+ */
+
+ if (acpi_ns_valid_root_prefix (external_name[0])) {
+ fully_qualified = TRUE;
+ external_name++;
+ }
+
+
+ /*
+ * Determine the number of ACPI name "segments" by counting
+ * the number of path separators within the string. Start
+ * with one segment since the segment count is (# separators)
+ * + 1, and zero separators is ok.
+ */
+
+ num_segments = 1;
+ for (i = 0; external_name[i]; i++) {
+ if (acpi_ns_valid_path_separator (external_name[i])) {
+ num_segments++;
+ }
+ }
+
+
+ /* We need a segment to store the internal version of the name */
+
+ internal_name = acpi_cm_callocate ((ACPI_NAME_SIZE * num_segments) + 4);
+ if (!internal_name) {
+ return (AE_NO_MEMORY);
+ }
+
+
+ /* Setup the correct prefixes, counts, and pointers */
+
+ if (fully_qualified) {
+ internal_name[0] = '\\';
+ internal_name[1] = AML_MULTI_NAME_PREFIX_OP;
+ internal_name[2] = (char) num_segments;
+ result = &internal_name[3];
+ }
+ else {
+ internal_name[0] = AML_MULTI_NAME_PREFIX_OP;
+ internal_name[1] = (char) num_segments;
+ result = &internal_name[2];
+ }
+
+
+ /* Build the name (minus path separators) */
+
+ for (; num_segments; num_segments--) {
+ for (i = 0; i < ACPI_NAME_SIZE; i++) {
+ if (acpi_ns_valid_path_separator (*external_name) ||
+ (*external_name == 0))
+ {
+ /*
+ * Pad the segment with underscore(s) if
+ * segment is short
+ */
+
+ result[i] = '_';
+ }
+
+ else {
+ /* Convert char to uppercase and save it */
+
+ result[i] = (char) TOUPPER (*external_name);
+ external_name++;
+ }
+
+ }
+
+ /* Now we must have a path separator, or the pathname is bad */
+
+ if (!acpi_ns_valid_path_separator (*external_name) &&
+ (*external_name != 0))
+ {
+ acpi_cm_free (internal_name);
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Move on the next segment */
+
+ external_name++;
+ result += ACPI_NAME_SIZE;
+ }
+
+
+ /* Return the completed name */
+
+ /* Terminate the string! */
+ *result = 0;
+ *converted_name = internal_name;
+
+
+
+ return (AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_externalize_name
+ *
+ * PARAMETERS: *Internal_name - Internal representation of name
+ * **Converted_name - Where to return the resulting
+ * external representation of name
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Convert internal name (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30)
+ * to its external form (e.g. "\_PR_.CPU0")
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ns_externalize_name (
+ u32 internal_name_length,
+ char *internal_name,
+ u32 *converted_name_length,
+ char **converted_name)
+{
+ u32 prefix_length = 0;
+ u32 names_index = 0;
+ u32 names_count = 0;
+ u32 i = 0;
+ u32 j = 0;
+
+ if (internal_name_length < 0 ||
+ !internal_name ||
+ !converted_name_length ||
+ !converted_name)
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Check for a prefix (one '\' | one or more '^').
+ */
+ switch (internal_name[0])
+ {
+ case '\\':
+ prefix_length = 1;
+ break;
+
+ case '^':
+ for (i = 0; i < internal_name_length; i++) {
+ if (internal_name[i] != '^') {
+ prefix_length = i + 1;
+ }
+ }
+
+ if (i == internal_name_length) {
+ prefix_length = i;
+ }
+
+ break;
+ }
+
+ /*
+ * Check for object names. Note that there could be 0-255 of these
+ * 4-byte elements.
+ */
+ if (prefix_length < internal_name_length) {
+ switch (internal_name[prefix_length])
+ {
+
+ /* <count> 4-byte names */
+
+ case AML_MULTI_NAME_PREFIX_OP:
+ names_index = prefix_length + 2;
+ names_count = (u32) internal_name[prefix_length + 1];
+ break;
+
+
+ /* two 4-byte names */
+
+ case AML_DUAL_NAME_PREFIX:
+ names_index = prefix_length + 1;
+ names_count = 2;
+ break;
+
+
+ /* Null_name */
+
+ case 0:
+ names_index = 0;
+ names_count = 0;
+ break;
+
+
+ /* one 4-byte name */
+
+ default:
+ names_index = prefix_length;
+ names_count = 1;
+ break;
+ }
+ }
+
+ /*
+ * Calculate the length of Converted_name, which equals the length
+ * of the prefix, length of all object names, length of any required
+ * punctuation ('.') between object names, plus the NULL terminator.
+ */
+ *converted_name_length = prefix_length + (4 * names_count) +
+ ((names_count > 0) ? (names_count - 1) : 0) + 1;
+
+ /*
+ * Check to see if we're still in bounds. If not, there's a problem
+ * with Internal_name (invalid format).
+ */
+ if (*converted_name_length > internal_name_length) {
+ REPORT_ERROR ("Ns_externalize_name: Invalid internal name.\n");
+ return (AE_BAD_PATHNAME);
+ }
+
+ /*
+ * Build Converted_name...
+ */
+
+ (*converted_name) = acpi_cm_callocate (*converted_name_length);
+ if (!(*converted_name)) {
+ return (AE_NO_MEMORY);
+ }
+
+ j = 0;
+
+ for (i = 0; i < prefix_length; i++) {
+ (*converted_name)[j++] = internal_name[i];
+ }
+
+ if (names_count > 0) {
+ for (i = 0; i < names_count; i++) {
+ if (i > 0) {
+ (*converted_name)[j++] = '.';
+ }
+
+ (*converted_name)[j++] = internal_name[names_index++];
+ (*converted_name)[j++] = internal_name[names_index++];
+ (*converted_name)[j++] = internal_name[names_index++];
+ (*converted_name)[j++] = internal_name[names_index++];
+ }
+ }
+
+ return (AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_convert_handle_to_entry
+ *
+ * PARAMETERS: Handle - Handle to be converted to an NTE
+ *
+ * RETURN: A Name table entry pointer
+ *
+ * DESCRIPTION: Convert a namespace handle to a real NTE
+ *
+ ****************************************************************************/
+
+ACPI_NAMED_OBJECT*
+acpi_ns_convert_handle_to_entry (
+ ACPI_HANDLE handle)
+{
+
+ /*
+ * Simple implementation for now;
+ * TBD: [Future] Real integer handles allow for more verification
+ * and keep all pointers within this subsystem!
+ */
+
+ if (!handle) {
+ return NULL;
+ }
+
+ if (handle == ACPI_ROOT_OBJECT) {
+ return acpi_gbl_root_object;
+ }
+
+
+ /* We can at least attempt to verify the handle */
+
+ if (!VALID_DESCRIPTOR_TYPE (handle, ACPI_DESC_TYPE_NAMED)) {
+ return NULL;
+ }
+
+ return (ACPI_NAMED_OBJECT*) handle;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_convert_entry_to_handle
+ *
+ * PARAMETERS: Nte - NTE to be converted to a Handle
+ *
+ * RETURN: An USER ACPI_HANDLE
+ *
+ * DESCRIPTION: Convert a real NTE to a namespace handle
+ *
+ ****************************************************************************/
+
+ACPI_HANDLE
+acpi_ns_convert_entry_to_handle(ACPI_NAMED_OBJECT*nte)
+{
+
+
+ /*
+ * Simple implementation for now;
+ * TBD: [Future] Real integer handles allow for more verification
+ * and keep all pointers within this subsystem!
+ */
+
+ return (ACPI_HANDLE) nte;
+
+
+/* ---------------------------------------------------
+
+ if (!Nte) {
+ return NULL;
+ }
+
+ if (Nte == Acpi_gbl_Root_object) {
+ return ACPI_ROOT_OBJECT;
+ }
+
+
+ return (ACPI_HANDLE) Nte;
+------------------------------------------------------*/
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ns_terminate
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: none
+ *
+ * DESCRIPTION: free memory allocated for table storage.
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_terminate (void)
+{
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ ACPI_NAMED_OBJECT *entry;
+
+
+ entry = acpi_gbl_root_object;
+
+ /*
+ * 1) Free the entire namespace -- all objects, tables, and stacks
+ */
+ /*
+ * Delete all objects linked to the root
+ * (additional table descriptors)
+ */
+
+ acpi_ns_delete_namespace_subtree (entry);
+
+ /* Detach any object(s) attached to the root */
+
+ obj_desc = acpi_ns_get_attached_object (entry);
+ if (obj_desc) {
+ acpi_ns_detach_object (entry);
+ acpi_cm_remove_reference (obj_desc);
+ }
+
+ acpi_ns_delete_name_table (entry->child_table);
+ entry->child_table = NULL;
+
+
+ REPORT_SUCCESS ("Entire namespace and objects deleted");
+
+ /*
+ * 2) Now we can delete the ACPI tables
+ */
+
+ acpi_tb_delete_acpi_tables ();
+
+ return;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_opens_scope
+ *
+ * PARAMETERS: Type - A valid namespace type
+ *
+ * RETURN: NEWSCOPE if the passed type "opens a name scope" according
+ * to the ACPI specification, else 0
+ *
+ ***************************************************************************/
+
+s32
+acpi_ns_opens_scope (
+ OBJECT_TYPE_INTERNAL type)
+{
+
+ if (!acpi_cm_valid_object_type (type)) {
+ /* type code out of range */
+
+ REPORT_WARNING ("Ns_opens_scope: Invalid Object Type");
+ return (NSP_NORMAL);
+ }
+
+ return (((s32) acpi_gbl_ns_properties[type]) & NSP_NEWSCOPE);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_get_named_object
+ *
+ * PARAMETERS: *Pathname - Name to be found, in external (ASL) format. The
+ * \ (backslash) and ^ (carat) prefixes, and the
+ * . (period) to separate segments are supported.
+ * In_scope - Root of subtree to be searched, or NS_ALL for the
+ * root of the name space. If Name is fully
+ * qualified (first char is '\'), the passed value
+ * of Scope will not be accessed.
+ * Out_nte - Where the Nte is returned
+ *
+ * DESCRIPTION: Look up a name relative to a given scope and return the
+ * corresponding NTE. NOTE: Scope can be null.
+ *
+ * MUTEX: Locks namespace
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ns_get_named_object (
+ char *pathname,
+ ACPI_NAME_TABLE *in_scope,
+ ACPI_NAMED_OBJECT **out_nte)
+{
+ ACPI_GENERIC_STATE scope_info;
+ ACPI_STATUS status;
+ ACPI_NAMED_OBJECT *obj_entry = NULL;
+ char *internal_path = NULL;
+
+
+ scope_info.scope.name_table = in_scope;
+
+ /* Ensure that the namespace has been initialized */
+
+ if (!acpi_gbl_root_object->child_table) {
+ return (AE_NO_NAMESPACE);
+ }
+
+ if (!pathname) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /* Convert path to internal representation */
+
+ status = acpi_ns_internalize_name (pathname, &internal_path);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+ /* NS_ALL means start from the root */
+
+ if (NS_ALL == scope_info.scope.name_table) {
+ scope_info.scope.name_table = acpi_gbl_root_object->child_table;
+ }
+
+ else {
+ scope_info.scope.name_table = in_scope;
+ if (!scope_info.scope.name_table) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+ }
+
+ /* Lookup the name in the namespace */
+
+ status = acpi_ns_lookup (&scope_info, internal_path,
+ ACPI_TYPE_ANY, IMODE_EXECUTE,
+ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE,
+ NULL, &obj_entry);
+
+
+ /* Return what was wanted - the NTE that matches the name */
+
+ *out_nte = obj_entry;
+
+
+unlock_and_exit:
+
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+
+ /* Cleanup */
+
+ acpi_cm_free (internal_path);
+
+ return (status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_find_parent_name
+ *
+ * PARAMETERS: *Child_entry - nte whose name is to be found
+ *
+ * RETURN: The ACPI name
+ *
+ * DESCRIPTION: Search for the given nte in its parent scope and return the
+ * name segment, or "????" if the parent name can't be found
+ * (which "should not happen").
+ *
+ ***************************************************************************/
+
+ACPI_NAME
+acpi_ns_find_parent_name (
+ ACPI_NAMED_OBJECT *child_entry)
+{
+ ACPI_NAMED_OBJECT *parent_entry;
+
+
+ if (child_entry) {
+ /* Valid entry. Get the parent Nte */
+
+ parent_entry = acpi_ns_get_parent_entry (child_entry);
+ if (parent_entry) {
+ if (parent_entry->name) {
+ return (parent_entry->name);
+ }
+ }
+
+ }
+
+
+ return (ACPI_UNKNOWN_NAME);
+}
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_exist_downstream_sibling
+ *
+ * PARAMETERS: *This_entry - pointer to first nte to examine
+ *
+ * RETURN: TRUE if sibling is found, FALSE otherwise
+ *
+ * DESCRIPTION: Searches remainder of scope being processed to determine
+ * whether there is a downstream sibling to the current
+ * object. This function is used to determine what type of
+ * line drawing character to use when displaying namespace
+ * trees.
+ *
+ ***************************************************************************/
+
+u8
+acpi_ns_exist_downstream_sibling (
+ ACPI_NAMED_OBJECT *this_entry)
+{
+
+ if (!this_entry) {
+ return FALSE;
+ }
+
+ if (this_entry->name) {
+ return TRUE;
+ }
+
+
+/* TBD: what did this really do?
+ if (This_entry->Next_entry) {
+ return TRUE;
+ }
+*/
+ return FALSE;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_get_owner_table
+ *
+ * PARAMETERS:
+ *
+ * RETURN:
+ *
+ * DESCRIPTION:
+ *
+ ***************************************************************************/
+
+
+ACPI_NAME_TABLE *
+acpi_ns_get_owner_table (
+ ACPI_NAMED_OBJECT *this_entry)
+{
+
+ /*
+ * Given an entry in the Name_table->Entries field of a name table,
+ * we can create a pointer to the beginning of the table as follows:
+ *
+ * 1) Starting with the the pointer to the entry,
+ * 2) Subtract the entry index * size of each entry to get a
+ * pointer to Entries[0]
+ * 3) Subtract the size of NAME_TABLE structure to get a pointer
+ * to the start.
+ *
+ * This saves having to put a pointer in every entry that points
+ * back to the beginning of the table and/or a pointer back to
+ * the parent.
+ */
+
+ return (ACPI_NAME_TABLE *) ((char *) this_entry -
+ (this_entry->this_index *
+ sizeof (ACPI_NAMED_OBJECT)) -
+ (sizeof (ACPI_NAME_TABLE) -
+ sizeof (ACPI_NAMED_OBJECT)));
+
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_get_parent_entry
+ *
+ * PARAMETERS: This_entry - Current table entry
+ *
+ * RETURN: Parent entry of the given entry
+ *
+ * DESCRIPTION: Obtain the parent entry for a given entry in the namespace.
+ *
+ ***************************************************************************/
+
+
+ACPI_NAMED_OBJECT *
+acpi_ns_get_parent_entry (
+ ACPI_NAMED_OBJECT *this_entry)
+{
+ ACPI_NAME_TABLE *name_table;
+
+
+ name_table = acpi_ns_get_owner_table (this_entry);
+
+ /*
+ * Now that we have a pointer to the name table, we can just pluck
+ * the parent
+ */
+
+ return (name_table->parent_entry);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_get_next_valid_entry
+ *
+ * PARAMETERS: This_entry - Current table entry
+ *
+ * RETURN: Next valid object in the table. NULL if no more valid
+ * objects
+ *
+ * DESCRIPTION: Find the next valid object within a name table.
+ *
+ ***************************************************************************/
+
+
+ACPI_NAMED_OBJECT *
+acpi_ns_get_next_valid_entry (
+ ACPI_NAMED_OBJECT *this_entry)
+{
+ ACPI_NAME_TABLE *name_table;
+ u32 index;
+
+
+ index = this_entry->this_index + 1;
+ name_table = acpi_ns_get_owner_table (this_entry);
+
+
+ while (name_table) {
+ if (index >= NS_TABLE_SIZE) {
+ /* We are at the end of this table */
+
+ name_table = name_table->next_table;
+ index = 0;
+ continue;
+ }
+
+
+ /* Is this a valid (occupied) slot? */
+
+ if (name_table->entries[index].name) {
+ /* Found a valid entry, all done */
+
+ return (&name_table->entries[index]);
+ }
+
+ /* Go to the next slot */
+
+ index++;
+ }
+
+ /* No more valid entries in this name table */
+
+ return NULL;
+}
+
+
diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c
new file mode 100644
index 000000000..6fcb14b76
--- /dev/null
+++ b/drivers/acpi/namespace/nswalk.c
@@ -0,0 +1,279 @@
+
+/******************************************************************************
+ *
+ * Module Name: nswalk - Functions for walking the APCI namespace
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "interp.h"
+#include "namesp.h"
+
+
+#define _COMPONENT NAMESPACE
+ MODULE_NAME ("nswalk");
+
+
+/****************************************************************************
+ *
+ * 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_NAMED_OBJECT*
+acpi_ns_get_next_object (
+ OBJECT_TYPE_INTERNAL type,
+ ACPI_NAMED_OBJECT *parent,
+ ACPI_NAMED_OBJECT *child)
+{
+ ACPI_NAMED_OBJECT *this_entry = NULL;
+
+
+ if (!child) {
+
+ /* It's really the parent's _scope_ that we want */
+
+ if (parent->child_table) {
+ this_entry = parent->child_table->entries;
+ }
+ }
+
+ else {
+ /* Start search at the NEXT object */
+
+ this_entry = acpi_ns_get_next_valid_entry (child);
+ }
+
+
+ /* If any type is OK, we are done */
+
+ if (type == ACPI_TYPE_ANY) {
+ /* Make sure this is valid entry first */
+
+ if ((!this_entry) ||
+ (!this_entry->name))
+ {
+ return NULL;
+ }
+
+ return (this_entry);
+ }
+
+
+ /* Must search for the object -- but within this scope only */
+
+ while (this_entry) {
+ /* If type matches, we are done */
+
+ if (this_entry->type == type) {
+ return (this_entry);
+ }
+
+ /* Otherwise, move on to the next object */
+
+ this_entry = acpi_ns_get_next_valid_entry (this_entry);
+ }
+
+
+ /* Not found */
+
+ return NULL;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ns_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
+ * Unlock_before_callback- Whether to unlock the NS before invoking
+ * the callback routine
+ * User_function - Called when an object of "Type" is found
+ * Context - Passed to user function
+ *
+ * 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_ns_walk_namespace (
+ OBJECT_TYPE_INTERNAL type,
+ ACPI_HANDLE start_object,
+ u32 max_depth,
+ u8 unlock_before_callback,
+ WALK_CALLBACK user_function,
+ void *context,
+ void **return_value)
+{
+ ACPI_STATUS status;
+ ACPI_NAMED_OBJECT *child_entry;
+ ACPI_NAMED_OBJECT *parent_entry;
+ OBJECT_TYPE_INTERNAL child_type;
+ u32 level;
+
+
+ /* Special case for the namespace root object */
+
+ if (start_object == ACPI_ROOT_OBJECT) {
+ start_object = acpi_gbl_root_object;
+ }
+
+
+ /* Null child means "get first object" */
+
+ parent_entry = start_object;
+ child_entry = 0;
+ child_type = ACPI_TYPE_ANY;
+ level = 1;
+
+ /*
+ * Traverse the tree of objects until we bubble back up to where we
+ * started. When Level is zero, the loop is done because we have
+ * bubbled up to (and passed) the original parent handle (Start_entry)
+ */
+
+ while (level > 0) {
+ /*
+ * Get the next typed object in this scope. Null returned
+ * if not found
+ */
+
+ status = AE_OK;
+ child_entry = acpi_ns_get_next_object (ACPI_TYPE_ANY,
+ parent_entry,
+ child_entry);
+
+ if (child_entry) {
+ /*
+ * Found an object, Get the type if we are not
+ * searching for ANY
+ */
+
+ if (type != ACPI_TYPE_ANY) {
+ child_type = child_entry->type;
+ }
+
+ if (child_type == type) {
+ /*
+ * Found a matching object, invoke the user
+ * callback function
+ */
+
+ if (unlock_before_callback) {
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ }
+
+ status = user_function (child_entry, level,
+ context, return_value);
+
+ if (unlock_before_callback) {
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+ }
+
+ switch (status)
+ {
+ case AE_OK:
+ case AE_CTRL_DEPTH:
+ /* Just keep going */
+ break;
+
+ case AE_CTRL_TERMINATE:
+ /* Exit now, with OK status */
+ return (AE_OK);
+ break;
+
+ default:
+ /* All others are valid exceptions */
+ return (status);
+ break;
+ }
+ }
+
+ /*
+ * Depth first search:
+ * Attempt to go down another level in the namespace
+ * if we are allowed to. Don't go any further if we
+ * have reached the caller specified maximum depth
+ * or if the user function has specified that the
+ * maximum depth has been reached.
+ */
+
+ if ((level < max_depth) && (status != AE_CTRL_DEPTH)) {
+ if (acpi_ns_get_next_object (ACPI_TYPE_ANY,
+ child_entry, 0))
+ {
+ /*
+ * There is at least one child of this
+ * object, visit the object
+ */
+ level++;
+ parent_entry = child_entry;
+ child_entry = 0;
+ }
+ }
+ }
+
+ else {
+ /*
+ * No more children in this object (Acpi_ns_get_next_object
+ * failed), go back upwards in the namespace tree to
+ * the object's parent.
+ */
+ level--;
+ child_entry = parent_entry;
+ parent_entry = acpi_ns_get_parent_entry (parent_entry);
+ }
+ }
+
+ /* Complete walk, not terminated by user function */
+ return (AE_OK);
+}
+
+
diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c
new file mode 100644
index 000000000..2622a9be8
--- /dev/null
+++ b/drivers/acpi/namespace/nsxfname.c
@@ -0,0 +1,372 @@
+/******************************************************************************
+ *
+ * Module Name: nsxfname - Public interfaces to the ACPI subsystem
+ * ACPI Namespace oriented interfaces
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "interp.h"
+#include "namesp.h"
+#include "amlcode.h"
+#include "parser.h"
+#include "dispatch.h"
+#include "events.h"
+
+
+#define _COMPONENT NAMESPACE
+ MODULE_NAME ("nsxfname");
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_load_namespace
+ *
+ * PARAMETERS: Display_aml_during_load
+ *
+ * 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_load_namespace (
+ void)
+{
+ ACPI_STATUS status;
+
+
+ /* There must be at least a DSDT installed */
+
+ if (acpi_gbl_DSDT == NULL) {
+ return (AE_NO_ACPI_TABLES);
+ }
+
+
+ /* Init the hardware */
+
+ /*
+ * TBD: [Restructure] Should this should be moved elsewhere,
+ * like Acpi_enable! ??
+ */
+
+ /* we need to be able to call this interface repeatedly! */
+ /* Does H/W require init before loading the namespace? */
+
+ status = acpi_cm_hardware_initialize ();
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /*
+ * 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 (status);
+ }
+
+ /* Ignore exceptions from these */
+
+ acpi_ns_load_table_by_type (ACPI_TABLE_SSDT);
+ acpi_ns_load_table_by_type (ACPI_TABLE_PSDT);
+
+
+ /*
+ * Install the default Op_region handlers, ignore the return
+ * code right now.
+ */
+
+ acpi_ev_install_default_address_space_handlers ();
+
+ return (status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_get_handle
+ *
+ * PARAMETERS: Parent - Object to search under (search scope).
+ * Path_name - Pointer to an asciiz string containing the
+ * name
+ * Ret_handle - Where the return handle is placed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This routine will search for a caller specified name in the
+ * name space. The caller can restrict the search region by
+ * specifying a non NULL parent. The parent value is itself a
+ * namespace handle.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_get_handle (
+ ACPI_HANDLE parent,
+ ACPI_STRING pathname,
+ ACPI_HANDLE *ret_handle)
+{
+ ACPI_STATUS status;
+ ACPI_NAMED_OBJECT *this_entry;
+ ACPI_NAME_TABLE *scope = NULL;
+
+
+ if (!ret_handle || !pathname) {
+ return AE_BAD_PARAMETER;
+ }
+
+ if (parent) {
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+ this_entry = acpi_ns_convert_handle_to_entry (parent);
+ if (!this_entry) {
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ return AE_BAD_PARAMETER;
+ }
+
+ scope = this_entry->child_table;
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ }
+
+ /* Special case for root, since we can't search for it */
+ /* TBD: [Investigate] Check for both forward and backslash?? */
+
+ if (STRCMP (pathname, NS_ROOT_PATH) == 0) {
+ *ret_handle = acpi_ns_convert_entry_to_handle (acpi_gbl_root_object);
+ return AE_OK;
+ }
+
+ /*
+ * Find the Nte and convert to the user format
+ */
+ this_entry = NULL;
+ status = acpi_ns_get_named_object (pathname, scope, &this_entry);
+
+ *ret_handle = acpi_ns_convert_entry_to_handle (this_entry);
+
+ return (status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_get_pathname
+ *
+ * PARAMETERS: Handle - Handle to be converted to a pathname
+ * Name_type - Full pathname or single segment
+ * Ret_path_ptr - Buffer for returned path
+ *
+ * RETURN: Pointer to a string containing the fully qualified Name.
+ *
+ * DESCRIPTION: This routine returns the fully qualified name associated with
+ * the Handle parameter. This and the Acpi_pathname_to_handle are
+ * complementary functions.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_get_name (
+ ACPI_HANDLE handle,
+ u32 name_type,
+ ACPI_BUFFER *ret_path_ptr)
+{
+ ACPI_STATUS status;
+ ACPI_NAMED_OBJECT *obj_entry;
+
+
+ /* Buffer pointer must be valid always */
+
+ if (!ret_path_ptr || (name_type > ACPI_NAME_TYPE_MAX)) {
+ return AE_BAD_PARAMETER;
+ }
+
+ /* Allow length to be zero and ignore the pointer */
+
+ if ((ret_path_ptr->length) &&
+ (!ret_path_ptr->pointer))
+ {
+ return AE_BAD_PARAMETER;
+ }
+
+ if (name_type == ACPI_FULL_PATHNAME) {
+ /* Get the full pathname (From the namespace root) */
+
+ status = acpi_ns_handle_to_pathname (handle, &ret_path_ptr->length,
+ ret_path_ptr->pointer);
+ return status;
+ }
+
+ /*
+ * Wants the single segment ACPI name.
+ * Validate handle and convert to an NTE
+ */
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+ obj_entry = acpi_ns_convert_handle_to_entry (handle);
+ if (!obj_entry) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Check if name will fit in buffer */
+
+ if (ret_path_ptr->length < PATH_SEGMENT_LENGTH) {
+ ret_path_ptr->length = PATH_SEGMENT_LENGTH;
+ status = AE_BUFFER_OVERFLOW;
+ goto unlock_and_exit;
+ }
+
+ /* Just copy the ACPI name from the NTE and zero terminate it */
+
+ STRNCPY (ret_path_ptr->pointer, (char *) &obj_entry->name,
+ ACPI_NAME_SIZE);
+ ((char *) ret_path_ptr->pointer) [ACPI_NAME_SIZE] = 0;
+ status = AE_OK;
+
+
+unlock_and_exit:
+
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ return status;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_get_object_info
+ *
+ * PARAMETERS: Handle - Object Handle
+ * Info - Where the info is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Returns information about an object as gleaned from running
+ * several standard control methods.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_get_object_info (
+ ACPI_HANDLE device,
+ ACPI_DEVICE_INFO *info)
+{
+ DEVICE_ID hid;
+ DEVICE_ID uid;
+ ACPI_STATUS status;
+ u32 device_status = 0;
+ u32 address = 0;
+ ACPI_NAMED_OBJECT *device_entry;
+
+
+ /* Parameter validation */
+
+ if (!device || !info) {
+ return AE_BAD_PARAMETER;
+ }
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+ device_entry = acpi_ns_convert_handle_to_entry (device);
+ if (!device_entry) {
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ return AE_BAD_PARAMETER;
+ }
+
+ info->type = device_entry->type;
+ info->name = device_entry->name;
+ info->parent =
+ acpi_ns_convert_entry_to_handle (acpi_ns_get_parent_entry (device_entry));
+
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+
+ /*
+ * If not a device, we are all done.
+ */
+ if (info->type != ACPI_TYPE_DEVICE) {
+ return AE_OK;
+ }
+
+
+ /* Get extra info for ACPI devices */
+
+ info->valid = 0;
+
+ /* Execute the _HID method and save the result */
+
+ status = acpi_cm_execute_HID (device_entry, &hid);
+ if (ACPI_SUCCESS (status)) {
+ if (hid.type == STRING_PTR_DEVICE_ID) {
+ STRCPY (info->hardware_id, hid.data.string_ptr);
+ }
+ else {
+ STRCPY (info->hardware_id, hid.data.buffer);
+ }
+
+ info->valid |= ACPI_VALID_HID;
+ }
+
+ /* Execute the _UID method and save the result */
+
+ status = acpi_cm_execute_UID (device_entry, &uid);
+ if (ACPI_SUCCESS (status)) {
+ if (hid.type == STRING_PTR_DEVICE_ID) {
+ STRCPY (info->unique_id, uid.data.string_ptr);
+ }
+ else {
+ STRCPY (info->unique_id, uid.data.buffer);
+ }
+
+ info->valid |= ACPI_VALID_UID;
+ }
+
+ /*
+ * Execute the _STA method and save the result
+ * _STA is not always present
+ */
+
+ status = acpi_cm_execute_STA (device_entry, &device_status);
+ if (ACPI_SUCCESS (status)) {
+ info->current_status = device_status;
+ info->valid |= ACPI_VALID_STA;
+ }
+
+ /*
+ * Execute the _ADR method and save result if successful
+ * _ADR is not always present
+ */
+
+ status = acpi_cm_evaluate_numeric_object (METHOD_NAME__ADR,
+ device_entry, &address);
+
+ if (ACPI_SUCCESS (status)) {
+ info->address = address;
+ info->valid |= ACPI_VALID_ADR;
+ }
+
+ return AE_OK;
+}
+
diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c
new file mode 100644
index 000000000..09c5e4e3d
--- /dev/null
+++ b/drivers/acpi/namespace/nsxfobj.c
@@ -0,0 +1,554 @@
+
+/******************************************************************************
+ *
+ * Module Name: nsxfobj - Public interfaces to the ACPI subsystem
+ * ACPI Object oriented interfaces
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "interp.h"
+#include "namesp.h"
+
+
+#define _COMPONENT NAMESPACE
+ MODULE_NAME ("nsxfobj");
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_evaluate_object
+ *
+ * PARAMETERS: Handle - Object handle (optional)
+ * *Pathname - Object pathname (optional)
+ * **Params - List of parameters to pass to
+ * method, terminated by NULL.
+ * Params itself may be NULL
+ * if no parameters are being
+ * passed.
+ * *Return_object - 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 *param_objects,
+ ACPI_BUFFER *return_buffer)
+{
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL **param_ptr = NULL;
+ ACPI_OBJECT_INTERNAL *return_obj = NULL;
+ ACPI_OBJECT_INTERNAL *object_ptr = NULL;
+ u32 buffer_space_needed;
+ u32 user_buffer_length;
+ u32 count;
+ u32 i;
+ u32 param_length;
+ u32 object_length;
+
+
+ /*
+ * 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 (param_objects && param_objects->count) {
+ /*
+ * Allocate a new parameter block for the internal objects
+ * Add 1 to count to allow for null terminated internal list
+ * TBD: [Restructure] merge into single allocation!
+ */
+
+ count = param_objects->count;
+ param_length = (count + 1) * sizeof (void *);
+ object_length = count * sizeof (ACPI_OBJECT_INTERNAL);
+
+ param_ptr = acpi_cm_callocate (param_length + /* Parameter List part */
+ object_length); /* Actual objects */
+ if (!param_ptr) {
+ return (AE_NO_MEMORY);
+ }
+
+ object_ptr = (ACPI_OBJECT_INTERNAL *) ((u8 *) param_ptr +
+ param_length);
+
+ /*
+ * Init the param array of pointers and NULL terminate
+ * the list
+ */
+
+ for (i = 0; i < count; i++) {
+ param_ptr[i] = &object_ptr[i];
+ acpi_cm_init_static_object (&object_ptr[i]);
+ }
+ param_ptr[count] = NULL;
+
+ /*
+ * Convert each external object in the list to an
+ * internal object
+ */
+ for (i = 0; i < count; i++) {
+ status =
+ acpi_cm_build_internal_object (&param_objects->pointer[i],
+ param_ptr[i]);
+
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_delete_internal_object_list (param_ptr);
+ return (status);
+ }
+ }
+ }
+
+
+ /*
+ * 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, param_ptr, &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
+ */
+
+
+
+ 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,
+ param_ptr,
+ &return_obj);
+ }
+
+ else {
+ /*
+ * Both a Handle and a relative Pathname
+ */
+ status = acpi_ns_evaluate_relative (handle, pathname,
+ param_ptr,
+ &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) {
+ user_buffer_length = return_buffer->length;
+ return_buffer->length = 0;
+
+ if (return_obj) {
+ if (VALID_DESCRIPTOR_TYPE (return_obj,
+ ACPI_DESC_TYPE_NAMED))
+ {
+ /*
+ * If we got an NTE as a return object,
+ * this means 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;
+ return_obj = NULL; /* No need to delete an NTE */
+ }
+
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * Find out how large a buffer is needed
+ * to contain the returned object
+ */
+ status = acpi_cm_get_object_size (return_obj,
+ &buffer_space_needed);
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * Check if there is enough room in the
+ * caller's buffer
+ */
+
+ if (user_buffer_length < buffer_space_needed) {
+ /*
+ * Caller's buffer is too small, can't
+ * give him partial results fail the call
+ * but return the buffer size needed
+ */
+
+ return_buffer->length = buffer_space_needed;
+ status = AE_BUFFER_OVERFLOW;
+ }
+
+ else {
+ /*
+ * We have enough space for the object, build it
+ */
+ status =
+ acpi_cm_build_external_object (return_obj,
+ return_buffer);
+ return_buffer->length = buffer_space_needed;
+ }
+ }
+ }
+ }
+ }
+
+
+ /* Delete the return and parameter objects */
+
+ if (return_obj) {
+ /*
+ * Delete the internal return object. (Or at least
+ * decrement the reference count by one)
+ */
+ acpi_cm_remove_reference (return_obj);
+ }
+
+ /*
+ * Free the input parameter list (if we created one),
+ */
+
+ if (param_ptr) {
+ /* Free the allocated parameter block */
+
+ acpi_cm_delete_internal_object_list (param_ptr);
+ }
+
+ return (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 = AE_OK;
+ ACPI_NAMED_OBJECT *entry;
+ ACPI_NAMED_OBJECT *parent_entry = NULL;
+ ACPI_NAMED_OBJECT *child_entry = NULL;
+
+
+ /* Parameter validation */
+
+ if (type > ACPI_TYPE_MAX) {
+ return AE_BAD_PARAMETER;
+ }
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+ /* If null handle, use the parent */
+
+ if (!child) {
+ /* Start search at the beginning of the specified scope */
+
+ parent_entry = acpi_ns_convert_handle_to_entry (parent);
+ if (!parent_entry) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+ }
+
+ /* Non-null handle, ignore the parent */
+
+ else {
+ /* Convert and validate the handle */
+
+ child_entry = acpi_ns_convert_handle_to_entry (child);
+ if (!child_entry) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+ }
+
+
+ /* Internal function does the real work */
+
+ entry = acpi_ns_get_next_object ((OBJECT_TYPE_INTERNAL) type,
+ parent_entry, child_entry);
+ if (!entry) {
+ status = AE_NOT_FOUND;
+ goto unlock_and_exit;
+ }
+
+ if (ret_handle) {
+ *ret_handle = acpi_ns_convert_entry_to_handle (entry);
+ }
+
+
+unlock_and_exit:
+
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ return status;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_get_type
+ *
+ * PARAMETERS: Handle - Handle of object whose type is desired
+ * *Ret_type - Where the type will be placed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This routine returns the type associatd with a particular handle
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_get_type (
+ ACPI_HANDLE handle,
+ ACPI_OBJECT_TYPE *ret_type)
+{
+ ACPI_NAMED_OBJECT *object;
+
+
+ /* Parameter Validation */
+
+ if (!ret_type) {
+ return AE_BAD_PARAMETER;
+ }
+
+ /*
+ * Special case for the predefined Root Object
+ * (return type ANY)
+ */
+
+ if (handle == ACPI_ROOT_OBJECT) {
+ *ret_type = ACPI_TYPE_ANY;
+ return AE_OK;
+ }
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+ /* Convert and validate the handle */
+
+ object = acpi_ns_convert_handle_to_entry (handle);
+ if (!object) {
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ return AE_BAD_PARAMETER;
+ }
+
+ *ret_type = object->type;
+
+
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ return AE_OK;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_get_parent
+ *
+ * PARAMETERS: Handle - Handle of object whose parent is desired
+ * Ret_handle - Where the parent handle will be placed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Returns a handle to the parent of the object represented by
+ * Handle.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_get_parent (
+ ACPI_HANDLE handle,
+ ACPI_HANDLE *ret_handle)
+{
+ ACPI_NAMED_OBJECT *object;
+ ACPI_STATUS status = AE_OK;
+
+
+ /* No trace macro, too verbose */
+
+
+ if (!ret_handle) {
+ return AE_BAD_PARAMETER;
+ }
+
+ /* Special case for the predefined Root Object (no parent) */
+
+ if (handle == ACPI_ROOT_OBJECT) {
+ return AE_NULL_ENTRY;
+ }
+
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+ /* Convert and validate the handle */
+
+ object = acpi_ns_convert_handle_to_entry (handle);
+ if (!object) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+
+ /* Get the parent entry */
+
+ *ret_handle =
+ acpi_ns_convert_entry_to_handle (acpi_ns_get_parent_entry (object));
+
+ /* Return exeption if parent is null */
+
+ if (!acpi_ns_get_parent_entry (object)) {
+ status = AE_NULL_ENTRY;
+ }
+
+
+unlock_and_exit:
+
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ return AE_OK;
+}
+
+
+/******************************************************************************
+ *
+ * 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
+ *
+ * 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,
+ WALK_CALLBACK user_function,
+ void *context,
+ void **return_value)
+{
+ ACPI_STATUS status;
+
+
+ /* Parameter validation */
+
+ if ((type > ACPI_TYPE_MAX) ||
+ (!max_depth) ||
+ (!user_function))
+ {
+ return (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.
+ */
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+ status = acpi_ns_walk_namespace ((OBJECT_TYPE_INTERNAL) type,
+ start_object, max_depth,
+ NS_WALK_UNLOCK,
+ user_function, context,
+ return_value);
+
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/osd.c b/drivers/acpi/osd.c
new file mode 100644
index 000000000..402df75d7
--- /dev/null
+++ b/drivers/acpi/osd.c
@@ -0,0 +1,1319 @@
+/*
+ * osd.c - Linux specific code
+ *
+ * Copyright (C) 2000 Andrew Henroid
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/pm.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/uaccess.h>
+#include "acpi.h"
+
+#define ACPI_MAX_THROTTLE 10
+#define ACPI_INVALID ~0UL
+#define ACPI_INFINITE ~0UL
+
+static struct acpi_facp *acpi_facp = NULL;
+
+static spinlock_t acpi_event_lock = SPIN_LOCK_UNLOCKED;
+static volatile u32 acpi_event_status = 0;
+static volatile acpi_sstate_t acpi_event_state = ACPI_S0;
+static DECLARE_WAIT_QUEUE_HEAD(acpi_event_wait);
+static int acpi_irq_irq = 0;
+static OSD_HANDLER acpi_irq_handler = NULL;
+static void *acpi_irq_context = NULL;
+
+static unsigned long acpi_pblk = ACPI_INVALID;
+static unsigned long acpi_c2_exit_latency = ACPI_INFINITE;
+static unsigned long acpi_c3_exit_latency = ACPI_INFINITE;
+static unsigned long acpi_c2_enter_latency = ACPI_INFINITE;
+static unsigned long acpi_c3_enter_latency = ACPI_INFINITE;
+static int acpi_c2_tested = 0;
+static int acpi_c3_tested = 0;
+
+struct acpi_intrp_entry
+{
+ int priority;
+ OSD_EXECUTION_CALLBACK callback;
+ void *context;
+ struct list_head list;
+};
+
+struct acpi_enter_sx_ctx
+{
+ wait_queue_head_t wait;
+ int state;
+};
+
+static volatile int acpi_intrp_pid = -1;
+static DECLARE_WAIT_QUEUE_HEAD(acpi_intrp_wait);
+static LIST_HEAD(acpi_intrp_exec);
+static spinlock_t acpi_intrp_exec_lock = SPIN_LOCK_UNLOCKED;
+
+#define ACPI_SLP_TYP(typa, typb) (((int)(typa) << 8) | (int)(typb))
+#define ACPI_SLP_TYPA(value) \
+ ((((value) >> 8) << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK)
+#define ACPI_SLP_TYPB(value) \
+ ((((value) & 0xff) << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK)
+
+static volatile acpi_sstate_t acpi_sleep_state = ACPI_S0;
+static unsigned long acpi_slptyp[ACPI_S5 + 1] = {ACPI_INVALID,};
+
+static struct ctl_table_header *acpi_sysctl = NULL;
+
+static int acpi_do_ulong(ctl_table * ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t * len);
+static int acpi_do_sleep(ctl_table * ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t * len);
+static int acpi_do_event(ctl_table * ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t * len);
+
+static struct ctl_table acpi_table[] =
+{
+ {ACPI_P_LVL2_LAT, "c2_exit_latency",
+ &acpi_c2_exit_latency, sizeof(acpi_c2_exit_latency),
+ 0644, NULL, &acpi_do_ulong},
+
+ {ACPI_ENTER_LVL2_LAT, "c2_enter_latency",
+ &acpi_c2_enter_latency, sizeof(acpi_c2_enter_latency),
+ 0644, NULL, &acpi_do_ulong},
+
+ {ACPI_P_LVL3_LAT, "c3_exit_latency",
+ &acpi_c3_exit_latency, sizeof(acpi_c3_exit_latency),
+ 0644, NULL, &acpi_do_ulong},
+
+ {ACPI_ENTER_LVL3_LAT, "c3_enter_latency",
+ &acpi_c3_enter_latency, sizeof(acpi_c3_enter_latency),
+ 0644, NULL, &acpi_do_ulong},
+
+ {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &acpi_do_sleep},
+
+ {ACPI_EVENT, "event", NULL, 0, 0400, NULL, &acpi_do_event},
+
+ {0}
+};
+
+static struct ctl_table acpi_dir_table[] =
+{
+ {CTL_ACPI, "acpi", NULL, 0, 0555, acpi_table},
+ {0}
+};
+
+static u32 FASTCALL(acpi_read_pm1_control(struct acpi_facp *));
+static u32 FASTCALL(acpi_read_pm1_status(struct acpi_facp *));
+static void FASTCALL(acpi_write_pm1_control(struct acpi_facp *, u32));
+static void FASTCALL(acpi_write_pm1_status(struct acpi_facp *, u32));
+
+/*
+ * Get the value of the PM1 control register (ACPI_SCI_EN, ...)
+ */
+static u32
+acpi_read_pm1_control(struct acpi_facp *facp)
+{
+ u32 value = 0;
+ if (facp->pm1a_cnt)
+ value = inw(facp->pm1a_cnt);
+ if (facp->pm1b_cnt)
+ value |= inw(facp->pm1b_cnt);
+ return value;
+}
+
+/*
+ * Set the value of the PM1 control register (ACPI_BM_RLD, ...)
+ */
+static void
+acpi_write_pm1_control(struct acpi_facp *facp, u32 value)
+{
+ if (facp->pm1a_cnt)
+ outw(value, facp->pm1a_cnt);
+ if (facp->pm1b_cnt)
+ outw(value, facp->pm1b_cnt);
+}
+
+/*
+ * Get the value of the fixed event status register
+ */
+static u32
+acpi_read_pm1_status(struct acpi_facp *facp)
+{
+ u32 value = 0;
+ if (facp->pm1a_evt)
+ value = inw(facp->pm1a_evt);
+ if (facp->pm1b_evt)
+ value |= inw(facp->pm1b_evt);
+ return value;
+}
+
+/*
+ * Set the value of the fixed event status register (clear events)
+ */
+static void
+acpi_write_pm1_status(struct acpi_facp *facp, u32 value)
+{
+ if (facp->pm1a_evt)
+ outw(value, facp->pm1a_evt);
+ if (facp->pm1b_evt)
+ outw(value, facp->pm1b_evt);
+}
+
+/*
+ * Examine/modify value
+ */
+static int
+acpi_do_ulong(ctl_table * ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t * len)
+{
+ char str[2 * sizeof(unsigned long) + 4], *strend;
+ unsigned long val;
+ int size;
+
+ if (!write) {
+ if (file->f_pos) {
+ *len = 0;
+ return 0;
+ }
+
+ val = *(unsigned long *) ctl->data;
+ size = sprintf(str, "0x%08lx\n", val);
+ if (*len >= size) {
+ copy_to_user(buffer, str, size);
+ *len = size;
+ }
+ else
+ *len = 0;
+ }
+ else {
+ size = sizeof(str) - 1;
+ if (size > *len)
+ size = *len;
+ copy_from_user(str, buffer, size);
+ str[size] = '\0';
+ val = simple_strtoul(str, &strend, 0);
+ if (strend == str)
+ return -EINVAL;
+ *(unsigned long *) ctl->data = val;
+ }
+
+ file->f_pos += *len;
+ return 0;
+}
+
+/*
+ * Handle ACPI event
+ */
+u32
+acpi_event(void *context)
+{
+ unsigned long flags;
+ int event = (int) context;
+ int mask = 0;
+
+ switch (event) {
+ case ACPI_EVENT_POWER_BUTTON:
+ mask = ACPI_PWRBTN;
+ break;
+ case ACPI_EVENT_SLEEP_BUTTON:
+ mask = ACPI_SLPBTN;
+ break;
+ }
+
+ if (mask) {
+ // notify process waiting on /dev/acpi
+ spin_lock_irqsave(&acpi_event_lock, flags);
+ acpi_event_status |= mask;
+ spin_unlock_irqrestore(&acpi_event_lock, flags);
+ acpi_event_state = acpi_sleep_state;
+ wake_up_interruptible(&acpi_event_wait);
+ }
+
+ return AE_OK;
+}
+
+/*
+ * Wait for next event
+ */
+int
+acpi_do_event(ctl_table * ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t * len)
+{
+ u32 event_status = 0;
+ acpi_sstate_t event_state = 0;
+ char str[27];
+ int size;
+
+ if (write)
+ return -EPERM;
+ if (*len < sizeof(str)) {
+ *len = 0;
+ return 0;
+ }
+
+ for (;;) {
+ unsigned long flags;
+
+ // we need an atomic exchange here
+ spin_lock_irqsave(&acpi_event_lock, flags);
+ event_status = acpi_event_status;
+ acpi_event_status = 0;
+ spin_unlock_irqrestore(&acpi_event_lock, flags);
+ event_state = acpi_event_state;
+
+ if (event_status)
+ break;
+
+ // wait for an event to arrive
+ interruptible_sleep_on(&acpi_event_wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ }
+
+ size = sprintf(str,
+ "0x%08x 0x%08x 0x%01x\n",
+ event_status,
+ 0,
+ event_state);
+ copy_to_user(buffer, str, size);
+ *len = size;
+ file->f_pos += size;
+
+ return 0;
+}
+
+/*
+ * Enter system sleep state
+ */
+static void
+acpi_enter_sx(void *context)
+{
+ struct acpi_enter_sx_ctx *ctx = (struct acpi_enter_sx_ctx*) context;
+ struct acpi_facp *facp = acpi_facp;
+ ACPI_OBJECT_LIST arg_list;
+ ACPI_OBJECT arg;
+ u16 value;
+
+ /*
+ * _PSW methods could be run here to enable wake-on keyboard, LAN, etc.
+ */
+
+ // run the _PTS method
+ memset(&arg_list, 0, sizeof(arg_list));
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.type = ACPI_TYPE_NUMBER;
+ arg.number.value = ctx->state;
+
+ acpi_evaluate_object(NULL, "\\_PTS", &arg_list, NULL);
+
+ // clear wake status
+ acpi_write_pm1_status(facp, ACPI_WAK);
+
+ acpi_sleep_state = ctx->state;
+
+ // set ACPI_SLP_TYPA/b and ACPI_SLP_EN
+ __cli();
+ if (facp->pm1a_cnt) {
+ value = inw(facp->pm1a_cnt) & ~ACPI_SLP_TYP_MASK;
+ value |= (ACPI_SLP_TYPA(acpi_slptyp[ctx->state])
+ | ACPI_SLP_EN);
+ outw(value, facp->pm1a_cnt);
+ }
+ if (facp->pm1b_cnt) {
+ value = inw(facp->pm1b_cnt) & ~ACPI_SLP_TYP_MASK;
+ value |= (ACPI_SLP_TYPB(acpi_slptyp[ctx->state])
+ | ACPI_SLP_EN);
+ outw(value, facp->pm1b_cnt);
+ }
+ __sti();
+
+ if (ctx->state != ACPI_S1) {
+ printk(KERN_ERR "ACPI: S%d failed\n", ctx->state);
+ goto out;
+ }
+
+ // wait until S1 is entered
+ while (!(acpi_read_pm1_status(facp) & ACPI_WAK))
+ safe_halt();
+
+ // run the _WAK method
+ memset(&arg_list, 0, sizeof(arg_list));
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.type = ACPI_TYPE_NUMBER;
+ arg.number.value = ctx->state;
+
+ acpi_evaluate_object(NULL, "\\_WAK", &arg_list, NULL);
+
+ out:
+ acpi_sleep_state = ACPI_S0;
+
+ if (waitqueue_active(&ctx->wait))
+ wake_up_interruptible(&ctx->wait);
+}
+
+/*
+ * Enter system sleep state and wait for completion
+ */
+static int
+acpi_enter_sx_and_wait(acpi_sstate_t state)
+{
+ struct acpi_enter_sx_ctx ctx;
+
+ if (!acpi_facp
+ || acpi_facp->hdr.signature != ACPI_FACP_SIG
+ || acpi_slptyp[state] == ACPI_INVALID)
+ return -EINVAL;
+
+ init_waitqueue_head(&ctx.wait);
+ ctx.state = state;
+
+ if (acpi_os_queue_for_execution(0, acpi_enter_sx, &ctx))
+ return -1;
+
+ interruptible_sleep_on(&ctx.wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ return 0;
+}
+
+/*
+ * Enter system sleep state
+ */
+static int
+acpi_do_sleep(ctl_table * ctl,
+ int write,
+ struct file *file,
+ void *buffer,
+ size_t * len)
+{
+ if (!write) {
+ if (file->f_pos) {
+ *len = 0;
+ return 0;
+ }
+ }
+ else {
+#ifdef CONFIG_ACPI_S1_SLEEP
+ int status = acpi_enter_sx_and_wait(ACPI_S1);
+ if (status)
+ return status;
+#endif
+ }
+ file->f_pos += *len;
+ return 0;
+}
+
+/*
+ * Clear busmaster activity flag
+ */
+static inline void
+acpi_clear_bm_activity(struct acpi_facp *facp)
+{
+ acpi_write_pm1_status(facp, ACPI_BM);
+}
+
+/*
+ * Returns 1 if there has been busmaster activity
+ */
+static inline int
+acpi_bm_activity(struct acpi_facp *facp)
+{
+ return acpi_read_pm1_status(facp) & ACPI_BM;
+}
+
+/*
+ * Set system to sleep through busmaster requests
+ */
+static void
+acpi_sleep_on_busmaster(struct acpi_facp *facp)
+{
+ u32 pm1_cntr = acpi_read_pm1_control(facp);
+ if (pm1_cntr & ACPI_BM_RLD) {
+ pm1_cntr &= ~ACPI_BM_RLD;
+ acpi_write_pm1_control(facp, pm1_cntr);
+ }
+}
+
+/*
+ * Set system to wake on busmaster requests
+ */
+static void
+acpi_wake_on_busmaster(struct acpi_facp *facp)
+{
+ u32 pm1_cntr = acpi_read_pm1_control(facp);
+ if (!(pm1_cntr & ACPI_BM_RLD)) {
+ pm1_cntr |= ACPI_BM_RLD;
+ acpi_write_pm1_control(facp, pm1_cntr);
+ }
+ acpi_clear_bm_activity(facp);
+}
+
+/* The ACPI timer is just the low 24 bits */
+#define TIME_BEGIN(tmr) inl(tmr)
+#define TIME_END(tmr, begin) ((inl(tmr) - (begin)) & 0x00ffffff)
+
+/*
+ * Idle loop (uniprocessor only)
+ */
+void
+acpi_idle(void)
+{
+ static int sleep_level = 1;
+ struct acpi_facp *facp = acpi_facp;
+
+ if (!facp
+ || facp->hdr.signature != ACPI_FACP_SIG
+ || !facp->pm_tmr
+ || !acpi_pblk)
+ goto not_initialized;
+
+ /*
+ * start from the previous sleep level..
+ */
+ if (sleep_level == 1)
+ goto sleep1;
+ if (sleep_level == 2)
+ goto sleep2;
+ sleep3:
+ sleep_level = 3;
+ if (!acpi_c3_tested) {
+ printk(KERN_DEBUG "ACPI C3 works\n");
+ acpi_c3_tested = 1;
+ }
+ acpi_wake_on_busmaster(facp);
+ if (facp->pm2_cnt)
+ goto sleep3_with_arbiter;
+
+ for (;;) {
+ unsigned long time;
+ unsigned int pm_tmr = facp->pm_tmr;
+
+ __cli();
+ if (current->need_resched)
+ goto out;
+ if (acpi_bm_activity(facp))
+ goto sleep2;
+
+ time = TIME_BEGIN(pm_tmr);
+ inb(acpi_pblk + ACPI_P_LVL3);
+ /* Dummy read, force synchronization with the PMU */
+ inl(pm_tmr);
+ time = TIME_END(pm_tmr, time);
+
+ __sti();
+ if (time < acpi_c3_exit_latency)
+ goto sleep2;
+ }
+
+ sleep3_with_arbiter:
+ for (;;) {
+ unsigned long time;
+ u8 arbiter;
+ unsigned int pm2_cntr = facp->pm2_cnt;
+ unsigned int pm_tmr = facp->pm_tmr;
+
+ __cli();
+ if (current->need_resched)
+ goto out;
+ if (acpi_bm_activity(facp))
+ goto sleep2;
+
+ time = TIME_BEGIN(pm_tmr);
+ arbiter = inb(pm2_cntr) & ~ACPI_ARB_DIS;
+ /* Disable arbiter, park on CPU */
+ outb(arbiter | ACPI_ARB_DIS, pm2_cntr);
+ inb(acpi_pblk + ACPI_P_LVL3);
+ /* Dummy read, force synchronization with the PMU */
+ inl(pm_tmr);
+ time = TIME_END(pm_tmr, time);
+ /* Enable arbiter again.. */
+ outb(arbiter, pm2_cntr);
+
+ __sti();
+ if (time < acpi_c3_exit_latency)
+ goto sleep2;
+ }
+
+ sleep2:
+ sleep_level = 2;
+ if (!acpi_c2_tested) {
+ printk(KERN_DEBUG "ACPI C2 works\n");
+ acpi_c2_tested = 1;
+ }
+ acpi_wake_on_busmaster(facp); /* Required to track BM activity.. */
+ for (;;) {
+ unsigned long time;
+ unsigned int pm_tmr = facp->pm_tmr;
+
+ __cli();
+ if (current->need_resched)
+ goto out;
+
+ time = TIME_BEGIN(pm_tmr);
+ inb(acpi_pblk + ACPI_P_LVL2);
+ /* Dummy read, force synchronization with the PMU */
+ inl(pm_tmr);
+ time = TIME_END(pm_tmr, time);
+
+ __sti();
+ if (time < acpi_c2_exit_latency)
+ goto sleep1;
+ if (acpi_bm_activity(facp)) {
+ acpi_clear_bm_activity(facp);
+ continue;
+ }
+ if (time > acpi_c3_enter_latency)
+ goto sleep3;
+ }
+
+ sleep1:
+ sleep_level = 1;
+ acpi_sleep_on_busmaster(facp);
+ for (;;) {
+ unsigned long time;
+ unsigned int pm_tmr = facp->pm_tmr;
+
+ __cli();
+ if (current->need_resched)
+ goto out;
+ time = TIME_BEGIN(pm_tmr);
+ safe_halt();
+ time = TIME_END(pm_tmr, time);
+ if (time > acpi_c2_enter_latency)
+ goto sleep2;
+ }
+
+ not_initialized:
+ for (;;) {
+ __cli();
+ if (current->need_resched)
+ goto out;
+ safe_halt();
+ }
+
+ out:
+ __sti();
+}
+
+/*
+ * Enter soft-off (S5)
+ */
+static void
+acpi_power_off(void)
+{
+ struct acpi_enter_sx_ctx ctx;
+
+ if (!acpi_facp
+ || acpi_facp->hdr.signature != ACPI_FACP_SIG
+ || acpi_slptyp[ACPI_S5] == ACPI_INVALID)
+ return;
+
+ init_waitqueue_head(&ctx.wait);
+ ctx.state = ACPI_S5;
+ acpi_enter_sx(&ctx);
+}
+
+/*
+ * Get processor information
+ */
+static ACPI_STATUS
+acpi_get_cpu_info(ACPI_HANDLE handle, u32 level, void *ctx, void **value)
+{
+ ACPI_OBJECT obj;
+ ACPI_CX_STATE lat[4];
+ ACPI_CPU_THROTTLING_STATE throttle[ACPI_MAX_THROTTLE];
+ ACPI_BUFFER buf;
+ int i, count;
+
+ buf.length = sizeof(obj);
+ buf.pointer = &obj;
+ if (!ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buf)))
+ return AE_OK;
+
+ printk(KERN_INFO "ACPI: PBLK %d @ 0x%04x:%d\n",
+ obj.processor.proc_id,
+ obj.processor.pblk_address,
+ obj.processor.pblk_length);
+ if (acpi_pblk != ACPI_INVALID
+ || !obj.processor.pblk_address
+ || obj.processor.pblk_length != 6)
+ return AE_OK;
+
+ acpi_pblk = obj.processor.pblk_address;
+
+ buf.length = sizeof(lat);
+ buf.pointer = lat;
+ if (!ACPI_SUCCESS(acpi_get_processor_cx_info(handle, &buf)))
+ return AE_OK;
+
+ if (lat[2].latency < MAX_CX_STATE_LATENCY) {
+ printk(KERN_INFO "ACPI: C2 supported\n");
+ acpi_c2_exit_latency = lat[2].latency;
+ }
+ if (lat[3].latency < MAX_CX_STATE_LATENCY) {
+ printk(KERN_INFO "ACPI: C3 supported\n");
+ acpi_c3_exit_latency = lat[3].latency;
+ }
+
+ memset(throttle, 0, sizeof(throttle));
+ buf.length = sizeof(throttle);
+ buf.pointer = throttle;
+
+ if (!ACPI_SUCCESS(acpi_get_processor_throttling_info(handle, &buf)))
+ return AE_OK;
+
+ for (i = 0, count = 0; i < ACPI_MAX_THROTTLE; i++) {
+ if (throttle[i].percent_of_clock)
+ count++;
+ }
+ count--;
+ if (count > 0)
+ printk(KERN_INFO "ACPI: %d throttling states\n", count);
+
+ return AE_OK;
+}
+
+/*
+ * Fetch the FACP information
+ */
+static int
+acpi_fetch_facp(void)
+{
+ ACPI_BUFFER buffer;
+
+ buffer.pointer = acpi_facp;
+ buffer.length = sizeof(*acpi_facp);
+ if (!ACPI_SUCCESS(acpi_get_table(ACPI_TABLE_FACP, 1, &buffer))) {
+ printk(KERN_ERR "ACPI: no FACP\n");
+ kfree(acpi_facp);
+ return -ENODEV;
+ }
+
+ if (acpi_facp->p_lvl2_lat
+ && acpi_facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) {
+ acpi_c2_exit_latency
+ = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl2_lat);
+ acpi_c2_enter_latency
+ = ACPI_uS_TO_TMR_TICKS(ACPI_TMR_HZ / 1000);
+ }
+ if (acpi_facp->p_lvl3_lat
+ && acpi_facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) {
+ acpi_c3_exit_latency
+ = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl3_lat);
+ acpi_c3_enter_latency
+ = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl3_lat * 5);
+ }
+
+ return 0;
+}
+
+/*
+ * Execute callbacks (interpret methods)
+ */
+static void
+acpi_intrp_run(void)
+{
+ for (;;) {
+ struct acpi_intrp_entry *entry;
+ unsigned long flags;
+
+ interruptible_sleep_on(&acpi_intrp_wait);
+ if (signal_pending(current))
+ return;
+
+ for (;;) {
+ entry = NULL;
+
+ spin_lock_irqsave(&acpi_intrp_exec_lock, flags);
+ if (!list_empty(&acpi_intrp_exec)) {
+ entry = list_entry(acpi_intrp_exec.next,
+ struct acpi_intrp_entry,
+ list);
+ list_del(&entry->list);
+ }
+ spin_unlock_irqrestore(&acpi_intrp_exec_lock, flags);
+
+ if (!entry)
+ break;
+
+ (*entry->callback)(entry->context);
+
+ kfree(entry);
+ }
+ }
+}
+
+/*
+ * Initialize and run interpreter within a kernel thread
+ */
+static int
+acpi_intrp_thread(void *context)
+{
+ ACPI_STATUS status;
+ u8 sx, typa, typb;
+
+ /*
+ * initialize interpreter
+ */
+ exit_files(current);
+ daemonize();
+ strcpy(current->comm, "acpi");
+
+ if (!ACPI_SUCCESS(acpi_initialize(NULL))) {
+ printk(KERN_ERR "ACPI: initialize failed\n");
+ return -ENODEV;
+ }
+
+ if (!ACPI_SUCCESS(acpi_load_firmware_tables())) {
+ printk(KERN_ERR "ACPI: table load failed\n");
+ acpi_terminate();
+ return -ENODEV;
+ }
+
+ if (acpi_fetch_facp()) {
+ acpi_terminate();
+ return -ENODEV;
+ }
+
+ status = acpi_load_namespace();
+ if (!ACPI_SUCCESS(status) && status != AE_CTRL_PENDING) {
+ printk(KERN_ERR "ACPI: namespace load failed\n");
+ acpi_terminate();
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO "ACPI: ACPI support found\n");
+
+ acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
+ ACPI_ROOT_OBJECT,
+ ACPI_INT32_MAX,
+ acpi_get_cpu_info,
+ NULL,
+ NULL);
+
+ for (sx = ACPI_S0; sx <= ACPI_S5; sx++) {
+ int ca_sx = (sx <= ACPI_S4) ? sx : (sx + 1);
+ if (ACPI_SUCCESS(
+ acpi_hw_obtain_sleep_type_register_data(ca_sx,
+ &typa,
+ &typb)))
+ acpi_slptyp[sx] = ACPI_SLP_TYP(typa, typb);
+ else
+ acpi_slptyp[sx] = ACPI_INVALID;
+ }
+ if (acpi_slptyp[ACPI_S1] != ACPI_INVALID)
+ printk(KERN_INFO "ACPI: S1 supported\n");
+ if (acpi_slptyp[ACPI_S5] != ACPI_INVALID)
+ printk(KERN_INFO "ACPI: S5 supported\n");
+
+ if (!ACPI_SUCCESS(acpi_enable())) {
+ printk(KERN_ERR "ACPI: enable failed\n");
+ acpi_terminate();
+ return -ENODEV;
+ }
+
+ if (!ACPI_SUCCESS(acpi_install_fixed_event_handler(
+ ACPI_EVENT_POWER_BUTTON,
+ acpi_event,
+ (void *) ACPI_EVENT_POWER_BUTTON))) {
+ printk(KERN_ERR "ACPI: power button enable failed\n");
+ }
+ if (!ACPI_SUCCESS(acpi_install_fixed_event_handler(
+ ACPI_EVENT_SLEEP_BUTTON,
+ acpi_event,
+ (void *) ACPI_EVENT_SLEEP_BUTTON))) {
+ printk(KERN_ERR "ACPI: sleep button enable failed\n");
+ }
+
+#ifdef CONFIG_SMP
+ if (smp_num_cpus == 1)
+ pm_idle = acpi_idle;
+#else
+ pm_idle = acpi_idle;
+#endif
+ pm_power_off = acpi_power_off;
+
+ acpi_sysctl = register_sysctl_table(acpi_dir_table, 1);
+
+ /*
+ * run interpreter
+ */
+ acpi_intrp_run();
+
+ /*
+ * terminate interpreter
+ */
+ unregister_sysctl_table(acpi_sysctl);
+ acpi_terminate();
+
+ acpi_intrp_pid = -1;
+
+ return 0;
+}
+
+/*
+ * Start the interpreter
+ */
+int __init
+acpi_init(void)
+{
+ acpi_facp = kmalloc(sizeof(*acpi_facp), GFP_KERNEL);
+ if (!acpi_facp)
+ return -ENOMEM;
+ memset(acpi_facp, 0, sizeof(*acpi_facp));
+
+ acpi_intrp_pid = kernel_thread(acpi_intrp_thread,
+ NULL,
+ (CLONE_FS | CLONE_FILES
+ | CLONE_SIGHAND | SIGCHLD));
+ return ((acpi_intrp_pid >= 0) ? 0:-ENODEV);
+}
+
+/*
+ * Terminate the interpreter
+ */
+void __exit
+acpi_exit(void)
+{
+ int count;
+
+ if (!kill_proc(acpi_intrp_pid, SIGTERM, 1)) {
+ // wait until interpreter thread terminates (at most 5 seconds)
+ count = 5 * HZ;
+ while (acpi_intrp_pid >= 0 && --count) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ }
+ }
+
+ // clean up after the interpreter
+
+ if (acpi_irq_handler) {
+ acpi_os_remove_interrupt_handler(acpi_irq_irq,
+ acpi_irq_handler);
+ }
+
+ if (pm_power_off == acpi_power_off)
+ pm_power_off = NULL;
+ if (pm_idle == acpi_idle)
+ pm_idle = NULL;
+
+ kfree(acpi_facp);
+}
+
+module_init(acpi_init);
+module_exit(acpi_exit);
+
+/*
+ * OS-dependent functions
+ *
+ */
+
+char *
+strupr(char *str)
+{
+ char *s = str;
+ while (*s) {
+ *s = TOUPPER(*s);
+ s++;
+ }
+ return str;
+}
+
+ACPI_STATUS
+acpi_os_initialize(void)
+{
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_terminate(void)
+{
+ return AE_OK;
+}
+
+s32
+acpi_os_printf(const char *fmt,...)
+{
+ s32 size;
+ va_list args;
+ va_start(args, fmt);
+ size = acpi_os_vprintf(fmt, args);
+ va_end(args);
+ return size;
+}
+
+s32
+acpi_os_vprintf(const char *fmt, va_list args)
+{
+ static char buffer[512];
+ int size = vsprintf(buffer, fmt, args);
+ printk(KERN_DEBUG "%s", buffer);
+ return size;
+}
+
+void *
+acpi_os_allocate(u32 size)
+{
+ return kmalloc(size, GFP_KERNEL);
+}
+
+void *
+acpi_os_callocate(u32 size)
+{
+ void *ptr = acpi_os_allocate(size);
+ if (ptr)
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+void
+acpi_os_free(void *ptr)
+{
+ kfree(ptr);
+}
+
+ACPI_STATUS
+acpi_os_map_memory(void *phys, u32 size, void **virt)
+{
+ if ((unsigned long) phys < virt_to_phys(high_memory)) {
+ *virt = phys_to_virt((unsigned long) phys);
+ return AE_OK;
+ }
+
+ *virt = ioremap((unsigned long) phys, size);
+ if (!*virt)
+ return AE_ERROR;
+
+ return AE_OK;
+}
+
+void
+acpi_os_unmap_memory(void *virt, u32 size)
+{
+ if (virt >= high_memory)
+ iounmap(virt);
+}
+
+static void
+acpi_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ (*acpi_irq_handler)(acpi_irq_context);
+}
+
+ACPI_STATUS
+acpi_os_install_interrupt_handler(u32 irq, OSD_HANDLER handler, void *context)
+{
+ acpi_irq_irq = irq;
+ acpi_irq_handler = handler;
+ acpi_irq_context = context;
+ if (request_irq(irq,
+ acpi_irq,
+ SA_INTERRUPT | SA_SHIRQ,
+ "acpi",
+ acpi_irq)) {
+ printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n", irq);
+ return AE_ERROR;
+ }
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_remove_interrupt_handler(u32 irq, OSD_HANDLER handler)
+{
+ if (acpi_irq_handler) {
+ free_irq(irq, acpi_irq);
+ acpi_irq_handler = NULL;
+ }
+ return AE_OK;
+}
+
+/*
+ * Running in interpreter thread context, safe to sleep
+ */
+
+void
+acpi_os_sleep(u32 sec, u32 ms)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ * sec + (ms * HZ) / 1000);
+}
+
+void
+acpi_os_sleep_usec(u32 us)
+{
+ udelay(us);
+}
+
+u8
+acpi_os_in8(ACPI_IO_ADDRESS port)
+{
+ return inb(port);
+}
+
+u16
+acpi_os_in16(ACPI_IO_ADDRESS port)
+{
+ return inw(port);
+}
+
+u32
+acpi_os_in32(ACPI_IO_ADDRESS port)
+{
+ return inl(port);
+}
+
+void
+acpi_os_out8(ACPI_IO_ADDRESS port, u8 val)
+{
+ outb(val, port);
+}
+
+void
+acpi_os_out16(ACPI_IO_ADDRESS port, u16 val)
+{
+ outw(val, port);
+}
+
+void
+acpi_os_out32(ACPI_IO_ADDRESS port, u32 val)
+{
+ outl(val, port);
+}
+
+ACPI_STATUS
+acpi_os_read_pci_cfg_byte(
+ u32 bus,
+ u32 func,
+ u32 addr,
+ u8 * val)
+{
+ int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
+ struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
+ if (!val || !dev || pci_read_config_byte(dev, addr, val))
+ return AE_ERROR;
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_read_pci_cfg_word(
+ u32 bus,
+ u32 func,
+ u32 addr,
+ u16 * val)
+{
+ int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
+ struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
+ if (!val || !dev || pci_read_config_word(dev, addr, val))
+ return AE_ERROR;
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_read_pci_cfg_dword(
+ u32 bus,
+ u32 func,
+ u32 addr,
+ u32 * val)
+{
+ int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
+ struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
+ if (!val || !dev || pci_read_config_dword(dev, addr, val))
+ return AE_ERROR;
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_write_pci_cfg_byte(
+ u32 bus,
+ u32 func,
+ u32 addr,
+ u8 val)
+{
+ int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
+ struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
+ if (!dev || pci_write_config_byte(dev, addr, val))
+ return AE_ERROR;
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_write_pci_cfg_word(
+ u32 bus,
+ u32 func,
+ u32 addr,
+ u16 val)
+{
+ int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
+ struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
+ if (!dev || pci_write_config_word(dev, addr, val))
+ return AE_ERROR;
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_write_pci_cfg_dword(
+ u32 bus,
+ u32 func,
+ u32 addr,
+ u32 val)
+{
+ int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff);
+ struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn);
+ if (!dev || pci_write_config_dword(dev, addr, val))
+ return AE_ERROR;
+ return AE_OK;
+}
+
+/*
+ * Queue for interpreter thread
+ */
+
+ACPI_STATUS
+acpi_os_queue_for_execution(
+ u32 priority,
+ OSD_EXECUTION_CALLBACK callback,
+ void *context)
+{
+ struct acpi_intrp_entry *entry;
+ unsigned long flags;
+
+ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry)
+ return AE_ERROR;
+
+ memset(entry, 0, sizeof(entry));
+ entry->priority = priority;
+ entry->callback = callback;
+ entry->context = context;
+ INIT_LIST_HEAD(&entry->list);
+
+ if (!waitqueue_active(&acpi_intrp_wait)) {
+ kfree(entry);
+ return AE_ERROR;
+ }
+
+ spin_lock_irqsave(&acpi_intrp_exec_lock, flags);
+ list_add(&entry->list, &acpi_intrp_exec);
+ wake_up(&acpi_intrp_wait);
+ spin_unlock_irqrestore(&acpi_intrp_exec_lock, flags);
+
+ return AE_OK;
+}
+
+/*
+ * Semaphores are unused, interpreter access is single threaded
+ */
+
+ACPI_STATUS
+acpi_os_create_semaphore(u32 max_units, u32 init, ACPI_HANDLE * handle)
+{
+ *handle = (ACPI_HANDLE) 0;
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_delete_semaphore(ACPI_HANDLE handle)
+{
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_wait_semaphore(ACPI_HANDLE handle, u32 units, u32 timeout)
+{
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_signal_semaphore(ACPI_HANDLE handle, u32 units)
+{
+ return AE_OK;
+}
+
+ACPI_STATUS
+acpi_os_breakpoint(char *msg)
+{
+ acpi_os_printf("breakpoint: %s", msg);
+ return AE_OK;
+}
+
+void
+acpi_os_dbg_trap(char *msg)
+{
+ acpi_os_printf("trap: %s", msg);
+}
+
+void
+acpi_os_dbg_assert(void *failure, void *file, u32 line, char *msg)
+{
+ acpi_os_printf("assert: %s", msg);
+}
+
+u32
+acpi_os_get_line(char *buffer)
+{
+ return 0;
+}
+
+/*
+ * We just have to assume we're dealing with valid memory
+ */
+
+BOOLEAN
+acpi_os_readable(void *ptr, u32 len)
+{
+ return 1;
+}
+
+BOOLEAN
+acpi_os_writable(void *ptr, u32 len)
+{
+ return 1;
+}
diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c
new file mode 100644
index 000000000..b9a5b5b5d
--- /dev/null
+++ b/drivers/acpi/parser/psargs.c
@@ -0,0 +1,735 @@
+/******************************************************************************
+ *
+ * Module Name: psargs - Parse AML opcode arguments
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "amlcode.h"
+#include "namesp.h"
+
+#define _COMPONENT PARSER
+ MODULE_NAME ("psargs");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_get_next_package_length
+ *
+ * PARAMETERS: Parser_state - Current parser state object
+ *
+ * RETURN: Decoded package length. On completion, the AML pointer points
+ * past the length byte or bytes.
+ *
+ * DESCRIPTION: Decode and return a package length field
+ *
+ ******************************************************************************/
+
+u32
+acpi_ps_get_next_package_length (
+ ACPI_PARSE_STATE *parser_state)
+{
+ s32 encoded_length;
+ s32 length = 0;
+
+
+ encoded_length = (s32) GET8 (parser_state->aml);
+ parser_state->aml++;
+
+
+ switch (encoded_length >> 6) /* bits 6-7 contain encoding scheme */
+ {
+ case 0: /* 1-byte encoding (bits 0-5) */
+
+ length = (encoded_length & 0x3f);
+ break;
+
+
+ case 1: /* 2-byte encoding (next byte + bits 0-3) */
+
+ length = (GET8 (parser_state->aml) << 4) | (encoded_length & 0xf);
+ parser_state->aml++;
+ break;
+
+
+ case 2: /* 3-byte encoding (next 2 bytes + bits 0-3) */
+
+ length = ( (GET8 (parser_state->aml + 1) << 12)
+ | (GET8 (parser_state->aml) << 4)
+ | (encoded_length & 0xf));
+ parser_state->aml += 2;
+ break;
+
+
+ case 3: /* 4-byte encoding (next 3 bytes + bits 0-3) */
+
+ length = ( (GET8 (parser_state->aml + 2) << 20)
+ | (GET8 (parser_state->aml + 1) << 12)
+ | (GET8 (parser_state->aml) << 4)
+ | (encoded_length & 0xf));
+ parser_state->aml += 3;
+ break;
+ }
+
+ return (length);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_get_next_package_end
+ *
+ * PARAMETERS: Parser_state - Current parser state object
+ *
+ * RETURN: Pointer to end-of-package +1
+ *
+ * DESCRIPTION: Get next package length and return a pointer past the end of
+ * the package. Consumes the package length field
+ *
+ ******************************************************************************/
+
+u8 *
+acpi_ps_get_next_package_end (
+ ACPI_PARSE_STATE *parser_state)
+{
+ u8 *start = parser_state->aml;
+ NATIVE_UINT length;
+
+
+ length = (NATIVE_UINT) acpi_ps_get_next_package_length (parser_state);
+
+ return (start + length); /* end of package */
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_get_next_namestring
+ *
+ * PARAMETERS: Parser_state - Current parser state object
+ *
+ * RETURN: Pointer to the start of the name string (pointer points into
+ * the AML.
+ *
+ * DESCRIPTION: Get next raw namestring within the AML stream. Handles all name
+ * prefix characters. Set parser state to point past the string.
+ * (Name is consumed from the AML.)
+ *
+ ******************************************************************************/
+
+char *
+acpi_ps_get_next_namestring (
+ ACPI_PARSE_STATE *parser_state)
+{
+ char *start = (char *) parser_state->aml;
+ char *end = (char *) parser_state->aml;
+ s32 length;
+
+
+ /* Handle multiple prefix characters */
+
+ while (acpi_ps_is_prefix_char (GET8 (end))) {
+ /* include prefix '\\' or '^' */
+
+ end++;
+ }
+
+ /* Decode the path */
+
+ switch (GET8 (end))
+ {
+ case 0:
+
+ /* Null_name */
+
+ if (end == start) {
+ start = NULL;
+ }
+ end++;
+ break;
+
+
+ case AML_DUAL_NAME_PREFIX:
+
+ /* two name segments */
+
+ end += 9;
+ break;
+
+
+ case AML_MULTI_NAME_PREFIX_OP:
+
+ /* multiple name segments */
+
+ length = (s32) GET8 (end + 1) * 4;
+ end += 2 + length;
+ break;
+
+
+ default:
+
+ /* single name segment */
+ /* assert (Acpi_ps_is_lead (GET8 (End))); */
+
+ end += 4;
+ break;
+ }
+
+ parser_state->aml = (u8*) end;
+
+ return (start);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_get_next_namepath
+ *
+ * PARAMETERS: Parser_state - Current parser state object
+ * Arg - Where the namepath will be stored
+ * Arg_count - If the namepath points to a control method
+ * the method's argument is returned here.
+ * Method_call - Whether the namepath can be the start
+ * of a method call
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Get next name (if method call, push appropriate # args). Names
+ * are looked up in either the parsed or internal namespace to
+ * determine if the name represents a control method. If a method
+ * is found, the number of arguments to the method is returned.
+ * This information is critical for parsing to continue correctly.
+ *
+ ******************************************************************************/
+
+
+#ifdef PARSER_ONLY
+
+void
+acpi_ps_get_next_namepath (
+ ACPI_PARSE_STATE *parser_state,
+ ACPI_GENERIC_OP *arg,
+ u32 *arg_count,
+ u8 method_call)
+{
+ char *path;
+ ACPI_GENERIC_OP *name;
+ ACPI_GENERIC_OP *op;
+ ACPI_GENERIC_OP *count;
+
+
+ path = acpi_ps_get_next_namestring (parser_state);
+ if (!path || !method_call) {
+ /* Null name case, create a null namepath object */
+
+ acpi_ps_init_op (arg, AML_NAMEPATH_OP);
+ arg->value.name = path;
+ return;
+ }
+
+
+ if (acpi_gbl_parsed_namespace_root) {
+ /*
+ * Lookup the name in the parsed namespace
+ */
+
+ op = NULL;
+ if (method_call) {
+ op = acpi_ps_find (acpi_ps_get_parent_scope (parser_state),
+ path, AML_METHOD_OP, 0);
+ }
+
+ if (op) {
+ if (op->opcode == AML_METHOD_OP) {
+ /*
+ * The name refers to a control method, so this namepath is a
+ * method invocation. We need to 1) Get the number of arguments
+ * associated with this method, and 2) Change the NAMEPATH
+ * object into a METHODCALL object.
+ */
+
+ count = acpi_ps_get_arg (op, 0);
+ if (count && count->opcode == AML_BYTE_OP) {
+ name = acpi_ps_alloc_op (AML_NAMEPATH_OP);
+ if (name) {
+ /* Change arg into a METHOD CALL and attach the name */
+
+ acpi_ps_init_op (arg, AML_METHODCALL_OP);
+
+ name->value.name = path;
+
+ /* Point METHODCALL/NAME to the METHOD NTE */
+
+ name->acpi_named_object = op;
+ acpi_ps_append_arg (arg, name);
+
+ *arg_count = count->value.integer &
+ METHOD_FLAGS_ARG_COUNT;
+ }
+ }
+
+ return;
+ }
+
+ /*
+ * Else this is normal named object reference.
+ * Just init the NAMEPATH object with the pathname.
+ * (See code below)
+ */
+ }
+ }
+
+
+ /*
+ * Either we didn't find the object in the namespace, or the object is
+ * something other than a control method. Just initialize the Op with the
+ * pathname
+ */
+
+ acpi_ps_init_op (arg, AML_NAMEPATH_OP);
+ arg->value.name = path;
+
+
+ return;
+}
+
+
+#else
+
+
+void
+acpi_ps_get_next_namepath (
+ ACPI_PARSE_STATE *parser_state,
+ ACPI_GENERIC_OP *arg,
+ u32 *arg_count,
+ u8 method_call)
+{
+ char *path;
+ ACPI_GENERIC_OP *name;
+ ACPI_STATUS status;
+ ACPI_NAMED_OBJECT *method = NULL;
+ ACPI_NAMED_OBJECT *entry;
+ ACPI_GENERIC_STATE scope_info;
+
+
+ path = acpi_ps_get_next_namestring (parser_state);
+ if (!path || !method_call) {
+ /* Null name case, create a null namepath object */
+
+ acpi_ps_init_op (arg, AML_NAMEPATH_OP);
+ arg->value.name = path;
+ return;
+ }
+
+
+ if (method_call) {
+ /*
+ * Lookup the name in the internal namespace
+ */
+ scope_info.scope.name_table = NULL;
+ entry = parser_state->start_op->acpi_named_object;
+ if (entry) {
+ scope_info.scope.name_table = entry->child_table;
+ }
+
+ /*
+ * Lookup object. We don't want to add anything new to the namespace
+ * here, however. So we use MODE_EXECUTE. Allow searching of the
+ * parent tree, but don't open a new scope -- we just want to lookup the
+ * object (MUST BE mode EXECUTE to perform upsearch)
+ */
+
+ status = acpi_ns_lookup (&scope_info, path, ACPI_TYPE_ANY, IMODE_EXECUTE,
+ NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE, NULL,
+ &entry);
+ if (ACPI_SUCCESS (status)) {
+ if (entry->type == ACPI_TYPE_METHOD) {
+ method = entry;
+ name = acpi_ps_alloc_op (AML_NAMEPATH_OP);
+ if (name) {
+ /* Change arg into a METHOD CALL and attach name to it */
+
+ acpi_ps_init_op (arg, AML_METHODCALL_OP);
+
+ name->value.name = path;
+
+ /* Point METHODCALL/NAME to the METHOD NTE */
+
+ name->acpi_named_object = method;
+ acpi_ps_append_arg (arg, name);
+
+ *arg_count = ((ACPI_OBJECT_INTERNAL *) method->object)->method.param_count;
+ }
+
+ return;
+ }
+
+ /*
+ * Else this is normal named object reference.
+ * Just init the NAMEPATH object with the pathname.
+ * (See code below)
+ */
+ }
+ }
+
+ /*
+ * Either we didn't find the object in the namespace, or the object is
+ * something other than a control method. Just initialize the Op with the
+ * pathname
+ */
+
+ acpi_ps_init_op (arg, AML_NAMEPATH_OP);
+ arg->value.name = path;
+
+
+ return;
+}
+
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_get_next_simple_arg
+ *
+ * PARAMETERS: Parser_state - Current parser state object
+ * Arg_type - The argument type (AML_*_ARG)
+ * Arg - Where the argument is returned
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Get the next simple argument (constant, string, or namestring)
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_get_next_simple_arg (
+ ACPI_PARSE_STATE *parser_state,
+ s32 arg_type,
+ ACPI_GENERIC_OP *arg)
+{
+
+
+ switch (arg_type)
+ {
+
+ case ARGP_BYTEDATA:
+
+ acpi_ps_init_op (arg, AML_BYTE_OP);
+ arg->value.integer = (u32) GET8 (parser_state->aml);
+ parser_state->aml++;
+ break;
+
+
+ case ARGP_WORDDATA:
+
+ acpi_ps_init_op (arg, AML_WORD_OP);
+
+ /* Get 2 bytes from the AML stream */
+
+ MOVE_UNALIGNED16_TO_32 (&arg->value.integer, parser_state->aml);
+ parser_state->aml += 2;
+ break;
+
+
+ case ARGP_DWORDDATA:
+
+ acpi_ps_init_op (arg, AML_DWORD_OP);
+
+ /* Get 4 bytes from the AML stream */
+
+ MOVE_UNALIGNED32_TO_32 (&arg->value.integer, parser_state->aml);
+ parser_state->aml += 4;
+ break;
+
+
+ case ARGP_CHARLIST:
+
+ acpi_ps_init_op (arg, AML_STRING_OP);
+ arg->value.string = (char*) parser_state->aml;
+
+ while (GET8 (parser_state->aml) != '\0') {
+ parser_state->aml++;
+ }
+ parser_state->aml++;
+ break;
+
+
+ case ARGP_NAME:
+ case ARGP_NAMESTRING:
+
+ acpi_ps_init_op (arg, AML_NAMEPATH_OP);
+ arg->value.name = acpi_ps_get_next_namestring (parser_state);
+ break;
+ }
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_get_next_field
+ *
+ * PARAMETERS: Parser_state - Current parser state object
+ *
+ * RETURN: A newly allocated FIELD op
+ *
+ * DESCRIPTION: Get next field (Named_field, Reserved_field, or Access_field)
+ *
+ ******************************************************************************/
+
+ACPI_GENERIC_OP *
+acpi_ps_get_next_field (
+ ACPI_PARSE_STATE *parser_state)
+{
+ ACPI_PTRDIFF aml_offset = parser_state->aml -
+ parser_state->aml_start;
+ ACPI_GENERIC_OP *field;
+ u16 opcode;
+ u32 name;
+
+
+ /* determine field type */
+
+ switch (GET8 (parser_state->aml))
+ {
+
+ default:
+
+ opcode = AML_NAMEDFIELD_OP;
+ break;
+
+
+ case 0x00:
+
+ opcode = AML_RESERVEDFIELD_OP;
+ parser_state->aml++;
+ break;
+
+
+ case 0x01:
+
+ opcode = AML_ACCESSFIELD_OP;
+ parser_state->aml++;
+ break;
+ }
+
+
+ /* Allocate a new field op */
+
+ field = acpi_ps_alloc_op (opcode);
+ if (field) {
+ field->aml_offset = aml_offset;
+
+ /* Decode the field type */
+
+ switch (opcode)
+ {
+ case AML_NAMEDFIELD_OP:
+
+ /* Get the 4-character name */
+
+ MOVE_UNALIGNED32_TO_32 (&name, parser_state->aml);
+ acpi_ps_set_name (field, name);
+ parser_state->aml += 4;
+
+ /* Get the length which is encoded as a package length */
+
+ field->value.size = acpi_ps_get_next_package_length (parser_state);
+ break;
+
+
+ case AML_RESERVEDFIELD_OP:
+
+ /* Get the length which is encoded as a package length */
+
+ field->value.size = acpi_ps_get_next_package_length (parser_state);
+ break;
+
+
+ case AML_ACCESSFIELD_OP:
+
+ /* Get Access_type and Access_atrib and merge into the field Op */
+
+ field->value.integer = ((GET8 (parser_state->aml) << 8) |
+ GET8 (parser_state->aml));
+ parser_state->aml += 2;
+ break;
+ }
+ }
+
+ return (field);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_get_next_arg
+ *
+ * PARAMETERS: Parser_state - Current parser state object
+ * Arg_type - The argument type (AML_*_ARG)
+ * Arg_count - If the argument points to a control method
+ * the method's argument is returned here.
+ *
+ * RETURN: An op object containing the next argument.
+ *
+ * DESCRIPTION: Get next argument (including complex list arguments that require
+ * pushing the parser stack)
+ *
+ ******************************************************************************/
+
+ACPI_GENERIC_OP *
+acpi_ps_get_next_arg (
+ ACPI_PARSE_STATE *parser_state,
+ s32 arg_type,
+ u32 *arg_count)
+{
+ ACPI_GENERIC_OP *arg = NULL;
+ ACPI_GENERIC_OP *prev = NULL;
+ ACPI_GENERIC_OP *field;
+ s32 subop;
+
+
+ switch (arg_type)
+ {
+ case ARGP_BYTEDATA:
+ case ARGP_WORDDATA:
+ case ARGP_DWORDDATA:
+ case ARGP_CHARLIST:
+ case ARGP_NAME:
+ case ARGP_NAMESTRING:
+
+ /* constants, strings, and namestrings are all the same size */
+
+ arg = acpi_ps_alloc_op (AML_BYTE_OP);
+ if (arg) {
+ acpi_ps_get_next_simple_arg (parser_state, arg_type, arg);
+ }
+ break;
+
+
+ case ARGP_PKGLENGTH:
+
+ /* package length, nothing returned */
+
+ parser_state->pkg_end = acpi_ps_get_next_package_end (parser_state);
+ break;
+
+
+ case ARGP_FIELDLIST:
+
+ if (parser_state->aml < parser_state->pkg_end) {
+ /* non-empty list */
+
+ while (parser_state->aml < parser_state->pkg_end) {
+ field = acpi_ps_get_next_field (parser_state);
+ if (!field) {
+ break;
+ }
+
+ if (prev) {
+ prev->next = field;
+ }
+
+ else {
+ arg = field;
+ }
+
+ prev = field;
+ }
+
+ /* skip to End of byte data */
+
+ parser_state->aml = parser_state->pkg_end;
+ }
+ break;
+
+
+ case ARGP_BYTELIST:
+
+ if (parser_state->aml < parser_state->pkg_end) {
+ /* non-empty list */
+
+ arg = acpi_ps_alloc_op (AML_BYTELIST_OP);
+ if (arg) {
+ /* fill in bytelist data */
+
+ arg->value.size = (parser_state->pkg_end - parser_state->aml);
+ acpi_ps_to_bytelist_op (arg)->data = parser_state->aml;
+ }
+
+ /* skip to End of byte data */
+
+ parser_state->aml = parser_state->pkg_end;
+ }
+ break;
+
+
+ case ARGP_TARGET:
+ case ARGP_SUPERNAME:
+ {
+ subop = acpi_ps_peek_opcode (parser_state);
+ if (subop == 0 ||
+ acpi_ps_is_leading_char (subop) ||
+ acpi_ps_is_prefix_char (subop))
+ {
+ /* Null_name or Name_string */
+
+ arg = acpi_ps_alloc_op (AML_NAMEPATH_OP);
+ if (arg) {
+ acpi_ps_get_next_namepath (parser_state, arg, arg_count, 0);
+ }
+ }
+
+ else {
+ /* single complex argument, nothing returned */
+
+ *arg_count = 1;
+ }
+ }
+ break;
+
+
+ case ARGP_DATAOBJ:
+ case ARGP_TERMARG:
+
+ /* single complex argument, nothing returned */
+
+ *arg_count = 1;
+ break;
+
+
+ case ARGP_DATAOBJLIST:
+ case ARGP_TERMLIST:
+ case ARGP_OBJLIST:
+
+ if (parser_state->aml < parser_state->pkg_end) {
+ /* non-empty list of variable arguments, nothing returned */
+
+ *arg_count = ACPI_VAR_ARGS;
+ }
+ break;
+ }
+
+ return (arg);
+}
diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c
new file mode 100644
index 000000000..682084e90
--- /dev/null
+++ b/drivers/acpi/parser/psopcode.c
@@ -0,0 +1,554 @@
+/******************************************************************************
+ *
+ * Module Name: psopcode - Parser opcode information table
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "amlcode.h"
+
+
+#define _COMPONENT PARSER
+ MODULE_NAME ("psopcode");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_get_opcode_info
+ *
+ * PARAMETERS: Opcode - The AML opcode
+ *
+ * RETURN: A pointer to the info about the opcode. NULL if the opcode was
+ * not found in the table.
+ *
+ * DESCRIPTION: Find AML opcode description based on the opcode
+ *
+ ******************************************************************************/
+
+ACPI_OP_INFO *
+acpi_ps_get_opcode_info (
+ u16 opcode)
+{
+ ACPI_OP_INFO *op;
+ s32 hash;
+
+
+ /* compute hash/index into the Acpi_aml_op_index table */
+
+ switch (opcode >> 8)
+ {
+ case 0:
+
+ /* Simple (8-bit) opcode */
+
+ hash = opcode;
+ break;
+
+
+ case AML_EXTOP:
+
+ /* Extended (16-bit, prefix+opcode) opcode */
+
+ hash = (opcode + AML_EXTOP_HASH_OFFSET) & 0xff;
+ break;
+
+
+ case AML_LNOT_OP:
+
+ /* This case is for the bogus opcodes LNOTEQUAL, LLESSEQUAL, LGREATEREQUAL */
+
+ hash = (opcode + AML_LNOT_HASH_OFFSET) & 0xff;
+ break;
+
+
+ default:
+
+ return NULL;
+ }
+
+
+ /* Get the Op info pointer for this opcode */
+
+ op = &acpi_gbl_aml_op_info [(s32) acpi_gbl_aml_op_info_index [hash]];
+
+
+ /* If the returned opcode matches, we have a valid opcode */
+
+ if (op->opcode == opcode) {
+ return op;
+ }
+
+ /* Otherwise, the opcode is an ASCII char or other non-opcode value */
+
+ return NULL;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_get_opcode_name
+ *
+ * PARAMETERS: Opcode - The AML opcode
+ *
+ * RETURN: A pointer to the name of the opcode (ASCII String)
+ * Note: Never returns NULL.
+ *
+ * DESCRIPTION: Translate an opcode into a human-readable string
+ *
+ ******************************************************************************/
+
+char *
+acpi_ps_get_opcode_name (
+ u16 opcode)
+{
+ ACPI_OP_INFO *op;
+
+
+ op = acpi_ps_get_opcode_info (opcode);
+
+ if (!op) {
+ return "*ERROR*";
+ }
+
+ DEBUG_ONLY_MEMBERS (return op->name);
+ return "AE_NOT_CONFIGURED";
+}
+
+
+/*******************************************************************************
+ *
+ * NAME: Acpi_gbl_Aml_op_info
+ *
+ * DESCRIPTION: Opcode table. Each entry contains <opcode, type, name, operands>
+ * The name is a simple ascii string, the operand specifier is an
+ * ascii string with one letter per operand. The letter specifies
+ * the operand type.
+ *
+ ******************************************************************************/
+
+
+/*
+ * Flags byte: 0-4 (5 bits) = Opcode Type
+ * 5 (1 bit) = Has arguments flag
+ * 6-7 (2 bits) = Reserved
+ */
+#define AML_NO_ARGS 0
+#define AML_HAS_ARGS OP_INFO_HAS_ARGS
+
+/*
+ * All AML opcodes and the parse-time arguments for each. Used by the AML parser Each list is compressed
+ * into a 32-bit number and stored in the master opcode table at the end of this file.
+ */
+
+#define ARGP_ZERO_OP ARG_NONE
+#define ARGP_ONE_OP ARG_NONE
+#define ARGP_ALIAS_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_NAME)
+#define ARGP_NAME_OP ARGP_LIST2 (ARGP_NAME, ARGP_DATAOBJ)
+#define ARGP_BYTE_OP ARGP_LIST1 (ARGP_BYTEDATA)
+#define ARGP_WORD_OP ARGP_LIST1 (ARGP_WORDDATA)
+#define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA)
+#define ARGP_STRING_OP ARGP_LIST1 (ARGP_CHARLIST)
+#define ARGP_SCOPE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_TERMLIST)
+#define ARGP_BUFFER_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_BYTELIST)
+#define ARGP_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST)
+#define ARGP_METHOD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMLIST)
+#define ARGP_LOCAL0 ARG_NONE
+#define ARGP_LOCAL1 ARG_NONE
+#define ARGP_LOCAL2 ARG_NONE
+#define ARGP_LOCAL3 ARG_NONE
+#define ARGP_LOCAL4 ARG_NONE
+#define ARGP_LOCAL5 ARG_NONE
+#define ARGP_LOCAL6 ARG_NONE
+#define ARGP_LOCAL7 ARG_NONE
+#define ARGP_ARG0 ARG_NONE
+#define ARGP_ARG1 ARG_NONE
+#define ARGP_ARG2 ARG_NONE
+#define ARGP_ARG3 ARG_NONE
+#define ARGP_ARG4 ARG_NONE
+#define ARGP_ARG5 ARG_NONE
+#define ARGP_ARG6 ARG_NONE
+#define ARGP_STORE_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SUPERNAME)
+#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_ADD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_CONCAT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_SUBTRACT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_INCREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_DECREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_MULTIPLY_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_DIVIDE_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET, ARGP_TARGET)
+#define ARGP_SHIFT_LEFT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_SHIFT_RIGHT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_AND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_NAND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_OR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_NOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_XOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_NOT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_FIND_SET_LEFT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_FIND_SET_RIGHT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_NOTIFY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG)
+#define ARGP_SIZE_OF_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_INDEX_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_MATCH_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_DWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_WORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_BYTE_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_BIT_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_TYPE_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_LAND_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LOR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LNOT_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_LEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LGREATER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LLESS_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_IF_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST)
+#define ARGP_ELSE_OP ARGP_LIST2 (ARGP_PKGLENGTH, ARGP_TERMLIST)
+#define ARGP_WHILE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST)
+#define ARGP_NOOP_CODE ARG_NONE
+#define ARGP_RETURN_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_BREAK_OP ARG_NONE
+#define ARGP_BREAK_POINT_OP ARG_NONE
+#define ARGP_ONES_OP ARG_NONE
+#define ARGP_MUTEX_OP ARGP_LIST2 (ARGP_NAME, ARGP_BYTEDATA)
+#define ARGP_EVENT_OP ARGP_LIST1 (ARGP_NAME)
+#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SUPERNAME)
+#define ARGP_CREATE_FIELD_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_LOAD_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_SUPERNAME)
+#define ARGP_STALL_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_SLEEP_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_ACQUIRE_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_WORDDATA)
+#define ARGP_SIGNAL_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_WAIT_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG)
+#define ARGP_RESET_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_RELEASE_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_FROM_BCDOP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TO_BCDOP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_UN_LOAD_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_REVISION_OP ARG_NONE
+#define ARGP_DEBUG_OP ARG_NONE
+#define ARGP_FATAL_OP ARGP_LIST3 (ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_TERMARG)
+#define ARGP_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_DEF_FIELD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_FIELDLIST)
+#define ARGP_DEVICE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST)
+#define ARGP_PROCESSOR_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_BYTEDATA, ARGP_OBJLIST)
+#define ARGP_POWER_RES_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_WORDDATA, ARGP_OBJLIST)
+#define ARGP_THERMAL_ZONE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST)
+#define ARGP_INDEX_FIELD_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_BYTEDATA, ARGP_FIELDLIST)
+#define ARGP_BANK_FIELD_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_TERMARG, ARGP_BYTEDATA, ARGP_FIELDLIST)
+#define ARGP_LNOTEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LLESSEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LGREATEREQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_NAMEPATH_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_METHODCALL_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_BYTELIST_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_RESERVEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_NAMEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_ACCESSFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_STATICSTRING_OP ARGP_LIST1 (ARGP_NAMESTRING)
+
+
+/*
+ * All AML opcodes and the runtime arguments for each. Used by the AML interpreter Each list is compressed
+ * into a 32-bit number and stored in the master opcode table at the end of this file.
+ *
+ * (Used by Acpi_aml_prep_operands procedure)
+ */
+
+#define ARGI_ZERO_OP ARG_NONE
+#define ARGI_ONE_OP ARG_NONE
+#define ARGI_ALIAS_OP ARGI_INVALID_OPCODE
+#define ARGI_NAME_OP ARGI_INVALID_OPCODE
+#define ARGI_BYTE_OP ARGI_INVALID_OPCODE
+#define ARGI_WORD_OP ARGI_INVALID_OPCODE
+#define ARGI_DWORD_OP ARGI_INVALID_OPCODE
+#define ARGI_STRING_OP ARGI_INVALID_OPCODE
+#define ARGI_SCOPE_OP ARGI_INVALID_OPCODE
+#define ARGI_BUFFER_OP ARGI_INVALID_OPCODE
+#define ARGI_PACKAGE_OP ARGI_INVALID_OPCODE
+#define ARGI_METHOD_OP ARGI_INVALID_OPCODE
+#define ARGI_LOCAL0 ARG_NONE
+#define ARGI_LOCAL1 ARG_NONE
+#define ARGI_LOCAL2 ARG_NONE
+#define ARGI_LOCAL3 ARG_NONE
+#define ARGI_LOCAL4 ARG_NONE
+#define ARGI_LOCAL5 ARG_NONE
+#define ARGI_LOCAL6 ARG_NONE
+#define ARGI_LOCAL7 ARG_NONE
+#define ARGI_ARG0 ARG_NONE
+#define ARGI_ARG1 ARG_NONE
+#define ARGI_ARG2 ARG_NONE
+#define ARGI_ARG3 ARG_NONE
+#define ARGI_ARG4 ARG_NONE
+#define ARGI_ARG5 ARG_NONE
+#define ARGI_ARG6 ARG_NONE
+#define ARGI_STORE_OP ARGI_LIST2 (ARGI_ANYTYPE, ARGI_TARGETREF)
+#define ARGI_REF_OF_OP ARGI_LIST1 (ARGI_REFERENCE)
+#define ARGI_ADD_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF)
+#define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_TARGETREF)
+#define ARGI_SUBTRACT_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF)
+#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_REFERENCE)
+#define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_REFERENCE)
+#define ARGI_MULTIPLY_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF)
+#define ARGI_DIVIDE_OP ARGI_LIST4 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF, ARGI_TARGETREF)
+#define ARGI_SHIFT_LEFT_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF)
+#define ARGI_SHIFT_RIGHT_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF)
+#define ARGI_BIT_AND_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF)
+#define ARGI_BIT_NAND_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF)
+#define ARGI_BIT_OR_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF)
+#define ARGI_BIT_NOR_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF)
+#define ARGI_BIT_XOR_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_TARGETREF)
+#define ARGI_BIT_NOT_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_TARGETREF)
+#define ARGI_FIND_SET_LEFT_BIT_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_TARGETREF)
+#define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_TARGETREF)
+#define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REFERENCE)
+#define ARGI_NOTIFY_OP ARGI_LIST2 (ARGI_REFERENCE, ARGI_NUMBER)
+#define ARGI_SIZE_OF_OP ARGI_LIST1 (ARGI_DATAOBJECT)
+#define ARGI_INDEX_OP ARGI_LIST3 (ARGI_COMPLEXOBJ, ARGI_NUMBER, ARGI_TARGETREF)
+#define ARGI_MATCH_OP ARGI_LIST6 (ARGI_PACKAGE, ARGI_NUMBER, ARGI_NUMBER, ARGI_NUMBER, ARGI_NUMBER, ARGI_NUMBER)
+#define ARGI_DWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_NUMBER, ARGI_REFERENCE)
+#define ARGI_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_NUMBER, ARGI_REFERENCE)
+#define ARGI_BYTE_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_NUMBER, ARGI_REFERENCE)
+#define ARGI_BIT_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_NUMBER, ARGI_REFERENCE)
+#define ARGI_TYPE_OP ARGI_LIST1 (ARGI_ANYTYPE)
+#define ARGI_LAND_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_NUMBER)
+#define ARGI_LOR_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_NUMBER)
+#define ARGI_LNOT_OP ARGI_LIST1 (ARGI_NUMBER)
+#define ARGI_LEQUAL_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_NUMBER)
+#define ARGI_LGREATER_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_NUMBER)
+#define ARGI_LLESS_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_NUMBER)
+#define ARGI_IF_OP ARGI_INVALID_OPCODE
+#define ARGI_ELSE_OP ARGI_INVALID_OPCODE
+#define ARGI_WHILE_OP ARGI_INVALID_OPCODE
+#define ARGI_NOOP_CODE ARG_NONE
+#define ARGI_RETURN_OP ARGI_INVALID_OPCODE
+#define ARGI_BREAK_OP ARG_NONE
+#define ARGI_BREAK_POINT_OP ARG_NONE
+#define ARGI_ONES_OP ARG_NONE
+#define ARGI_MUTEX_OP ARGI_INVALID_OPCODE
+#define ARGI_EVENT_OP ARGI_INVALID_OPCODE
+#define ARGI_COND_REF_OF_OP ARGI_LIST2 (ARGI_REFERENCE, ARGI_TARGETREF)
+#define ARGI_CREATE_FIELD_OP ARGI_LIST4 (ARGI_BUFFER, ARGI_NUMBER, ARGI_NUMBER, ARGI_REFERENCE)
+#define ARGI_LOAD_OP ARGI_LIST2 (ARGI_REGION, ARGI_TARGETREF)
+#define ARGI_STALL_OP ARGI_LIST1 (ARGI_NUMBER)
+#define ARGI_SLEEP_OP ARGI_LIST1 (ARGI_NUMBER)
+#define ARGI_ACQUIRE_OP ARGI_LIST2 (ARGI_MUTEX, ARGI_NUMBER)
+#define ARGI_SIGNAL_OP ARGI_LIST1 (ARGI_EVENT)
+#define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_NUMBER)
+#define ARGI_RESET_OP ARGI_LIST1 (ARGI_EVENT)
+#define ARGI_RELEASE_OP ARGI_LIST1 (ARGI_MUTEX)
+#define ARGI_FROM_BCDOP ARGI_LIST2 (ARGI_NUMBER, ARGI_TARGETREF)
+#define ARGI_TO_BCDOP ARGI_LIST2 (ARGI_NUMBER, ARGI_TARGETREF)
+#define ARGI_UN_LOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE)
+#define ARGI_REVISION_OP ARG_NONE
+#define ARGI_DEBUG_OP ARG_NONE
+#define ARGI_FATAL_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_NUMBER)
+#define ARGI_REGION_OP ARGI_INVALID_OPCODE
+#define ARGI_DEF_FIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_DEVICE_OP ARGI_INVALID_OPCODE
+#define ARGI_PROCESSOR_OP ARGI_INVALID_OPCODE
+#define ARGI_POWER_RES_OP ARGI_INVALID_OPCODE
+#define ARGI_THERMAL_ZONE_OP ARGI_INVALID_OPCODE
+#define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_BANK_FIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_LNOTEQUAL_OP ARGI_INVALID_OPCODE
+#define ARGI_LLESSEQUAL_OP ARGI_INVALID_OPCODE
+#define ARGI_LGREATEREQUAL_OP ARGI_INVALID_OPCODE
+#define ARGI_NAMEPATH_OP ARGI_INVALID_OPCODE
+#define ARGI_METHODCALL_OP ARGI_INVALID_OPCODE
+#define ARGI_BYTELIST_OP ARGI_INVALID_OPCODE
+#define ARGI_RESERVEDFIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_NAMEDFIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_ACCESSFIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_STATICSTRING_OP ARGI_INVALID_OPCODE
+
+
+/*
+ * Master Opcode information table. A summary of everything we know about each opcode, all in one place.
+ */
+
+
+ACPI_OP_INFO acpi_gbl_aml_op_info[] =
+{
+/* Opcode Opcode Type Has Arguments? Child Name Parser Args Interpreter Args */
+
+/* 00 */ OP_INFO_ENTRY (AML_ZERO_OP, OPTYPE_CONSTANT| AML_NO_ARGS| 0, "Zero_op", ARGP_ZERO_OP, ARGI_ZERO_OP),
+/* 01 */ OP_INFO_ENTRY (AML_ONE_OP, OPTYPE_CONSTANT| AML_NO_ARGS| 0, "One_op", ARGP_ONE_OP, ARGI_ONE_OP),
+/* 02 */ OP_INFO_ENTRY (AML_ALIAS_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Alias", ARGP_ALIAS_OP, ARGI_ALIAS_OP),
+/* 03 */ OP_INFO_ENTRY (AML_NAME_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Name", ARGP_NAME_OP, ARGI_NAME_OP),
+/* 04 */ OP_INFO_ENTRY (AML_BYTE_OP, OPTYPE_LITERAL| AML_NO_ARGS| 0, "Byte_const", ARGP_BYTE_OP, ARGI_BYTE_OP),
+/* 05 */ OP_INFO_ENTRY (AML_WORD_OP, OPTYPE_LITERAL| AML_NO_ARGS| 0, "Word_const", ARGP_WORD_OP, ARGI_WORD_OP),
+/* 06 */ OP_INFO_ENTRY (AML_DWORD_OP, OPTYPE_LITERAL| AML_NO_ARGS| 0, "Dword_const", ARGP_DWORD_OP, ARGI_DWORD_OP),
+/* 07 */ OP_INFO_ENTRY (AML_STRING_OP, OPTYPE_LITERAL| AML_NO_ARGS| 0, "String", ARGP_STRING_OP, ARGI_STRING_OP),
+/* 08 */ OP_INFO_ENTRY (AML_SCOPE_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Scope", ARGP_SCOPE_OP, ARGI_SCOPE_OP),
+/* 09 */ OP_INFO_ENTRY (AML_BUFFER_OP, OPTYPE_DATA_TERM| AML_HAS_ARGS| 0, "Buffer", ARGP_BUFFER_OP, ARGI_BUFFER_OP),
+/* 0A */ OP_INFO_ENTRY (AML_PACKAGE_OP, OPTYPE_DATA_TERM| AML_HAS_ARGS| 0, "Package", ARGP_PACKAGE_OP, ARGI_PACKAGE_OP),
+/* 0B */ OP_INFO_ENTRY (AML_METHOD_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Method", ARGP_METHOD_OP, ARGI_METHOD_OP),
+/* 0C */ OP_INFO_ENTRY (AML_LOCAL0, OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS| 0, "Local0", ARGP_LOCAL0, ARGI_LOCAL0),
+/* 0D */ OP_INFO_ENTRY (AML_LOCAL1, OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS| 0, "Local1", ARGP_LOCAL1, ARGI_LOCAL1),
+/* 0E */ OP_INFO_ENTRY (AML_LOCAL2, OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS| 0, "Local2", ARGP_LOCAL2, ARGI_LOCAL2),
+/* 0F */ OP_INFO_ENTRY (AML_LOCAL3, OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS| 0, "Local3", ARGP_LOCAL3, ARGI_LOCAL3),
+/* 10 */ OP_INFO_ENTRY (AML_LOCAL4, OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS| 0, "Local4", ARGP_LOCAL4, ARGI_LOCAL4),
+/* 11 */ OP_INFO_ENTRY (AML_LOCAL5, OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS| 0, "Local5", ARGP_LOCAL5, ARGI_LOCAL5),
+/* 12 */ OP_INFO_ENTRY (AML_LOCAL6, OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS| 0, "Local6", ARGP_LOCAL6, ARGI_LOCAL6),
+/* 13 */ OP_INFO_ENTRY (AML_LOCAL7, OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS| 0, "Local7", ARGP_LOCAL7, ARGI_LOCAL7),
+/* 14 */ OP_INFO_ENTRY (AML_ARG0, OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS| 0, "Arg0", ARGP_ARG0, ARGI_ARG0),
+/* 15 */ OP_INFO_ENTRY (AML_ARG1, OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS| 0, "Arg1", ARGP_ARG1, ARGI_ARG1),
+/* 16 */ OP_INFO_ENTRY (AML_ARG2, OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS| 0, "Arg2", ARGP_ARG2, ARGI_ARG2),
+/* 17 */ OP_INFO_ENTRY (AML_ARG3, OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS| 0, "Arg3", ARGP_ARG3, ARGI_ARG3),
+/* 18 */ OP_INFO_ENTRY (AML_ARG4, OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS| 0, "Arg4", ARGP_ARG4, ARGI_ARG4),
+/* 19 */ OP_INFO_ENTRY (AML_ARG5, OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS| 0, "Arg5", ARGP_ARG5, ARGI_ARG5),
+/* 1_a */ OP_INFO_ENTRY (AML_ARG6, OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS| 0, "Arg6", ARGP_ARG6, ARGI_ARG6),
+/* 1_b */ OP_INFO_ENTRY (AML_STORE_OP, OPTYPE_MONADIC2_r| AML_HAS_ARGS| 0, "Store", ARGP_STORE_OP, ARGI_STORE_OP),
+/* 1_c */ OP_INFO_ENTRY (AML_REF_OF_OP, OPTYPE_MONADIC2| AML_HAS_ARGS| 0, "Ref_of", ARGP_REF_OF_OP, ARGI_REF_OF_OP),
+/* 1_d */ OP_INFO_ENTRY (AML_ADD_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "Add", ARGP_ADD_OP, ARGI_ADD_OP),
+/* 1_e */ OP_INFO_ENTRY (AML_CONCAT_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "Concat", ARGP_CONCAT_OP, ARGI_CONCAT_OP),
+/* 1_f */ OP_INFO_ENTRY (AML_SUBTRACT_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "Subtract", ARGP_SUBTRACT_OP, ARGI_SUBTRACT_OP),
+/* 20 */ OP_INFO_ENTRY (AML_INCREMENT_OP, OPTYPE_MONADIC2| AML_HAS_ARGS| 0, "Increment", ARGP_INCREMENT_OP, ARGI_INCREMENT_OP),
+/* 21 */ OP_INFO_ENTRY (AML_DECREMENT_OP, OPTYPE_MONADIC2| AML_HAS_ARGS| 0, "Decrement", ARGP_DECREMENT_OP, ARGI_DECREMENT_OP),
+/* 22 */ OP_INFO_ENTRY (AML_MULTIPLY_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "Multiply", ARGP_MULTIPLY_OP, ARGI_MULTIPLY_OP),
+/* 23 */ OP_INFO_ENTRY (AML_DIVIDE_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "Divide", ARGP_DIVIDE_OP, ARGI_DIVIDE_OP),
+/* 24 */ OP_INFO_ENTRY (AML_SHIFT_LEFT_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "Shift_left", ARGP_SHIFT_LEFT_OP, ARGI_SHIFT_LEFT_OP),
+/* 25 */ OP_INFO_ENTRY (AML_SHIFT_RIGHT_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "Shift_right", ARGP_SHIFT_RIGHT_OP, ARGI_SHIFT_RIGHT_OP),
+/* 26 */ OP_INFO_ENTRY (AML_BIT_AND_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "And", ARGP_BIT_AND_OP, ARGI_BIT_AND_OP),
+/* 27 */ OP_INFO_ENTRY (AML_BIT_NAND_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "NAnd", ARGP_BIT_NAND_OP, ARGI_BIT_NAND_OP),
+/* 28 */ OP_INFO_ENTRY (AML_BIT_OR_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "Or", ARGP_BIT_OR_OP, ARGI_BIT_OR_OP),
+/* 29 */ OP_INFO_ENTRY (AML_BIT_NOR_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "NOr", ARGP_BIT_NOR_OP, ARGI_BIT_NOR_OP),
+/* 2_a */ OP_INFO_ENTRY (AML_BIT_XOR_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "XOr", ARGP_BIT_XOR_OP, ARGI_BIT_XOR_OP),
+/* 2_b */ OP_INFO_ENTRY (AML_BIT_NOT_OP, OPTYPE_MONADIC2_r| AML_HAS_ARGS| 0, "Not", ARGP_BIT_NOT_OP, ARGI_BIT_NOT_OP),
+/* 2_c */ OP_INFO_ENTRY (AML_FIND_SET_LEFT_BIT_OP, OPTYPE_MONADIC2_r| AML_HAS_ARGS| 0, "Find_set_left_bit", ARGP_FIND_SET_LEFT_BIT_OP, ARGI_FIND_SET_LEFT_BIT_OP),
+/* 2_d */ OP_INFO_ENTRY (AML_FIND_SET_RIGHT_BIT_OP, OPTYPE_MONADIC2_r| AML_HAS_ARGS| 0, "Find_set_right_bit", ARGP_FIND_SET_RIGHT_BIT_OP, ARGI_FIND_SET_RIGHT_BIT_OP),
+/* 2_e */ OP_INFO_ENTRY (AML_DEREF_OF_OP, OPTYPE_MONADIC2| AML_HAS_ARGS| 0, "Deref_of", ARGP_DEREF_OF_OP, ARGI_DEREF_OF_OP),
+/* 2_f */ OP_INFO_ENTRY (AML_NOTIFY_OP, OPTYPE_DYADIC1| AML_HAS_ARGS| 0, "Notify", ARGP_NOTIFY_OP, ARGI_NOTIFY_OP),
+/* 30 */ OP_INFO_ENTRY (AML_SIZE_OF_OP, OPTYPE_MONADIC2| AML_HAS_ARGS| 0, "Size_of", ARGP_SIZE_OF_OP, ARGI_SIZE_OF_OP),
+/* 31 */ OP_INFO_ENTRY (AML_INDEX_OP, OPTYPE_INDEX| AML_HAS_ARGS| 0, "Index", ARGP_INDEX_OP, ARGI_INDEX_OP),
+/* 32 */ OP_INFO_ENTRY (AML_MATCH_OP, OPTYPE_MATCH| AML_HAS_ARGS| 0, "Match", ARGP_MATCH_OP, ARGI_MATCH_OP),
+/* 33 */ OP_INFO_ENTRY (AML_DWORD_FIELD_OP, OPTYPE_CREATE_FIELD| AML_HAS_ARGS| 0, "Create_dWord_field", ARGP_DWORD_FIELD_OP, ARGI_DWORD_FIELD_OP),
+/* 34 */ OP_INFO_ENTRY (AML_WORD_FIELD_OP, OPTYPE_CREATE_FIELD| AML_HAS_ARGS| 0, "Create_word_field", ARGP_WORD_FIELD_OP, ARGI_WORD_FIELD_OP),
+/* 35 */ OP_INFO_ENTRY (AML_BYTE_FIELD_OP, OPTYPE_CREATE_FIELD| AML_HAS_ARGS| 0, "Create_byte_field", ARGP_BYTE_FIELD_OP, ARGI_BYTE_FIELD_OP),
+/* 36 */ OP_INFO_ENTRY (AML_BIT_FIELD_OP, OPTYPE_CREATE_FIELD| AML_HAS_ARGS| 0, "Create_bit_field", ARGP_BIT_FIELD_OP, ARGI_BIT_FIELD_OP),
+/* 37 */ OP_INFO_ENTRY (AML_TYPE_OP, OPTYPE_MONADIC2| AML_HAS_ARGS| 0, "Object_type", ARGP_TYPE_OP, ARGI_TYPE_OP),
+/* 38 */ OP_INFO_ENTRY (AML_LAND_OP, OPTYPE_DYADIC2| AML_HAS_ARGS| 0, "LAnd", ARGP_LAND_OP, ARGI_LAND_OP),
+/* 39 */ OP_INFO_ENTRY (AML_LOR_OP, OPTYPE_DYADIC2| AML_HAS_ARGS| 0, "LOr", ARGP_LOR_OP, ARGI_LOR_OP),
+/* 3_a */ OP_INFO_ENTRY (AML_LNOT_OP, OPTYPE_MONADIC2| AML_HAS_ARGS| 0, "LNot", ARGP_LNOT_OP, ARGI_LNOT_OP),
+/* 3_b */ OP_INFO_ENTRY (AML_LEQUAL_OP, OPTYPE_DYADIC2| AML_HAS_ARGS| 0, "LEqual", ARGP_LEQUAL_OP, ARGI_LEQUAL_OP),
+/* 3_c */ OP_INFO_ENTRY (AML_LGREATER_OP, OPTYPE_DYADIC2| AML_HAS_ARGS| 0, "LGreater", ARGP_LGREATER_OP, ARGI_LGREATER_OP),
+/* 3_d */ OP_INFO_ENTRY (AML_LLESS_OP, OPTYPE_DYADIC2| AML_HAS_ARGS| 0, "LLess", ARGP_LLESS_OP, ARGI_LLESS_OP),
+/* 3_e */ OP_INFO_ENTRY (AML_IF_OP, OPTYPE_CONTROL| AML_HAS_ARGS| 0, "If", ARGP_IF_OP, ARGI_IF_OP),
+/* 3_f */ OP_INFO_ENTRY (AML_ELSE_OP, OPTYPE_CONTROL| AML_HAS_ARGS| 0, "Else", ARGP_ELSE_OP, ARGI_ELSE_OP),
+/* 40 */ OP_INFO_ENTRY (AML_WHILE_OP, OPTYPE_CONTROL| AML_HAS_ARGS| 0, "While", ARGP_WHILE_OP, ARGI_WHILE_OP),
+/* 41 */ OP_INFO_ENTRY (AML_NOOP_CODE, OPTYPE_CONTROL| AML_NO_ARGS| 0, "Noop", ARGP_NOOP_CODE, ARGI_NOOP_CODE),
+/* 42 */ OP_INFO_ENTRY (AML_RETURN_OP, OPTYPE_CONTROL| AML_HAS_ARGS| 0, "Return", ARGP_RETURN_OP, ARGI_RETURN_OP),
+/* 43 */ OP_INFO_ENTRY (AML_BREAK_OP, OPTYPE_CONTROL| AML_NO_ARGS| 0, "Break", ARGP_BREAK_OP, ARGI_BREAK_OP),
+/* 44 */ OP_INFO_ENTRY (AML_BREAK_POINT_OP, OPTYPE_CONTROL| AML_NO_ARGS| 0, "Break_point", ARGP_BREAK_POINT_OP, ARGI_BREAK_POINT_OP),
+/* 45 */ OP_INFO_ENTRY (AML_ONES_OP, OPTYPE_CONSTANT| AML_NO_ARGS| 0, "Ones_op", ARGP_ONES_OP, ARGI_ONES_OP),
+
+/* Prefixed opcodes (Two-byte opcodes with a prefix op) */
+
+/* 46 */ OP_INFO_ENTRY (AML_MUTEX_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Mutex", ARGP_MUTEX_OP, ARGI_MUTEX_OP),
+/* 47 */ OP_INFO_ENTRY (AML_EVENT_OP, OPTYPE_NAMED_OBJECT| AML_NO_ARGS| 0, "Event", ARGP_EVENT_OP, ARGI_EVENT_OP),
+/* 48 */ OP_INFO_ENTRY (AML_COND_REF_OF_OP, OPTYPE_MONADIC2_r| AML_HAS_ARGS| 0, "Cond_ref_of", ARGP_COND_REF_OF_OP, ARGI_COND_REF_OF_OP),
+/* 49 */ OP_INFO_ENTRY (AML_CREATE_FIELD_OP, OPTYPE_CREATE_FIELD| AML_HAS_ARGS| 0, "Create_field", ARGP_CREATE_FIELD_OP, ARGI_CREATE_FIELD_OP),
+/* 4_a */ OP_INFO_ENTRY (AML_LOAD_OP, OPTYPE_RECONFIGURATION| AML_HAS_ARGS| 0, "Load", ARGP_LOAD_OP, ARGI_LOAD_OP),
+/* 4_b */ OP_INFO_ENTRY (AML_STALL_OP, OPTYPE_MONADIC1| AML_HAS_ARGS| 0, "Stall", ARGP_STALL_OP, ARGI_STALL_OP),
+/* 4_c */ OP_INFO_ENTRY (AML_SLEEP_OP, OPTYPE_MONADIC1| AML_HAS_ARGS| 0, "Sleep", ARGP_SLEEP_OP, ARGI_SLEEP_OP),
+/* 4_d */ OP_INFO_ENTRY (AML_ACQUIRE_OP, OPTYPE_DYADIC2_s| AML_HAS_ARGS| 0, "Acquire", ARGP_ACQUIRE_OP, ARGI_ACQUIRE_OP),
+/* 4_e */ OP_INFO_ENTRY (AML_SIGNAL_OP, OPTYPE_MONADIC1| AML_HAS_ARGS| 0, "Signal", ARGP_SIGNAL_OP, ARGI_SIGNAL_OP),
+/* 4_f */ OP_INFO_ENTRY (AML_WAIT_OP, OPTYPE_DYADIC2_s| AML_HAS_ARGS| 0, "Wait", ARGP_WAIT_OP, ARGI_WAIT_OP),
+/* 50 */ OP_INFO_ENTRY (AML_RESET_OP, OPTYPE_MONADIC1| AML_HAS_ARGS| 0, "Reset", ARGP_RESET_OP, ARGI_RESET_OP),
+/* 51 */ OP_INFO_ENTRY (AML_RELEASE_OP, OPTYPE_MONADIC1| AML_HAS_ARGS| 0, "Release", ARGP_RELEASE_OP, ARGI_RELEASE_OP),
+/* 52 */ OP_INFO_ENTRY (AML_FROM_BCDOP, OPTYPE_MONADIC2_r| AML_HAS_ARGS| 0, "From_bCD", ARGP_FROM_BCDOP, ARGI_FROM_BCDOP),
+/* 53 */ OP_INFO_ENTRY (AML_TO_BCDOP, OPTYPE_MONADIC2_r| AML_HAS_ARGS| 0, "To_bCD", ARGP_TO_BCDOP, ARGI_TO_BCDOP),
+/* 54 */ OP_INFO_ENTRY (AML_UN_LOAD_OP, OPTYPE_RECONFIGURATION| AML_HAS_ARGS| 0, "Unload", ARGP_UN_LOAD_OP, ARGI_UN_LOAD_OP),
+/* 55 */ OP_INFO_ENTRY (AML_REVISION_OP, OPTYPE_CONSTANT| AML_NO_ARGS| 0, "Revision", ARGP_REVISION_OP, ARGI_REVISION_OP),
+/* 56 */ OP_INFO_ENTRY (AML_DEBUG_OP, OPTYPE_CONSTANT| AML_NO_ARGS| 0, "Debug", ARGP_DEBUG_OP, ARGI_DEBUG_OP),
+/* 57 */ OP_INFO_ENTRY (AML_FATAL_OP, OPTYPE_FATAL| AML_HAS_ARGS| 0, "Fatal", ARGP_FATAL_OP, ARGI_FATAL_OP),
+/* 58 */ OP_INFO_ENTRY (AML_REGION_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Op_region", ARGP_REGION_OP, ARGI_REGION_OP),
+/* 59 */ OP_INFO_ENTRY (AML_DEF_FIELD_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Field", ARGP_DEF_FIELD_OP, ARGI_DEF_FIELD_OP),
+/* 5_a */ OP_INFO_ENTRY (AML_DEVICE_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Device", ARGP_DEVICE_OP, ARGI_DEVICE_OP),
+/* 5_b */ OP_INFO_ENTRY (AML_PROCESSOR_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Processor", ARGP_PROCESSOR_OP, ARGI_PROCESSOR_OP),
+/* 5_c */ OP_INFO_ENTRY (AML_POWER_RES_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Power_res", ARGP_POWER_RES_OP, ARGI_POWER_RES_OP),
+/* 5_d */ OP_INFO_ENTRY (AML_THERMAL_ZONE_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Thermal_zone", ARGP_THERMAL_ZONE_OP, ARGI_THERMAL_ZONE_OP),
+/* 5_e */ OP_INFO_ENTRY (AML_INDEX_FIELD_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Index_field", ARGP_INDEX_FIELD_OP, ARGI_INDEX_FIELD_OP),
+/* 5_f */ OP_INFO_ENTRY (AML_BANK_FIELD_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Bank_field", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP),
+
+/* Internal opcodes that map to invalid AML opcodes */
+
+/* 60 */ OP_INFO_ENTRY (AML_LNOTEQUAL_OP, OPTYPE_BOGUS| AML_HAS_ARGS| 0, "LNot_equal", ARGP_LNOTEQUAL_OP, ARGI_LNOTEQUAL_OP),
+/* 61 */ OP_INFO_ENTRY (AML_LLESSEQUAL_OP, OPTYPE_BOGUS| AML_HAS_ARGS| 0, "LLess_equal", ARGP_LLESSEQUAL_OP, ARGI_LLESSEQUAL_OP),
+/* 62 */ OP_INFO_ENTRY (AML_LGREATEREQUAL_OP, OPTYPE_BOGUS| AML_HAS_ARGS| 0, "LGreater_equal", ARGP_LGREATEREQUAL_OP, ARGI_LGREATEREQUAL_OP),
+/* 63 */ OP_INFO_ENTRY (AML_NAMEPATH_OP, OPTYPE_LITERAL| AML_NO_ARGS| 0, "Name_path", ARGP_NAMEPATH_OP, ARGI_NAMEPATH_OP),
+/* 64 */ OP_INFO_ENTRY (AML_METHODCALL_OP, OPTYPE_METHOD_CALL| AML_HAS_ARGS| 0, "Method_call", ARGP_METHODCALL_OP, ARGI_METHODCALL_OP),
+/* 65 */ OP_INFO_ENTRY (AML_BYTELIST_OP, OPTYPE_LITERAL| AML_NO_ARGS| 0, "Byte_list", ARGP_BYTELIST_OP, ARGI_BYTELIST_OP),
+/* 66 */ OP_INFO_ENTRY (AML_RESERVEDFIELD_OP, OPTYPE_BOGUS| AML_NO_ARGS| 0, "Reserved_field", ARGP_RESERVEDFIELD_OP, ARGI_RESERVEDFIELD_OP),
+/* 67 */ OP_INFO_ENTRY (AML_NAMEDFIELD_OP, OPTYPE_BOGUS| AML_NO_ARGS| 0, "Named_field", ARGP_NAMEDFIELD_OP, ARGI_NAMEDFIELD_OP),
+/* 68 */ OP_INFO_ENTRY (AML_ACCESSFIELD_OP, OPTYPE_BOGUS| AML_NO_ARGS| 0, "Access_field", ARGP_ACCESSFIELD_OP, ARGI_ACCESSFIELD_OP),
+/* 69 */ OP_INFO_ENTRY (AML_STATICSTRING_OP, OPTYPE_BOGUS| AML_NO_ARGS| 0, "Static_string", ARGP_STATICSTRING_OP, ARGI_STATICSTRING_OP),
+/* 6_a */ OP_INFO_ENTRY (0, OPTYPE_BOGUS| AML_HAS_ARGS| 0, "UNKNOWN_OP!", ARG_NONE, ARG_NONE),
+ OP_INFO_ENTRY (0, 0| AML_HAS_ARGS| 0, NULL, ARG_NONE, ARG_NONE)
+};
+
+#define _UNK 0x6A
+#define _UNKNOWN_OPCODE 0x02 /* An example unknown opcode */
+
+/*
+ * This table is directly indexed by the opcodes, and returns an
+ * index into the table above
+ */
+
+u8 acpi_gbl_aml_op_info_index[256] =
+{
+/* 0 1 2 3 4 5 6 7 */
+/* 0x00 */ 0x00, 0x01, _UNK, _UNK, _UNK, _UNK, 0x02, _UNK,
+/* 0x08 */ 0x03, _UNK, 0x04, 0x05, 0x06, 0x07, _UNK, _UNK,
+/* 0x10 */ 0x08, 0x09, 0x0a, _UNK, 0x0b, _UNK, _UNK, 0x46,
+/* 0x18 */ 0x47, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x20 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x28 */ 0x48, 0x49, _UNK, _UNK, _UNK, 0x63, _UNK, _UNK,
+/* 0x30 */ 0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x4a, 0x4b,
+/* 0x38 */ 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53,
+/* 0x40 */ 0x54, _UNK, _UNK, _UNK, _UNK, _UNK, 0x55, 0x56,
+/* 0x48 */ 0x57, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x50 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x58 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x60 */ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+/* 0x68 */ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, _UNK,
+/* 0x70 */ 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
+/* 0x78 */ 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
+/* 0x80 */ 0x2b, 0x2c, 0x2d, 0x2e, _UNK, _UNK, 0x2f, 0x30,
+/* 0x88 */ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, _UNK,
+/* 0x90 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x58, 0x59,
+/* 0x98 */ 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, _UNK, _UNK,
+/* 0xA0 */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x60, 0x61,
+/* 0xA8 */ 0x62, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xB0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xB8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xC0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xC8 */ _UNK, _UNK, _UNK, _UNK, 0x44, _UNK, _UNK, _UNK,
+/* 0xD0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xD8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xE0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xE8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xF0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xF8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x45,
+};
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
new file mode 100644
index 000000000..7ec1e70fa
--- /dev/null
+++ b/drivers/acpi/parser/psparse.c
@@ -0,0 +1,726 @@
+/******************************************************************************
+ *
+ * Module Name: psparse - Parser top level AML parse routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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
+ */
+
+
+/*
+ * Parse the AML and build an operation tree as most interpreters,
+ * like Perl, do. Parsing is done by hand rather than with a YACC
+ * generated parser to tightly constrain stack and dynamic memory
+ * usage. At the same time, parsing is kept flexible and the code
+ * fairly compact by parsing based on a list of AML opcode
+ * templates in Acpi_gbl_Aml_op_info[]
+ */
+
+#include "acpi.h"
+#include "parser.h"
+#include "dispatch.h"
+#include "amlcode.h"
+#include "namesp.h"
+#include "debugger.h"
+
+#define _COMPONENT PARSER
+ MODULE_NAME ("psparse");
+
+
+u32 acpi_gbl_depth = 0;
+extern u32 acpi_gbl_scope_depth;
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_delete_completed_op
+ *
+ * PARAMETERS: State - Walk state
+ * Op - Completed op
+ *
+ * RETURN: AE_OK
+ *
+ * DESCRIPTION: Callback function for Acpi_ps_get_next_walk_op(). Used during
+ * Acpi_ps_delete_parse tree to delete Op objects when all sub-objects
+ * have been visited (and deleted.)
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ps_delete_completed_op (
+ ACPI_WALK_STATE *state,
+ ACPI_GENERIC_OP *op)
+{
+
+ acpi_ps_free_op (op);
+ return AE_OK;
+}
+
+
+#ifndef PARSER_ONLY
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_delete_parse_tree
+ *
+ * PARAMETERS: Root - Root of tree (or subtree) to delete
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Delete a portion of or an entire parse tree.
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_delete_parse_tree (
+ ACPI_GENERIC_OP *root)
+{
+ ACPI_GENERIC_OP *op;
+ ACPI_WALK_STATE walk_state;
+
+
+ walk_state.origin = root;
+ op = root;
+
+ /* TBD: [Restructure] hack for root case */
+
+ if (op == acpi_gbl_parsed_namespace_root) {
+ op = acpi_ps_get_child (op);
+ }
+
+ /* Save root until last, so that we know when the tree has been walked */
+
+ walk_state.next_op = op;
+ walk_state.next_op_info = NEXT_OP_DOWNWARD;
+
+ while (walk_state.next_op) {
+ acpi_ps_get_next_walk_op (&walk_state, walk_state.next_op,
+ acpi_ps_delete_completed_op);
+ }
+}
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_peek_opcode
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get next AML opcode (without incrementing AML pointer)
+ *
+ ******************************************************************************/
+
+u32
+acpi_ps_get_opcode_size (
+ u32 opcode)
+{
+
+ /* Extended (2-byte) opcode if > 255 */
+
+ if (opcode > 0x00FF) {
+ return 2;
+ }
+
+ /* Otherwise, just a single byte opcode */
+
+ return 1;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_peek_opcode
+ *
+ * PARAMETERS: Parser_state - A parser state object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get next AML opcode (without incrementing AML pointer)
+ *
+ ******************************************************************************/
+
+u16
+acpi_ps_peek_opcode (
+ ACPI_PARSE_STATE *parser_state)
+{
+ u8 *aml;
+ u16 opcode;
+
+
+ aml = parser_state->aml;
+ opcode = (u16) GET8 (aml);
+
+ aml++;
+
+
+ /*
+ * Original code special cased LNOTEQUAL, LLESSEQUAL, LGREATEREQUAL.
+ * These opcodes are no longer recognized. Instead, they are broken into
+ * two opcodes.
+ *
+ *
+ * if (Opcode == AML_EXTOP
+ * || (Opcode == AML_LNOT
+ * && (GET8 (Acpi_aml) == AML_LEQUAL
+ * || GET8 (Acpi_aml) == AML_LGREATER
+ * || GET8 (Acpi_aml) == AML_LLESS)))
+ *
+ * extended Opcode, !=, <=, or >=
+ */
+
+ if (opcode == AML_EXTOP) {
+ /* Extended opcode */
+
+ opcode = (u16) ((opcode << 8) | GET8 (aml));
+ aml++;
+ }
+
+ /* don't convert bare name to a namepath */
+
+ return opcode;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_create_state
+ *
+ * PARAMETERS: Acpi_aml - Acpi_aml code pointer
+ * Acpi_aml_size - Length of AML code
+ *
+ * RETURN: A new parser state object
+ *
+ * DESCRIPTION: Create and initialize a new parser state object
+ *
+ ******************************************************************************/
+
+ACPI_PARSE_STATE *
+acpi_ps_create_state (
+ u8 *aml,
+ s32 aml_size)
+{
+ ACPI_PARSE_STATE *parser_state;
+
+
+ parser_state = acpi_cm_callocate (sizeof (ACPI_PARSE_STATE));
+ if (!parser_state) {
+ return (NULL);
+ }
+
+ parser_state->aml = aml;
+ parser_state->aml_end = aml + aml_size;
+ parser_state->pkg_end = parser_state->aml_end;
+ parser_state->aml_start = aml;
+
+
+ return (parser_state);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_find_object
+ *
+ * PARAMETERS: Opcode - Current opcode
+ * Parser_state - Current state
+ * Walk_state - Current state
+ * *Op - Where found/new op is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Find a named object. Two versions - one to search the parse
+ * tree (for parser-only applications such as acpidump), another
+ * to search the ACPI internal namespace (the parse tree may no
+ * longer exist)
+ *
+ ******************************************************************************/
+
+#ifdef PARSER_ONLY
+
+ACPI_STATUS
+acpi_ps_find_object (
+ u16 opcode,
+ ACPI_PARSE_STATE *parser_state,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP **op)
+{
+ char *path;
+
+
+ /* Find the name in the parse tree */
+
+ path = acpi_ps_get_next_namestring (parser_state);
+
+ *op = acpi_ps_find (acpi_ps_get_parent_scope (parser_state),
+ path, opcode, 1);
+
+ if (!(*op)) {
+ return AE_NOT_FOUND;
+ }
+
+ return AE_OK;
+}
+#else
+
+ACPI_STATUS
+acpi_ps_find_object (
+ u16 opcode,
+ ACPI_PARSE_STATE *parser_state,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP **out_op)
+{
+ char *path;
+ ACPI_GENERIC_OP *op;
+ OBJECT_TYPE_INTERNAL data_type;
+ ACPI_STATUS status;
+ ACPI_NAMED_OBJECT *entry = NULL;
+
+
+ /*
+ * The full parse tree has already been deleted -- therefore, we are parsing
+ * a control method. We can lookup the name in the namespace instead of
+ * the parse tree!
+ */
+
+
+ path = acpi_ps_get_next_namestring (parser_state);
+
+ /* Map the raw opcode into an internal object type */
+
+ data_type = acpi_ds_map_named_opcode_to_data_type (opcode);
+
+ /*
+ * Enter the object into the namespace
+ * LOAD_PASS1 means Create if not found
+ */
+
+ status = acpi_ns_lookup (walk_state->scope_info, path, data_type,
+ IMODE_LOAD_PASS1,
+ NS_NO_UPSEARCH, walk_state, &entry);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Create a new op */
+
+ op = acpi_ps_alloc_op (opcode);
+ if (!op) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Initialize */
+
+ ((ACPI_NAMED_OP *)op)->name = entry->name;
+ op->acpi_named_object = entry;
+
+
+ acpi_ps_append_arg (acpi_ps_get_parent_scope (parser_state), op);
+
+ *out_op = op;
+
+
+ return (AE_OK);
+}
+#endif
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_parse_loop
+ *
+ * PARAMETERS: Parser_state - Current parser state object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Parse AML (pointed to by the current parser state) and return
+ * a tree of ops.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ps_parse_loop (
+ ACPI_PARSE_STATE *parser_state,
+ ACPI_WALK_STATE *walk_state,
+ u32 parse_flags)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_GENERIC_OP *op = NULL; /* current op */
+ ACPI_OP_INFO *op_info;
+ ACPI_GENERIC_OP *arg = NULL;
+ ACPI_DEFERRED_OP *deferred_op;
+ u32 arg_count; /* push for fixed or var args */
+ u32 arg_types = 0;
+ ACPI_PTRDIFF aml_offset;
+ u16 opcode;
+ ACPI_GENERIC_OP pre_op;
+
+
+#ifndef PARSER_ONLY
+ OBJECT_TYPE_INTERNAL data_type;
+#endif
+
+
+ /*
+ * Iterative parsing loop, while there is more aml to process:
+ */
+ while (parser_state->aml < parser_state->aml_end) {
+ if (!op) {
+ /* Get the next opcode from the AML stream */
+
+ aml_offset = parser_state->aml - parser_state->aml_start;
+ opcode = acpi_ps_peek_opcode (parser_state);
+ op_info = acpi_ps_get_opcode_info (opcode);
+
+ /*
+ * First cut to determine what we have found:
+ * 1) A valid AML opcode
+ * 2) A name string
+ * 3) An unknown/invalid opcode
+ */
+
+ if (op_info) {
+ /* Found opcode info, this is a normal opcode */
+
+ parser_state->aml += acpi_ps_get_opcode_size (opcode);
+ arg_types = op_info->parse_args;
+ }
+
+ else if (acpi_ps_is_prefix_char (opcode) ||
+ acpi_ps_is_leading_char (opcode))
+ {
+ /*
+ * Starts with a valid prefix or ASCII char, this is a name
+ * string. Convert the bare name string to a namepath.
+ */
+
+ opcode = AML_NAMEPATH_OP;
+ arg_types = ARGP_NAMESTRING;
+ }
+
+ else {
+ /* The opcode is unrecognized. Just skip unknown opcodes */
+
+ parser_state->aml += acpi_ps_get_opcode_size (opcode);
+ continue;
+ }
+
+
+ /* Create Op structure and append to parent's argument list */
+
+ if (acpi_ps_is_named_op (opcode)) {
+ pre_op.value.arg = NULL;
+ pre_op.opcode = opcode;
+
+ while (GET_CURRENT_ARG_TYPE (arg_types) != ARGP_NAME) {
+ arg = acpi_ps_get_next_arg (parser_state,
+ GET_CURRENT_ARG_TYPE (arg_types),
+ &arg_count);
+ acpi_ps_append_arg (&pre_op, arg);
+ INCREMENT_ARG_LIST (arg_types);
+ }
+
+
+ /* We know that this arg is a name, move to next arg */
+
+ INCREMENT_ARG_LIST (arg_types);
+
+ status = acpi_ps_find_object (opcode, parser_state, walk_state, &op);
+ if (ACPI_FAILURE (status)) {
+ return (AE_NOT_FOUND);
+ }
+
+ acpi_ps_append_arg (op, pre_op.value.arg);
+ acpi_gbl_depth++;
+
+
+ if (op->opcode == AML_REGION_OP) {
+ deferred_op = acpi_ps_to_deferred_op (op);
+ if (deferred_op) {
+ /*
+ * Skip parsing of control method or opregion body,
+ * because we don't have enough info in the first pass
+ * to parse them correctly.
+ *
+ * Backup to beginning of Op_region declaration (2 for
+ * Opcode, 4 for name)
+ *
+ * Body_length is unknown until we parse the body
+ */
+
+ deferred_op->body = parser_state->aml - 6;
+ deferred_op->body_length = 0;
+ }
+ }
+ }
+
+ else {
+ /* Not a named opcode, just allocate Op and append to parent */
+
+ op = acpi_ps_alloc_op (opcode);
+ if (!op) {
+ return (AE_NO_MEMORY);
+ }
+
+ acpi_ps_append_arg (acpi_ps_get_parent_scope (parser_state), op);
+ }
+
+ op->aml_offset = aml_offset;
+
+ }
+
+
+ arg_count = 0;
+ if (arg_types) /* Are there any arguments that must be processed? */ {
+ /* get arguments */
+
+ switch (op->opcode)
+ {
+ case AML_BYTE_OP: /* AML_BYTEDATA_ARG */
+ case AML_WORD_OP: /* AML_WORDDATA_ARG */
+ case AML_DWORD_OP: /* AML_DWORDATA_ARG */
+ case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */
+
+ /* fill in constant or string argument directly */
+
+ acpi_ps_get_next_simple_arg (parser_state,
+ GET_CURRENT_ARG_TYPE (arg_types), op);
+ break;
+
+ case AML_NAMEPATH_OP: /* AML_NAMESTRING_ARG */
+
+ acpi_ps_get_next_namepath (parser_state, op, &arg_count, 1);
+ arg_types = 0;
+ break;
+
+
+ default:
+
+ /* Op is not a constant or string, append each argument */
+
+ while (GET_CURRENT_ARG_TYPE (arg_types) && !arg_count) {
+ aml_offset = parser_state->aml - parser_state->aml_start;
+ arg = acpi_ps_get_next_arg (parser_state,
+ GET_CURRENT_ARG_TYPE (arg_types),
+ &arg_count);
+
+ if (arg) {
+ arg->aml_offset = aml_offset;
+ }
+
+ acpi_ps_append_arg (op, arg);
+ INCREMENT_ARG_LIST (arg_types);
+ }
+
+
+ /* For a method, save the length and address of the body */
+
+ if (op->opcode == AML_METHOD_OP) {
+ deferred_op = acpi_ps_to_deferred_op (op);
+ if (deferred_op) {
+ /*
+ * Skip parsing of control method or opregion body,
+ * because we don't have enough info in the first pass
+ * to parse them correctly.
+ */
+
+ deferred_op->body = parser_state->aml;
+ deferred_op->body_length = parser_state->pkg_end -
+ parser_state->aml;
+
+ /*
+ * Skip body of method. For Op_regions, we must continue
+ * parsing because the opregion is not a standalone
+ * package (We don't know where the end is).
+ */
+ parser_state->aml = parser_state->pkg_end;
+ arg_count = 0;
+ }
+ }
+
+ break;
+ }
+ }
+
+ if (!arg_count) {
+ /* completed Op, prepare for next */
+
+ if (acpi_ps_is_named_op (op->opcode)) {
+ if (acpi_gbl_depth) {
+ acpi_gbl_depth--;
+ }
+
+ if (op->opcode == AML_REGION_OP) {
+ deferred_op = acpi_ps_to_deferred_op (op);
+ if (deferred_op) {
+ /*
+ * Skip parsing of control method or opregion body,
+ * because we don't have enough info in the first pass
+ * to parse them correctly.
+ *
+ * Completed parsing an Op_region declaration, we now
+ * know the length.
+ */
+
+ deferred_op->body_length = parser_state->aml -
+ deferred_op->body;
+ }
+ }
+
+
+#ifndef PARSER_ONLY
+ data_type = acpi_ds_map_named_opcode_to_data_type (op->opcode);
+
+ if (op->opcode == AML_NAME_OP) {
+ if (op->value.arg) {
+ data_type = acpi_ds_map_opcode_to_data_type (
+ (op->value.arg)->opcode, NULL);
+ ((ACPI_NAMED_OBJECT*)op->acpi_named_object)->type =
+ (u8) data_type;
+ }
+ }
+
+ /* Pop the scope stack */
+
+ if (acpi_ns_opens_scope (data_type)) {
+
+ acpi_ds_scope_stack_pop (walk_state);
+ }
+#endif
+ }
+
+
+ parser_state->scope->arg_count--;
+
+
+ /* Delete op if asked to */
+
+#ifndef PARSER_ONLY
+ if (parse_flags & PARSE_DELETE_TREE) {
+ acpi_ps_delete_parse_tree (op);
+ }
+#endif
+
+
+ if (acpi_ps_has_completed_scope (parser_state)) {
+ acpi_ps_pop_scope (parser_state, &op, &arg_types);
+ }
+
+ else {
+ op = NULL;
+ }
+ }
+
+ else {
+ /* complex argument, push Op and prepare for argument */
+
+ acpi_ps_push_scope (parser_state, op, arg_types, arg_count);
+ op = NULL;
+ }
+
+ } /* while Parser_state->Aml */
+
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_parse_aml
+ *
+ * PARAMETERS: Start_scope - The starting point of the parse. Becomes the
+ * root of the parsed op tree.
+ * Aml - Pointer to the raw AML code to parse
+ * Aml_size - Length of the AML to parse
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Parse raw AML and return a tree of ops
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ps_parse_aml (
+ ACPI_GENERIC_OP *start_scope,
+ u8 *aml,
+ u32 aml_size,
+ u32 parse_flags)
+{
+ ACPI_STATUS status;
+ ACPI_PARSE_STATE *parser_state;
+ ACPI_WALK_STATE *walk_state;
+ ACPI_WALK_LIST walk_list;
+ ACPI_NAMED_OBJECT *entry = NULL;
+
+
+ /* Initialize parser state and scope */
+
+ parser_state = acpi_ps_create_state (aml, aml_size);
+ if (!parser_state) {
+ return (AE_NO_MEMORY);
+ }
+
+ acpi_ps_init_scope (parser_state, start_scope);
+
+
+ /* Initialize a new walk list */
+
+ walk_list.walk_state = NULL;
+
+ walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, NULL, NULL, &walk_list);
+ if (!walk_state) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+
+ /* Setup the current scope */
+
+ entry = parser_state->start_op->acpi_named_object;
+ if (entry) {
+ /* Push start scope on scope stack and make it current */
+
+ status = acpi_ds_scope_stack_push (entry->child_table, entry->type,
+ walk_state);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ }
+
+
+ /* Create the parse tree */
+
+ status = acpi_ps_parse_loop (parser_state, walk_state, parse_flags);
+
+
+cleanup:
+
+ /* Cleanup */
+
+ acpi_ds_delete_walk_state (walk_state);
+ acpi_ps_cleanup_scope (parser_state);
+ acpi_cm_free (parser_state);
+
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c
new file mode 100644
index 000000000..c47cbf84a
--- /dev/null
+++ b/drivers/acpi/parser/psscope.c
@@ -0,0 +1,271 @@
+/******************************************************************************
+ *
+ * Module Name: psscope - Parser scope stack management routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+
+#define _COMPONENT PARSER
+ MODULE_NAME ("psscope");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_get_parent_scope
+ *
+ * PARAMETERS: Parser_state - Current parser state object
+ *
+ * RETURN: Pointer to an Op object
+ *
+ * DESCRIPTION: Get parent of current op being parsed
+ *
+ ******************************************************************************/
+
+ACPI_GENERIC_OP *
+acpi_ps_get_parent_scope (
+ ACPI_PARSE_STATE *parser_state)
+{
+ return parser_state->scope->op;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_has_completed_scope
+ *
+ * PARAMETERS: Parser_state - Current parser state object
+ *
+ * RETURN: Boolean, TRUE = scope completed.
+ *
+ * DESCRIPTION: Is parsing of current argument complete? Determined by
+ * 1) AML pointer is at or beyond the end of the scope
+ * 2) The scope argument count has reached zero.
+ *
+ ******************************************************************************/
+
+u8
+acpi_ps_has_completed_scope (
+ ACPI_PARSE_STATE *parser_state)
+{
+ return (u8) ((parser_state->aml >= parser_state->scope->arg_end ||
+ !parser_state->scope->arg_count));
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_init_scope
+ *
+ * PARAMETERS: Parser_state - Current parser state object
+ * Root - the root object of this new scope
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Allocate and init a new scope object
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ps_init_scope (
+ ACPI_PARSE_STATE *parser_state,
+ ACPI_GENERIC_OP *root)
+{
+ ACPI_PARSE_SCOPE *scope;
+
+
+ scope = acpi_cm_callocate (sizeof (ACPI_PARSE_SCOPE));
+ if (!scope) {
+ return AE_NO_MEMORY;
+ }
+
+ scope->op = root;
+ scope->arg_count = ACPI_VAR_ARGS;
+ scope->arg_end = parser_state->aml_end;
+ scope->pkg_end = parser_state->aml_end;
+ parser_state->scope = scope;
+ parser_state->start_op = root;
+
+ return AE_OK;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_push_scope
+ *
+ * PARAMETERS: Parser_state - Current parser state object
+ * Op - Current op to be pushed
+ * Next_arg - Next op argument (to be pushed)
+ * Arg_count - Fixed or variable number of args
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Push current op to begin parsing its argument
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ps_push_scope (
+ ACPI_PARSE_STATE *parser_state,
+ ACPI_GENERIC_OP *op,
+ u32 remaining_args,
+ u32 arg_count)
+{
+ ACPI_PARSE_SCOPE *scope = parser_state->scope_avail;
+
+
+ if (scope) {
+ /* grabbed scope from available list */
+
+ parser_state->scope_avail = scope->parent;
+ }
+
+ else {
+ /* allocate scope from the heap */
+
+ scope = (ACPI_PARSE_SCOPE*) acpi_cm_allocate (sizeof (ACPI_PARSE_SCOPE));
+ if (!scope) {
+ return (AE_NO_MEMORY);
+ }
+ }
+
+ /* Always zero out the scope before init */
+
+ MEMSET (scope, 0, sizeof (*scope));
+
+ scope->op = op;
+ scope->arg_list = remaining_args;
+ scope->arg_count = arg_count;
+ scope->pkg_end = parser_state->pkg_end;
+ scope->parent = parser_state->scope;
+ parser_state->scope = scope;
+
+ if (arg_count == ACPI_VAR_ARGS) {
+ /* multiple arguments */
+
+ scope->arg_end = parser_state->pkg_end;
+ }
+
+ else {
+ /* single argument */
+
+ scope->arg_end = ACPI_MAX_AML;
+ }
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_pop_scope
+ *
+ * PARAMETERS: Parser_state - Current parser state object
+ * Op - Where the popped op is returned
+ * Next_arg - Where the popped "next argument" is
+ * returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Return to parsing a previous op
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_pop_scope (
+ ACPI_PARSE_STATE *parser_state,
+ ACPI_GENERIC_OP **op,
+ u32 *arg_list)
+{
+ ACPI_PARSE_SCOPE *scope = parser_state->scope;
+
+
+ if (scope->parent) {
+ /* return to parsing previous op */
+
+ *op = scope->op;
+ *arg_list = scope->arg_list;
+ parser_state->pkg_end = scope->pkg_end;
+ parser_state->scope = scope->parent;
+
+ /* add scope to available list */
+
+ scope->parent = parser_state->scope_avail;
+ parser_state->scope_avail = scope;
+ }
+
+ else {
+ /* empty parse stack, prepare to fetch next opcode */
+
+ *op = NULL;
+ *arg_list = 0;
+ }
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_cleanup_scope
+ *
+ * PARAMETERS: Parser_state - Current parser state object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Destroy available list, remaining stack levels, and return
+ * root scope
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_cleanup_scope (
+ ACPI_PARSE_STATE *parser_state)
+{
+ ACPI_PARSE_SCOPE *scope;
+
+
+ if (!parser_state) {
+ return;
+ }
+
+ /* destroy available list */
+
+ while (parser_state->scope_avail) {
+ scope = parser_state->scope_avail;
+ parser_state->scope_avail = scope->parent;
+ acpi_cm_free (scope);
+ }
+
+ /* destroy scope stack */
+
+ while (parser_state->scope) {
+ scope = parser_state->scope;
+ parser_state->scope = scope->parent;
+ acpi_cm_free (scope);
+ }
+
+ return;
+}
+
diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c
new file mode 100644
index 000000000..377574071
--- /dev/null
+++ b/drivers/acpi/parser/pstree.c
@@ -0,0 +1,399 @@
+/******************************************************************************
+ *
+ * Module Name: pstree - Parser op tree manipulation/traversal/search
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "amlcode.h"
+
+#define _COMPONENT PARSER
+ MODULE_NAME ("pstree");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_get_arg
+ *
+ * PARAMETERS: Op - Get an argument for this op
+ * Argn - Nth argument to get
+ *
+ * RETURN: The argument (as an Op object). NULL if argument does not exist
+ *
+ * DESCRIPTION: Get the specified op's argument.
+ *
+ ******************************************************************************/
+
+ACPI_GENERIC_OP *
+acpi_ps_get_arg (
+ ACPI_GENERIC_OP *op,
+ u32 argn)
+{
+ ACPI_GENERIC_OP *arg = NULL;
+ ACPI_OP_INFO *op_info;
+
+
+ /* Get the info structure for this opcode */
+
+ op_info = acpi_ps_get_opcode_info (op->opcode);
+ if (!op_info) {
+ /* Invalid opcode */
+
+ return NULL;
+ }
+
+ /* Check if this opcode requires argument sub-objects */
+
+ if (!(op_info->flags & OP_INFO_HAS_ARGS)) {
+ /* Has no linked argument objects */
+
+ return NULL;
+ }
+
+ /* Get the requested argument object */
+
+ arg = op->value.arg;
+ while (arg && argn) {
+ argn--;
+ arg = arg->next;
+ }
+
+ return arg;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_append_arg
+ *
+ * PARAMETERS: Op - Append an argument to this Op.
+ * Arg - Argument Op to append
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Append an argument to an op's argument list (a NULL arg is OK)
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_append_arg (
+ ACPI_GENERIC_OP *op,
+ ACPI_GENERIC_OP *arg)
+{
+ ACPI_GENERIC_OP *prev_arg;
+ ACPI_OP_INFO *op_info;
+
+
+ if (!op) {
+ return;
+ }
+
+ /* Get the info structure for this opcode */
+
+ op_info = acpi_ps_get_opcode_info (op->opcode);
+ if (!op_info) {
+ /* Invalid opcode */
+
+ return;
+ }
+
+ /* Check if this opcode requires argument sub-objects */
+
+ if (!(op_info->flags & OP_INFO_HAS_ARGS)) {
+ /* Has no linked argument objects */
+
+ return;
+ }
+
+
+ /* Append the argument to the linked argument list */
+
+ if (op->value.arg) {
+ /* Append to existing argument list */
+
+ prev_arg = op->value.arg;
+ while (prev_arg->next) {
+ prev_arg = prev_arg->next;
+ }
+ prev_arg->next = arg;
+ }
+
+ else {
+ /* No argument list, this will be the first argument */
+
+ op->value.arg = arg;
+ }
+
+
+ /* Set the parent in this arg and any args linked after it */
+
+ while (arg) {
+ arg->parent = op;
+ arg = arg->next;
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_get_child
+ *
+ * PARAMETERS: Op - Get the child of this Op
+ *
+ * RETURN: Child Op, Null if none is found.
+ *
+ * DESCRIPTION: Get op's children or NULL if none
+ *
+ ******************************************************************************/
+
+ACPI_GENERIC_OP *
+acpi_ps_get_child (
+ ACPI_GENERIC_OP *op)
+{
+ ACPI_GENERIC_OP *child = NULL;
+
+
+ switch (op->opcode)
+ {
+ case AML_SCOPE_OP:
+ case AML_ELSE_OP:
+ case AML_DEVICE_OP:
+ case AML_THERMAL_ZONE_OP:
+ case AML_METHODCALL_OP:
+
+ child = acpi_ps_get_arg (op, 0);
+ break;
+
+
+ case AML_BUFFER_OP:
+ case AML_PACKAGE_OP:
+ case AML_METHOD_OP:
+ case AML_IF_OP:
+ case AML_WHILE_OP:
+ case AML_DEF_FIELD_OP:
+
+ child = acpi_ps_get_arg (op, 1);
+ break;
+
+
+ case AML_POWER_RES_OP:
+ case AML_INDEX_FIELD_OP:
+
+ child = acpi_ps_get_arg (op, 2);
+ break;
+
+
+ case AML_PROCESSOR_OP:
+ case AML_BANK_FIELD_OP:
+
+ child = acpi_ps_get_arg (op, 3);
+ break;
+
+ }
+
+ return child;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_get_depth_next
+ *
+ * PARAMETERS: Origin - Root of subtree to search
+ * Op - Last (previous) Op that was found
+ *
+ * RETURN: Next Op found in the search.
+ *
+ * DESCRIPTION: Get next op in tree (walking the tree in depth-first order)
+ * Return NULL when reaching "origin" or when walking up from root
+ *
+ ******************************************************************************/
+
+ACPI_GENERIC_OP *
+acpi_ps_get_depth_next (
+ ACPI_GENERIC_OP *origin,
+ ACPI_GENERIC_OP *op)
+{
+ ACPI_GENERIC_OP *next = NULL;
+ ACPI_GENERIC_OP *parent;
+ ACPI_GENERIC_OP *arg;
+
+
+ if (!op) {
+ return NULL;
+ }
+
+ /* look for an argument or child */
+
+ next = acpi_ps_get_arg (op, 0);
+ if (next) {
+ return next;
+ }
+
+ /* look for a sibling */
+
+ next = op->next;
+ if (next) {
+ return next;
+ }
+
+ /* look for a sibling of parent */
+
+ parent = op->parent;
+
+ while (parent) {
+ arg = acpi_ps_get_arg (parent, 0);
+ while (arg && (arg != origin) && (arg != op)) {
+ arg = arg->next;
+ }
+
+ if (arg == origin) {
+ /* reached parent of origin, end search */
+
+ return NULL;
+ }
+
+ if (parent->next) {
+ /* found sibling of parent */
+ return parent->next;
+ }
+
+ op = parent;
+ parent = parent->parent;
+ }
+
+ return next;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_fetch_prefix
+ *
+ * PARAMETERS: Scope - Op to fetch prefix for
+ * Path - A namestring containing the prefix
+ * io - Direction flag
+ *
+ * RETURN: Op referenced by the prefix
+ *
+ * DESCRIPTION: Fetch and handle path prefix ('\\' or '^')
+ *
+ ******************************************************************************/
+
+ACPI_GENERIC_OP *
+acpi_ps_fetch_prefix (
+ ACPI_GENERIC_OP *scope,
+ char **path,
+ u32 io)
+{
+ u32 prefix = io ? GET8 (*path):**path;
+
+
+ switch (prefix)
+ {
+ case '\\':
+ case '/':
+
+ /* go to the root */
+
+ *path += 1;
+ while (scope->parent) {
+ scope = scope->parent;
+ }
+ break;
+
+
+ case '^':
+
+ /* go up one level */
+
+ *path += 1;
+ scope = scope->parent;
+ break;
+ }
+
+ if (scope && !scope->parent) {
+ /* searching from the root, start with its children */
+
+ scope = acpi_ps_get_child (scope);
+ }
+
+ return scope;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_fetch_name
+ *
+ * PARAMETERS: Path - A string containing the name segment
+ * io - Direction flag
+ *
+ * RETURN: The 4-char ASCII ACPI Name as a u32
+ *
+ * DESCRIPTION: Fetch ACPI name segment (dot-delimited)
+ *
+ ******************************************************************************/
+
+u32
+acpi_ps_fetch_name (
+ char **path,
+ u32 io)
+{
+ u32 name = 0;
+ char *nm;
+ u32 i;
+ char ch;
+
+
+ if (io) {
+ /* Get the name from the path pointer */
+
+ MOVE_UNALIGNED32_TO_32 (&name, *path);
+ *path += 4;
+ }
+
+ else {
+ if (**path == '.') {
+ *path += 1;
+ }
+
+ nm = (char*) &name;
+ for (i = 0; i < 4; i++) {
+ ch = **path;
+ if (ch && ch != '.') {
+ *nm = ch;
+ *path += 1;
+ }
+
+ else {
+ *nm = '_';
+ }
+ nm++;
+ }
+ }
+
+ return name;
+}
+
+
diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c
new file mode 100644
index 000000000..dff77c52d
--- /dev/null
+++ b/drivers/acpi/parser/psutils.c
@@ -0,0 +1,498 @@
+/******************************************************************************
+ *
+ * Module Name: psutils - Parser miscellaneous utilities (Parser only)
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "amlcode.h"
+
+#define _COMPONENT PARSER
+ MODULE_NAME ("psutils");
+
+
+#define PARSEOP_GENERIC 1
+#define PARSEOP_NAMED 2
+#define PARSEOP_DEFERRED 3
+#define PARSEOP_BYTELIST 4
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_init_op
+ *
+ * PARAMETERS: Op - A newly allocated Op object
+ * Opcode - Opcode to store in the Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Allocate an acpi_op, choose op type (and thus size) based on
+ * opcode
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_init_op (
+ ACPI_GENERIC_OP *op,
+ u16 opcode)
+{
+ ACPI_OP_INFO *aml_op;
+
+
+ op->data_type = ACPI_DESC_TYPE_PARSER;
+ op->opcode = opcode;
+
+
+ aml_op = acpi_ps_get_opcode_info (opcode);
+ if (aml_op) {
+ DEBUG_ONLY_MEMBERS (STRNCPY (op->op_name, aml_op->name,
+ sizeof (op->op_name)));
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_alloc_op
+ *
+ * PARAMETERS: Opcode - Opcode that will be stored in the new Op
+ *
+ * RETURN: Pointer to the new Op.
+ *
+ * DESCRIPTION: Allocate an acpi_op, choose op type (and thus size) based on
+ * opcode. A cache of opcodes is available for the pure
+ * GENERIC_OP, since this is by far the most commonly used.
+ *
+ ******************************************************************************/
+
+ACPI_GENERIC_OP*
+acpi_ps_alloc_op (
+ u16 opcode)
+{
+ ACPI_GENERIC_OP *op = NULL;
+ u32 size;
+ u8 flags;
+
+
+ /* Allocate the minimum required size object */
+
+ if (acpi_ps_is_deferred_op (opcode)) {
+ size = sizeof (ACPI_DEFERRED_OP);
+ flags = PARSEOP_DEFERRED;
+ }
+
+ else if (acpi_ps_is_named_op (opcode)) {
+ size = sizeof (ACPI_NAMED_OP);
+ flags = PARSEOP_NAMED;
+ }
+
+ else if (acpi_ps_is_bytelist_op (opcode)) {
+ size = sizeof (ACPI_BYTELIST_OP);
+ flags = PARSEOP_BYTELIST;
+ }
+
+ else {
+ size = sizeof (ACPI_GENERIC_OP);
+ flags = PARSEOP_GENERIC;
+
+ /*
+ * The generic op is by far the most common (16 to 1), and therefore
+ * the op cache is implemented with this type.
+ *
+ * Check if there is an Op already available in the cache
+ */
+
+ acpi_cm_acquire_mutex (ACPI_MTX_CACHES);
+ acpi_gbl_parse_cache_requests++;
+ if (acpi_gbl_parse_cache) {
+ /* Extract an op from the front of the cache list */
+
+ acpi_gbl_parse_cache_depth--;
+ acpi_gbl_parse_cache_hits++;
+
+ op = acpi_gbl_parse_cache;
+ acpi_gbl_parse_cache = op->next;
+
+ /* Clear the previously used Op */
+
+ MEMSET (op, 0, sizeof (ACPI_GENERIC_OP));
+ }
+ acpi_cm_release_mutex (ACPI_MTX_CACHES);
+ }
+
+ /* Allocate a new Op if necessary */
+
+ if (!op) {
+ op = acpi_cm_callocate (size);
+ }
+
+ /* Initialize the Op */
+ if (op) {
+ acpi_ps_init_op (op, opcode);
+ op->flags = flags;
+ }
+
+ return op;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_free_op
+ *
+ * PARAMETERS: Op - Op to be freed
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Free an Op object. Either put it on the GENERIC_OP cache list
+ * or actually free it.
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_free_op (
+ ACPI_GENERIC_OP *op)
+{
+
+
+ if (op->flags == PARSEOP_GENERIC) {
+ /* Is the cache full? */
+
+ if (acpi_gbl_parse_cache_depth < MAX_PARSE_CACHE_DEPTH) {
+ /* Put a GENERIC_OP back into the cache */
+
+ acpi_cm_acquire_mutex (ACPI_MTX_CACHES);
+ acpi_gbl_parse_cache_depth++;
+
+ op->next = acpi_gbl_parse_cache;
+ acpi_gbl_parse_cache = op;
+
+ acpi_cm_release_mutex (ACPI_MTX_CACHES);
+ return;
+ }
+ }
+
+ /*
+ * Not a GENERIC OP, or the cache is full, just free the Op
+ */
+
+ acpi_cm_free (op);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_delete_parse_cache
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Free all objects that are on the parse cache list.
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_delete_parse_cache (
+ void)
+{
+ ACPI_GENERIC_OP *next;
+
+
+ /* Traverse the global cache list */
+
+ while (acpi_gbl_parse_cache) {
+ /* Delete one cached state object */
+
+ next = acpi_gbl_parse_cache->next;
+ acpi_cm_free (acpi_gbl_parse_cache);
+ acpi_gbl_parse_cache = next;
+ }
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Utility functions
+ *
+ * DESCRIPTION: Low level functions
+ *
+ * TBD: [Restructure]
+ * 1) Some of these functions should be macros
+ * 2) Some can be simplified
+ *
+ ******************************************************************************/
+
+
+/*
+ * Is "c" a namestring lead character?
+ */
+
+
+u8
+acpi_ps_is_leading_char (
+ s32 c)
+{
+ return ((u8) (c == '_' || (c >= 'A' && c <= 'Z')));
+}
+
+
+/*
+ * Is "c" a namestring prefix character?
+ */
+u8
+acpi_ps_is_prefix_char (
+ s32 c)
+{
+ return ((u8) (c == '\\' || c == '^'));
+}
+
+
+u8
+acpi_ps_is_namespace_object_op (
+ u16 opcode)
+{
+ return ((u8)
+ (opcode == AML_SCOPE_OP ||
+ opcode == AML_DEVICE_OP ||
+ opcode == AML_THERMAL_ZONE_OP ||
+ opcode == AML_METHOD_OP ||
+ opcode == AML_POWER_RES_OP ||
+ opcode == AML_PROCESSOR_OP ||
+ opcode == AML_DEF_FIELD_OP ||
+ opcode == AML_INDEX_FIELD_OP ||
+ opcode == AML_BANK_FIELD_OP ||
+ opcode == AML_NAMEDFIELD_OP ||
+ opcode == AML_NAME_OP ||
+ opcode == AML_ALIAS_OP ||
+ opcode == AML_MUTEX_OP ||
+ opcode == AML_EVENT_OP ||
+ opcode == AML_REGION_OP ||
+ opcode == AML_CREATE_FIELD_OP ||
+ opcode == AML_BIT_FIELD_OP ||
+ opcode == AML_BYTE_FIELD_OP ||
+ opcode == AML_WORD_FIELD_OP ||
+ opcode == AML_DWORD_FIELD_OP ||
+ opcode == AML_METHODCALL_OP ||
+ opcode == AML_NAMEPATH_OP));
+}
+
+u8
+acpi_ps_is_namespace_op (
+ u16 opcode)
+{
+ return ((u8)
+ (opcode == AML_SCOPE_OP ||
+ opcode == AML_DEVICE_OP ||
+ opcode == AML_THERMAL_ZONE_OP ||
+ opcode == AML_METHOD_OP ||
+ opcode == AML_POWER_RES_OP ||
+ opcode == AML_PROCESSOR_OP ||
+ opcode == AML_DEF_FIELD_OP ||
+ opcode == AML_INDEX_FIELD_OP ||
+ opcode == AML_BANK_FIELD_OP ||
+ opcode == AML_NAME_OP ||
+ opcode == AML_ALIAS_OP ||
+ opcode == AML_MUTEX_OP ||
+ opcode == AML_EVENT_OP ||
+ opcode == AML_REGION_OP ||
+ opcode == AML_NAMEDFIELD_OP));
+}
+
+
+/*
+ * Is opcode for a named object Op?
+ * (Includes all named object opcodes)
+ *
+ * TBD: [Restructure] Need a better way than this brute force approach!
+ */
+u8
+acpi_ps_is_named_object_op (
+ u16 opcode)
+{
+ return ((u8)
+ (opcode == AML_SCOPE_OP ||
+ opcode == AML_DEVICE_OP ||
+ opcode == AML_THERMAL_ZONE_OP ||
+ opcode == AML_METHOD_OP ||
+ opcode == AML_POWER_RES_OP ||
+ opcode == AML_PROCESSOR_OP ||
+ opcode == AML_NAMEDFIELD_OP ||
+ opcode == AML_NAME_OP ||
+ opcode == AML_ALIAS_OP ||
+ opcode == AML_MUTEX_OP ||
+ opcode == AML_EVENT_OP ||
+ opcode == AML_REGION_OP ||
+
+
+ opcode == AML_CREATE_FIELD_OP ||
+ opcode == AML_BIT_FIELD_OP ||
+ opcode == AML_BYTE_FIELD_OP ||
+ opcode == AML_WORD_FIELD_OP ||
+ opcode == AML_DWORD_FIELD_OP ||
+ opcode == AML_METHODCALL_OP ||
+ opcode == AML_NAMEPATH_OP));
+}
+
+
+/*
+ * Is opcode for a named Op?
+ */
+u8
+acpi_ps_is_named_op (
+ u16 opcode)
+{
+ return ((u8)
+ (opcode == AML_SCOPE_OP ||
+ opcode == AML_DEVICE_OP ||
+ opcode == AML_THERMAL_ZONE_OP ||
+ opcode == AML_METHOD_OP ||
+ opcode == AML_POWER_RES_OP ||
+ opcode == AML_PROCESSOR_OP ||
+ opcode == AML_NAME_OP ||
+ opcode == AML_ALIAS_OP ||
+ opcode == AML_MUTEX_OP ||
+ opcode == AML_EVENT_OP ||
+ opcode == AML_REGION_OP ||
+ opcode == AML_NAMEDFIELD_OP));
+}
+
+
+u8
+acpi_ps_is_deferred_op (
+ u16 opcode)
+{
+ return ((u8)
+ (opcode == AML_METHOD_OP ||
+ opcode == AML_REGION_OP));
+}
+
+
+/*
+ * Is opcode for a bytelist?
+ */
+u8
+acpi_ps_is_bytelist_op (
+ u16 opcode)
+{
+ return ((u8) (opcode == AML_BYTELIST_OP));
+}
+
+
+/*
+ * Is opcode for a Field, Index_field, or Bank_field
+ */
+u8
+acpi_ps_is_field_op (
+ u16 opcode)
+{
+ return ((u8)
+ (opcode == AML_CREATE_FIELD_OP
+ || opcode == AML_DEF_FIELD_OP
+ || opcode == AML_INDEX_FIELD_OP
+ || opcode == AML_BANK_FIELD_OP));
+}
+
+
+/*
+ * Is field creation op
+ */
+u8
+acpi_ps_is_create_field_op (
+ u16 opcode)
+{
+ return ((u8)
+ (opcode == AML_CREATE_FIELD_OP ||
+ opcode == AML_BIT_FIELD_OP ||
+ opcode == AML_BYTE_FIELD_OP ||
+ opcode == AML_WORD_FIELD_OP ||
+ opcode == AML_DWORD_FIELD_OP));
+}
+
+
+/*
+ * Cast an acpi_op to an acpi_deferred_op if possible
+ */
+ACPI_DEFERRED_OP *
+acpi_ps_to_deferred_op (
+ ACPI_GENERIC_OP *op)
+{
+ return (acpi_ps_is_deferred_op (op->opcode)
+ ? ( (ACPI_DEFERRED_OP *) op) : NULL);
+}
+
+
+/*
+ * Cast an acpi_op to an acpi_named_op if possible
+ */
+ACPI_NAMED_OP*
+acpi_ps_to_named_op (
+ ACPI_GENERIC_OP *op)
+{
+ return (acpi_ps_is_named_op (op->opcode)
+ ? ( (ACPI_NAMED_OP *) op) : NULL);
+}
+
+
+/*
+ * Cast an acpi_op to an acpi_bytelist_op if possible
+ */
+ACPI_BYTELIST_OP*
+acpi_ps_to_bytelist_op (
+ ACPI_GENERIC_OP *op)
+{
+ return (acpi_ps_is_bytelist_op (op->opcode)
+ ? ( (ACPI_BYTELIST_OP*) op) : NULL);
+}
+
+
+/*
+ * Get op's name (4-byte name segment) or 0 if unnamed
+ */
+u32
+acpi_ps_get_name (
+ ACPI_GENERIC_OP *op)
+{
+ ACPI_NAMED_OP *named = acpi_ps_to_named_op (op);
+
+ return (named ? named->name : 0);
+}
+
+
+/*
+ * Set op's name
+ */
+void
+acpi_ps_set_name (
+ ACPI_GENERIC_OP *op,
+ u32 name)
+{
+ ACPI_NAMED_OP *named = acpi_ps_to_named_op (op);
+
+ if (named) {
+ named->name = name;
+ }
+}
+
diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c
new file mode 100644
index 000000000..da83c33b0
--- /dev/null
+++ b/drivers/acpi/parser/pswalk.c
@@ -0,0 +1,581 @@
+/******************************************************************************
+ *
+ * Module Name: pswalk - Parser routines to walk parsed op tree(s)
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "amlcode.h"
+#include "parser.h"
+#include "dispatch.h"
+#include "namesp.h"
+#include "interp.h"
+
+#define _COMPONENT PARSER
+ MODULE_NAME ("pswalk");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_get_next_walk_op
+ *
+ * PARAMETERS: Walk_state - Current state of the walk
+ * Op - Current Op to be walked
+ * Ascending_callback - Procedure called when Op is complete
+ * Prev_op - Where the previous Op is stored
+ * Next_op - Where the next Op in the walk is stored
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get the next Op in a walk of the parse tree.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ps_get_next_walk_op (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_GENERIC_OP *op,
+ INTERPRETER_CALLBACK ascending_callback)
+{
+ ACPI_GENERIC_OP *next;
+ ACPI_GENERIC_OP *parent;
+ ACPI_GENERIC_OP *grand_parent;
+ ACPI_STATUS status;
+
+
+ /* Check for a argument only if we are descending in the tree */
+
+ if (walk_state->next_op_info != NEXT_OP_UPWARD) {
+ /* Look for an argument or child of the current op */
+
+ next = acpi_ps_get_arg (op, 0);
+ if (next) {
+ /* Still going downward in tree (Op is not completed yet) */
+
+ walk_state->prev_op = op;
+ walk_state->next_op = next;
+ walk_state->next_op_info = NEXT_OP_DOWNWARD;
+
+ return (AE_OK);
+ }
+
+
+ /*
+ * No more children, this Op is complete. Save Next and Parent
+ * in case the Op object gets deleted by the callback routine
+ */
+
+ next = op->next;
+ parent = op->parent;
+
+ status = ascending_callback (walk_state, op);
+
+ switch (status)
+ {
+ case AE_CTRL_TERMINATE:
+
+ /*
+ * A control method was terminated via a RETURN statement.
+ * The walk of this method is complete.
+ */
+ walk_state->prev_op = walk_state->origin;
+ walk_state->next_op = NULL;
+
+ return (AE_OK);
+ break;
+
+
+ case AE_CTRL_FALSE:
+
+ /*
+ * Either an IF/WHILE Predicate was false or we encountered a BREAK
+ * opcode. In both cases, we do not execute the rest of the
+ * package; We simply close out the parent (finishing the walk of
+ * this branch of the tree) and continue execution at the parent
+ * level.
+ */
+
+ next = parent->next;
+ status = AE_OK;
+
+ /*
+ * If there is a sibling to the parent, we must close out the
+ * parent now, because we are going to continue to go downward (to
+ * the sibling) in the parse tree.
+ */
+ if (next) {
+ status = ascending_callback (walk_state, parent);
+
+ /* The parent sibling will be next */
+
+ walk_state->prev_op = op;
+ walk_state->next_op = next;
+ walk_state->next_op_info = NEXT_OP_DOWNWARD;
+
+ /* Continue downward */
+
+ return (AE_OK);
+ }
+
+ /*
+ * Drop into the loop below because we are moving upwards in
+ * the tree
+ */
+
+ break;
+
+
+ default:
+ /*
+ * Check for a sibling to the current op. A sibling means
+ * we are still going "downward" in the tree.
+ */
+
+ if (next) {
+ /* There is a sibling, it will be next */
+
+ walk_state->prev_op = op;
+ walk_state->next_op = next;
+ walk_state->next_op_info = NEXT_OP_DOWNWARD;
+
+ /* Continue downward */
+
+ return (status);
+ }
+
+ /*
+ * No sibling, but check status.
+ * Abort on error from callback routine
+ */
+ if (status != AE_OK) {
+ /* Next op will be the parent */
+
+ walk_state->prev_op = op;
+ walk_state->next_op = parent;
+ walk_state->next_op_info = NEXT_OP_UPWARD;
+
+ return (status);
+ }
+
+ /*
+ * Drop into the loop below because we are moving upwards in
+ * the tree
+ */
+
+ break;
+ }
+ }
+
+ else {
+ /*
+ * We are resuming a walk, and we were (are) going upward in the tree.
+ * So, we want to drop into the parent loop below.
+ */
+
+ parent = op;
+ }
+
+
+ /*
+ * Look for a sibling of the current Op's parent
+ * Continue moving up the tree until we find a node that has not been
+ * visited, or we get back to where we started.
+ */
+ while (parent) {
+ /* We are moving up the tree, therefore this parent Op is complete */
+
+ grand_parent = parent->parent;
+ next = parent->next;
+
+ status = ascending_callback (walk_state, parent);
+
+
+ switch (status)
+ {
+ case AE_CTRL_FALSE:
+
+ /*
+ * Either an IF/WHILE Predicate was false or we encountered a
+ * BREAK opcode. In both cases, we do not execute the rest of the
+ * package; We simply close out the parent (finishing the walk of
+ * this branch of the tree) and continue execution at the parent
+ * level.
+ */
+
+ parent = grand_parent;
+ next = grand_parent->next;
+ grand_parent = grand_parent->parent;
+
+ status = ascending_callback (walk_state, parent);
+
+ /* Now continue to the next node in the tree */
+
+ break;
+
+
+ case AE_CTRL_TRUE:
+
+ /*
+ * Predicate of a WHILE was true and the loop just completed an
+ * execution. Go back to the start of the loop and reevaluate the
+ * predicate.
+ */
+
+ op = walk_state->control_state->control.predicate_op;
+
+ walk_state->control_state->common.state = CONTROL_PREDICATE_EXECUTING;
+
+ /*
+ * Acpi_evaluate the predicate again (next)
+ * Because we will traverse WHILE tree again
+ */
+
+ walk_state->prev_op = op->parent;
+ walk_state->next_op = op;
+ walk_state->next_op_info = NEXT_OP_DOWNWARD;
+
+ return (AE_OK);
+ break;
+
+
+ case AE_CTRL_TERMINATE:
+
+ /*
+ * A control method was terminated via a RETURN statement.
+ * The walk of this method is complete.
+ */
+ walk_state->prev_op = walk_state->origin;
+ walk_state->next_op = NULL;
+
+ return (AE_OK);
+ break;
+ }
+
+
+ /*
+ * If we are back to the starting point, the walk is complete.
+ */
+ if (parent == walk_state->origin) {
+ /* Reached the point of origin, the walk is complete */
+
+ walk_state->prev_op = parent;
+ walk_state->next_op = NULL;
+
+ return (status);
+ }
+
+
+ /*
+ * If there is a sibling to this parent (it is not the starting point
+ * Op), then we will visit it.
+ */
+ if (next) {
+ /* found sibling of parent */
+
+ walk_state->prev_op = parent;
+ walk_state->next_op = next;
+ walk_state->next_op_info = NEXT_OP_DOWNWARD;
+
+ return (status);
+ }
+
+ /*
+ * No sibling, check for an error from closing the parent
+ * (Also, AE_PENDING if a method call was encountered)
+ */
+ if (status != AE_OK) {
+ walk_state->prev_op = parent;
+ walk_state->next_op = grand_parent;
+ walk_state->next_op_info = NEXT_OP_UPWARD;
+
+ return (status);
+ }
+
+ /* No siblings, no errors, just move up one more level in the tree */
+
+ op = parent;
+ parent = grand_parent;
+ walk_state->prev_op = op;
+ }
+
+
+ /* Got all the way to the top of the tree, we must be done! */
+ /* However, the code should have terminated in the loop above */
+
+ walk_state->next_op = NULL;
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_walk_loop
+ *
+ * PARAMETERS: Walk_list - State of the walk
+ * Start_op - Starting Op of the subtree to be walked
+ * Descending_callback - Procedure called when a new Op is
+ * encountered
+ * Ascending_callback - Procedure called when Op is complete
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Perform a walk of the parsed AML tree. Begins and terminates at
+ * the Start_op.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ps_walk_loop (
+ ACPI_WALK_LIST *walk_list,
+ ACPI_GENERIC_OP *start_op,
+ INTERPRETER_CALLBACK descending_callback,
+ INTERPRETER_CALLBACK ascending_callback)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_WALK_STATE *walk_state;
+ ACPI_GENERIC_OP *op = start_op;
+
+
+ walk_state = acpi_ds_get_current_walk_state (walk_list);
+
+
+ /* Walk entire subtree, visiting all nodes depth-first */
+
+ while (op) {
+ if (walk_state->next_op_info != NEXT_OP_UPWARD) {
+ status = descending_callback (walk_state, op);
+ }
+
+ /*
+ * A TRUE exception means that an ELSE was detected, but the IF
+ * predicate evaluated TRUE.
+ */
+ if (status == AE_CTRL_TRUE) {
+ /*
+ * Ignore the entire ELSE block by moving on to the the next opcode.
+ * And we do that by simply going up in the tree (either to the next
+ * sibling or to the parent) from here.
+ */
+
+ walk_state->next_op_info = NEXT_OP_UPWARD;
+ }
+
+ /* Get the next node (op) in the depth-first walk */
+
+ status = acpi_ps_get_next_walk_op (walk_state, op, ascending_callback);
+
+ /*
+ * A PENDING exception means that a control method invocation has been
+ * detected
+ */
+
+ if (status == AE_CTRL_PENDING) {
+ /* Transfer control to the called control method */
+
+ status = acpi_ds_call_control_method (walk_list, walk_state, op);
+
+ /*
+ * If the transfer to the new method method call worked, a new walk
+ * state was created -- get it
+ */
+
+ walk_state = acpi_ds_get_current_walk_state (walk_list);
+ }
+
+ /* Abort the walk on any exception */
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ op = walk_state->next_op;
+ }
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ps_walk_parsed_aml
+ *
+ * PARAMETERS: Start_op - Starting Op of the subtree to be walked
+ * End_op - Where to terminate the walk
+ * Descending_callback - Procedure called when a new Op is
+ * encountered
+ * Ascending_callback - Procedure called when Op is complete
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Top level interface to walk the parsed AML tree. Handles
+ * preemption of executing control methods.
+ *
+ * NOTE: The End_op is usually only different from the Start_op if
+ * we don't want to visit the Start_op during the tree descent.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ps_walk_parsed_aml (
+ ACPI_GENERIC_OP *start_op,
+ ACPI_GENERIC_OP *end_op,
+ ACPI_OBJECT_INTERNAL *mth_desc,
+ ACPI_NAME_TABLE *start_scope,
+ ACPI_OBJECT_INTERNAL **params,
+ ACPI_OBJECT_INTERNAL **caller_return_desc,
+ ACPI_OWNER_ID owner_id,
+ INTERPRETER_CALLBACK descending_callback,
+ INTERPRETER_CALLBACK ascending_callback)
+{
+ ACPI_GENERIC_OP *op;
+ ACPI_WALK_STATE *walk_state;
+ ACPI_OBJECT_INTERNAL *return_desc;
+ ACPI_STATUS status;
+ ACPI_WALK_LIST walk_list;
+ ACPI_WALK_LIST *prev_walk_list;
+
+
+ /* Parameter Validation */
+
+ if (!start_op || !end_op) {
+ return AE_BAD_PARAMETER;
+ }
+
+ /* Initialize a new walk list */
+
+ walk_list.walk_state = NULL;
+
+ walk_state = acpi_ds_create_walk_state (owner_id, end_op, mth_desc, &walk_list);
+ if (!walk_state) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* TBD: [Restructure] TEMP until we pass Walk_state to the interpreter
+ */
+ prev_walk_list = acpi_gbl_current_walk_list;
+ acpi_gbl_current_walk_list = &walk_list;
+
+ if (start_scope) {
+ /* Push start scope on scope stack and make it current */
+
+ status = acpi_ds_scope_stack_push (start_scope, ACPI_TYPE_METHOD, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ }
+
+ if (mth_desc) {
+ /* Init arguments if this is a control method */
+ /* TBD: [Restructure] add walkstate as a param */
+
+ acpi_ds_method_data_init_args (params, MTH_NUM_ARGS);
+ }
+
+ op = start_op;
+ status = AE_OK;
+
+
+ /*
+ * Execute the walk loop as long as there is a valid Walk State. This
+ * handles nested control method invocations without recursion.
+ */
+
+ while (walk_state) {
+ if (status == AE_OK) {
+ status = acpi_ps_walk_loop (&walk_list, op, descending_callback,
+ ascending_callback);
+ }
+
+ /* We are done with this walk, move on to the parent if any */
+
+ BREAKPOINT3;
+
+ walk_state = acpi_ds_pop_walk_state (&walk_list);
+
+ /* Extract return value before we delete Walk_state */
+
+ return_desc = walk_state->return_desc;
+
+ /* Reset the current scope to the beginning of scope stack */
+
+ acpi_ds_scope_stack_clear (walk_state);
+
+ /*
+ * If we just returned from the execution of a control method,
+ * there's lots of cleanup to do
+ */
+
+ if (walk_state->method_desc &&
+ walk_state->method_desc->method.parser_op)
+ {
+ acpi_ds_terminate_control_method (walk_state);
+ }
+
+ /* Delete this walk state and all linked control states */
+
+ acpi_ds_delete_walk_state (walk_state);
+
+ /* Check if we have restarted a preempted walk */
+
+ walk_state = acpi_ds_get_current_walk_state (&walk_list);
+ if (walk_state &&
+ status == AE_OK)
+ {
+ /* There is another walk state, restart it */
+
+ /*
+ * If the method returned value is not used by the parent,
+ * The object is deleted
+ */
+
+ acpi_ds_restart_control_method (walk_state, return_desc);
+
+ /* Get the next Op to process */
+
+ op = walk_state->next_op;
+ }
+
+ /*
+ * Just completed a 1st-level method, save the final internal return
+ * value (if any)
+ */
+
+ else if (caller_return_desc) {
+ *caller_return_desc = return_desc; /* NULL if no return value */
+ }
+
+ else if (return_desc) {
+ /* Caller doesn't want it, must delete it */
+
+ acpi_cm_remove_reference (return_desc);
+ }
+ }
+
+
+ acpi_gbl_current_walk_list = prev_walk_list;
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c
new file mode 100644
index 000000000..667df681e
--- /dev/null
+++ b/drivers/acpi/parser/psxface.c
@@ -0,0 +1,132 @@
+
+/******************************************************************************
+ *
+ * Module Name: psxface - Parser external interfaces
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "parser.h"
+#include "dispatch.h"
+#include "interp.h"
+#include "amlcode.h"
+#include "namesp.h"
+
+
+#define _COMPONENT PARSER
+ MODULE_NAME ("psxface");
+
+
+char *acpi_gbl_parser_id = "Non-recursive AML Parser";
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_psx_execute
+ *
+ * PARAMETERS: Obj_desc - A method object containing both the AML
+ * address and length.
+ * **Params - List of parameters to pass to method,
+ * terminated by NULL. Params itself may be
+ * NULL if no parameters are being passed.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute a control method
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_psx_execute (
+ ACPI_NAMED_OBJECT *method_entry,
+ ACPI_OBJECT_INTERNAL **params,
+ ACPI_OBJECT_INTERNAL **return_obj_desc)
+{
+ ACPI_STATUS status;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+ u32 i;
+
+
+ /* Validate the NTE and get the attached object */
+
+ if (!method_entry) {
+ return (AE_NULL_ENTRY);
+ }
+
+ obj_desc = acpi_ns_get_attached_object (method_entry);
+ if (!obj_desc) {
+ return (AE_NULL_OBJECT);
+ }
+
+ /* Parse method if necessary, wait on concurrency semaphore */
+
+ status = acpi_ds_begin_method_execution (method_entry, obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ if (params) {
+ /*
+ * The caller "owns" the parameters, so give each one an extra
+ * reference
+ */
+
+ for (i = 0; params[i]; i++) {
+ acpi_cm_add_reference (params[i]);
+ }
+ }
+
+ /*
+ * Method is parsed and ready to execute
+ * The walk of the parse tree is where we actually execute the method
+ */
+
+ status = acpi_ps_walk_parsed_aml (obj_desc->method.parser_op,
+ obj_desc->method.parser_op, obj_desc,
+ method_entry->child_table, params, return_obj_desc,
+ obj_desc->method.owning_id, acpi_ds_exec_begin_op,
+ acpi_ds_exec_end_op);
+
+ if (params) {
+ /* Take away the extra reference that we gave the parameters above */
+
+ for (i = 0; params[i]; i++) {
+ acpi_cm_update_object_reference (params[i], REF_DECREMENT);
+ }
+ }
+
+
+ /*
+ * Normal exit is with Status == AE_RETURN_VALUE when a Return_op has been
+ * executed, or with Status == AE_PENDING at end of AML block (end of
+ * Method code)
+ */
+
+ if (*return_obj_desc) {
+ status = AE_CTRL_RETURN_VALUE;
+ }
+
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c
new file mode 100644
index 000000000..70c8001aa
--- /dev/null
+++ b/drivers/acpi/resources/rsaddr.c
@@ -0,0 +1,810 @@
+/******************************************************************************
+ *
+ * Module Name: rsaddr - Acpi_rs_address16_resource
+ * Acpi_rs_address16_stream
+ * Acpi_rs_address32_resource
+ * Acpi_rs_address32_stream
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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"
+
+#define _COMPONENT RESOURCE_MANAGER
+ MODULE_NAME ("rsaddr");
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_address16_resource
+ *
+ * PARAMETERS:
+ * Byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes consumed from
+ * the Byte_stream_buffer
+ * Output_buffer - Pointer to the user's return buffer
+ * Structure_size - u32 pointer that is filled with
+ * the number of bytes in the filled
+ * in structure
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the Output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_address16_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ RESOURCE *output_struct = (RESOURCE *) * output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u32 index;
+ u32 struct_size = sizeof(ADDRESS16_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+
+
+ /*
+ * Point past the Descriptor to get the number of bytes consumed
+ */
+ buffer += 1;
+
+ temp16 = *(u16 *)buffer;
+
+ *bytes_consumed = temp16 + 3;
+
+ output_struct->id = address16;
+
+ output_struct->length = struct_size;
+
+ /*
+ * Get the Resource Type (Byte3)
+ */
+ buffer += 2;
+ temp8 = *buffer;
+
+ /* Values 0-2 are valid */
+ if (temp8 > 2) {
+ return (AE_ERROR);
+ }
+
+ output_struct->data.address16.resource_type = temp8 & 0x03;
+
+ /*
+ * Get the General Flags (Byte4)
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ /*
+ * Producer / Consumer
+ */
+ output_struct->data.address16.producer_consumer = temp8 & 0x01;
+
+ /*
+ * Decode
+ */
+ output_struct->data.address16.decode = (temp8 >> 1) & 0x01;
+
+ /*
+ * Min Address Fixed
+ */
+ output_struct->data.address16.min_address_fixed = (temp8 >> 2) & 0x01;
+
+ /*
+ * Max Address Fixed
+ */
+ output_struct->data.address16.max_address_fixed = (temp8 >> 3) & 0x01;
+
+ /*
+ * Get the Type Specific Flags (Byte5)
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ if (MEMORY_RANGE == output_struct->data.address16.resource_type) {
+ output_struct->data.address16.attribute.memory.read_write_attribute =
+ (u16) (temp8 & 0x01);
+ output_struct->data.address16.attribute.memory.cache_attribute =
+ (u16) ((temp8 >> 1) & 0x0F);
+ }
+
+ else {
+ if (IO_RANGE == output_struct->data.address16.resource_type) {
+ output_struct->data.address16.attribute.io.range_attribute =
+ (u16) (temp8 & 0x03);
+ }
+
+ else {
+ /* BUS_NUMBER_RANGE == Address32_data->Resource_type */
+ /* Nothing needs to be filled in */
+ }
+ }
+
+ /*
+ * Get Granularity (Bytes 6-7)
+ */
+ buffer += 1;
+ MOVE_UNALIGNED16_TO_16 (&output_struct->data.address16.granularity,
+ buffer);
+
+ /*
+ * Get Min_address_range (Bytes 8-9)
+ */
+ buffer += 2;
+ MOVE_UNALIGNED16_TO_16 (&output_struct->data.address16.min_address_range,
+ buffer);
+
+ /*
+ * Get Max_address_range (Bytes 10-11)
+ */
+ buffer += 2;
+ MOVE_UNALIGNED16_TO_16
+ (&output_struct->data.address16.max_address_range,
+ buffer);
+
+ /*
+ * Get Address_translation_offset (Bytes 12-13)
+ */
+ buffer += 2;
+ MOVE_UNALIGNED16_TO_16
+ (&output_struct->data.address16.address_translation_offset,
+ buffer);
+
+ /*
+ * Get Address_length (Bytes 14-15)
+ */
+ buffer += 2;
+ MOVE_UNALIGNED16_TO_16
+ (&output_struct->data.address16.address_length,
+ buffer);
+
+ /*
+ * Resource Source Index (if present)
+ */
+ buffer += 2;
+
+ /*
+ * This will leave us pointing to the Resource Source Index
+ * If it is present, then save it off and calculate the
+ * pointer to where the null terminated string goes:
+ * Each Interrupt takes 32-bits + the 5 bytes of the
+ * stream that are default.
+ */
+ if (*bytes_consumed > 16) {
+ /* Dereference the Index */
+
+ temp8 = *buffer;
+ output_struct->data.address16.resource_source_index =
+ (u32) temp8;
+
+ /* Point to the String */
+
+ buffer += 1;
+
+ /* Copy the string into the buffer */
+
+ index = 0;
+
+ while (0x00 != *buffer) {
+ output_struct->data.address16.resource_source[index] =
+ *buffer;
+
+ buffer += 1;
+ index += 1;
+ }
+
+ /*
+ * Add the terminating null
+ */
+ output_struct->data.address16.resource_source[index] = 0x00;
+
+ output_struct->data.address16.resource_source_string_length =
+ index + 1;
+
+ /*
+ * In order for the Struct_size to fall on a 32-bit boundry,
+ * calculate the length of the string and expand the
+ * Struct_size to the next 32-bit boundry.
+ */
+ temp8 = (u8) (index + 1);
+ struct_size += ROUND_UP_TO_32_bITS (temp8);
+ }
+ else {
+ output_struct->data.address16.resource_source_index = 0x00;
+ output_struct->data.address16.resource_source_string_length = 0;
+ output_struct->data.address16.resource_source[0] = 0x00;
+ }
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_address16_stream
+ *
+ * PARAMETERS:
+ * Linked_list - Pointer to the resource linked list
+ * Output_buffer - Pointer to the user's return buffer
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes of the
+ * Output_buffer used
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_address16_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u8 *length_field;
+ u8 temp8 = 0;
+ u8 *temp_pointer = NULL;
+ u32 actual_bytes;
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x88;
+ buffer += 1;
+
+ /*
+ * Save a pointer to the Length field - to be filled in later
+ */
+ length_field = buffer;
+ buffer += 2;
+
+ /*
+ * Set the Resource Type (Memory, Io, Bus_number)
+ */
+ temp8 = (u8) (linked_list->data.address16.resource_type & 0x03);
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the general flags
+ */
+ temp8 = (u8) (linked_list->data.address16.producer_consumer & 0x01);
+
+ temp8 |= (linked_list->data.address16.decode & 0x01) << 1;
+ temp8 |= (linked_list->data.address16.min_address_fixed & 0x01) << 2;
+ temp8 |= (linked_list->data.address16.max_address_fixed & 0x01) << 3;
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the type specific flags
+ */
+ temp8 = 0;
+
+ if (MEMORY_RANGE == linked_list->data.address16.resource_type) {
+ temp8 = (u8)
+ (linked_list->data.address16.attribute.memory.read_write_attribute &
+ 0x01);
+
+ temp8 |=
+ (linked_list->data.address16.attribute.memory.cache_attribute &
+ 0x0F) << 1;
+ }
+
+ else if (IO_RANGE == linked_list->data.address16.resource_type) {
+ temp8 = (u8)
+ (linked_list->data.address16.attribute.io.range_attribute &
+ 0x03);
+ }
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the address space granularity
+ */
+ MOVE_UNALIGNED16_TO_16 (buffer,
+ &linked_list->data.address16.granularity);
+ buffer += 2;
+
+ /*
+ * Set the address range minimum
+ */
+ MOVE_UNALIGNED16_TO_16 (buffer,
+ &linked_list->data.address16.min_address_range);
+
+ buffer += 2;
+
+ /*
+ * Set the address range maximum
+ */
+ MOVE_UNALIGNED16_TO_16 (buffer,
+ &linked_list->data.address16.max_address_range);
+
+ buffer += 2;
+
+ /*
+ * Set the address translation offset
+ */
+ MOVE_UNALIGNED16_TO_16 (buffer,
+ &linked_list->data.address16.address_translation_offset);
+
+ buffer += 2;
+
+ /*
+ * Set the address length
+ */
+ MOVE_UNALIGNED16_TO_16 (buffer,
+ &linked_list->data.address16.address_length);
+
+ buffer += 2;
+
+ /*
+ * Resource Source Index and Resource Source are optional
+ */
+ if (0 != linked_list->data.address16.resource_source_string_length) {
+ temp8 = (u8) linked_list->data.address16.resource_source_index;
+
+ *buffer = temp8;
+ buffer += 1;
+
+ temp_pointer = buffer;
+
+ /*
+ * Copy the string
+ */
+ STRCPY (temp_pointer, linked_list->data.address16.resource_source);
+
+ /*
+ * Buffer needs to be set to the length of the sting + one for the
+ * terminating null
+ */
+ buffer += (STRLEN (linked_list->data.address16.resource_source) + 1);
+ }
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ actual_bytes = (u32) ((NATIVE_UINT) buffer -
+ (NATIVE_UINT) *output_buffer);
+
+ *bytes_consumed = actual_bytes;
+
+ /*
+ * Set the length field to the number of bytes consumed
+ * minus the header size (3 bytes)
+ */
+ actual_bytes -= 3;
+ MOVE_UNALIGNED16_TO_16 (length_field, &actual_bytes);
+
+ return (AE_OK);
+}
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_address32_resource
+ *
+ * PARAMETERS:
+ * Byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes consumed from
+ * the Byte_stream_buffer
+ * Output_buffer - Pointer to the user's return buffer
+ * Structure_size - u32 pointer that is filled with
+ * the number of bytes in the filled
+ * in structure
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the Output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_address32_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ RESOURCE *output_struct = (RESOURCE *) * output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u32 struct_size = sizeof (ADDRESS32_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+ u32 index;
+
+
+ /*
+ * Point past the Descriptor to get the number of bytes consumed
+ */
+ buffer += 1;
+ MOVE_UNALIGNED16_TO_16 (&temp16, buffer);
+
+ *bytes_consumed = temp16 + 3;
+
+ output_struct->id = address32;
+
+ /*
+ * Get the Resource Type (Byte3)
+ */
+ buffer += 2;
+ temp8 = *buffer;
+
+ /* Values 0-2 are valid */
+ if(temp8 > 2) {
+ return (AE_ERROR);
+ }
+
+ output_struct->data.address32.resource_type = temp8 & 0x03;
+
+ /*
+ * Get the General Flags (Byte4)
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ /*
+ * Producer / Consumer
+ */
+ output_struct->data.address32.producer_consumer = temp8 & 0x01;
+
+ /*
+ * Decode
+ */
+ output_struct->data.address32.decode = (temp8 >> 1) & 0x01;
+
+ /*
+ * Min Address Fixed
+ */
+ output_struct->data.address32.min_address_fixed = (temp8 >> 2) & 0x01;
+
+ /*
+ * Max Address Fixed
+ */
+ output_struct->data.address32.max_address_fixed = (temp8 >> 3) & 0x01;
+
+ /*
+ * Get the Type Specific Flags (Byte5)
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ if (MEMORY_RANGE == output_struct->data.address32.resource_type) {
+ output_struct->data.address32.attribute.memory.read_write_attribute =
+ (u16) (temp8 & 0x01);
+
+ output_struct->data.address32.attribute.memory.cache_attribute =
+ (u16) ((temp8 >> 1) & 0x0F);
+ }
+
+ else {
+ if (IO_RANGE == output_struct->data.address32.resource_type) {
+ output_struct->data.address32.attribute.io.range_attribute =
+ (u16) (temp8 & 0x03);
+ }
+
+ else {
+ /* BUS_NUMBER_RANGE == Output_struct->Data.Address32.Resource_type */
+ /* Nothing needs to be filled in */
+ }
+ }
+
+ /*
+ * Get Granularity (Bytes 6-9)
+ */
+ buffer += 1;
+ MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.granularity,
+ buffer);
+
+ /*
+ * Get Min_address_range (Bytes 10-13)
+ */
+ buffer += 4;
+ MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.min_address_range,
+ buffer);
+
+ /*
+ * Get Max_address_range (Bytes 14-17)
+ */
+ buffer += 4;
+ MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.max_address_range,
+ buffer);
+
+ /*
+ * Get Address_translation_offset (Bytes 18-21)
+ */
+ buffer += 4;
+ MOVE_UNALIGNED32_TO_32
+ (&output_struct->data.address32.address_translation_offset,
+ buffer);
+
+ /*
+ * Get Address_length (Bytes 22-25)
+ */
+ buffer += 4;
+ MOVE_UNALIGNED32_TO_32 (&output_struct->data.address32.address_length,
+ buffer);
+
+ /*
+ * Resource Source Index (if present)
+ */
+ buffer += 4;
+
+ /*
+ * This will leave us pointing to the Resource Source Index
+ * If it is present, then save it off and calculate the
+ * pointer to where the null terminated string goes:
+ * Each Interrupt takes 32-bits + the 5 bytes of the
+ * stream that are default.
+ */
+ if (*bytes_consumed > 26) {
+ /* Dereference the Index */
+
+ temp8 = *buffer;
+ output_struct->data.address32.resource_source_index = (u32)temp8;
+
+ /* Point to the String */
+
+ buffer += 1;
+
+ /* Copy the string into the buffer */
+
+ index = 0;
+
+ while (0x00 != *buffer) {
+ output_struct->data.address32.resource_source[index] = *buffer;
+ buffer += 1;
+ index += 1;
+ }
+
+ /*
+ * Add the terminating null
+ */
+ output_struct->data.address32.resource_source[index] = 0x00;
+
+ output_struct->data.address32.resource_source_string_length = index + 1;
+
+ /*
+ * In order for the Struct_size to fall on a 32-bit boundry,
+ * calculate the length of the string and expand the
+ * Struct_size to the next 32-bit boundry.
+ */
+ temp8 = (u8) (index + 1);
+ struct_size += ROUND_UP_TO_32_bITS (temp8);
+ }
+
+ else {
+ output_struct->data.address32.resource_source_index = 0x00;
+ output_struct->data.address32.resource_source_string_length = 0;
+ output_struct->data.address32.resource_source[0] = 0x00;
+ }
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_address32_stream
+ *
+ * PARAMETERS:
+ * Linked_list - Pointer to the resource linked list
+ * Output_buffer - Pointer to the user's return buffer
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes of the
+ * Output_buffer used
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_address32_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 *length_field;
+ u8 temp8 = 0;
+ u8 *temp_pointer = NULL;
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x87;
+
+ buffer += 1;
+
+ /*
+ * Set a pointer to the Length field - to be filled in later
+ */
+
+ length_field = (u16 *)buffer;
+
+ buffer += 2;
+
+ /*
+ * Set the Resource Type (Memory, Io, Bus_number)
+ */
+ temp8 = (u8) (linked_list->data.address32.resource_type & 0x03);
+
+ *buffer = temp8;
+
+ buffer += 1;
+
+ /*
+ * Set the general flags
+ */
+ temp8 = (u8) (linked_list->data.address32.producer_consumer & 0x01);
+
+ temp8 |= (linked_list->data.address32.decode & 0x01) << 1;
+
+ temp8 |= (linked_list->data.address32.min_address_fixed & 0x01) << 2;
+
+ temp8 |= (linked_list->data.address32.max_address_fixed & 0x01) << 3;
+
+ *buffer = temp8;
+
+ buffer += 1;
+
+ /*
+ * Set the type specific flags
+ */
+ temp8 = 0;
+
+ if(MEMORY_RANGE == linked_list->data.address32.resource_type) {
+ temp8 = (u8)
+ (linked_list->data.address32.attribute.memory.read_write_attribute &
+ 0x01);
+
+ temp8 |=
+ (linked_list->data.address32.attribute.memory.cache_attribute &
+ 0x0F) << 1;
+ }
+
+ else if (IO_RANGE == linked_list->data.address32.resource_type) {
+ temp8 = (u8)
+ (linked_list->data.address32.attribute.io.range_attribute &
+ 0x03);
+ }
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the address space granularity
+ */
+ MOVE_UNALIGNED32_TO_32 (buffer,
+ &linked_list->data.address32.granularity);
+ buffer += 4;
+
+ /*
+ * Set the address range minimum
+ */
+ MOVE_UNALIGNED32_TO_32 (buffer,
+ &linked_list->data.address32.min_address_range);
+
+ buffer += 4;
+
+ /*
+ * Set the address range maximum
+ */
+ MOVE_UNALIGNED32_TO_32 (buffer,
+ &linked_list->data.address32.max_address_range);
+
+ buffer += 4;
+
+ /*
+ * Set the address translation offset
+ */
+ MOVE_UNALIGNED32_TO_32 (buffer,
+ &linked_list->data.address32.address_translation_offset);
+
+ buffer += 4;
+
+ /*
+ * Set the address length
+ */
+ MOVE_UNALIGNED32_TO_32 (buffer,
+ &linked_list->data.address32.address_length);
+
+ buffer += 4;
+
+ /*
+ * Resource Source Index and Resource Source are optional
+ */
+ if (0 != linked_list->data.address32.resource_source_string_length) {
+ temp8 = (u8) linked_list->data.address32.resource_source_index;
+
+ *buffer = temp8;
+
+ buffer += 1;
+
+ temp_pointer = buffer;
+
+ /*
+ * Copy the string
+ */
+ STRCPY (temp_pointer, linked_list->data.address32.resource_source);
+
+ /*
+ * Buffer needs to be set to the length of the sting + one for the
+ * terminating null
+ */
+ buffer += (STRLEN (linked_list->data.address32.resource_source) + 1);
+ }
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = (u32) ((NATIVE_UINT) buffer -
+ (NATIVE_UINT) *output_buffer);
+
+ /*
+ * Set the length field to the number of bytes consumed
+ * minus the header size (3 bytes)
+ */
+ *length_field = (u16) (*bytes_consumed - 3);
+
+ return (AE_OK);
+}
+
diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c
new file mode 100644
index 000000000..3893d2799
--- /dev/null
+++ b/drivers/acpi/resources/rscalc.c
@@ -0,0 +1,754 @@
+/******************************************************************************
+ *
+ * Module Name: rscalc - Acpi_rs_calculate_byte_stream_length
+ * Acpi_rs_calculate_list_length
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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"
+
+#define _COMPONENT RESOURCE_MANAGER
+ MODULE_NAME ("rscalc");
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_calculate_byte_stream_length
+ *
+ * PARAMETERS:
+ * Linked_list - Pointer to the resource linked list
+ * Size_needed - u32 pointer of the size buffer needed
+ * to properly return the parsed data
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Takes the resource byte stream and parses it once, calculating
+ * the size buffer needed to hold the linked list that conveys
+ * the resource data.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_calculate_byte_stream_length (
+ RESOURCE *linked_list,
+ u32 *size_needed)
+{
+ ACPI_STATUS status = AE_OK;
+ u32 byte_stream_size_needed = 0;
+ u32 size_of_this_bit;
+ EXTENDED_IRQ_RESOURCE *ex_irq = NULL;
+ u8 done = FALSE;
+
+
+ while (!done) {
+
+ /*
+ * Init the variable that will hold the size to add to the
+ * total.
+ */
+ size_of_this_bit = 0;
+
+ switch (linked_list->id)
+ {
+ case irq:
+ /*
+ * IRQ Resource
+ */
+ /*
+ * For an IRQ Resource, Byte 3, although optional, will
+ * always be created - it holds IRQ information.
+ */
+ size_of_this_bit = 4;
+ break;
+
+ case dma:
+ /*
+ * DMA Resource
+ */
+ /*
+ * For this resource the size is static
+ */
+ size_of_this_bit = 3;
+ break;
+
+ case start_dependent_functions:
+ /*
+ * Start Dependent Functions Resource
+ */
+ /*
+ * For a Start_dependent_functions Resource, Byte 1,
+ * although optional, will always be created.
+ */
+ size_of_this_bit = 2;
+ break;
+
+ case end_dependent_functions:
+ /*
+ * End Dependent Functions Resource
+ */
+ /*
+ * For this resource the size is static
+ */
+ size_of_this_bit = 1;
+ break;
+
+ case io:
+ /*
+ * IO Port Resource
+ */
+ /*
+ * For this resource the size is static
+ */
+ size_of_this_bit = 8;
+ break;
+
+ case fixed_io:
+ /*
+ * Fixed IO Port Resource
+ */
+ /*
+ * For this resource the size is static
+ */
+ size_of_this_bit = 4;
+ break;
+
+ case vendor_specific:
+ /*
+ * Vendor Defined Resource
+ */
+ /*
+ * For a Vendor Specific resource, if the Length is
+ * between 1 and 7 it will be created as a Small
+ * Resource data type, otherwise it is a Large
+ * Resource data type.
+ */
+ if(linked_list->data.vendor_specific.length > 7) {
+ size_of_this_bit = 3;
+ }
+ else {
+ size_of_this_bit = 1;
+ }
+ size_of_this_bit +=
+ linked_list->data.vendor_specific.length;
+ break;
+
+ case end_tag:
+ /*
+ * End Tag
+ */
+ /*
+ * For this resource the size is static
+ */
+ size_of_this_bit = 2;
+ done = TRUE;
+ break;
+
+ case memory24:
+ /*
+ * 24-Bit Memory Resource
+ */
+ /*
+ * For this resource the size is static
+ */
+ size_of_this_bit = 12;
+ break;
+
+ case memory32:
+ /*
+ * 32-Bit Memory Range Resource
+ */
+ /*
+ * For this resource the size is static
+ */
+ size_of_this_bit = 20;
+ break;
+
+ case fixed_memory32:
+ /*
+ * 32-Bit Fixed Memory Resource
+ */
+ /*
+ * For this resource the size is static
+ */
+ size_of_this_bit = 12;
+ break;
+
+ case address16:
+ /*
+ * 16-Bit Address Resource
+ */
+ /*
+ * The base size of this byte stream is 16. If a
+ * Resource Source string is not NULL, add 1 for
+ * the Index + the length of the null terminated
+ * string Resource Source + 1 for the null.
+ */
+ size_of_this_bit = 16;
+
+ if(NULL != linked_list->data.address16.resource_source) {
+ size_of_this_bit += (1 +
+ linked_list->data.address16.resource_source_string_length);
+ }
+ break;
+
+ case address32:
+ /*
+ * 32-Bit Address Resource
+ */
+ /*
+ * The base size of this byte stream is 26. If a Resource
+ * Source string is not NULL, add 1 for the Index + the
+ * length of the null terminated string Resource Source +
+ * 1 for the null.
+ */
+ size_of_this_bit = 26;
+
+ if(NULL != linked_list->data.address16.resource_source) {
+ size_of_this_bit += (1 +
+ linked_list->data.address16.resource_source_string_length);
+ }
+ break;
+
+ case extended_irq:
+ /*
+ * Extended IRQ Resource
+ */
+ /*
+ * The base size of this byte stream is 9. This is for an
+ * Interrupt table length of 1. For each additional
+ * interrupt, add 4.
+ * If a Resource Source string is not NULL, add 1 for the
+ * Index + the length of the null terminated string
+ * Resource Source + 1 for the null.
+ */
+ size_of_this_bit = 9;
+
+ size_of_this_bit +=
+ (linked_list->data.extended_irq.number_of_interrupts -
+ 1) * 4;
+
+ if(NULL != ex_irq->resource_source) {
+ size_of_this_bit += (1 +
+ linked_list->data.extended_irq.resource_source_string_length);
+ }
+ break;
+
+ default:
+ /*
+ * If we get here, everything is out of sync,
+ * so exit with an error
+ */
+ return (AE_ERROR);
+ break;
+
+ } /* switch (Linked_list->Id) */
+
+ /*
+ * Update the total
+ */
+ byte_stream_size_needed += size_of_this_bit;
+
+ /*
+ * Point to the next object
+ */
+ linked_list = (RESOURCE *) ((NATIVE_UINT) linked_list +
+ (NATIVE_UINT) linked_list->length);
+ }
+
+ /*
+ * This is the data the caller needs
+ */
+ *size_needed = byte_stream_size_needed;
+
+ return (status);
+
+} /* Acpi_rs_calculate_byte_stream_length */
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_calculate_list_length
+ *
+ * PARAMETERS:
+ * Byte_stream_buffer - Pointer to the resource byte stream
+ * Byte_stream_buffer_length - Size of Byte_stream_buffer
+ * Size_needed - u32 pointer of the size buffer
+ * needed to properly return the
+ * parsed data
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Takes the resource byte stream and parses it once, calculating
+ * the size buffer needed to hold the linked list that conveys
+ * the resource data.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_calculate_list_length (
+ u8 *byte_stream_buffer,
+ u32 byte_stream_buffer_length,
+ u32 *size_needed)
+{
+ u32 buffer_size = 0;
+ u32 bytes_parsed = 0;
+ u8 resource_type = 0;
+ u32 structure_size = 0;
+ u32 bytes_consumed = 0;
+ u8 *buffer;
+ u8 number_of_interrupts = 0;
+ u8 temp8;
+ u16 temp16;
+ u8 index;
+ u8 number_of_channels = 0;
+ u8 additional_bytes = 0;
+
+
+ while (bytes_parsed < byte_stream_buffer_length) {
+ /*
+ * Look at the next byte in the stream
+ */
+ resource_type = *byte_stream_buffer;
+
+ /*
+ * See if this is a small or large resource
+ */
+ if(resource_type & 0x80) {
+ /*
+ * Large Resource Type
+ */
+ switch (resource_type)
+ {
+ case MEMORY_RANGE_24:
+ /*
+ * 24-Bit Memory Resource
+ */
+ bytes_consumed = 12;
+
+ structure_size = sizeof (MEMORY24_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+
+ break;
+
+ case LARGE_VENDOR_DEFINED:
+ /*
+ * Vendor Defined Resource
+ */
+ buffer = byte_stream_buffer;
+ ++buffer;
+
+ MOVE_UNALIGNED16_TO_16 (&temp16, buffer);
+ bytes_consumed = temp16 + 3;
+
+ /*
+ * Ensure a 32-bit boundary for the structure
+ */
+ temp16 = (u16) ROUND_UP_TO_32_bITS (temp16);
+
+ structure_size = sizeof (VENDOR_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA +
+ (temp16 * sizeof (u8));
+ break;
+
+ case MEMORY_RANGE_32:
+ /*
+ * 32-Bit Memory Range Resource
+ */
+
+ bytes_consumed = 20;
+
+ structure_size = sizeof (MEMORY32_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+ break;
+
+ case FIXED_MEMORY_RANGE_32:
+ /*
+ * 32-Bit Fixed Memory Resource
+ */
+ bytes_consumed = 12;
+
+ structure_size = sizeof(FIXED_MEMORY32_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+ break;
+
+ case DWORD_ADDRESS_SPACE:
+ /*
+ * 32-Bit Address Resource
+ */
+ buffer = byte_stream_buffer;
+
+ ++buffer;
+ MOVE_UNALIGNED16_TO_16 (&temp16, buffer);
+
+ bytes_consumed = temp16 + 3;
+
+ /*
+ * Resource Source Index and Resource Source are
+ * optional elements. Check the length of the
+ * Bytestream. If it is greater than 23, that
+ * means that an Index exists and is followed by
+ * a null termininated string. Therefore, set
+ * the temp variable to the length minus the minimum
+ * byte stream length plus the byte for the Index to
+ * determine the size of the NULL terminiated string.
+ */
+ if (23 < temp16) {
+ temp8 = (u8) (temp16 - 24);
+ }
+ else {
+ temp8 = 0;
+ }
+
+ /*
+ * Ensure a 32-bit boundary for the structure
+ */
+ temp8 = (u8) ROUND_UP_TO_32_bITS (temp8);
+
+ structure_size = sizeof (ADDRESS32_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA +
+ (temp8 * sizeof (u8));
+ break;
+
+ case WORD_ADDRESS_SPACE:
+ /*
+ * 16-Bit Address Resource
+ */
+ buffer = byte_stream_buffer;
+
+ ++buffer;
+ MOVE_UNALIGNED16_TO_16 (&temp16, buffer);
+
+ bytes_consumed = temp16 + 3;
+
+ /*
+ * Resource Source Index and Resource Source are
+ * optional elements. Check the length of the
+ * Bytestream. If it is greater than 13, that
+ * means that an Index exists and is followed by
+ * a null termininated string. Therefore, set
+ * the temp variable to the length minus the minimum
+ * byte stream length plus the byte for the Index to
+ * determine the size of the NULL terminiated string.
+ */
+ if (13 < temp16) {
+ temp8 = (u8) (temp16 - 14);
+ }
+ else {
+ temp8 = 0;
+ }
+
+ /*
+ * Ensure a 32-bit boundry for the structure
+ */
+ temp8 = (u8) ROUND_UP_TO_32_bITS (temp8);
+
+ structure_size = sizeof (ADDRESS16_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA +
+ (temp8 * sizeof (u8));
+ break;
+
+ case EXTENDED_IRQ:
+ /*
+ * Extended IRQ
+ */
+ buffer = byte_stream_buffer;
+
+ ++buffer;
+ MOVE_UNALIGNED16_TO_16 (&temp16, buffer);
+
+ bytes_consumed = temp16 + 3;
+
+ /*
+ * Point past the length field and the
+ * Interrupt vector flags to save off the
+ * Interrupt table length to the Temp8 variable.
+ */
+ buffer += 3;
+
+ temp8 = *buffer;
+
+ /*
+ * To compensate for multiple interrupt numbers,
+ * Add 4 bytes for each additional interrupts
+ * greater than 1
+ */
+ additional_bytes = (u8) ((temp8 - 1) * 4);
+
+ /*
+ * Resource Source Index and Resource Source are
+ * optional elements. Check the length of the
+ * Bytestream. If it is greater than 9, that
+ * means that an Index exists and is followed by
+ * a null termininated string. Therefore, set
+ * the temp variable to the length minus the minimum
+ * byte stream length plus the byte for the Index to
+ * determine the size of the NULL terminiated string.
+ */
+ if (9 + additional_bytes < temp16) {
+ temp8 = (u8) (temp16 - (9 + additional_bytes));
+ }
+
+ else {
+ temp8 = 0;
+ }
+
+ /*
+ * Ensure a 32-bit boundry for the structure
+ */
+ temp8 = (u8) ROUND_UP_TO_32_bITS (temp8);
+
+ structure_size = sizeof (EXTENDED_IRQ_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA +
+ (additional_bytes * sizeof (u8)) +
+ (temp8 * sizeof (u8));
+
+ break;
+
+/* 64-bit not currently supported */
+/*
+ case 0x8A:
+ break;
+*/
+
+ default:
+ /*
+ * If we get here, everything is out of sync,
+ * so exit with an error
+ */
+ return (AE_ERROR);
+ break;
+ }
+ }
+
+ else {
+ /*
+ * Small Resource Type
+ * Only bits 7:3 are valid
+ */
+ resource_type >>= 3;
+
+ switch (resource_type)
+ {
+ case IRQ_FORMAT:
+ /*
+ * IRQ Resource
+ */
+ /*
+ * Determine if it there are two or three
+ * trailing bytes
+ */
+ buffer = byte_stream_buffer;
+
+ temp8 = *buffer;
+
+ if(temp8 & 0x01) {
+ bytes_consumed = 4;
+ }
+
+ else {
+ bytes_consumed = 3;
+ }
+
+ /*
+ * Point past the descriptor
+ */
+ ++buffer;
+
+ /*
+ * Look at the number of bits set
+ */
+ MOVE_UNALIGNED16_TO_16 (&temp16, buffer);
+
+ for (index = 0; index < 16; index++) {
+ if (temp16 & 0x1) {
+ ++number_of_interrupts;
+ }
+
+ temp16 >>= 1;
+ }
+
+ structure_size = sizeof (IO_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA +
+ (number_of_interrupts * sizeof (u32));
+
+ break;
+
+
+ case DMA_FORMAT:
+
+ /*
+ * DMA Resource
+ */
+ buffer = byte_stream_buffer;
+
+ bytes_consumed = 3;
+
+ /*
+ * Point past the descriptor
+ */
+ ++buffer;
+
+ /*
+ * Look at the number of bits set
+ */
+ temp8 = *buffer;
+
+ for(index = 0; index < 8; index++) {
+ if(temp8 & 0x1) {
+ ++number_of_channels;
+ }
+
+ temp8 >>= 1;
+ }
+
+ structure_size = sizeof (DMA_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA +
+ (number_of_channels * sizeof (u32));
+
+ break;
+
+
+ case START_DEPENDENT_TAG:
+
+ /*
+ * Start Dependent Functions Resource
+ */
+ /*
+ * Determine if it there are two or three trailing bytes
+ */
+ buffer = byte_stream_buffer;
+
+ temp8 = *buffer;
+
+ if(temp8 & 0x01) {
+ bytes_consumed = 2;
+ }
+ else {
+ bytes_consumed = 1;
+ }
+
+
+ structure_size =
+ sizeof (START_DEPENDENT_FUNCTIONS_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+ break;
+
+
+ case END_DEPENDENT_TAG:
+
+ /*
+ * End Dependent Functions Resource
+ */
+ bytes_consumed = 1;
+
+ structure_size = RESOURCE_LENGTH;
+ break;
+
+
+ case IO_PORT_DESCRIPTOR:
+ /*
+ * IO Port Resource
+ */
+ bytes_consumed = 8;
+
+ structure_size = sizeof (IO_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+ break;
+
+
+ case FIXED_LOCATION_IO_DESCRIPTOR:
+
+ /*
+ * Fixed IO Port Resource
+ */
+ bytes_consumed = 4;
+
+ structure_size = sizeof (FIXED_IO_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+ break;
+
+
+ case SMALL_VENDOR_DEFINED:
+
+ /*
+ * Vendor Specific Resource
+ */
+ buffer = byte_stream_buffer;
+
+ temp8 = *buffer;
+ temp8 = (u8) (temp8 & 0x7);
+ bytes_consumed = temp8 + 1;
+
+ /*
+ * Ensure a 32-bit boundry for the structure
+ */
+ temp8 = (u8) ROUND_UP_TO_32_bITS (temp8);
+
+ structure_size = sizeof (VENDOR_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA +
+ (temp8 * sizeof (u8));
+ break;
+
+
+ case END_TAG:
+
+ /*
+ * End Tag
+ */
+ bytes_consumed = 2;
+
+ structure_size = RESOURCE_LENGTH;
+ break;
+
+
+ default:
+ /*
+ * If we get here, everything is out of sync,
+ * so exit with an error
+ */
+ return (AE_ERROR);
+ break;
+
+ } /* switch */
+
+ } /* if(Resource_type & 0x80) */
+
+ /*
+ * Update the return value and counter
+ */
+ buffer_size += structure_size;
+ bytes_parsed += bytes_consumed;
+
+ /*
+ * Set the byte stream to point to the next resource
+ */
+ byte_stream_buffer += bytes_consumed;
+
+ }
+
+ /*
+ * This is the data the caller needs
+ */
+ *size_needed = buffer_size;
+
+ return (AE_OK);
+
+} /* Acpi_rs_calculate_list_length */
+
diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c
new file mode 100644
index 000000000..3bb46eb48
--- /dev/null
+++ b/drivers/acpi/resources/rscreate.c
@@ -0,0 +1,505 @@
+/******************************************************************************
+ *
+ * Module Name: rscreate - Acpi_rs_create_resource_list
+ * Acpi_rs_create_pci_routing_table
+ * Acpi_rs_create_byte_stream
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "resource.h"
+
+#define _COMPONENT RESOURCE_MANAGER
+ MODULE_NAME ("rscreate");
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_create_resource_list
+ *
+ * PARAMETERS:
+ * Byte_stream_buffer - Pointer to the resource byte stream
+ * Output_buffer - Pointer to the user's buffer
+ * Output_buffer_length - Pointer to the size of Output_buffer
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ * If Output_buffer is not large enough, Output_buffer_length
+ * indicates how large Output_buffer should be, else it
+ * indicates how may u8 elements of Output_buffer are
+ * valid.
+ *
+ * DESCRIPTION: Takes the byte stream returned from a _CRS, _PRS control method
+ * execution and parses the stream to create a linked list
+ * of device resources.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_create_resource_list (
+ ACPI_OBJECT_INTERNAL *byte_stream_buffer,
+ u8 *output_buffer,
+ u32 *output_buffer_length)
+{
+
+ ACPI_STATUS status = AE_UNKNOWN_STATUS;
+ u8 *byte_stream_start = NULL;
+ u32 list_size_needed = 0;
+ u32 byte_stream_buffer_length = 0;
+
+
+ /*
+ * Validate parameters:
+ *
+ * 1. If Byte_stream_buffer is NULL after we know that
+ * Byte_steam_length is not zero, or
+ * 2. If Output_buffer is NULL and Output_buffer_length
+ * is not zero
+ *
+ * Return an error
+ */
+ if (!byte_stream_buffer ||
+ (!output_buffer && 0 != *output_buffer_length))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+ byte_stream_buffer_length = byte_stream_buffer->buffer.length;
+ byte_stream_start = byte_stream_buffer->buffer.pointer;
+
+ /*
+ * Pass the Byte_stream_buffer into a module that can calculate
+ * the buffer size needed for the linked list
+ */
+ status = acpi_rs_calculate_list_length (byte_stream_start,
+ byte_stream_buffer_length,
+ &list_size_needed);
+
+ /*
+ * Exit with the error passed back
+ */
+ if (AE_OK != status) {
+ return (status);
+ }
+
+ /*
+ * If the linked list will fit into the available buffer
+ * call to fill in the list
+ */
+
+ if (list_size_needed <= *output_buffer_length) {
+ /*
+ * Zero out the return buffer before proceeding
+ */
+ MEMSET (output_buffer, 0x00, *output_buffer_length);
+
+ status = acpi_rs_byte_stream_to_list (byte_stream_start,
+ byte_stream_buffer_length,
+ &output_buffer);
+
+ /*
+ * Exit with the error passed back
+ */
+ if (AE_OK != status) {
+ return (status);
+ }
+
+ }
+
+ else {
+ *output_buffer_length = list_size_needed;
+ return (AE_BUFFER_OVERFLOW);
+ }
+
+ *output_buffer_length = list_size_needed;
+ return (AE_OK);
+
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_create_pci_routing_table
+ *
+ * PARAMETERS:
+ * Package_object - Pointer to an ACPI_OBJECT_INTERNAL
+ * package
+ * Output_buffer - Pointer to the user's buffer
+ * Output_buffer_length - Size of Output_buffer
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code.
+ * If the Output_buffer is too small, the error will be
+ * AE_BUFFER_OVERFLOW and Output_buffer_length will point
+ * to the size buffer needed.
+ *
+ * DESCRIPTION: Takes the ACPI_OBJECT_INTERNAL package and creates a
+ * linked list of PCI interrupt descriptions
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_create_pci_routing_table (
+ ACPI_OBJECT_INTERNAL *package_object,
+ u8 *output_buffer,
+ u32 *output_buffer_length)
+{
+ u8 *buffer = output_buffer;
+ ACPI_OBJECT_INTERNAL **top_object_list = NULL;
+ ACPI_OBJECT_INTERNAL **sub_object_list = NULL;
+ ACPI_OBJECT_INTERNAL *package_element = NULL;
+ u32 buffer_size_needed = 0;
+ u32 number_of_elements = 0;
+ u32 index = 0;
+ u8 table_index = 0;
+ u8 name_found = FALSE;
+ PCI_ROUTING_TABLE *user_prt = NULL;
+
+
+ /*
+ * Validate parameters:
+ *
+ * 1. If Method_return_object is NULL, or
+ * 2. If Output_buffer is NULL and Output_buffer_length is not zero
+ *
+ * Return an error
+ */
+ if (!package_object ||
+ (!output_buffer && 0 != *output_buffer_length))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Calculate the buffer size needed for the routing table.
+ */
+ number_of_elements = package_object->package.count;
+
+ /*
+ * Properly calculate the size of the return buffer.
+ * The base size is the number of elements * the sizes of the
+ * structures. Additional space for the strings is added below.
+ * The minus one is to subtract the size of the u8 Source[1]
+ * member because it is added below.
+ * NOTE: The Number_of_elements is incremented by one to add an end
+ * table structure that is essentially a structure of zeros.
+ */
+ buffer_size_needed = (number_of_elements + 1) *
+ (sizeof (PCI_ROUTING_TABLE) - 1);
+
+ /*
+ * But each PRT_ENTRY structure has a pointer to a string and
+ * the size of that string must be found.
+ */
+ top_object_list = package_object->package.elements;
+
+ for (index = 0; index < number_of_elements; index++) {
+ /*
+ * Dereference the sub-package
+ */
+ package_element = *top_object_list;
+
+ /*
+ * The Sub_object_list will now point to an array of the
+ * four IRQ elements: Address, Pin, Source and Source_index
+ */
+ sub_object_list = package_element->package.elements;
+
+ /*
+ * Scan the Irq_table_elements for the Source Name String
+ */
+ name_found = FALSE;
+
+ for (table_index = 0; table_index < 4 && !name_found; table_index++) {
+ if (ACPI_TYPE_STRING == (*sub_object_list)->common.type) {
+ name_found = TRUE;
+ }
+
+ else {
+ /*
+ * Look at the next element
+ */
+ sub_object_list++;
+ }
+ }
+
+ /*
+ * Was a String type found?
+ */
+ if (TRUE == name_found) {
+ /*
+ * The length String.Length field includes the
+ * terminating NULL
+ */
+ buffer_size_needed += ((*sub_object_list)->string.length);
+ }
+
+ else {
+ /*
+ * If no name was found, then this is a NULL, which is
+ * translated as a u32 zero.
+ */
+ buffer_size_needed += sizeof(u32);
+ }
+
+ /*
+ * Point to the next ACPI_OBJECT_INTERNAL
+ */
+ top_object_list++;
+ }
+
+ /*
+ * If the data will fit into the available buffer
+ * call to fill in the list
+ */
+ if (buffer_size_needed <= *output_buffer_length) {
+ /*
+ * Zero out the return buffer before proceeding
+ */
+ MEMSET (output_buffer, 0x00, *output_buffer_length);
+
+ /*
+ * Loop through the ACPI_INTERNAL_OBJECTS - Each object should
+ * contain a u32 Address, a u8 Pin, a Name and a u8
+ * Source_index.
+ */
+ top_object_list = package_object->package.elements;
+
+ number_of_elements = package_object->package.count;
+
+ user_prt = (PCI_ROUTING_TABLE *)buffer;
+
+ for (index = 0; index < number_of_elements; index++) {
+ /*
+ * Point User_prt past this current structure
+ *
+ * NOTE: On the first iteration, User_prt->Length will
+ * be zero because we zero'ed out the return buffer
+ * earlier
+ */
+ buffer += user_prt->length;
+
+ user_prt = (PCI_ROUTING_TABLE *)buffer;
+
+ /*
+ * Fill in the Length field with the information we
+ * have at this point.
+ * The minus one is to subtract the size of the
+ * u8 Source[1] member because it is added below.
+ */
+ user_prt->length = (sizeof(PCI_ROUTING_TABLE) - 1);
+
+ /*
+ * Dereference the sub-package
+ */
+ package_element = *top_object_list;
+
+ /*
+ * The Sub_object_list will now point to an array of
+ * the four IRQ elements: Address, Pin, Source and
+ * Source_index
+ */
+ sub_object_list = package_element->package.elements;
+
+ /*
+ * Dereference the Address
+ */
+ if (ACPI_TYPE_NUMBER == (*sub_object_list)->common.type) {
+ user_prt->data.address =
+ (*sub_object_list)->number.value;
+ }
+
+ else {
+ return (AE_BAD_DATA);
+ }
+
+ /*
+ * Dereference the Pin
+ */
+ sub_object_list++;
+
+ if (ACPI_TYPE_NUMBER == (*sub_object_list)->common.type) {
+ user_prt->data.pin =
+ (*sub_object_list)->number.value;
+ }
+
+ else {
+ return (AE_BAD_DATA);
+ }
+
+ /*
+ * Dereference the Source Name
+ */
+ sub_object_list++;
+
+ if (ACPI_TYPE_STRING == (*sub_object_list)->common.type) {
+ STRCPY(user_prt->data.source,
+ (*sub_object_list)->string.pointer);
+
+ /*
+ * Add to the Length field the length of the string
+ */
+ user_prt->length += (*sub_object_list)->string.length;
+ }
+
+ else {
+ /*
+ * If this is a number, then the Source Name
+ * is NULL, since the entire buffer was zeroed
+ * out, we can leave this alone.
+ */
+ if (ACPI_TYPE_NUMBER == (*sub_object_list)->common.type) {
+ /*
+ * Add to the Length field the length of
+ * the u32 NULL
+ */
+ user_prt->length += sizeof(u32);
+ }
+
+ else {
+ return (AE_BAD_DATA);
+ }
+ }
+
+ /*
+ * Dereference the Source Index
+ */
+ sub_object_list++;
+
+ if (ACPI_TYPE_NUMBER == (*sub_object_list)->common.type) {
+ user_prt->data.source_index =
+ (*sub_object_list)->number.value;
+ }
+
+ else {
+ return (AE_BAD_DATA);
+ }
+
+ /*
+ * Point to the next ACPI_OBJECT_INTERNAL
+ */
+ top_object_list++;
+ }
+
+ }
+
+ else {
+ *output_buffer_length = buffer_size_needed;
+
+ return (AE_BUFFER_OVERFLOW);
+ }
+
+ /*
+ * Report the amount of buffer used
+ */
+ *output_buffer_length = buffer_size_needed;
+
+ return (AE_OK);
+
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_create_byte_stream
+ *
+ * PARAMETERS:
+ * Linked_list_buffer - Pointer to the resource linked list
+ * Output_buffer - Pointer to the user's buffer
+ * Output_buffer_length - Size of Output_buffer
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code.
+ * If the Output_buffer is too small, the error will be
+ * AE_BUFFER_OVERFLOW and Output_buffer_length will point
+ * to the size buffer needed.
+ *
+ * DESCRIPTION: Takes the linked list of device resources and
+ * creates a bytestream to be used as input for the
+ * _SRS control method.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_create_byte_stream (
+ RESOURCE *linked_list_buffer,
+ u8 *output_buffer,
+ u32 *output_buffer_length)
+{
+ ACPI_STATUS status = AE_UNKNOWN_STATUS;
+ u32 byte_stream_size_needed = 0;
+
+
+ /*
+ * Validate parameters:
+ *
+ * 1. If Linked_list_buffer is NULL, or
+ * 2. If Output_buffer is NULL and Output_buffer_length is not zero
+ *
+ * Return an error
+ */
+ if (!linked_list_buffer ||
+ (!output_buffer && 0 != *output_buffer_length))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Pass the Linked_list_buffer into a module that can calculate
+ * the buffer size needed for the byte stream.
+ */
+ status = acpi_rs_calculate_byte_stream_length (linked_list_buffer,
+ &byte_stream_size_needed);
+
+ /*
+ * Exit with the error passed back
+ */
+ if (AE_OK != status) {
+ return (status);
+ }
+
+ /*
+ * If the linked list will fit into the available buffer
+ * call to fill in the list
+ */
+
+ if (byte_stream_size_needed <= *output_buffer_length) {
+ /*
+ * Zero out the return buffer before proceeding
+ */
+ MEMSET (output_buffer, 0x00, *output_buffer_length);
+
+ status = acpi_rs_list_to_byte_stream (linked_list_buffer,
+ byte_stream_size_needed,
+ &output_buffer);
+
+ /*
+ * Exit with the error passed back
+ */
+ if (AE_OK != status) {
+ return (status);
+ }
+
+ }
+ else {
+ *output_buffer_length = byte_stream_size_needed;
+ return (AE_BUFFER_OVERFLOW);
+ }
+
+ return (AE_OK);
+
+}
+
diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c
new file mode 100644
index 000000000..490b6e167
--- /dev/null
+++ b/drivers/acpi/resources/rsdump.c
@@ -0,0 +1,938 @@
+/******************************************************************************
+ *
+ * Module Name: rsdump - Functions do dump out the resource structures.
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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"
+
+#define _COMPONENT RESOURCE_MANAGER
+ MODULE_NAME ("rsdump");
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_dump_irq
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN:
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_irq (
+ RESOURCE_DATA *data)
+{
+ IRQ_RESOURCE *irq_data = (IRQ_RESOURCE*) data;
+ u8 index = 0;
+
+
+ acpi_os_printf ("\t_iRQ Resource\n");
+
+ acpi_os_printf ("\t\t%s Triggered\n",
+ LEVEL_SENSITIVE == irq_data->edge_level ?
+ "Level" : "Edge");
+
+ acpi_os_printf ("\t\t_active %s\n",
+ ACTIVE_LOW == irq_data->active_high_low ?
+ "Low" : "High");
+
+ acpi_os_printf ("\t\t%s\n",
+ SHARED == irq_data->shared_exclusive ?
+ "Shared" : "Exclusive");
+
+ acpi_os_printf ("\t\t%d Interrupts ( ",
+ irq_data->number_of_interrupts);
+
+ for (index = 0; index < irq_data->number_of_interrupts; index++) {
+ acpi_os_printf ("%d ", irq_data->interrupts[index]);
+ }
+
+ acpi_os_printf (")\n");
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_dump_dma
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN:
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_dma (
+ RESOURCE_DATA *data)
+{
+ DMA_RESOURCE *dma_data = (DMA_RESOURCE*) data;
+ u8 index = 0;
+
+
+ acpi_os_printf ("\t_dMA Resource\n");
+
+ switch (dma_data->type)
+ {
+ case COMPATIBILITY:
+ acpi_os_printf ("\t\t_compatibility mode\n");
+ break;
+
+ case TYPE_A:
+ acpi_os_printf ("\t\t_type A\n");
+ break;
+
+ case TYPE_B:
+ acpi_os_printf ("\t\t_type B\n");
+ break;
+
+ case TYPE_F:
+ acpi_os_printf ("\t\t_type F\n");
+ break;
+
+ default:
+ acpi_os_printf ("\t\t_invalid DMA type\n");
+ break;
+ }
+
+ acpi_os_printf ("\t\t%s_bus Master\n",
+ BUS_MASTER == dma_data->bus_master ?
+ "" : "Not a ");
+
+ switch (dma_data->transfer)
+ {
+ case TRANSFER_8:
+ acpi_os_printf ("\t\t8-bit only transfer\n");
+ break;
+
+ case TRANSFER_8_16:
+ acpi_os_printf ("\t\t8 and 16-bit transfer\n");
+ break;
+
+ case TRANSFER_16:
+ acpi_os_printf ("\t\t16 bit only transfer\n");
+ break;
+
+ default:
+ acpi_os_printf ("\t\t_invalid transfer preference\n");
+ break;
+ }
+
+ acpi_os_printf ("\t\t_number of Channels: %d ( ",
+ dma_data->number_of_channels);
+
+ for (index = 0; index < dma_data->number_of_channels; index++) {
+ acpi_os_printf ("%d ", dma_data->channels[index]);
+ }
+
+ acpi_os_printf (")\n");
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_dump_start_dependent_functions
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN:
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_start_dependent_functions (
+ RESOURCE_DATA *data)
+{
+ START_DEPENDENT_FUNCTIONS_RESOURCE *sdf_data =
+ (START_DEPENDENT_FUNCTIONS_RESOURCE*) data;
+
+
+ acpi_os_printf ("\t_start Dependent Functions Resource\n");
+
+ switch (sdf_data->compatibility_priority)
+ {
+ case GOOD_CONFIGURATION:
+ acpi_os_printf ("\t\t_good configuration\n");
+ break;
+
+ case ACCEPTABLE_CONFIGURATION:
+ acpi_os_printf ("\t\t_acceptable configuration\n");
+ break;
+
+ case SUB_OPTIMAL_CONFIGURATION:
+ acpi_os_printf ("\t\t_sub-optimal configuration\n");
+ break;
+
+ default:
+ acpi_os_printf ("\t\t_invalid compatibility priority\n");
+ break;
+ }
+
+ switch(sdf_data->performance_robustness)
+ {
+ case GOOD_CONFIGURATION:
+ acpi_os_printf ("\t\t_good configuration\n");
+ break;
+
+ case ACCEPTABLE_CONFIGURATION:
+ acpi_os_printf ("\t\t_acceptable configuration\n");
+ break;
+
+ case SUB_OPTIMAL_CONFIGURATION:
+ acpi_os_printf ("\t\t_sub-optimal configuration\n");
+ break;
+
+ default:
+ acpi_os_printf ("\t\t_invalid performance "
+ "robustness preference\n");
+ break;
+ }
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_dump_io
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN:
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_io (
+ RESOURCE_DATA *data)
+{
+ IO_RESOURCE *io_data = (IO_RESOURCE*) data;
+
+
+ acpi_os_printf ("\t_io Resource\n");
+
+ acpi_os_printf ("\t\t%d bit decode\n",
+ DECODE_16 == io_data->io_decode ? 16 : 10);
+
+ acpi_os_printf ("\t\t_range minimum base: 0x%08x\n",
+ io_data->min_base_address);
+
+ acpi_os_printf ("\t\t_range maximum base: 0x%08x\n",
+ io_data->max_base_address);
+
+ acpi_os_printf ("\t\t_alignment: 0x%08x\n",
+ io_data->alignment);
+
+ acpi_os_printf ("\t\t_range Length: 0x%08x\n",
+ io_data->range_length);
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_dump_fixed_io
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN:
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_fixed_io (
+ RESOURCE_DATA *data)
+{
+ FIXED_IO_RESOURCE *fixed_io_data = (FIXED_IO_RESOURCE*) data;
+
+
+ acpi_os_printf ("\t_fixed Io Resource\n");
+ acpi_os_printf ("\t\t_range base address: 0x%08x",
+ fixed_io_data->base_address);
+
+ acpi_os_printf ("\t\t_range length: 0x%08x",
+ fixed_io_data->range_length);
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_dump_vendor_specific
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN:
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_vendor_specific (
+ RESOURCE_DATA *data)
+{
+ VENDOR_RESOURCE *vendor_data = (VENDOR_RESOURCE*) data;
+ u16 index = 0;
+
+
+ acpi_os_printf ("\t_vendor Specific Resource\n");
+
+ acpi_os_printf ("\t\t_length: 0x%08x\n", vendor_data->length);
+
+ for (index = 0; index < vendor_data->length; index++) {
+ acpi_os_printf ("\t\t_byte %d: 0x%08x\n",
+ index, vendor_data->reserved[index]);
+ }
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_dump_memory24
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN:
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_memory24 (
+ RESOURCE_DATA *data)
+{
+ MEMORY24_RESOURCE *memory24_data = (MEMORY24_RESOURCE*) data;
+
+
+ acpi_os_printf ("\t24-Bit Memory Range Resource\n");
+
+ acpi_os_printf ("\t\t_read%s\n",
+ READ_WRITE_MEMORY ==
+ memory24_data->read_write_attribute ?
+ "/Write" : " only");
+
+ acpi_os_printf ("\t\t_range minimum base: 0x%08x\n",
+ memory24_data->min_base_address);
+
+ acpi_os_printf ("\t\t_range maximum base: 0x%08x\n",
+ memory24_data->max_base_address);
+
+ acpi_os_printf ("\t\t_alignment: 0x%08x\n",
+ memory24_data->alignment);
+
+ acpi_os_printf ("\t\t_range length: 0x%08x\n",
+ memory24_data->range_length);
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_dump_memory32
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN:
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_memory32 (
+ RESOURCE_DATA *data)
+{
+ MEMORY32_RESOURCE *memory32_data = (MEMORY32_RESOURCE*) data;
+
+
+ acpi_os_printf ("\t32-Bit Memory Range Resource\n");
+
+ acpi_os_printf ("\t\t_read%s\n",
+ READ_WRITE_MEMORY ==
+ memory32_data->read_write_attribute ?
+ "/Write" : " only");
+
+ acpi_os_printf ("\t\t_range minimum base: 0x%08x\n",
+ memory32_data->min_base_address);
+
+ acpi_os_printf ("\t\t_range maximum base: 0x%08x\n",
+ memory32_data->max_base_address);
+
+ acpi_os_printf ("\t\t_alignment: 0x%08x\n",
+ memory32_data->alignment);
+
+ acpi_os_printf ("\t\t_range length: 0x%08x\n",
+ memory32_data->range_length);
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_dump_fixed_memory32
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN:
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_fixed_memory32 (
+ RESOURCE_DATA *data)
+{
+ FIXED_MEMORY32_RESOURCE *fixed_memory32_data = (FIXED_MEMORY32_RESOURCE*) data;
+
+
+ acpi_os_printf ("\t32-Bit Fixed Location Memory Range Resource\n");
+
+ acpi_os_printf ("\t\t_read%s\n",
+ READ_WRITE_MEMORY ==
+ fixed_memory32_data->read_write_attribute ?
+ "/Write" : " Only");
+
+ acpi_os_printf ("\t\t_range base address: 0x%08x\n",
+ fixed_memory32_data->range_base_address);
+
+ acpi_os_printf ("\t\t_range length: 0x%08x\n",
+ fixed_memory32_data->range_length);
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_dump_address16
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN:
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_address16 (
+ RESOURCE_DATA *data)
+{
+ ADDRESS16_RESOURCE *address16_data = (ADDRESS16_RESOURCE*) data;
+
+
+ acpi_os_printf ("\t16-Bit Address Space Resource\n");
+ acpi_os_printf ("\t\t_resource Type: ");
+
+ switch (address16_data->resource_type)
+ {
+ case MEMORY_RANGE:
+
+ acpi_os_printf ("Memory Range\n");
+
+ switch (address16_data->attribute.memory.cache_attribute)
+ {
+ case NON_CACHEABLE_MEMORY:
+ acpi_os_printf ("\t\t_type Specific: "
+ "Noncacheable memory\n");
+ break;
+
+ case CACHABLE_MEMORY:
+ acpi_os_printf ("\t\t_type Specific: "
+ "Cacheable memory\n");
+ break;
+
+ case WRITE_COMBINING_MEMORY:
+ acpi_os_printf ("\t\t_type Specific: "
+ "Write-combining memory\n");
+ break;
+
+ case PREFETCHABLE_MEMORY:
+ acpi_os_printf ("\t\t_type Specific: "
+ "Prefetchable memory\n");
+ break;
+
+ default:
+ acpi_os_printf ("\t\t_type Specific: "
+ "Invalid cache attribute\n");
+ break;
+ }
+
+ acpi_os_printf ("\t\t_type Specific: Read%s\n",
+ READ_WRITE_MEMORY ==
+ address16_data->attribute.memory.read_write_attribute ?
+ "/Write" : " Only");
+ break;
+
+ case IO_RANGE:
+
+ acpi_os_printf ("I/O Range\n");
+
+ switch (address16_data->attribute.io.range_attribute)
+ {
+ case NON_ISA_ONLY_RANGES:
+ acpi_os_printf ("\t\t_type Specific: "
+ "Non-ISA Io Addresses\n");
+ break;
+
+ case ISA_ONLY_RANGES:
+ acpi_os_printf ("\t\t_type Specific: "
+ "ISA Io Addresses\n");
+ break;
+
+ case ENTIRE_RANGE:
+ acpi_os_printf ("\t\t_type Specific: "
+ "ISA and non-ISA Io Addresses\n");
+ break;
+
+ default:
+ acpi_os_printf ("\t\t_type Specific: "
+ "Invalid range attribute\n");
+ break;
+ }
+ break;
+
+ case BUS_NUMBER_RANGE:
+
+ acpi_os_printf ("Bus Number Range\n");
+ break;
+
+ default:
+
+ acpi_os_printf ("Invalid resource type. Exiting.\n");
+ return;
+ }
+
+ acpi_os_printf ("\t\t_resource %s\n",
+ CONSUMER == address16_data->producer_consumer ?
+ "Consumer" : "Producer");
+
+ acpi_os_printf ("\t\t%s decode\n",
+ SUB_DECODE == address16_data->decode ?
+ "Subtractive" : "Positive");
+
+ acpi_os_printf ("\t\t_min address is %s fixed\n",
+ ADDRESS_FIXED == address16_data->min_address_fixed ?
+ "" : "not");
+
+ acpi_os_printf ("\t\t_max address is %s fixed\n",
+ ADDRESS_FIXED == address16_data->max_address_fixed ?
+ "" : "not");
+
+ acpi_os_printf ("\t\t_granularity: 0x%08x\n",
+ address16_data->granularity);
+
+ acpi_os_printf ("\t\t_address range min: 0x%08x\n",
+ address16_data->min_address_range);
+
+ acpi_os_printf ("\t\t_address range max: 0x%08x\n",
+ address16_data->max_address_range);
+
+ acpi_os_printf ("\t\t_address translation offset: 0x%08x\n",
+ address16_data->address_translation_offset);
+
+ acpi_os_printf ("\t\t_address Length: 0x%08x\n",
+ address16_data->address_length);
+
+ if (0xFF != address16_data->resource_source_index) {
+ acpi_os_printf ("\t\t_resource Source Index: %d\n",
+ address16_data->resource_source_index);
+ acpi_os_printf ("\t\t_resource Source: %s\n",
+ address16_data->resource_source);
+ }
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_dump_address32
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN:
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_address32 (
+ RESOURCE_DATA *data)
+{
+ ADDRESS32_RESOURCE *address32_data = (ADDRESS32_RESOURCE*) data;
+
+
+ acpi_os_printf ("\t32-Bit Address Space Resource\n");
+
+ switch (address32_data->resource_type)
+ {
+ case MEMORY_RANGE:
+
+ acpi_os_printf ("\t\t_resource Type: Memory Range\n");
+
+ switch (address32_data->attribute.memory.cache_attribute)
+ {
+ case NON_CACHEABLE_MEMORY:
+ acpi_os_printf ("\t\t_type Specific: "
+ "Noncacheable memory\n");
+ break;
+
+ case CACHABLE_MEMORY:
+ acpi_os_printf ("\t\t_type Specific: "
+ "Cacheable memory\n");
+ break;
+
+ case WRITE_COMBINING_MEMORY:
+ acpi_os_printf ("\t\t_type Specific: "
+ "Write-combining memory\n");
+ break;
+
+ case PREFETCHABLE_MEMORY:
+ acpi_os_printf ("\t\t_type Specific: "
+ "Prefetchable memory\n");
+ break;
+
+ default:
+ acpi_os_printf ("\t\t_type Specific: "
+ "Invalid cache attribute\n");
+ break;
+ }
+
+ acpi_os_printf ("\t\t_type Specific: Read%s\n",
+ READ_WRITE_MEMORY ==
+ address32_data->attribute.memory.read_write_attribute ?
+ "/Write" : " Only");
+ break;
+
+ case IO_RANGE:
+
+ acpi_os_printf ("\t\t_resource Type: Io Range\n");
+
+ switch (address32_data->attribute.io.range_attribute)
+ {
+ case NON_ISA_ONLY_RANGES:
+ acpi_os_printf ("\t\t_type Specific: "
+ "Non-ISA Io Addresses\n");
+ break;
+
+ case ISA_ONLY_RANGES:
+ acpi_os_printf ("\t\t_type Specific: "
+ "ISA Io Addresses\n");
+ break;
+
+ case ENTIRE_RANGE:
+ acpi_os_printf ("\t\t_type Specific: "
+ "ISA and non-ISA Io Addresses\n");
+ break;
+
+ default:
+ acpi_os_printf ("\t\t_type Specific: "
+ "Invalid Range attribute");
+ break;
+ }
+ break;
+
+ case BUS_NUMBER_RANGE:
+
+ acpi_os_printf ("\t\t_resource Type: Bus Number Range\n");
+ break;
+
+ default:
+
+ acpi_os_printf ("\t\t_invalid Resource Type..exiting.\n");
+ return;
+ }
+
+ acpi_os_printf ("\t\t_resource %s\n",
+ CONSUMER == address32_data->producer_consumer ?
+ "Consumer" : "Producer");
+
+ acpi_os_printf ("\t\t%s decode\n",
+ SUB_DECODE == address32_data->decode ?
+ "Subtractive" : "Positive");
+
+ acpi_os_printf ("\t\t_min address is %s fixed\n",
+ ADDRESS_FIXED == address32_data->min_address_fixed ?
+ "" : "not ");
+
+ acpi_os_printf ("\t\t_max address is %s fixed\n",
+ ADDRESS_FIXED == address32_data->max_address_fixed ?
+ "" : "not ");
+
+ acpi_os_printf ("\t\t_granularity: 0x%08x\n",
+ address32_data->granularity);
+
+ acpi_os_printf ("\t\t_address range min: 0x%08x\n",
+ address32_data->min_address_range);
+
+ acpi_os_printf ("\t\t_address range max: 0x%08x\n",
+ address32_data->max_address_range);
+
+ acpi_os_printf ("\t\t_address translation offset: 0x%08x\n",
+ address32_data->address_translation_offset);
+
+ acpi_os_printf ("\t\t_address Length: 0x%08x\n",
+ address32_data->address_length);
+
+ if(0xFF != address32_data->resource_source_index) {
+ acpi_os_printf ("\t\t_resource Source Index: %d\n",
+ address32_data->resource_source_index);
+ acpi_os_printf ("\t\t_resource Source: %s\n",
+ address32_data->resource_source);
+ }
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_dump_extended_irq
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN:
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_extended_irq (
+ RESOURCE_DATA *data)
+{
+ EXTENDED_IRQ_RESOURCE *ext_irq_data = (EXTENDED_IRQ_RESOURCE*) data;
+ u8 index = 0;
+
+
+ acpi_os_printf ("\t_extended IRQ Resource\n");
+
+ acpi_os_printf ("\t\t_resource %s\n",
+ CONSUMER == ext_irq_data->producer_consumer ?
+ "Consumer" : "Producer");
+
+ acpi_os_printf ("\t\t%s\n",
+ LEVEL_SENSITIVE == ext_irq_data->edge_level ?
+ "Level" : "Edge");
+
+ acpi_os_printf ("\t\t_active %s\n",
+ ACTIVE_LOW == ext_irq_data->active_high_low ?
+ "low" : "high");
+
+ acpi_os_printf ("\t\t%s\n",
+ SHARED == ext_irq_data->shared_exclusive ?
+ "Shared" : "Exclusive");
+
+ acpi_os_printf ("\t\t_interrupts : %d ( ",
+ ext_irq_data->number_of_interrupts);
+
+ for (index = 0; index < ext_irq_data->number_of_interrupts; index++) {
+ acpi_os_printf ("%d ", ext_irq_data->interrupts[index]);
+ }
+
+ acpi_os_printf (")\n");
+
+ if(0xFF != ext_irq_data->resource_source_index) {
+ acpi_os_printf ("\t\t_resource Source Index: %d",
+ ext_irq_data->resource_source_index);
+ acpi_os_printf ("\t\t_resource Source: %s",
+ ext_irq_data->resource_source);
+ }
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_dump_resource_list
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN:
+ *
+ * DESCRIPTION: Dispatches the structure to the correct dump routine.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_resource_list (
+ RESOURCE *resource)
+{
+ s8 count = 0;
+ u8 done = FALSE;
+
+
+ if (acpi_dbg_level & TRACE_RESOURCES && _COMPONENT & acpi_dbg_layer) {
+ while (!done) {
+ acpi_os_printf ("\t_resource structure %x.\n", count++);
+
+ switch (resource->id)
+ {
+ case irq:
+ acpi_rs_dump_irq (&resource->data);
+ break;
+
+ case dma:
+ acpi_rs_dump_dma (&resource->data);
+ break;
+
+ case start_dependent_functions:
+ acpi_rs_dump_start_dependent_functions (&resource->data);
+ break;
+
+ case end_dependent_functions:
+ acpi_os_printf ("\t_end_dependent_functions Resource\n");
+ /* Acpi_rs_dump_end_dependent_functions (Resource->Data);*/
+ break;
+
+ case io:
+ acpi_rs_dump_io (&resource->data);
+ break;
+
+ case fixed_io:
+ acpi_rs_dump_fixed_io (&resource->data);
+ break;
+
+ case vendor_specific:
+ acpi_rs_dump_vendor_specific (&resource->data);
+ break;
+
+ case end_tag:
+ /*Rs_dump_end_tag (Resource->Data);*/
+ acpi_os_printf ("\t_end_tag Resource\n");
+ done = TRUE;
+ break;
+
+ case memory24:
+ acpi_rs_dump_memory24 (&resource->data);
+ break;
+
+ case memory32:
+ acpi_rs_dump_memory32 (&resource->data);
+ break;
+
+ case fixed_memory32:
+ acpi_rs_dump_fixed_memory32 (&resource->data);
+ break;
+
+ case address16:
+ acpi_rs_dump_address16 (&resource->data);
+ break;
+
+ case address32:
+ acpi_rs_dump_address32 (&resource->data);
+ break;
+
+ case extended_irq:
+ acpi_rs_dump_extended_irq (&resource->data);
+ break;
+
+ default:
+ acpi_os_printf ("Invalid resource type\n");
+ break;
+
+ }
+
+ resource = (RESOURCE *) ((NATIVE_UINT) resource +
+ (NATIVE_UINT) resource->length);
+ }
+ }
+
+ return;
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_dump_irq_list
+ *
+ * PARAMETERS: Data - pointer to the routing table to dump.
+ *
+ * RETURN:
+ *
+ * DESCRIPTION: Dispatches the structures to the correct dump routine.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_irq_list (
+ u8 *route_table)
+{
+ u8 *buffer = route_table;
+ s8 count = 0;
+ u8 done = FALSE;
+ PCI_ROUTING_TABLE *prt_element;
+
+
+ if (acpi_dbg_level & TRACE_RESOURCES && _COMPONENT & acpi_dbg_layer) {
+ prt_element = (PCI_ROUTING_TABLE *)buffer;
+
+ while (!done) {
+ acpi_os_printf ("\t_pCI IRQ Routing Table structure %x.\n", count++);
+
+ acpi_os_printf ("\t\t_address: 0x%x\n",
+ prt_element->data.address);
+
+ acpi_os_printf ("\t\t_pin: 0x%x\n", prt_element->data.pin);
+
+ acpi_os_printf ("\t\t_source: %s\n", prt_element->data.source);
+
+ acpi_os_printf ("\t\t_source_index: 0x%x\n",
+ prt_element->data.source_index);
+
+ buffer += prt_element->length;
+
+ prt_element = (PCI_ROUTING_TABLE *)buffer;
+
+ if(0 == prt_element->length) {
+ done = TRUE;
+ }
+ }
+ }
+
+ return;
+}
+
diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/resources/rsio.c
new file mode 100644
index 000000000..cc8e38c45
--- /dev/null
+++ b/drivers/acpi/resources/rsio.c
@@ -0,0 +1,544 @@
+/******************************************************************************
+ *
+ * Module Name: rsio - Acpi_rs_io_resource
+ * Acpi_rs_fixed_io_resource
+ * Acpi_rs_io_stream
+ * Acpi_rs_fixed_io_stream
+ * Acpi_rs_dma_resource
+ * Acpi_rs_dma_stream
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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"
+
+#define _COMPONENT RESOURCE_MANAGER
+ MODULE_NAME ("rsio");
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_io_resource
+ *
+ * PARAMETERS:
+ * Byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes consumed from
+ * the Byte_stream_buffer
+ * Output_buffer - Pointer to the user's return buffer
+ * Structure_size - u32 pointer that is filled with
+ * the number of bytes in the filled
+ * in structure
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the Output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_io_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ RESOURCE *output_struct = (RESOURCE *) * output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u32 struct_size = sizeof (IO_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+
+
+ /*
+ * The number of bytes consumed are Constant
+ */
+ *bytes_consumed = 8;
+
+ output_struct->id = io;
+
+ /*
+ * Check Decode
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ output_struct->data.io.io_decode = temp8 & 0x01;
+
+ /*
+ * Check Min_base Address
+ */
+ buffer += 1;
+ temp16 = *(u16 *)buffer;
+
+ output_struct->data.io.min_base_address = temp16;
+
+ /*
+ * Check Max_base Address
+ */
+ buffer += 2;
+ temp16 = *(u16 *)buffer;
+
+ output_struct->data.io.max_base_address = temp16;
+
+ /*
+ * Check Base alignment
+ */
+ buffer += 2;
+ temp8 = *buffer;
+
+ output_struct->data.io.alignment = temp8;
+
+ /*
+ * Check Range_length
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ output_struct->data.io.range_length = temp8;
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_fixed_io_resource
+ *
+ * PARAMETERS:
+ * Byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes consumed from
+ * the Byte_stream_buffer
+ * Output_buffer - Pointer to the user's return buffer
+ * Structure_size - u32 pointer that is filled with
+ * the number of bytes in the filled
+ * in structure
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the Output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_fixed_io_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ RESOURCE *output_struct = (RESOURCE *) * output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u32 struct_size = sizeof (FIXED_IO_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+
+
+ /*
+ * The number of bytes consumed are Constant
+ */
+ *bytes_consumed = 4;
+
+ output_struct->id = fixed_io;
+
+ /*
+ * Check Range Base Address
+ */
+ buffer += 1;
+ MOVE_UNALIGNED16_TO_16 (&temp16, buffer);
+
+ output_struct->data.fixed_io.base_address = temp16;
+
+ /*
+ * Check Range_length
+ */
+ buffer += 2;
+ temp8 = *buffer;
+
+ output_struct->data.fixed_io.range_length = temp8;
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_io_stream
+ *
+ * PARAMETERS:
+ * Linked_list - Pointer to the resource linked list
+ * Output_buffer - Pointer to the user's return buffer
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes of the
+ * Output_buffer used
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_io_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x47;
+
+ buffer += 1;
+
+ /*
+ * Io Information Byte
+ */
+ temp8 = (u8) (linked_list->data.io.io_decode & 0x01);
+
+ *buffer = temp8;
+
+ buffer += 1;
+
+ /*
+ * Set the Range minimum base address
+ */
+ temp16 = (u16) linked_list->data.io.min_base_address;
+
+ *(u16 *)buffer = temp16;
+
+ buffer += 2;
+
+ /*
+ * Set the Range maximum base address
+ */
+ temp16 = (u16) linked_list->data.io.max_base_address;
+
+ *(u16 *)buffer = temp16;
+
+ buffer += 2;
+
+ /*
+ * Set the base alignment
+ */
+ temp8 = (u8) linked_list->data.io.alignment;
+
+ *buffer = temp8;
+
+ buffer += 1;
+
+ /*
+ * Set the range length
+ */
+ temp8 = (u8) linked_list->data.io.range_length;
+
+ *buffer = temp8;
+
+ buffer += 1;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = (u32) ((NATIVE_UINT) buffer -
+ (NATIVE_UINT) *output_buffer);
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_fixed_io_stream
+ *
+ * PARAMETERS:
+ * Linked_list - Pointer to the resource linked list
+ * Output_buffer - Pointer to the user's return buffer
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes of the
+ * Output_buffer used
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_fixed_io_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x4B;
+
+ buffer += 1;
+
+ /*
+ * Set the Range base address
+ */
+ temp16 = (u16) linked_list->data.fixed_io.base_address;
+
+ *(u16 *)buffer = temp16;
+
+ buffer += 2;
+
+ /*
+ * Set the range length
+ */
+ temp8 = (u8) linked_list->data.fixed_io.range_length;
+
+ *buffer = temp8;
+
+ buffer += 1;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = (u32) ((NATIVE_UINT) buffer -
+ (NATIVE_UINT) *output_buffer);
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_dma_resource
+ *
+ * PARAMETERS:
+ * Byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes consumed from
+ * the Byte_stream_buffer
+ * Output_buffer - Pointer to the user's return buffer
+ * Structure_size - u32 pointer that is filled with
+ * the number of bytes in the filled
+ * in structure
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the Output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_dma_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ RESOURCE *output_struct = (RESOURCE *) * output_buffer;
+ u8 temp8 = 0;
+ u8 index;
+ u8 i;
+ u32 struct_size = sizeof(DMA_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+
+
+ /*
+ * The number of bytes consumed are Constant
+ */
+ *bytes_consumed = 3;
+
+ output_struct->id = dma;
+
+ /*
+ * Point to the 8-bits of Byte 1
+ */
+ buffer += 1;
+
+ temp8 = *buffer;
+
+ /* Decode the IRQ bits */
+
+ for (i = 0, index = 0; index < 8; index++) {
+ if ((temp8 >> index) & 0x01) {
+ output_struct->data.dma.channels[i] = index;
+ i++;
+ }
+ }
+ output_struct->data.dma.number_of_channels = i;
+
+
+ /*
+ * Calculate the structure size based upon the number of interrupts
+ */
+ struct_size += (output_struct->data.dma.number_of_channels - 1) * 4;
+
+ /*
+ * Point to Byte 2
+ */
+ buffer += 1;
+
+ temp8 = *buffer;
+
+ /*
+ * Check for transfer preference (Bits[1:0])
+ */
+ output_struct->data.dma.transfer = temp8 & 0x03;
+
+ if (0x03 == output_struct->data.dma.transfer) {
+ return (AE_BAD_DATA);
+ }
+
+ /*
+ * Get bus master preference (Bit[2])
+ */
+ output_struct->data.dma.bus_master = (temp8 >> 2) & 0x01;
+
+ /*
+ * Get channel speed support (Bits[6:5])
+ */
+ output_struct->data.dma.type = (temp8 >> 5) & 0x03;
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_dma_stream
+ *
+ * PARAMETERS:
+ * Linked_list - Pointer to the resource linked list
+ * Output_buffer - Pointer to the user's return buffer
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes of the
+ * Output_buffer used
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_dma_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u8 index;
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x2A;
+
+ buffer += 1;
+
+ temp8 = 0;
+
+ /*
+ * Loop through all of the Channels and set the mask bits
+ */
+ for (index = 0;
+ index < linked_list->data.dma.number_of_channels;
+ index++)
+ {
+ temp16 = (u16) linked_list->data.dma.channels[index];
+ temp8 |= 0x1 << temp16;
+ }
+
+ *buffer = temp8;
+
+ buffer += 1;
+
+ /*
+ * Set the DMA Info
+ */
+ temp8 = (u8) ((linked_list->data.dma.type & 0x03) << 5);
+
+ temp8 |= ((linked_list->data.dma.bus_master & 0x01) << 2);
+
+ temp8 |= (linked_list->data.dma.transfer & 0x03);
+
+ *buffer = temp8;
+
+ buffer += 1;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = (u32) ((NATIVE_UINT) buffer -
+ (NATIVE_UINT) *output_buffer);
+
+ return (AE_OK);
+}
+
diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c
new file mode 100644
index 000000000..964d126e2
--- /dev/null
+++ b/drivers/acpi/resources/rsirq.c
@@ -0,0 +1,568 @@
+/******************************************************************************
+ *
+ * Module Name: rsirq - Acpi_rs_irq_resource,
+ * Acpi_rs_irq_stream
+ * Acpi_rs_extended_irq_resource
+ * Acpi_rs_extended_irq_stream
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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"
+
+#define _COMPONENT RESOURCE_MANAGER
+ MODULE_NAME ("rsirq");
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_irq_resource
+ *
+ * PARAMETERS:
+ * Byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes consumed from
+ * the Byte_stream_buffer
+ * Output_buffer - Pointer to the user's return buffer
+ * Structure_size - u32 pointer that is filled with
+ * the number of bytes in the filled
+ * in structure
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the Output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_irq_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ RESOURCE *output_struct = (RESOURCE *) * output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u8 index;
+ u8 i;
+ u32 struct_size = sizeof (IRQ_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+
+
+ /*
+ * The number of bytes consumed are contained in the descriptor
+ * (Bits:0-1)
+ */
+ temp8 = *buffer;
+
+ *bytes_consumed = (temp8 & 0x03) + 1;
+
+ output_struct->id = irq;
+
+ /*
+ * Point to the 16-bits of Bytes 1 and 2
+ */
+ buffer += 1;
+ temp16 = *(u16 *)buffer;
+
+ output_struct->data.irq.number_of_interrupts = 0;
+
+ /* Decode the IRQ bits */
+ for (i = 0, index = 0; index < 16; index++) {
+ if((temp16 >> index) & 0x01) {
+ output_struct->data.irq.interrupts[i] = index;
+ i++;
+ }
+ }
+ output_struct->data.irq.number_of_interrupts = i;
+
+ /*
+ * Calculate the structure size based upon the number of interrupts
+ */
+ struct_size += (output_struct->data.irq.number_of_interrupts - 1) * 4;
+
+ /*
+ * Point to Byte 3 if it is used
+ */
+ if (4 == *bytes_consumed) {
+ buffer += 2;
+
+ temp8 = *buffer;
+
+ /*
+ * Check for HE, LL or HL
+ */
+ if (temp8 & 0x01) {
+ output_struct->data.irq.edge_level = EDGE_SENSITIVE;
+ output_struct->data.irq.active_high_low = ACTIVE_HIGH;
+ }
+
+ else {
+ if (temp8 & 0x8) {
+ output_struct->data.irq.edge_level = LEVEL_SENSITIVE;
+ output_struct->data.irq.active_high_low = ACTIVE_LOW;
+ }
+
+ else {
+ /*
+ * Only _LL and _HE polarity/trigger interrupts
+ * are allowed (ACPI spec v1.0b ection 6.4.2.1),
+ * so an error will occur if we reach this point
+ */
+ return (AE_BAD_DATA);
+ }
+ }
+
+ /*
+ * Check for sharable
+ */
+ output_struct->data.irq.shared_exclusive = (temp8 >> 3) & 0x01;
+ }
+
+ else {
+ /*
+ * Assume Edge Sensitive, Active High, Non-Sharable
+ * per ACPI Specification
+ */
+ output_struct->data.irq.edge_level = EDGE_SENSITIVE;
+ output_struct->data.irq.active_high_low = ACTIVE_HIGH;
+ output_struct->data.irq.shared_exclusive = EXCLUSIVE;
+ }
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_irq_stream
+ *
+ * PARAMETERS:
+ * Linked_list - Pointer to the resource linked list
+ * Output_buffer - Pointer to the user's return buffer
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes of the
+ * Output_buffer used
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_irq_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u8 index;
+ u8 IRQinfo_byte_needed;
+
+
+ /*
+ * The descriptor field is set based upon whether a third byte is
+ * needed to contain the IRQ Information.
+ */
+ if (EDGE_SENSITIVE == linked_list->data.irq.edge_level &&
+ ACTIVE_HIGH == linked_list->data.irq.active_high_low &&
+ EXCLUSIVE == linked_list->data.irq.shared_exclusive)
+ {
+ *buffer = 0x22;
+ IRQinfo_byte_needed = FALSE;
+ }
+ else {
+ *buffer = 0x23;
+ IRQinfo_byte_needed = TRUE;
+ }
+
+ buffer += 1;
+
+ temp16 = 0;
+
+ /*
+ * Loop through all of the interrupts and set the mask bits
+ */
+ for(index = 0;
+ index < linked_list->data.irq.number_of_interrupts;
+ index++)
+ {
+ temp8 = (u8) linked_list->data.irq.interrupts[index];
+ temp16 |= 0x1 << temp8;
+ }
+
+ *(u16 *)buffer = temp16;
+
+ buffer += 2;
+
+ /*
+ * Set the IRQ Info byte if needed.
+ */
+ if (IRQinfo_byte_needed) {
+ temp8 = 0;
+
+ temp8 = (u8) ((linked_list->data.irq.shared_exclusive &
+ 0x01) << 4);
+
+ if (LEVEL_SENSITIVE == linked_list->data.irq.edge_level &&
+ ACTIVE_LOW == linked_list->data.irq.active_high_low)
+ {
+ temp8 |= 0x08;
+ }
+
+ else {
+ temp8 |= 0x01;
+ }
+
+ *buffer = temp8;
+
+ buffer += 1;
+ }
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = (u32) ((NATIVE_UINT) buffer -
+ (NATIVE_UINT) *output_buffer);
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_extended_irq_resource
+ *
+ * PARAMETERS:
+ * Byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes consumed from
+ * the Byte_stream_buffer
+ * Output_buffer - Pointer to the user's return buffer
+ * Structure_size - u32 pointer that is filled with
+ * the number of bytes in the filled
+ * in structure
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the Output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_extended_irq_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ RESOURCE *output_struct = (RESOURCE *) * output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u8 index;
+ u32 struct_size = sizeof (EXTENDED_IRQ_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+
+
+ /*
+ * Point past the Descriptor to get the number of bytes consumed
+ */
+ buffer += 1;
+ temp16 = *(u16 *)buffer;
+
+ *bytes_consumed = temp16 + 3;
+ output_struct->id = extended_irq;
+
+ /*
+ * Point to the Byte3
+ */
+ buffer += 2;
+ temp8 = *buffer;
+
+ output_struct->data.extended_irq.producer_consumer = temp8 & 0x01;
+
+ /*
+ * Check for HE, LL or HL
+ */
+ if(temp8 & 0x02) {
+ output_struct->data.extended_irq.edge_level = EDGE_SENSITIVE;
+ output_struct->data.extended_irq.active_high_low = ACTIVE_HIGH;
+ }
+
+ else {
+ if(temp8 & 0x4) {
+ output_struct->data.extended_irq.edge_level = LEVEL_SENSITIVE;
+ output_struct->data.extended_irq.active_high_low = ACTIVE_LOW;
+ }
+
+ else {
+ /*
+ * Only _LL and _HE polarity/trigger interrupts
+ * are allowed (ACPI spec v1.0b ection 6.4.2.1),
+ * so an error will occur if we reach this point
+ */
+ return (AE_BAD_DATA);
+ }
+ }
+
+ /*
+ * Check for sharable
+ */
+ output_struct->data.extended_irq.shared_exclusive =
+ (temp8 >> 3) & 0x01;
+
+ /*
+ * Point to Byte4 (IRQ Table length)
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ output_struct->data.extended_irq.number_of_interrupts = temp8;
+
+ /*
+ * Add any additional structure size to properly calculate
+ * the next pointer at the end of this function
+ */
+ struct_size += (temp8 - 1) * 4;
+
+ /*
+ * Point to Byte5 (First IRQ Number)
+ */
+ buffer += 1;
+
+ /*
+ * Cycle through every IRQ in the table
+ */
+ for (index = 0; index < temp8; index++) {
+ output_struct->data.extended_irq.interrupts[index] =
+ (u32)*buffer;
+
+ /* Point to the next IRQ */
+
+ buffer += 4;
+ }
+
+ /*
+ * This will leave us pointing to the Resource Source Index
+ * If it is present, then save it off and calculate the
+ * pointer to where the null terminated string goes:
+ * Each Interrupt takes 32-bits + the 5 bytes of the
+ * stream that are default.
+ */
+ if (*bytes_consumed >
+ (u32)(output_struct->data.extended_irq.number_of_interrupts *
+ 4) + 5)
+ {
+ /* Dereference the Index */
+
+ temp8 = *buffer;
+ output_struct->data.extended_irq.resource_source_index =
+ (u32)temp8;
+
+ /* Point to the String */
+
+ buffer += 1;
+
+ /* Copy the string into the buffer */
+
+ index = 0;
+
+ while (0x00 != *buffer) {
+ output_struct->data.extended_irq.resource_source[index] =
+ *buffer;
+
+ buffer += 1;
+ index += 1;
+ }
+
+ /*
+ * Add the terminating null
+ */
+ output_struct->data.extended_irq.resource_source[index] = 0x00;
+ output_struct->data.extended_irq.resource_source_string_length =
+ index + 1;
+
+ /*
+ * In order for the Struct_size to fall on a 32-bit boundry,
+ * calculate the length of the string and expand the
+ * Struct_size to the next 32-bit boundry.
+ */
+ temp8 = (u8) (index + 1);
+ temp8 = (u8) ROUND_UP_TO_32_bITS (temp8);
+ }
+
+ else {
+ output_struct->data.extended_irq.resource_source_index = 0x00;
+ output_struct->data.extended_irq.resource_source_string_length = 0;
+ output_struct->data.extended_irq.resource_source[0] = 0x00;
+ }
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_extended_irq_stream
+ *
+ * PARAMETERS:
+ * Linked_list - Pointer to the resource linked list
+ * Output_buffer - Pointer to the user's return buffer
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes of the
+ * Output_buffer used
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_extended_irq_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 *length_field;
+ u8 temp8 = 0;
+ u8 index;
+ u8 *temp_pointer = NULL;
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x89;
+ buffer += 1;
+
+ /*
+ * Set a pointer to the Length field - to be filled in later
+ */
+
+ length_field = (u16 *)buffer;
+ buffer += 2;
+
+ /*
+ * Set the Interrupt vector flags
+ */
+ temp8 = (u8)(linked_list->data.extended_irq.producer_consumer & 0x01);
+
+ temp8 |= ((linked_list->data.extended_irq.shared_exclusive & 0x01) << 3);
+
+ if (LEVEL_SENSITIVE == linked_list->data.extended_irq.edge_level &&
+ ACTIVE_LOW == linked_list->data.extended_irq.active_high_low)
+ {
+ temp8 |= 0x04;
+ }
+ else {
+ temp8 |= 0x02;
+ }
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the Interrupt table length
+ */
+ temp8 = (u8) linked_list->data.extended_irq.number_of_interrupts;
+
+ *buffer = temp8;
+
+ buffer += 1;
+
+ for (index = 0;
+ index < linked_list->data.extended_irq.number_of_interrupts;
+ index++)
+ {
+ MOVE_UNALIGNED32_TO_32 (buffer,
+ &linked_list->data.extended_irq.interrupts[index]);
+ buffer += 4;
+ }
+
+ /*
+ * Resource Source Index and Resource Source are optional
+ */
+ if (0 != linked_list->data.extended_irq.resource_source_string_length) {
+ temp8 = (u8) linked_list->data.extended_irq.resource_source_index;
+
+ *buffer = temp8;
+ buffer += 1;
+ temp_pointer = buffer;
+
+ /*
+ * Copy the string
+ */
+ STRCPY (temp_pointer, linked_list->data.extended_irq.resource_source);
+
+ /*
+ * Buffer needs to be set to the length of the sting + one for the
+ * terminating null
+ */
+ buffer += (STRLEN (linked_list->data.extended_irq.resource_source) + 1);
+ }
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = (u32) ((NATIVE_UINT) buffer -
+ (NATIVE_UINT) *output_buffer);
+
+ /*
+ * Set the length field to the number of bytes consumed
+ * minus the header size (3 bytes)
+ */
+ *length_field = (u16) (*bytes_consumed - 3);
+
+ return (AE_OK);
+}
+
diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c
new file mode 100644
index 000000000..3f96e5314
--- /dev/null
+++ b/drivers/acpi/resources/rslist.c
@@ -0,0 +1,506 @@
+/******************************************************************************
+ *
+ * Module Name: rslist - Acpi_rs_byte_stream_to_list
+ * Acpi_list_to_byte_stream
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "resource.h"
+
+#define _COMPONENT RESOURCE_MANAGER
+ MODULE_NAME ("rslist");
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_byte_stream_to_list
+ *
+ * PARAMETERS:
+ * Byte_stream_buffer - Pointer to the resource byte stream
+ * Byte_stream_buffer_length - Length of Byte_stream_buffer
+ * Output_buffer - Pointer to the buffer that will
+ * contain the output structures
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Takes the resource byte stream and parses it, creating a
+ * linked list of resources in the caller's output buffer
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_byte_stream_to_list (
+ u8 *byte_stream_buffer,
+ u32 byte_stream_buffer_length,
+ u8 **output_buffer)
+{
+ ACPI_STATUS status = AE_UNKNOWN_STATUS;
+ u32 bytes_parsed = 0;
+ u8 resource_type = 0;
+ u32 bytes_consumed = 0;
+ u8 **buffer = output_buffer;
+ u32 structure_size = 0;
+ u8 end_tag_processed = FALSE;
+
+
+ while (bytes_parsed < byte_stream_buffer_length &&
+ FALSE == end_tag_processed)
+ {
+ /*
+ * Look at the next byte in the stream
+ */
+ resource_type = *byte_stream_buffer;
+
+ /*
+ * See if this is a small or large resource
+ */
+ if(resource_type & 0x80) {
+ /*
+ * Large Resource Type
+ */
+ switch (resource_type)
+ {
+ case MEMORY_RANGE_24:
+ /*
+ * 24-Bit Memory Resource
+ */
+ status = acpi_rs_memory24_resource(byte_stream_buffer,
+ &bytes_consumed,
+ buffer,
+ &structure_size);
+
+ break;
+
+ case LARGE_VENDOR_DEFINED:
+ /*
+ * Vendor Defined Resource
+ */
+ status = acpi_rs_vendor_resource(byte_stream_buffer,
+ &bytes_consumed,
+ buffer,
+ &structure_size);
+
+ break;
+
+ case MEMORY_RANGE_32:
+ /*
+ * 32-Bit Memory Range Resource
+ */
+ status = acpi_rs_memory32_range_resource(byte_stream_buffer,
+ &bytes_consumed,
+ buffer,
+ &structure_size);
+
+ break;
+
+ case FIXED_MEMORY_RANGE_32:
+ /*
+ * 32-Bit Fixed Memory Resource
+ */
+ status = acpi_rs_fixed_memory32_resource(byte_stream_buffer,
+ &bytes_consumed,
+ buffer,
+ &structure_size);
+
+ break;
+
+ case DWORD_ADDRESS_SPACE:
+ /*
+ * 32-Bit Address Resource
+ */
+ status = acpi_rs_address32_resource(byte_stream_buffer,
+ &bytes_consumed,
+ buffer,
+ &structure_size);
+
+ break;
+
+ case WORD_ADDRESS_SPACE:
+ /*
+ * 16-Bit Address Resource
+ */
+ status = acpi_rs_address16_resource(byte_stream_buffer,
+ &bytes_consumed,
+ buffer,
+ &structure_size);
+
+ break;
+
+ case EXTENDED_IRQ:
+ /*
+ * Extended IRQ
+ */
+ status = acpi_rs_extended_irq_resource(byte_stream_buffer,
+ &bytes_consumed,
+ buffer,
+ &structure_size);
+
+ break;
+
+/* 64-bit not currently supported */
+/*
+ case 0x8A:
+ break;
+*/
+
+ default:
+ /*
+ * If we get here, everything is out of sync,
+ * so exit with an error
+ */
+ return (AE_ERROR);
+ break;
+ }
+ }
+
+ else {
+ /*
+ * Small Resource Type
+ * Only bits 7:3 are valid
+ */
+ resource_type >>= 3;
+
+ switch(resource_type)
+ {
+ case IRQ_FORMAT:
+ /*
+ * IRQ Resource
+ */
+ status = acpi_rs_irq_resource(byte_stream_buffer,
+ &bytes_consumed,
+ buffer,
+ &structure_size);
+
+ break;
+
+ case DMA_FORMAT:
+ /*
+ * DMA Resource
+ */
+ status = acpi_rs_dma_resource(byte_stream_buffer,
+ &bytes_consumed,
+ buffer,
+ &structure_size);
+
+ break;
+
+ case START_DEPENDENT_TAG:
+ /*
+ * Start Dependent Functions Resource
+ */
+ status = acpi_rs_start_dependent_functions_resource(byte_stream_buffer,
+ &bytes_consumed,
+ buffer,
+ &structure_size);
+
+ break;
+
+ case END_DEPENDENT_TAG:
+ /*
+ * End Dependent Functions Resource
+ */
+ status = acpi_rs_end_dependent_functions_resource(byte_stream_buffer,
+ &bytes_consumed,
+ buffer,
+ &structure_size);
+
+ break;
+
+ case IO_PORT_DESCRIPTOR:
+ /*
+ * IO Port Resource
+ */
+ status = acpi_rs_io_resource(byte_stream_buffer,
+ &bytes_consumed,
+ buffer,
+ &structure_size);
+
+ break;
+
+ case FIXED_LOCATION_IO_DESCRIPTOR:
+ /*
+ * Fixed IO Port Resource
+ */
+ status = acpi_rs_fixed_io_resource(byte_stream_buffer,
+ &bytes_consumed,
+ buffer,
+ &structure_size);
+
+ break;
+
+ case SMALL_VENDOR_DEFINED:
+ /*
+ * Vendor Specific Resource
+ */
+ status = acpi_rs_vendor_resource(byte_stream_buffer,
+ &bytes_consumed,
+ buffer,
+ &structure_size);
+
+ break;
+
+ case END_TAG:
+ /*
+ * End Tag
+ */
+ status = acpi_rs_end_tag_resource(byte_stream_buffer,
+ &bytes_consumed,
+ buffer,
+ &structure_size);
+ end_tag_processed = TRUE;
+
+ break;
+
+ default:
+ /*
+ * If we get here, everything is out of sync,
+ * so exit with an error
+ */
+ return (AE_ERROR);
+ break;
+
+ } /* switch */
+ } /* if(Resource_type & 0x80) */
+
+ /*
+ * Update the return value and counter
+ */
+ bytes_parsed += bytes_consumed;
+
+ /*
+ * Set the byte stream to point to the next resource
+ */
+ byte_stream_buffer += bytes_consumed;
+
+ /*
+ * Set the Buffer to the next structure
+ */
+ *buffer += structure_size;
+
+ } /* while (Bytes_parsed < Byte_stream_buffer_length &&
+ FALSE == End_tag_processed) */
+
+ /*
+ * Check the reason for exiting the while loop
+ */
+ if (byte_stream_buffer_length != bytes_parsed || TRUE != end_tag_processed) {
+ return (AE_ERROR);
+ }
+
+ return (AE_OK);
+
+} /* Acpi_rs_byte_stream_to_list */
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_list_to_byte_stream
+ *
+ * PARAMETERS:
+ * Linked_list - Pointer to the resource linked list
+ * Byte_steam_size_needed - Calculated size of the byte stream
+ * needed from calling
+ * Acpi_rs_calculate_byte_stream_length()
+ * The size of the Output_buffer is
+ * guaranteed to be >=
+ * Byte_stream_size_needed
+ * Output_buffer - Pointer to the buffer that will
+ * contain the byte stream
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Takes the resource linked list and parses it, creating a
+ * byte stream of resources in the caller's output buffer
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_list_to_byte_stream (
+ RESOURCE *linked_list,
+ u32 byte_stream_size_needed,
+ u8 **output_buffer)
+{
+ ACPI_STATUS status = AE_UNKNOWN_STATUS;
+ u8 *buffer = *output_buffer;
+ u32 bytes_consumed = 0;
+ u8 done = FALSE;
+
+
+ while (!done) {
+ switch (linked_list->id)
+ {
+ case irq:
+ /*
+ * IRQ Resource
+ */
+ status = acpi_rs_irq_stream (linked_list,
+ &buffer,
+ &bytes_consumed);
+ break;
+
+ case dma:
+ /*
+ * DMA Resource
+ */
+ status = acpi_rs_dma_stream (linked_list,
+ &buffer,
+ &bytes_consumed);
+ break;
+
+ case start_dependent_functions:
+ /*
+ * Start Dependent Functions Resource
+ */
+ status = acpi_rs_start_dependent_functions_stream (linked_list,
+ &buffer,
+ &bytes_consumed);
+ break;
+
+ case end_dependent_functions:
+ /*
+ * End Dependent Functions Resource
+ */
+ status = acpi_rs_end_dependent_functions_stream (linked_list,
+ &buffer,
+ &bytes_consumed);
+ break;
+
+ case io:
+ /*
+ * IO Port Resource
+ */
+ status = acpi_rs_io_stream (linked_list,
+ &buffer,
+ &bytes_consumed);
+ break;
+
+ case fixed_io:
+ /*
+ * Fixed IO Port Resource
+ */
+ status = acpi_rs_fixed_io_stream (linked_list,
+ &buffer,
+ &bytes_consumed);
+ break;
+
+ case vendor_specific:
+ /*
+ * Vendor Defined Resource
+ */
+ status = acpi_rs_vendor_stream (linked_list,
+ &buffer,
+ &bytes_consumed);
+ break;
+
+ case end_tag:
+ /*
+ * End Tag
+ */
+ status = acpi_rs_end_tag_stream (linked_list,
+ &buffer,
+ &bytes_consumed);
+
+ /*
+ * An End Tag indicates the end of the Resource Template
+ */
+ done = TRUE;
+ break;
+
+ case memory24:
+ /*
+ * 24-Bit Memory Resource
+ */
+ status = acpi_rs_memory24_stream (linked_list,
+ &buffer,
+ &bytes_consumed);
+ break;
+
+ case memory32:
+ /*
+ * 32-Bit Memory Range Resource
+ */
+ status = acpi_rs_memory32_range_stream (linked_list,
+ &buffer,
+ &bytes_consumed);
+ break;
+
+ case fixed_memory32:
+ /*
+ * 32-Bit Fixed Memory Resource
+ */
+ status = acpi_rs_fixed_memory32_stream (linked_list,
+ &buffer,
+ &bytes_consumed);
+ break;
+
+ case address16:
+ /*
+ * 16-Bit Address Descriptor Resource
+ */
+ status = acpi_rs_address16_stream (linked_list,
+ &buffer,
+ &bytes_consumed);
+ break;
+
+ case address32:
+ /*
+ * 32-Bit Address Descriptor Resource
+ */
+ status = acpi_rs_address32_stream (linked_list,
+ &buffer,
+ &bytes_consumed);
+ break;
+
+ case extended_irq:
+ /*
+ * Extended IRQ Resource
+ */
+ status = acpi_rs_extended_irq_stream (linked_list,
+ &buffer,
+ &bytes_consumed);
+ break;
+
+ default:
+ /*
+ * If we get here, everything is out of sync,
+ * so exit with an error
+ */
+ return (AE_BAD_DATA);
+ break;
+
+ } /* switch (Linked_list->Id) */
+
+ /*
+ * Set the Buffer to point to the open byte
+ */
+ buffer += bytes_consumed;
+
+ /*
+ * Point to the next object
+ */
+ linked_list = (RESOURCE *) ((NATIVE_UINT) linked_list +
+ (NATIVE_UINT) linked_list->length);
+ }
+
+ return (AE_OK);
+
+} /* Acpi_rs_list_to_byte_stream */
+
diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/resources/rsmemory.c
new file mode 100644
index 000000000..2fdb40501
--- /dev/null
+++ b/drivers/acpi/resources/rsmemory.c
@@ -0,0 +1,570 @@
+/******************************************************************************
+ *
+ * Module Name: rsmem24 - Acpi_rs_memory24_resource
+ * Acpi_rs_memory24_stream
+ * Acpi_rs_memory32_range_resource
+ * Acpi_rs_fixed_memory32_resource
+ * Acpi_rs_memory32_range_stream
+ * Acpi_rs_fixed_memory32_stream
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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"
+
+#define _COMPONENT RESOURCE_MANAGER
+ MODULE_NAME ("rsmemory");
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_memory24_resource
+ *
+ * PARAMETERS:
+ * Byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes consumed from
+ * the Byte_stream_buffer
+ * Output_buffer - Pointer to the user's return buffer
+ * Structure_size - u32 pointer that is filled with
+ * the number of bytes in the filled
+ * in structure
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the Output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_memory24_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ RESOURCE *output_struct = (RESOURCE *) * output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u32 struct_size = sizeof (MEMORY24_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+
+
+ /*
+ * Point past the Descriptor to get the number of bytes consumed
+ */
+ buffer += 1;
+
+ temp16 = *(u16 *)buffer;
+
+ buffer += 2;
+
+ *bytes_consumed = temp16 + 3;
+
+ output_struct->id = memory24;
+
+ /*
+ * Check Byte 3 the Read/Write bit
+ */
+ temp8 = *buffer;
+
+ buffer += 1;
+
+ output_struct->data.memory24.read_write_attribute = temp8 & 0x01;
+
+ /*
+ * Get Min_base_address (Bytes 4-5)
+ */
+ temp16 = *(u16 *)buffer;
+
+ buffer += 2;
+
+ output_struct->data.memory24.min_base_address = temp16;
+
+ /*
+ * Get Max_base_address (Bytes 6-7)
+ */
+ temp16 = *(u16 *)buffer;
+
+ buffer += 2;
+
+ output_struct->data.memory24.max_base_address = temp16;
+
+ /*
+ * Get Alignment (Bytes 8-9)
+ */
+ temp16 = *(u16 *)buffer;
+
+ buffer += 2;
+
+ output_struct->data.memory24.alignment = temp16;
+
+ /*
+ * Get Range_length (Bytes 10-11)
+ */
+ temp16 = *(u16 *)buffer;
+
+ output_struct->data.memory24.range_length = temp16;
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_memory24_stream
+ *
+ * PARAMETERS:
+ * Linked_list - Pointer to the resource linked list
+ * Output_buffer - Pointer to the user's return buffer
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes of the
+ * Output_buffer used
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_memory24_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x81;
+
+ buffer += 1;
+
+ /*
+ * The length field is static
+ */
+ temp16 = 0x09;
+
+ MOVE_UNALIGNED16_TO_16 (buffer, &temp16);
+
+ buffer += 2;
+
+ /*
+ * Set the Information Byte
+ */
+ temp8 = (u8) (linked_list->data.memory24.read_write_attribute & 0x01);
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the Range minimum base address
+ */
+ MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.min_base_address);
+ buffer += 2;
+
+ /*
+ * Set the Range maximum base address
+ */
+ MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.max_base_address);
+ buffer += 2;
+
+ /*
+ * Set the base alignment
+ */
+ MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.alignment);
+ buffer += 2;
+
+ /*
+ * Set the range length
+ */
+ MOVE_UNALIGNED16_TO_16 (buffer, &linked_list->data.memory24.range_length);
+ buffer += 2;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = (u32) ((NATIVE_UINT) buffer -
+ (NATIVE_UINT) *output_buffer);
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_memory32_range_resource
+ *
+ * PARAMETERS:
+ * Byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes consumed from
+ * the Byte_stream_buffer
+ * Output_buffer - Pointer to the user's return buffer
+ * Structure_size - u32 pointer that is filled with
+ * the number of bytes in the filled
+ * in structure
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the Output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_memory32_range_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ RESOURCE *output_struct = (RESOURCE *) * output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u32 struct_size = sizeof (MEMORY32_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+
+
+ /*
+ * Point past the Descriptor to get the number of bytes consumed
+ */
+ buffer += 1;
+
+ MOVE_UNALIGNED16_TO_16 (&temp16, buffer);
+ buffer += 2;
+ *bytes_consumed = temp16 + 3;
+
+ output_struct->id = memory32;
+
+ /*
+ * Point to the place in the output buffer where the data portion will
+ * begin.
+ * 1. Set the RESOURCE_DATA * Data to point to it's own address, then
+ * 2. Set the pointer to the next address.
+ *
+ * NOTE: Output_struct->Data is cast to u8, otherwise, this addition adds
+ * 4 * sizeof(RESOURCE_DATA) instead of 4 * sizeof(u8)
+ */
+
+ /*
+ * Check Byte 3 the Read/Write bit
+ */
+ temp8 = *buffer;
+ buffer += 1;
+
+ output_struct->data.memory32.read_write_attribute = temp8 & 0x01;
+
+ /*
+ * Get Min_base_address (Bytes 4-7)
+ */
+ MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.min_base_address,
+ buffer);
+ buffer += 4;
+
+ /*
+ * Get Max_base_address (Bytes 8-11)
+ */
+ MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.max_base_address,
+ buffer);
+ buffer += 4;
+
+ /*
+ * Get Alignment (Bytes 12-15)
+ */
+ MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.alignment, buffer);
+ buffer += 4;
+
+ /*
+ * Get Range_length (Bytes 16-19)
+ */
+ MOVE_UNALIGNED32_TO_32 (&output_struct->data.memory32.range_length, buffer);
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_fixed_memory32_resource
+ *
+ * PARAMETERS:
+ * Byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes consumed from
+ * the Byte_stream_buffer
+ * Output_buffer - Pointer to the user's return buffer
+ * Structure_size - u32 pointer that is filled with
+ * the number of bytes in the filled
+ * in structure
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the Output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_fixed_memory32_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ RESOURCE *output_struct = (RESOURCE *) * output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u32 struct_size = sizeof (FIXED_MEMORY32_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+
+
+ /*
+ * Point past the Descriptor to get the number of bytes consumed
+ */
+ buffer += 1;
+ MOVE_UNALIGNED16_TO_16 (&temp16, buffer);
+
+ buffer += 2;
+ *bytes_consumed = temp16 + 3;
+
+ output_struct->id = fixed_memory32;
+
+ /*
+ * Check Byte 3 the Read/Write bit
+ */
+ temp8 = *buffer;
+ buffer += 1;
+ output_struct->data.fixed_memory32.read_write_attribute = temp8 & 0x01;
+
+ /*
+ * Get Range_base_address (Bytes 4-7)
+ */
+ MOVE_UNALIGNED32_TO_32 (&output_struct->data.fixed_memory32.range_base_address,
+ buffer);
+ buffer += 4;
+
+ /*
+ * Get Range_length (Bytes 8-11)
+ */
+ MOVE_UNALIGNED32_TO_32 (&output_struct->data.fixed_memory32.range_length,
+ buffer);
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_memory32_range_stream
+ *
+ * PARAMETERS:
+ * Linked_list - Pointer to the resource linked list
+ * Output_buffer - Pointer to the user's return buffer
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes of the
+ * Output_buffer used
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_memory32_range_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x85;
+ buffer += 1;
+
+ /*
+ * The length field is static
+ */
+ temp16 = 0x11;
+
+ MOVE_UNALIGNED16_TO_16 (buffer, &temp16);
+ buffer += 2;
+
+ /*
+ * Set the Information Byte
+ */
+ temp8 = (u8) (linked_list->data.memory32.read_write_attribute & 0x01);
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the Range minimum base address
+ */
+ MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.min_base_address);
+ buffer += 4;
+
+ /*
+ * Set the Range maximum base address
+ */
+ MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.max_base_address);
+ buffer += 4;
+
+ /*
+ * Set the base alignment
+ */
+ MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.alignment);
+ buffer += 4;
+
+ /*
+ * Set the range length
+ */
+ MOVE_UNALIGNED32_TO_32 (buffer, &linked_list->data.memory32.range_length);
+ buffer += 4;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = (u32) ((NATIVE_UINT) buffer -
+ (NATIVE_UINT) *output_buffer);
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_fixed_memory32_stream
+ *
+ * PARAMETERS:
+ * Linked_list - Pointer to the resource linked list
+ * Output_buffer - Pointer to the user's return buffer
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes of the
+ * Output_buffer used
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_fixed_memory32_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x86;
+ buffer += 1;
+
+ /*
+ * The length field is static
+ */
+ temp16 = 0x09;
+
+ MOVE_UNALIGNED16_TO_16 (buffer, &temp16);
+ buffer += 2;
+
+ /*
+ * Set the Information Byte
+ */
+ temp8 = (u8) (linked_list->data.fixed_memory32.read_write_attribute & 0x01);
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the Range base address
+ */
+ MOVE_UNALIGNED32_TO_32 (buffer,
+ &linked_list->data.fixed_memory32.range_base_address);
+ buffer += 4;
+
+ /*
+ * Set the range length
+ */
+ MOVE_UNALIGNED32_TO_32 (buffer,
+ &linked_list->data.fixed_memory32.range_length);
+ buffer += 4;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = (u32) ((NATIVE_UINT) buffer -
+ (NATIVE_UINT) *output_buffer);
+
+ return (AE_OK);
+}
+
diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c
new file mode 100644
index 000000000..fc5a6725f
--- /dev/null
+++ b/drivers/acpi/resources/rsmisc.c
@@ -0,0 +1,612 @@
+/******************************************************************************
+ *
+ * Module Name: rsmisc - Acpi_rs_end_tag_resource
+ * Acpi_rs_end_tag_stream
+ * Acpi_rs_vendor_resource
+ * Acpi_rs_vendor_stream
+ * Acpi_rs_start_dependent_functions_resource
+ * Acpi_rs_end_dependent_functions_resource
+ * Acpi_rs_start_dependent_functions_stream
+ * Acpi_rs_end_dependent_functions_stream
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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"
+
+#define _COMPONENT RESOURCE_MANAGER
+ MODULE_NAME ("rsmisc");
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_end_tag_resource
+ *
+ * PARAMETERS:
+ * Byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes consumed from
+ * the Byte_stream_buffer
+ * Output_buffer - Pointer to the user's return buffer
+ * Structure_size - u32 pointer that is filled with
+ * the number of bytes in the filled
+ * in structure
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the Output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_end_tag_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size)
+{
+ RESOURCE *output_struct = (RESOURCE *) * output_buffer;
+ u32 struct_size = RESOURCE_LENGTH;
+
+
+ /*
+ * The number of bytes consumed is static
+ */
+ *bytes_consumed = 2;
+
+ /*
+ * Fill out the structure
+ */
+ output_struct->id = end_tag;
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = 0;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_end_tag_stream
+ *
+ * PARAMETERS:
+ * Linked_list - Pointer to the resource linked list
+ * Output_buffer - Pointer to the user's return buffer
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes of the
+ * Output_buffer used
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_end_tag_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u8 temp8 = 0;
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x79;
+
+ buffer += 1;
+
+ /*
+ * Set the Checksum - zero means that the resource data is treated as if
+ * the checksum operation succeeded (ACPI Spec 1.0b Section 6.4.2.8)
+ */
+ temp8 = 0;
+
+ *buffer = temp8;
+
+ buffer += 1;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = (u32) ((NATIVE_UINT) buffer -
+ (NATIVE_UINT) *output_buffer);
+
+ return (AE_OK);
+}
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_vendor_resource
+ *
+ * PARAMETERS:
+ * Byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes consumed from
+ * the Byte_stream_buffer
+ * Output_buffer - Pointer to the user's return buffer
+ * Structure_size - u32 pointer that is filled with
+ * the number of bytes in the filled
+ * in structure
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the Output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_vendor_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ RESOURCE *output_struct = (RESOURCE *) * output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u8 index;
+ u32 struct_size = sizeof (VENDOR_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+
+
+ /*
+ * Dereference the Descriptor to find if this is a large or small item.
+ */
+ temp8 = *buffer;
+
+ if (temp8 & 0x80) {
+ /*
+ * Large Item
+ */
+ /* Point to the length field */
+
+ buffer += 1;
+
+ /* Dereference */
+
+ temp16 = *(u16 *)buffer;
+
+ /* Calculate bytes consumed */
+
+ *bytes_consumed = temp16 + 3;
+
+ /* Point to the first vendor byte */
+
+ buffer += 2;
+ }
+
+ else {
+ /*
+ * Small Item
+ */
+
+ /* Dereference the size */
+
+ temp16 = (u8)(*buffer & 0x07);
+
+ /* Calculate bytes consumed */
+
+ *bytes_consumed = temp16 + 1;
+
+ /* Point to the first vendor byte */
+
+ buffer += 1;
+ }
+
+ output_struct->id = vendor_specific;
+
+ output_struct->data.vendor_specific.length = temp16;
+
+ for (index = 0; index < temp16; index++) {
+ output_struct->data.vendor_specific.reserved[index] = *buffer;
+ buffer += 1;
+ }
+
+ /*
+ * In order for the Struct_size to fall on a 32-bit boundry,
+ * calculate the length of the vendor string and expand the
+ * Struct_size to the next 32-bit boundry.
+ */
+ struct_size += ROUND_UP_TO_32_bITS (temp16);
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_vendor_stream
+ *
+ * PARAMETERS:
+ * Linked_list - Pointer to the resource linked list
+ * Output_buffer - Pointer to the user's return buffer
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes of the
+ * Output_buffer used
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_vendor_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u8 index;
+
+
+ /*
+ * Dereference the length to find if this is a large or small item.
+ */
+
+ if(linked_list->data.vendor_specific.length > 7) {
+ /*
+ * Large Item
+ */
+ /*
+ * Set the descriptor field and length bytes
+ */
+ *buffer = 0x84;
+
+ buffer += 1;
+
+ temp16 = (u16) linked_list->data.vendor_specific.length;
+
+ *(u16 *)buffer = temp16;
+
+ buffer += 2;
+ }
+
+ else {
+ /*
+ * Small Item
+ */
+
+ /*
+ * Set the descriptor field
+ */
+ temp8 = 0x70;
+
+ temp8 |= linked_list->data.vendor_specific.length;
+
+ *buffer = temp8;
+
+ buffer += 1;
+ }
+
+ /*
+ * Loop through all of the Vendor Specific fields
+ */
+ for (index = 0; index < linked_list->data.vendor_specific.length; index++) {
+ temp8 = linked_list->data.vendor_specific.reserved[index];
+ *buffer = temp8;
+ buffer += 1;
+ }
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = (u32) ((NATIVE_UINT) buffer -
+ (NATIVE_UINT) *output_buffer);
+
+ return (AE_OK);
+}
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_start_dependent_functions_resource
+ *
+ * PARAMETERS:
+ * Byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes consumed from
+ * the Byte_stream_buffer
+ * Output_buffer - Pointer to the user's return buffer
+ * Structure_size - u32 pointer that is filled with
+ * the number of bytes in the filled
+ * in structure
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the Output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_start_dependent_functions_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ RESOURCE *output_struct = (RESOURCE *) * output_buffer;
+ u8 temp8 = 0;
+ u32 struct_size =
+ sizeof(START_DEPENDENT_FUNCTIONS_RESOURCE) +
+ RESOURCE_LENGTH_NO_DATA;
+
+
+ /*
+ * The number of bytes consumed are contained in the descriptor (Bits:0-1)
+ */
+ temp8 = *buffer;
+
+ *bytes_consumed = (temp8 & 0x01) + 1;
+
+ output_struct->id = start_dependent_functions;
+
+ /*
+ * Point to Byte 1 if it is used
+ */
+ if (2 == *bytes_consumed) {
+ buffer += 1;
+ temp8 = *buffer;
+
+ /*
+ * Check Compatibility priority
+ */
+ output_struct->data.start_dependent_functions.compatibility_priority =
+ temp8 & 0x03;
+
+ if (3 == output_struct->data.start_dependent_functions.compatibility_priority) {
+ return (AE_ERROR);
+ }
+
+ /*
+ * Check Performance/Robustness preference
+ */
+ output_struct->data.start_dependent_functions.performance_robustness =
+ (temp8 >> 2) & 0x03;
+
+ if (3 == output_struct->data.start_dependent_functions.performance_robustness) {
+ return (AE_ERROR);
+ }
+ }
+
+ else {
+ output_struct->data.start_dependent_functions.compatibility_priority =
+ ACCEPTABLE_CONFIGURATION;
+
+ output_struct->data.start_dependent_functions.performance_robustness =
+ ACCEPTABLE_CONFIGURATION;
+ }
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_end_dependent_functions_resource
+ *
+ * PARAMETERS:
+ * Byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes consumed from
+ * the Byte_stream_buffer
+ * Output_buffer - Pointer to the user's return buffer
+ * Structure_size - u32 pointer that is filled with
+ * the number of bytes in the filled
+ * in structure
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the Output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_end_dependent_functions_resource (
+ u8 *byte_stream_buffer,
+ u32 *bytes_consumed,
+ u8 **output_buffer,
+ u32 *structure_size)
+{
+ RESOURCE *output_struct = (RESOURCE *) * output_buffer;
+ u32 struct_size = RESOURCE_LENGTH;
+
+
+ /*
+ * The number of bytes consumed is static
+ */
+ *bytes_consumed = 1;
+
+ /*
+ * Fill out the structure
+ */
+ output_struct->id = end_dependent_functions;
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_start_dependent_functions_stream
+ *
+ * PARAMETERS:
+ * Linked_list - Pointer to the resource linked list
+ * Output_buffer - Pointer to the user's return buffer
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes of the
+ * Output_buffer used
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ***************************************************************************/
+ACPI_STATUS
+acpi_rs_start_dependent_functions_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u8 temp8 = 0;
+
+
+ /*
+ * The descriptor field is set based upon whether a byte is needed
+ * to contain Priority data.
+ */
+ if (ACCEPTABLE_CONFIGURATION ==
+ linked_list->data.start_dependent_functions.compatibility_priority &&
+ ACCEPTABLE_CONFIGURATION ==
+ linked_list->data.start_dependent_functions.performance_robustness)
+ {
+ *buffer = 0x30;
+ }
+ else {
+ *buffer = 0x31;
+
+ buffer += 1;
+
+ /*
+ * Set the Priority Byte Definition
+ */
+ temp8 = 0;
+
+ temp8 = (u8)
+ ((linked_list->data.start_dependent_functions.performance_robustness &
+ 0x03) << 2);
+
+ temp8 |=
+ (linked_list->data.start_dependent_functions.compatibility_priority &
+ 0x03);
+
+ *buffer = temp8;
+ }
+
+ buffer += 1;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = (u32) ((NATIVE_UINT) buffer -
+ (NATIVE_UINT) *output_buffer);
+
+ return (AE_OK);
+}
+
+
+/***************************************************************************
+ * FUNCTION: Acpi_rs_end_dependent_functions_stream
+ *
+ * PARAMETERS:
+ * Linked_list - Pointer to the resource linked list
+ * Output_buffer - Pointer to the user's return buffer
+ * Bytes_consumed - u32 pointer that is filled with
+ * the number of bytes of the
+ * Output_buffer used
+ *
+ * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_rs_end_dependent_functions_stream (
+ RESOURCE *linked_list,
+ u8 **output_buffer,
+ u32 *bytes_consumed
+ )
+{
+ u8 *buffer = *output_buffer;
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x38;
+
+ buffer += 1;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = (u32) ((NATIVE_UINT) buffer -
+ (NATIVE_UINT) *output_buffer);
+
+ return (AE_OK);
+}
+
diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c
new file mode 100644
index 000000000..cfd8949f3
--- /dev/null
+++ b/drivers/acpi/resources/rsutils.c
@@ -0,0 +1,430 @@
+/******************************************************************************
+ *
+ * Module Name: rsutils - Utilities for the resource manager
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "namesp.h"
+#include "resource.h"
+
+
+#define _COMPONENT RESOURCE_MANAGER
+ MODULE_NAME ("rsutils");
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_get_prt_method_data
+ *
+ * PARAMETERS: Device_handle - a handle to the containing object
+ * Ret_buffer - a pointer to a buffer structure for the
+ * results
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to get the _PRT value of an object
+ * contained in an object specified by the handle passed in
+ *
+ * If the function fails an appropriate status will be returned
+ * and the contents of the callers buffer is undefined.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_rs_get_prt_method_data (
+ ACPI_HANDLE handle,
+ ACPI_BUFFER *ret_buffer)
+{
+ ACPI_OBJECT_INTERNAL *ret_obj;
+ ACPI_STATUS status;
+ u32 buffer_space_needed = ret_buffer->length;
+
+
+ /*
+ * Must have a valid handle and buffer, So we have to have a handle
+ * a return buffer structure and if there is a non-zero buffer length
+ * we also need a valid pointer in the buffer
+ */
+ if ((!handle) ||
+ (!ret_buffer) ||
+ ((!ret_buffer->pointer) && (ret_buffer->length)))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Execute the method, no parameters
+ */
+ status = acpi_ns_evaluate_relative (handle, "_PRT", NULL, &ret_obj);
+ if (status != AE_OK) {
+ return (status);
+ }
+
+ if (!ret_obj) {
+ /* Return object is required */
+
+ return (AE_TYPE);
+ }
+
+
+ /*
+ * The return object will be a package, so check the
+ * parameters. If the return object is not a package,
+ * then the underlying AML code is corrupt or improperly
+ * written.
+ */
+ if (ACPI_TYPE_PACKAGE != ret_obj->common.type) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+ /*
+ * Make the call to create a resource linked list from the
+ * byte stream buffer that comes back from the _CRS method
+ * execution.
+ */
+ status = acpi_rs_create_pci_routing_table (ret_obj,
+ ret_buffer->pointer,
+ &buffer_space_needed);
+
+ /*
+ * Tell the user how much of the buffer we have used or is needed
+ * and return the final status.
+ */
+ ret_buffer->length = buffer_space_needed;
+
+
+ /* On exit, we must delete the object returned by evaluate_object */
+
+cleanup:
+
+ acpi_cm_remove_reference (ret_obj);
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_get_crs_method_data
+ *
+ * PARAMETERS: Device_handle - a handle to the containing object
+ * Ret_buffer - a pointer to a buffer structure for the
+ * results
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to get the _CRS value of an object
+ * contained in an object specified by the handle passed in
+ *
+ * If the function fails an appropriate status will be returned
+ * and the contents of the callers buffer is undefined.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_rs_get_crs_method_data (
+ ACPI_HANDLE handle,
+ ACPI_BUFFER *ret_buffer)
+{
+ ACPI_OBJECT_INTERNAL *ret_obj;
+ ACPI_STATUS status;
+ u32 buffer_space_needed = ret_buffer->length;
+
+
+ /*
+ * Must have a valid handle and buffer, So we have to have a handle
+ * a return buffer structure and if there is a non-zero buffer length
+ * we also need a valid pointer in the buffer
+ */
+ if ((!handle) ||
+ (!ret_buffer) ||
+ ((!ret_buffer->pointer) && (ret_buffer->length)))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Execute the method, no parameters
+ */
+ status = acpi_ns_evaluate_relative (handle, "_CRS", NULL, &ret_obj);
+ if (status != AE_OK) {
+ return (status);
+ }
+
+ if (!ret_obj) {
+ /* Return object is required */
+
+ return (AE_TYPE);
+ }
+
+ /*
+ * The return object will be a buffer, but check the
+ * parameters. If the return object is not a buffer,
+ * then the underlying AML code is corrupt or improperly
+ * written.
+ */
+ if (ACPI_TYPE_BUFFER != ret_obj->common.type) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+ /*
+ * Make the call to create a resource linked list from the
+ * byte stream buffer that comes back from the _CRS method
+ * execution.
+ */
+ status = acpi_rs_create_resource_list (ret_obj,
+ ret_buffer->pointer,
+ &buffer_space_needed);
+
+ if (AE_OK == status) {
+ acpi_rs_dump_resource_list((RESOURCE *)ret_buffer->pointer);
+ }
+
+ /*
+ * Tell the user how much of the buffer we have used or is needed
+ * and return the final status.
+ */
+ ret_buffer->length = buffer_space_needed;
+
+
+ /* On exit, we must delete the object returned by evaluate_object */
+
+cleanup:
+
+ acpi_cm_remove_reference (ret_obj);
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_get_prs_method_data
+ *
+ * PARAMETERS: Device_handle - a handle to the containing object
+ * Ret_buffer - a pointer to a buffer structure for the
+ * results
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to get the _PRS value of an object
+ * contained in an object specified by the handle passed in
+ *
+ * If the function fails an appropriate status will be returned
+ * and the contents of the callers buffer is undefined.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_rs_get_prs_method_data (
+ ACPI_HANDLE handle,
+ ACPI_BUFFER *ret_buffer)
+{
+ ACPI_OBJECT_INTERNAL *ret_obj;
+ ACPI_STATUS status;
+ u32 buffer_space_needed = ret_buffer->length;
+
+
+ /*
+ * Must have a valid handle and buffer, So we have to have a handle
+ * a return buffer structure and if there is a non-zero buffer length
+ * we also need a valid pointer in the buffer
+ */
+ if ((!handle) ||
+ (!ret_buffer) ||
+ ((!ret_buffer->pointer) && (ret_buffer->length)))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Execute the method, no parameters
+ */
+ status = acpi_ns_evaluate_relative (handle, "_PRS", NULL, &ret_obj);
+ if (status != AE_OK) {
+ return (status);
+ }
+
+ if (!ret_obj) {
+ /* Return object is required */
+
+ return (AE_TYPE);
+ }
+
+ /*
+ * The return object will be a buffer, but check the
+ * parameters. If the return object is not a buffer,
+ * then the underlying AML code is corrupt or improperly
+ * written..
+ */
+ if (ACPI_TYPE_BUFFER != ret_obj->common.type) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+ /*
+ * Make the call to create a resource linked list from the
+ * byte stream buffer that comes back from the _CRS method
+ * execution.
+ */
+ status = acpi_rs_create_resource_list (ret_obj,
+ ret_buffer->pointer,
+ &buffer_space_needed);
+
+ /*
+ * Tell the user how much of the buffer we have used or is needed
+ * and return the final status.
+ */
+ ret_buffer->length = buffer_space_needed;
+
+
+ /* On exit, we must delete the object returned by evaluate_object */
+
+cleanup:
+
+ acpi_cm_remove_reference (ret_obj);
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_rs_set_srs_method_data
+ *
+ * PARAMETERS: Device_handle - a handle to the containing object
+ * *Method_name - Name of method to execute, If NULL, the
+ * handle is the object to execute
+ * In_buffer - a pointer to a buffer structure of the
+ * parameter
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to set the _SRS of an object contained
+ * in an object specified by the handle passed in
+ *
+ * If the function fails an appropriate status will be returned
+ * and the contents of the callers buffer is undefined.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_rs_set_srs_method_data (
+ ACPI_HANDLE handle,
+ ACPI_BUFFER *in_buffer)
+{
+ ACPI_OBJECT_INTERNAL *params[2];
+ ACPI_OBJECT_INTERNAL param_obj;
+ ACPI_STATUS status;
+ u8 *byte_stream = NULL;
+ u32 buffer_size_needed = 0;
+
+ /*
+ * Must have a valid handle and buffer
+ */
+ if ((!handle) ||
+ (!in_buffer) ||
+ (!in_buffer->pointer) ||
+ (!in_buffer->length))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * The In_buffer parameter will point to a linked list of
+ * resource parameters. It needs to be formatted into a
+ * byte stream to be sent in as an input parameter.
+ */
+ buffer_size_needed = 0;
+
+ /*
+ * First call is to get the buffer size needed
+ */
+ status = acpi_rs_create_byte_stream (in_buffer->pointer,
+ byte_stream,
+ &buffer_size_needed);
+
+ /*
+ * We expect a return of AE_BUFFER_OVERFLOW
+ * if not, exit with the error
+ */
+ if (AE_BUFFER_OVERFLOW != status) {
+ return (status);
+ }
+
+ /*
+ * Allocate the buffer needed
+ */
+ byte_stream = acpi_cm_callocate(buffer_size_needed);
+
+ if (NULL == byte_stream) {
+ return (AE_NO_MEMORY);
+ }
+
+ /*
+ * Now call to convert the linked list into a byte stream
+ */
+ status = acpi_rs_create_byte_stream (in_buffer->pointer,
+ byte_stream,
+ &buffer_size_needed);
+
+ if(AE_OK != status) {
+ /*
+ * Failed the call
+ */
+ acpi_cm_free (byte_stream);
+ return (status);
+ }
+
+ /*
+ * Init the param object
+ */
+ acpi_cm_init_static_object (&param_obj);
+
+ /*
+ * Method requires one parameter. Set it up
+ */
+ params [0] = &param_obj;
+ params [1] = NULL;
+
+ /*
+ * Set up the parameter object
+ */
+ param_obj.common.type = ACPI_TYPE_BUFFER;
+ param_obj.buffer.length = buffer_size_needed;
+ param_obj.buffer.pointer = byte_stream;
+
+ /*
+ * Execute the method, no return value
+ */
+ status = acpi_ns_evaluate_relative (handle, "_SRS", params, NULL);
+
+ /*
+ * Clean up and return the status from Acpi_ns_evaluate_relative
+ */
+ acpi_cm_free (byte_stream);
+ return (status);
+}
+
diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c
new file mode 100644
index 000000000..230bcb9c5
--- /dev/null
+++ b/drivers/acpi/resources/rsxface.c
@@ -0,0 +1,177 @@
+/******************************************************************************
+ *
+ * Module Name: rsxface - Public interfaces to the ACPI subsystem
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "interp.h"
+#include "namesp.h"
+#include "resource.h"
+
+#define _COMPONENT RESOURCE_MANAGER
+ MODULE_NAME ("rsxface");
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_get_irq_routing_table
+ *
+ * PARAMETERS: Device_handle - a handle to the Bus device we are querying
+ * Out_buffer - a pointer to a buffer to receive the
+ * current resources for the device
+ * Buffer_length - the number of bytes available in the buffer
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to get the IRQ routing table for a
+ * specific bus. The caller must first acquire a handle for the
+ * desired bus. The routine table is placed in the buffer pointed
+ * to by the Out_buffer variable parameter.
+ *
+ * If the function fails an appropriate status will be returned
+ * and the value of Out_buffer is undefined.
+ *
+ * This function attempts to execute the _PRT method contained in
+ * the object indicated by the passed Device_handle.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_get_irq_routing_table (
+ ACPI_HANDLE device_handle,
+ ACPI_BUFFER *ret_buffer)
+{
+ ACPI_STATUS status;
+
+
+ status = acpi_rs_get_prt_method_data (device_handle, ret_buffer);
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_get_current_resources
+ *
+ * PARAMETERS: Device_handle - a handle to the device object for the
+ * device we are querying
+ * Out_buffer - a pointer to a buffer to receive the
+ * current resources for the device
+ * Buffer_length - the number of bytes available in the buffer
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to get the current resources for a
+ * specific device. The caller must first acquire a handle for
+ * the desired device. The resource data is placed in the buffer
+ * pointed to by the Out_buffer variable parameter.
+ *
+ * If the function fails an appropriate status will be returned
+ * and the value of Out_buffer is undefined.
+ *
+ * This function attempts to execute the _CRS method contained in
+ * the object indicated by the passed Device_handle.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_get_current_resources (
+ ACPI_HANDLE device_handle,
+ ACPI_BUFFER *ret_buffer)
+{
+ ACPI_STATUS status;
+
+
+ status = acpi_rs_get_crs_method_data (device_handle, ret_buffer);
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_get_possible_resources
+ *
+ * PARAMETERS: Device_handle - a handle to the device object for the
+ * device we are querying
+ * Out_buffer - a pointer to a buffer to receive the
+ * resources for the device
+ * Buffer_length - the number of bytes available in the buffer
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to get a list of the possible resources
+ * for a specific device. The caller must first acquire a handle
+ * for the desired device. The resource data is placed in the
+ * buffer pointed to by the Out_buffer variable.
+ *
+ * If the function fails an appropriate status will be returned
+ * and the value of Out_buffer is undefined.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_get_possible_resources (
+ ACPI_HANDLE device_handle,
+ ACPI_BUFFER *ret_buffer)
+{
+ ACPI_STATUS status;
+
+
+ status = acpi_rs_get_prs_method_data (device_handle, ret_buffer);
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_set_current_resources
+ *
+ * PARAMETERS: Device_handle - a handle to the device object for the
+ * device we are changing the resources of
+ * Out_buffer - a pointer to a buffer containing the
+ * resources to be set for the device
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to set the current resources for a
+ * specific device. The caller must first acquire a handle for
+ * the desired device. The resource data is passed to the routine
+ * the buffer pointed to by the In_buffer variable.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_set_current_resources (
+ ACPI_HANDLE device_handle,
+ ACPI_BUFFER *in_buffer)
+{
+ ACPI_STATUS status;
+
+
+ status = acpi_rs_set_srs_method_data (device_handle, in_buffer);
+
+ return (status);
+}
diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c
new file mode 100644
index 000000000..255ca172d
--- /dev/null
+++ b/drivers/acpi/tables/tbget.c
@@ -0,0 +1,324 @@
+
+/******************************************************************************
+ *
+ * Module Name: tbget - ACPI Table get* routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "hardware.h"
+#include "tables.h"
+
+
+#define _COMPONENT TABLE_MANAGER
+ MODULE_NAME ("tbget");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_get_table_ptr
+ *
+ * PARAMETERS: Table_type - one of the defined table types
+ * Instance - Which table of this type
+ * Table_ptr_loc - pointer to location to place the pointer for
+ * return
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to get the pointer to an ACPI table.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_tb_get_table_ptr (
+ ACPI_TABLE_TYPE table_type,
+ u32 instance,
+ ACPI_TABLE_HEADER **table_ptr_loc)
+{
+ ACPI_TABLE_DESC *table_desc;
+ u32 i;
+
+
+ if (!acpi_gbl_DSDT) {
+ return (AE_NO_ACPI_TABLES);
+ }
+
+ if (table_type > ACPI_TABLE_MAX) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /*
+ * For all table types (Single/Multiple), the first
+ * instance is always in the list head.
+ */
+
+ if (instance == 1) {
+ /*
+ * Just pluck the pointer out of the global table!
+ * Will be null if no table is present
+ */
+
+ *table_ptr_loc = acpi_gbl_acpi_tables[table_type].pointer;
+ return (AE_OK);
+ }
+
+
+ /*
+ * Check for instance out of range
+ */
+ if (instance > acpi_gbl_acpi_tables[table_type].count) {
+ return (AE_NOT_EXIST);
+ }
+
+ /* Walk the list to get the table */
+
+ table_desc = acpi_gbl_acpi_tables[table_type].next;
+ for (i = 1; i < acpi_gbl_acpi_tables[table_type].count; i++) {
+ table_desc = table_desc->next;
+ }
+
+ /* We are now pointing to the requested table's descriptor */
+
+ *table_ptr_loc = table_desc->pointer;
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_get_table
+ *
+ * PARAMETERS: Physical_address - Physical address of table to retrieve
+ * *Buffer_ptr - If == NULL, read data from buffer
+ * rather than searching memory
+ * *Table_info - Where the table info is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Maps the physical address of table into a logical address
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_tb_get_table (
+ void *physical_address,
+ char *buffer_ptr,
+ ACPI_TABLE_DESC *table_info)
+{
+ ACPI_TABLE_HEADER *table_header = NULL;
+ ACPI_TABLE_HEADER *full_table = NULL;
+ u32 size;
+ u8 allocation;
+ ACPI_STATUS status = AE_OK;
+
+
+ if (!table_info) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ if (buffer_ptr) {
+ /*
+ * Getting data from a buffer, not BIOS tables
+ */
+
+ table_header = (ACPI_TABLE_HEADER *) buffer_ptr;
+ status = acpi_tb_validate_table_header (table_header);
+ if (ACPI_FAILURE (status)) {
+ /* Table failed verification, map all errors to BAD_DATA */
+
+ return (AE_BAD_DATA);
+ }
+
+ /* Allocate buffer for the entire table */
+
+ full_table = acpi_cm_allocate (table_header->length);
+ if (!full_table) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Copy the entire table (including header) to the local buffer */
+
+ size = (ACPI_SIZE) table_header->length;
+ MEMCPY (full_table, buffer_ptr, size);
+
+ /* Save allocation type */
+
+ allocation = ACPI_MEM_ALLOCATED;
+ }
+
+
+ /*
+ * Not reading from a buffer, just map the table's physical memory
+ * into our address space.
+ */
+ else {
+ size = SIZE_IN_HEADER;
+
+ status = acpi_tb_map_acpi_table (physical_address, &size,
+ (void **) &full_table);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Save allocation type */
+
+ allocation = ACPI_MEM_MAPPED;
+ }
+
+
+ /* Return values */
+
+ table_info->pointer = full_table;
+ table_info->length = size;
+ table_info->allocation = allocation;
+ table_info->base_pointer = full_table;
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_get_all_tables
+ *
+ * PARAMETERS: Number_of_tables - Number of tables to get
+ * Table_ptr - Input buffer pointer, optional
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Load and validate all tables other than the RSDT. The RSDT must
+ * already be loaded and validated.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_tb_get_all_tables (
+ u32 number_of_tables,
+ char *table_ptr)
+{
+ ACPI_STATUS status = AE_OK;
+ u32 index;
+ ACPI_TABLE_DESC table_info;
+
+
+ /*
+ * Loop through all table pointers found in RSDT.
+ * This will NOT include the FACS and DSDT - we must get
+ * them after the loop
+ */
+
+ for (index = 0; index < number_of_tables; index++) {
+ /* Clear the Table_info each time */
+
+ MEMSET (&table_info, 0, sizeof (ACPI_TABLE_DESC));
+
+ /* Get the table via the RSDT */
+
+ status = acpi_tb_get_table ((void *) acpi_gbl_RSDT->table_offset_entry[index],
+ table_ptr, &table_info);
+
+ /* Ignore a table that failed verification */
+
+ if (status == AE_BAD_DATA) {
+ continue;
+ }
+
+ /* However, abort on serious errors */
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Recognize and install the table */
+
+ status = acpi_tb_install_table (table_ptr, &table_info);
+ if (ACPI_FAILURE (status)) {
+ /*
+ * Unrecognized or unsupported table, delete it and ignore the
+ * error. Just get as many tables as we can, later we will
+ * determine if there are enough tables to continue.
+ */
+
+ acpi_tb_delete_single_table (&table_info);
+ }
+ }
+
+
+ /*
+ * Get the minimum set of ACPI tables, namely:
+ *
+ * 1) FACP (via RSDT in loop above)
+ * 2) FACS
+ * 3) DSDT
+ *
+ */
+
+
+ /*
+ * Get the FACS (must have the FACP first, from loop above)
+ * Acpi_tb_get_table_facs will fail if FACP pointer is not valid
+ */
+
+ status = acpi_tb_get_table_facs (table_ptr, &table_info);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Install the FACS */
+
+ status = acpi_tb_install_table (table_ptr, &table_info);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+
+ /* Get the DSDT (We know that the FACP if valid now) */
+
+ status = acpi_tb_get_table ((void *) acpi_gbl_FACP->dsdt, table_ptr, &table_info);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Install the DSDT */
+
+ status = acpi_tb_install_table (table_ptr, &table_info);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Dump the DSDT Header */
+
+ /* Dump the entire DSDT */
+
+ /*
+ * Initialize the capabilities flags.
+ * Assumes that platform supports ACPI_MODE since we have tables!
+ */
+
+ acpi_gbl_system_flags |= acpi_hw_get_mode_capabilities ();
+
+ return (status);
+}
+
diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
new file mode 100644
index 000000000..54e077f08
--- /dev/null
+++ b/drivers/acpi/tables/tbinstal.c
@@ -0,0 +1,533 @@
+
+/******************************************************************************
+ *
+ * Module Name: tbinstal - ACPI table installation and removal
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "hardware.h"
+#include "tables.h"
+
+
+#define _COMPONENT TABLE_MANAGER
+ MODULE_NAME ("tbinstal");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_install_table
+ *
+ * PARAMETERS: Table_ptr - Input buffer pointer, optional
+ * Table_info - Return value from Acpi_tb_get_table
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Load and validate all tables other than the RSDT. The RSDT must
+ * already be loaded and validated.
+ * Install the table into the global data structs.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_tb_install_table (
+ char *table_ptr,
+ ACPI_TABLE_DESC *table_info)
+{
+ ACPI_TABLE_TYPE table_type;
+ ACPI_TABLE_HEADER *table_header;
+ ACPI_STATUS status;
+
+
+ /*
+ * Check the table signature and make sure it is recognized
+ * Also checks the header checksum
+ */
+
+ status = acpi_tb_recognize_table (table_ptr, table_info);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Table type is returned by Recognize_table */
+
+ table_type = table_info->type;
+ table_header = table_info->pointer;
+
+ /* Lock tables while installing */
+
+ acpi_cm_acquire_mutex (ACPI_MTX_TABLES);
+
+ /* Install the table into the global data structure */
+
+ status = acpi_tb_init_table_descriptor (table_info->type, table_info);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ acpi_cm_release_mutex (ACPI_MTX_TABLES);
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_recognize_table
+ *
+ * PARAMETERS: Table_ptr - Input buffer pointer, optional
+ * Table_info - Return value from Acpi_tb_get_table
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Check a table signature for a match against known table types
+ *
+ * NOTE: All table pointers are validated as follows:
+ * 1) Table pointer must point to valid physical memory
+ * 2) Signature must be 4 ASCII chars, even if we don't recognize the
+ * name
+ * 3) Table must be readable for length specified in the header
+ * 4) Table checksum must be valid (with the exception of the FACS
+ * which has no checksum for some odd reason)
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_tb_recognize_table (
+ char *table_ptr,
+ ACPI_TABLE_DESC *table_info)
+{
+ ACPI_TABLE_HEADER *table_header;
+ ACPI_STATUS status;
+ ACPI_TABLE_TYPE table_type = 0;
+ u32 i;
+
+
+ /* Ensure that we have a valid table pointer */
+
+ table_header = (ACPI_TABLE_HEADER *) table_info->pointer;
+ if (!table_header) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Search for a signature match among the known table types
+ * Start at index one -> Skip the RSDP
+ */
+
+ status = AE_SUPPORT;
+ for (i = 1; i < NUM_ACPI_TABLES; i++) {
+ if (!STRNCMP (table_header->signature,
+ acpi_gbl_acpi_table_data[i].signature,
+ acpi_gbl_acpi_table_data[i].sig_length))
+ {
+ /*
+ * Found a signature match, get the pertinent info from the
+ * Table_data structure
+ */
+
+ table_type = i;
+ status = acpi_gbl_acpi_table_data[i].status;
+
+ break;
+ }
+ }
+
+ /* Return the table type and length via the info struct */
+
+ table_info->type = (u8) table_type;
+ table_info->length = table_header->length;
+
+
+ /*
+ * Validate checksum for _most_ tables,
+ * even the ones whose signature we don't recognize
+ */
+
+ if (table_type != ACPI_TABLE_FACS) {
+ /* But don't abort if the checksum is wrong */
+ /* TBD: [Future] make this a configuration option? */
+
+ acpi_tb_verify_table_checksum (table_header);
+ }
+
+ /*
+ * An AE_SUPPORT means that the table was not recognized.
+ * We basically ignore this; just print a debug message
+ */
+
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_init_table_descriptor
+ *
+ * PARAMETERS: Table_type - The type of the table
+ * Table_info - A table info struct
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Install a table into the global data structs.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_tb_init_table_descriptor (
+ ACPI_TABLE_TYPE table_type,
+ ACPI_TABLE_DESC *table_info)
+{
+ ACPI_TABLE_DESC *list_head;
+ ACPI_TABLE_DESC *table_desc;
+
+
+ /*
+ * Install the table into the global data structure
+ */
+
+ list_head = &acpi_gbl_acpi_tables[table_type];
+ table_desc = list_head;
+
+
+ /*
+ * Two major types of tables: 1) Only one instance is allowed. This
+ * includes most ACPI tables such as the DSDT. 2) Multiple instances of
+ * the table are allowed. This includes SSDT and PSDTs.
+ */
+
+ if (acpi_gbl_acpi_table_data[table_type].flags == ACPI_TABLE_SINGLE) {
+ /*
+ * Only one table allowed, just update the list head
+ */
+
+ if (list_head->pointer) {
+ return (AE_EXIST);
+ }
+
+ table_desc->count = 1;
+ }
+
+
+ else {
+ /*
+ * Multiple tables allowed for this table type, we must link
+ * the new table in to the list of tables of this type.
+ */
+
+ if (list_head->pointer) {
+ table_desc = acpi_cm_callocate (sizeof (ACPI_TABLE_DESC));
+ if (!table_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+ list_head->count++;
+
+ /* Update the original previous */
+
+ list_head->prev->next = table_desc;
+
+ /* Update new entry */
+
+ table_desc->prev = list_head->prev;
+ table_desc->next = (ACPI_TABLE_DESC *) list_head;
+
+ /* Update list head */
+
+ list_head->prev = table_desc;
+ }
+
+ else {
+ table_desc->count = 1;
+ }
+ }
+
+
+ /* Common initialization of the table descriptor */
+
+ table_desc->pointer = table_info->pointer;
+ table_desc->base_pointer = table_info->base_pointer;
+ table_desc->length = table_info->length;
+ table_desc->allocation = table_info->allocation;
+ table_desc->aml_pointer = (u8 *) (table_desc->pointer + 1),
+ table_desc->aml_length = (u32) (table_desc->length -
+ (u32) sizeof (ACPI_TABLE_HEADER));
+ table_desc->table_id = acpi_cm_allocate_owner_id (OWNER_TYPE_TABLE);
+ table_desc->loaded_into_namespace = FALSE;
+
+ /*
+ * Set the appropriate global pointer (if there is one) to point to the
+ * newly installed table
+ */
+
+ if (acpi_gbl_acpi_table_data[table_type].global_ptr) {
+ *(acpi_gbl_acpi_table_data[table_type].global_ptr) = table_info->pointer;
+ }
+
+
+ /* Return Data */
+
+ table_info->table_id = table_desc->table_id;
+ table_info->installed_desc = table_desc;
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_delete_acpi_tables
+ *
+ * PARAMETERS: None.
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Delete all internal ACPI tables
+ *
+ ******************************************************************************/
+
+void
+acpi_tb_delete_acpi_tables (void)
+{
+ u32 i;
+
+
+ /*
+ * Free memory allocated for ACPI tables
+ * Memory can either be mapped or allocated
+ */
+
+ for (i = 0; i < ACPI_TABLE_MAX; i++) {
+ acpi_tb_delete_acpi_table (i);
+ }
+
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_delete_acpi_table
+ *
+ * PARAMETERS: Type - The table type to be deleted
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Delete an internal ACPI table
+ * Locks the ACPI table mutex
+ *
+ ******************************************************************************/
+
+void
+acpi_tb_delete_acpi_table (
+ ACPI_TABLE_TYPE type)
+{
+
+ if (type > ACPI_TABLE_MAX) {
+ return;
+ }
+
+
+ acpi_cm_acquire_mutex (ACPI_MTX_TABLES);
+
+ /* Free the table */
+
+ acpi_tb_free_acpi_tables_of_type (&acpi_gbl_acpi_tables[type]);
+
+
+ /* Clear the appropriate "typed" global table pointer */
+
+ switch (type)
+ {
+ case ACPI_TABLE_RSDP:
+ acpi_gbl_RSDP = NULL;
+ break;
+
+ case ACPI_TABLE_APIC:
+ acpi_gbl_APIC = NULL;
+ break;
+
+ case ACPI_TABLE_DSDT:
+ acpi_gbl_DSDT = NULL;
+ break;
+
+ case ACPI_TABLE_FACP:
+ acpi_gbl_FACP = NULL;
+ break;
+
+ case ACPI_TABLE_FACS:
+ acpi_gbl_FACS = NULL;
+ break;
+
+ case ACPI_TABLE_PSDT:
+ break;
+
+ case ACPI_TABLE_RSDT:
+ acpi_gbl_RSDT = NULL;
+ break;
+
+ case ACPI_TABLE_SSDT:
+ break;
+
+ case ACPI_TABLE_SBST:
+ acpi_gbl_SBST = NULL;
+
+ default:
+ break;
+ }
+
+ acpi_cm_release_mutex (ACPI_MTX_TABLES);
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_delete_single_table
+ *
+ * PARAMETERS: Table_info - A table info struct
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Free the memory associated with an internal ACPI table that
+ * is either installed or has never been installed.
+ * Table mutex should be locked.
+ *
+ ******************************************************************************/
+
+ACPI_TABLE_DESC *
+acpi_tb_delete_single_table (
+ ACPI_TABLE_DESC *table_desc)
+{
+ ACPI_TABLE_DESC *next_desc;
+
+
+ if (!table_desc) {
+ return (NULL);
+ }
+
+
+ /* Unlink the descriptor */
+
+ if (table_desc->prev) {
+ table_desc->prev->next = table_desc->next;
+ }
+
+ if (table_desc->next) {
+ table_desc->next->prev = table_desc->prev;
+ }
+
+
+ /* Free the memory allocated for the table itself */
+
+ if (table_desc->pointer) {
+ /* Valid table, determine type of memory allocation */
+
+ switch (table_desc->allocation)
+ {
+
+ case ACPI_MEM_NOT_ALLOCATED:
+
+ break;
+
+
+ case ACPI_MEM_ALLOCATED:
+
+ acpi_cm_free (table_desc->base_pointer);
+ break;
+
+
+ case ACPI_MEM_MAPPED:
+
+ acpi_os_unmap_memory (table_desc->base_pointer, table_desc->length);
+ break;
+ }
+ }
+
+
+ /* Free the table descriptor (Don't delete the list head, tho) */
+
+
+ if ((table_desc->prev) == (table_desc->next)) {
+
+ next_desc = NULL;
+
+ /* Clear the list head */
+
+ table_desc->pointer = NULL;
+ table_desc->length = 0;
+ table_desc->count = 0;
+
+ }
+
+ else {
+ /* Free the table descriptor */
+
+ next_desc = table_desc->next;
+ acpi_cm_free (table_desc);
+ }
+
+
+ return (next_desc);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_free_acpi_tables_of_type
+ *
+ * PARAMETERS: Table_info - A table info struct
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Free the memory associated with an internal ACPI table
+ * Table mutex should be locked.
+ *
+ ******************************************************************************/
+
+void
+acpi_tb_free_acpi_tables_of_type (
+ ACPI_TABLE_DESC *list_head)
+{
+ ACPI_TABLE_DESC *table_desc;
+ u32 count;
+ u32 i;
+
+
+ /* Get the head of the list */
+
+ table_desc = list_head;
+ count = list_head->count;
+
+ /*
+ * Walk the entire list, deleting both the allocated tables
+ * and the table descriptors
+ */
+
+ for (i = 0; i < count; i++) {
+ table_desc = acpi_tb_delete_single_table (table_desc);
+ }
+
+ return;
+}
+
+
diff --git a/drivers/acpi/tables/tbtable.c b/drivers/acpi/tables/tbtable.c
new file mode 100644
index 000000000..a78a23acf
--- /dev/null
+++ b/drivers/acpi/tables/tbtable.c
@@ -0,0 +1,388 @@
+
+/******************************************************************************
+ *
+ * Module Name: tbtable - ACPI tables: FACP, FACS, and RSDP utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "hardware.h"
+#include "tables.h"
+
+
+#define _COMPONENT TABLE_MANAGER
+ MODULE_NAME ("tbtable");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_get_table_rsdt
+ *
+ * PARAMETERS: Number_of_tables - Where the table count is placed
+ * Table_ptr - Input buffer pointer, optional
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table)
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_tb_get_table_rsdt (
+ u32 *number_of_tables)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_TABLE_DESC table_info;
+
+
+ /* Get the RSDP */
+
+ status = acpi_tb_find_rsdp (&table_info);
+ if (ACPI_FAILURE (status)) {
+ REPORT_WARNING ("RSDP structure not found");
+ return (AE_NO_ACPI_TABLES);
+ }
+
+ /* Save the table pointers and allocation info */
+
+ status = acpi_tb_init_table_descriptor (ACPI_TABLE_RSDP, &table_info);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ acpi_gbl_RSDP = (ROOT_SYSTEM_DESCRIPTOR_POINTER *) table_info.pointer;
+
+
+ /*
+ * RSDP structure was found; Now get the RSDT
+ */
+
+ status = acpi_tb_get_table ((void *) acpi_gbl_RSDP->rsdt_physical_address, NULL,
+ &table_info);
+ if (ACPI_FAILURE (status)) {
+ if (status == AE_BAD_SIGNATURE) {
+ /* Invalid RSDT signature */
+
+ REPORT_ERROR ("Invalid signature where RSDP indicates RSDT should be located");
+
+ }
+ }
+
+
+ /* Always delete the RSDP mapping */
+
+ acpi_tb_delete_acpi_table (ACPI_TABLE_RSDP);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Save the table pointers and allocation info */
+
+ status = acpi_tb_init_table_descriptor (ACPI_TABLE_RSDT, &table_info);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ acpi_gbl_RSDT = (ROOT_SYSTEM_DESCRIPTION_TABLE *) table_info.pointer;
+
+
+ /* Valid RSDT signature, verify the checksum */
+
+ status = acpi_tb_verify_table_checksum ((ACPI_TABLE_HEADER *) acpi_gbl_RSDT);
+
+ /* Determine the number of tables pointed to by the RSDT */
+
+ *number_of_tables = (s32) DIV_4 (acpi_gbl_RSDT->header.length -
+ sizeof (ACPI_TABLE_HEADER));
+
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_scan_memory_for_rsdp
+ *
+ * PARAMETERS: Start_address - Starting pointer for search
+ * Length - Maximum length to search
+ *
+ * RETURN: Pointer to the RSDP if found, otherwise NULL.
+ *
+ * DESCRIPTION: Search a block of memory for the RSDP signature
+ *
+ ******************************************************************************/
+
+char *
+acpi_tb_scan_memory_for_rsdp (
+ char *start_address,
+ u32 length)
+{
+ u32 offset;
+ char *mem_rover;
+
+
+ /* Search from given start addr for the requested length */
+
+ for (offset = 0, mem_rover = start_address;
+ offset < length;
+ offset += RSDP_SCAN_STEP, mem_rover += RSDP_SCAN_STEP)
+ {
+
+ /* The signature and checksum must both be correct */
+
+ if (STRNCMP (mem_rover, RSDP_SIG, sizeof (RSDP_SIG)-1) == 0 &&
+ acpi_tb_checksum (mem_rover,
+ sizeof (ROOT_SYSTEM_DESCRIPTOR_POINTER)) == 0)
+ {
+ /* If so, we have found the RSDP */
+
+ return mem_rover;
+ }
+ }
+
+ /* Searched entire block, no RSDP was found */
+
+ return NULL;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_find_rsdp
+ *
+ * PARAMETERS: *Buffer_ptr - If == NULL, read data from buffer
+ * rather than searching memory
+ * *Table_info - Where the table info is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor
+ * pointer structure. If it is found, set *RSDP to point to it.
+ *
+ * NOTE: The RSDP must be either in the first 1_k of the Extended
+ * BIOS Data Area or between E0000 and FFFFF (ACPI 1.0 section
+ * 5.2.2; assertion #421).
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_tb_find_rsdp (
+ ACPI_TABLE_DESC *table_info)
+{
+ char *table_ptr;
+ char *mem_rover;
+ ACPI_STATUS status = AE_OK;
+
+ if (acpi_gbl_acpi_init_data.RSDP_physical_address) {
+ /*
+ * RSDP address was supplied as part of the initialization data
+ */
+
+ status = acpi_os_map_memory(acpi_gbl_acpi_init_data.RSDP_physical_address,
+ sizeof (ROOT_SYSTEM_DESCRIPTOR_POINTER),
+ (void **)&table_ptr);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ if (!table_ptr) {
+ return (AE_NO_MEMORY);
+ }
+
+ /*
+ * The signature and checksum must both be correct
+ */
+
+ if (STRNCMP (table_ptr, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) {
+ /* Nope, BAD Signature */
+
+ return (AE_BAD_SIGNATURE);
+ }
+
+ /* The signature and checksum must both be correct */
+
+ if (acpi_tb_checksum (table_ptr,
+ sizeof (ROOT_SYSTEM_DESCRIPTOR_POINTER)) != 0)
+ {
+ /* Nope, BAD Checksum */
+
+ return (AE_BAD_CHECKSUM);
+ }
+
+ /* RSDP supplied is OK */
+ /* If so, we have found the RSDP */
+
+ table_info->pointer = (ACPI_TABLE_HEADER *) table_ptr;
+ table_info->length = sizeof (ROOT_SYSTEM_DESCRIPTOR_POINTER);
+ table_info->allocation = ACPI_MEM_MAPPED;
+ table_info->base_pointer = table_ptr;
+
+ return (AE_OK);
+ }
+
+ /*
+ * Search memory for RSDP. First map low physical memory.
+ */
+
+ status = acpi_os_map_memory (LO_RSDP_WINDOW_BASE, LO_RSDP_WINDOW_SIZE,
+ (void **)&table_ptr);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /*
+ * 1) Search EBDA (low memory) paragraphs
+ */
+
+ if (NULL != (mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr,
+ LO_RSDP_WINDOW_SIZE)))
+ {
+ /* Found it, return pointer and don't delete the mapping */
+
+ table_info->pointer = (ACPI_TABLE_HEADER *) mem_rover;
+ table_info->length = LO_RSDP_WINDOW_SIZE;
+ table_info->allocation = ACPI_MEM_MAPPED;
+ table_info->base_pointer = table_ptr;
+
+ return (AE_OK);
+ }
+
+ /* This mapping is no longer needed */
+
+ acpi_os_unmap_memory (table_ptr, LO_RSDP_WINDOW_SIZE);
+
+
+ /*
+ * 2) Search upper memory: 16-byte boundaries in E0000h-F0000h
+ */
+
+ status = acpi_os_map_memory (HI_RSDP_WINDOW_BASE, HI_RSDP_WINDOW_SIZE,
+ (void **)&table_ptr);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ if (NULL != (mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr,
+ HI_RSDP_WINDOW_SIZE)))
+ {
+ /* Found it, return pointer and don't delete the mapping */
+
+ table_info->pointer = (ACPI_TABLE_HEADER *) mem_rover;
+ table_info->length = HI_RSDP_WINDOW_SIZE;
+ table_info->allocation = ACPI_MEM_MAPPED;
+ table_info->base_pointer = table_ptr;
+
+ return (AE_OK);
+ }
+
+ /* This mapping is no longer needed */
+
+ acpi_os_unmap_memory (table_ptr, HI_RSDP_WINDOW_SIZE);
+
+
+ /* RSDP signature was not found */
+
+ return (AE_NOT_FOUND);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_get_table_facs
+ *
+ * PARAMETERS: *Buffer_ptr - If == NULL, read data from buffer
+ * rather than searching memory
+ * *Table_info - Where the table info is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Returns a pointer to the FACS as defined in FACP. This
+ * function assumes the global variable FACP has been
+ * correctly initialized. The value of FACP->Firmware_ctrl
+ * into a far pointer which is returned.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_tb_get_table_facs (
+ char *buffer_ptr,
+ ACPI_TABLE_DESC *table_info)
+{
+ void *table_ptr = NULL;
+ u32 size;
+ u8 allocation;
+ ACPI_STATUS status = AE_OK;
+
+
+ /* Must have a valid FACP pointer */
+
+ if (!acpi_gbl_FACP) {
+ return (AE_NO_ACPI_TABLES);
+ }
+
+ size = sizeof (FIRMWARE_ACPI_CONTROL_STRUCTURE);
+ if (buffer_ptr) {
+ /*
+ * Getting table from a file -- allocate a buffer and
+ * read the table.
+ */
+ table_ptr = acpi_cm_allocate (size);
+ if(!table_ptr) {
+ return (AE_NO_MEMORY);
+ }
+
+ MEMCPY (table_ptr, buffer_ptr, size);
+
+ /* Save allocation type */
+
+ allocation = ACPI_MEM_ALLOCATED;
+ }
+
+ else {
+ /* Just map the physical memory to our address space */
+
+ status = acpi_tb_map_acpi_table ((void *) acpi_gbl_FACP->firmware_ctrl,
+ &size, &table_ptr);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /* Save allocation type */
+
+ allocation = ACPI_MEM_MAPPED;
+ }
+
+
+ /* Return values */
+
+ table_info->pointer = table_ptr;
+ table_info->length = size;
+ table_info->allocation = allocation;
+ table_info->base_pointer = table_ptr;
+
+ return (status);
+}
+
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
new file mode 100644
index 000000000..45519a824
--- /dev/null
+++ b/drivers/acpi/tables/tbutils.c
@@ -0,0 +1,352 @@
+
+/******************************************************************************
+ *
+ * Module Name: tbutils - Table manipulation utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "tables.h"
+#include "interp.h"
+
+
+#define _COMPONENT TABLE_MANAGER
+ MODULE_NAME ("tbutils");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_system_table_pointer
+ *
+ * PARAMETERS: *Where - Pointer to be examined
+ *
+ * RETURN: TRUE if Where is within the AML stream (in one of the ACPI
+ * system tables such as the DSDT or an SSDT.)
+ * FALSE otherwise
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_tb_handle_to_object (
+ u16 table_id,
+ ACPI_TABLE_DESC **table_desc)
+{
+ u32 i;
+ ACPI_TABLE_DESC *list_head;
+
+
+ for (i = 0; i < ACPI_TABLE_MAX; i++) {
+ list_head = &acpi_gbl_acpi_tables[i];
+ do
+ {
+ if (list_head->table_id == table_id) {
+ *table_desc = list_head;
+ return AE_OK;
+ }
+
+ list_head = list_head->next;
+
+ } while (list_head != &acpi_gbl_acpi_tables[i]);
+ }
+
+
+ return AE_BAD_PARAMETER;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_system_table_pointer
+ *
+ * PARAMETERS: *Where - Pointer to be examined
+ *
+ * RETURN: TRUE if Where is within the AML stream (in one of the ACPI
+ * system tables such as the DSDT or an SSDT.)
+ * FALSE otherwise
+ *
+ ******************************************************************************/
+
+u8
+acpi_tb_system_table_pointer (
+ void *where)
+{
+ u32 i;
+ ACPI_TABLE_DESC *table_desc;
+ ACPI_TABLE_HEADER *table;
+
+
+ /* No function trace, called too often! */
+
+
+ /* Ignore null pointer */
+
+ if (!where) {
+ return (FALSE);
+ }
+
+
+ /* Check for a pointer within the DSDT */
+
+ if (IS_IN_ACPI_TABLE (where, acpi_gbl_DSDT)) {
+ return (TRUE);
+ }
+
+
+ /* Check each of the loaded SSDTs (if any)*/
+
+ table_desc = &acpi_gbl_acpi_tables[ACPI_TABLE_SSDT];
+
+ for (i = 0; i < acpi_gbl_acpi_tables[ACPI_TABLE_SSDT].count; i++) {
+ table = table_desc->pointer;
+
+ if (IS_IN_ACPI_TABLE (where, table)) {
+ return (TRUE);
+ }
+
+ table_desc = table_desc->next;
+ }
+
+
+ /* Check each of the loaded PSDTs (if any)*/
+
+ table_desc = &acpi_gbl_acpi_tables[ACPI_TABLE_PSDT];
+
+ for (i = 0; i < acpi_gbl_acpi_tables[ACPI_TABLE_PSDT].count; i++) {
+ table = table_desc->pointer;
+
+ if (IS_IN_ACPI_TABLE (where, table)) {
+ return (TRUE);
+ }
+
+ table_desc = table_desc->next;
+ }
+
+
+ /* Pointer does not point into any system table */
+
+ return (FALSE);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_validate_table_header
+ *
+ * PARAMETERS: Table_header - Logical pointer to the table
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Check an ACPI table header for validity
+ *
+ * NOTE: Table pointers are validated as follows:
+ * 1) Table pointer must point to valid physical memory
+ * 2) Signature must be 4 ASCII chars, even if we don't recognize the
+ * name
+ * 3) Table must be readable for length specified in the header
+ * 4) Table checksum must be valid (with the exception of the FACS
+ * which has no checksum for some odd reason)
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_tb_validate_table_header (
+ ACPI_TABLE_HEADER *table_header)
+{
+ ACPI_NAME signature;
+
+
+ /* Verify that this is a valid address */
+
+ if (!acpi_os_readable (table_header, sizeof (ACPI_TABLE_HEADER))) {
+ return AE_BAD_ADDRESS;
+ }
+
+
+ /* Ensure that the signature is 4 ASCII characters */
+
+ MOVE_UNALIGNED32_TO_32 (&signature, &table_header->signature);
+ if (!acpi_cm_valid_acpi_name (signature)) {
+ REPORT_WARNING ("Invalid table signature found");
+ return AE_BAD_SIGNATURE;
+ }
+
+
+ /* Validate the table length */
+
+ if (table_header->length < sizeof (ACPI_TABLE_HEADER)) {
+ REPORT_WARNING ("Invalid table header length found");
+ return AE_BAD_HEADER;
+ }
+
+ return AE_OK;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_map_acpi_table
+ *
+ * PARAMETERS: Physical_address - Physical address of table to map
+ * *Size - Size of the table. If zero, the size
+ * from the table header is used.
+ * Actual size is returned here.
+ * **Logical_address - Logical address of mapped table
+ *
+ * RETURN: Logical address of the mapped table.
+ *
+ * DESCRIPTION: Maps the physical address of table into a logical address
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_tb_map_acpi_table (
+ void *physical_address,
+ u32 *size,
+ void **logical_address)
+{
+ ACPI_TABLE_HEADER *table;
+ u32 table_size = *size;
+ ACPI_STATUS status = AE_OK;
+
+
+ /* If size is zero, look at the table header to get the actual size */
+
+ if ((*size) == 0) {
+ /* Get the table header so we can extract the table length */
+
+ status = acpi_os_map_memory (physical_address, sizeof (ACPI_TABLE_HEADER),
+ (void **) &table);
+ if (ACPI_FAILURE (status)) {
+ return status;
+ }
+
+ /* Extract the full table length before we delete the mapping */
+
+ table_size = table->length;
+
+ /*
+ * Validate the header and delete the mapping.
+ * We will create a mapping for the full table below.
+ */
+
+ status = acpi_tb_validate_table_header (table);
+
+ /* Always unmap the memory for the header */
+
+ acpi_os_unmap_memory (table, sizeof (ACPI_TABLE_HEADER));
+
+ /* Exit if header invalid */
+
+ if (ACPI_FAILURE (status)) {
+ return status;
+ }
+ }
+
+
+ /* Map the physical memory for the correct length */
+
+ status = acpi_os_map_memory (physical_address, table_size, (void **) &table);
+ if (ACPI_FAILURE (status)) {
+ return status;
+ }
+
+ *size = table_size;
+ *logical_address = table;
+
+ return status;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_verify_table_checksum
+ *
+ * PARAMETERS: *Table_header - ACPI table to verify
+ *
+ * RETURN: 8 bit checksum of table
+ *
+ * DESCRIPTION: Does an 8 bit checksum of table and returns status. A correct
+ * table should have a checksum of 0.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_tb_verify_table_checksum (
+ ACPI_TABLE_HEADER *table_header)
+{
+ u8 check_sum;
+ ACPI_STATUS status = AE_OK;
+
+
+ /* Compute the checksum on the table */
+
+ check_sum = acpi_tb_checksum (table_header, table_header->length);
+
+ /* Return the appropriate exception */
+
+ if (check_sum) {
+ REPORT_ERROR ("Invalid ACPI table checksum");
+ status = AE_BAD_CHECKSUM;
+ }
+
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_tb_checksum
+ *
+ * PARAMETERS: Buffer - Buffer to checksum
+ * Length - Size of the buffer
+ *
+ * RETURNS 8 bit checksum of buffer
+ *
+ * DESCRIPTION: Computes an 8 bit checksum of the buffer(length) and returns it.
+ *
+ ******************************************************************************/
+
+u8
+acpi_tb_checksum (
+ void *buffer,
+ u32 length)
+{
+ u8 *limit;
+ u8 *rover;
+ u8 sum = 0;
+
+
+ if (buffer && length) {
+ /* Buffer and Length are valid */
+
+ limit = (u8 *) buffer + length;
+
+ for (rover = buffer; rover < limit; rover++) {
+ sum = (u8) (sum + *rover);
+ }
+ }
+
+ return sum;
+}
+
+
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
new file mode 100644
index 000000000..ba650c114
--- /dev/null
+++ b/drivers/acpi/tables/tbxface.c
@@ -0,0 +1,352 @@
+
+/******************************************************************************
+ *
+ * Module Name: tbxface - Public interfaces to the ACPI subsystem
+ * ACPI table oriented interfaces
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "namesp.h"
+#include "interp.h"
+#include "tables.h"
+
+
+#define _COMPONENT TABLE_MANAGER
+ MODULE_NAME ("tbxface");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_load_firmware_tables
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to load the ACPI tables from BIOS
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_load_firmware_tables (void)
+{
+ ACPI_STATUS status = AE_OK;
+ u32 number_of_tables = 0;
+
+
+ /* Get the RSDT first */
+
+ status = acpi_tb_get_table_rsdt (&number_of_tables);
+ if (status != AE_OK) {
+ goto error_exit;
+ }
+
+
+ /* Now get the rest of the tables */
+
+ status = acpi_tb_get_all_tables (number_of_tables, NULL);
+ if (status != AE_OK) {
+ goto error_exit;
+ }
+
+
+ return (AE_OK);
+
+
+error_exit:
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_load_table
+ *
+ * PARAMETERS: Table_ptr - pointer to a buffer containing the entire
+ * table to be loaded
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to load a table from the caller's
+ * buffer. The buffer must contain an entire ACPI Table including
+ * a valid header. The header fields will be verified, and if it
+ * is determined that the table is invalid, the call will fail.
+ *
+ * If the call fails an appropriate status will be returned.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_load_table (
+ ACPI_TABLE_HEADER *table_ptr)
+{
+ ACPI_STATUS status;
+ ACPI_TABLE_DESC table_info;
+
+
+ if (!table_ptr) {
+ return AE_BAD_PARAMETER;
+ }
+
+ /* Copy the table to a local buffer */
+
+ status = acpi_tb_get_table (NULL, ((char *) table_ptr), &table_info);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Install the new table into the local data structures */
+
+ status = acpi_tb_install_table (NULL, &table_info);
+ if (ACPI_FAILURE (status)) {
+ /* TBD: [Errors] must free table allocated by Acpi_tb_get_table */
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_unload_table
+ *
+ * PARAMETERS: Table_type - Type of table to be unloaded
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This routine is used to force the unload of a table
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_unload_table (
+ ACPI_TABLE_TYPE table_type)
+{
+ ACPI_TABLE_DESC *list_head;
+
+
+ /* Parameter validation */
+
+ if (table_type > ACPI_TABLE_MAX) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /* Find all tables of the requested type */
+
+ list_head = &acpi_gbl_acpi_tables[table_type];
+ do
+ {
+ /* Delete the entire namespace under this table NTE */
+
+ acpi_ns_delete_namespace_by_owner (list_head->table_id);
+
+ /* Delete (or unmap) the actual table */
+
+ acpi_tb_delete_acpi_table (table_type);
+
+ } while (list_head != &acpi_gbl_acpi_tables[table_type]);
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_get_table_header
+ *
+ * PARAMETERS: Table_type - one of the defined table types
+ * Instance - the non zero instance of the table, allows
+ * support for multiple tables of the same type
+ * see Acpi_gbl_Acpi_table_flag
+ * Out_table_header - pointer to the ACPI_TABLE_HEADER if successful
+ *
+ * DESCRIPTION: This function is called to get an ACPI table header. The caller
+ * supplies an pointer to a data area sufficient to contain an ACPI
+ * ACPI_TABLE_HEADER structure.
+ *
+ * The header contains a length field that can be used to determine
+ * the size of the buffer needed to contain the entire table. This
+ * function is not valid for the RSD PTR table since it does not
+ * have a standard header and is fixed length.
+ *
+ * If the operation fails for any reason an appropriate status will
+ * be returned and the contents of Out_table_header are undefined.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_get_table_header (
+ ACPI_TABLE_TYPE table_type,
+ u32 instance,
+ ACPI_TABLE_HEADER *out_table_header)
+{
+ ACPI_TABLE_HEADER *tbl_ptr;
+ ACPI_STATUS status;
+
+
+ status = AE_OK;
+
+ if ((instance == 0) ||
+ (table_type == ACPI_TABLE_RSDP) ||
+ (!out_table_header))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Check the table type and instance */
+
+ if ((table_type > ACPI_TABLE_MAX) ||
+ (acpi_gbl_acpi_table_data[table_type].flags == ACPI_TABLE_SINGLE &&
+ instance > 1))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /* Get a pointer to the entire table */
+
+ status = acpi_tb_get_table_ptr (table_type, instance, &tbl_ptr);
+ if (status != AE_OK) {
+ return (status);
+ }
+
+ /*
+ * The function will return a NULL pointer if the table is not loaded
+ */
+ if (tbl_ptr == NULL) {
+ return (AE_NOT_EXIST);
+ }
+
+ /*
+ * Copy the header to the caller's buffer
+ */
+ MEMCPY ((void *) out_table_header, (void *) tbl_ptr,
+ sizeof (ACPI_TABLE_HEADER));
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_get_table
+ *
+ * PARAMETERS: Table_type - one of the defined table types
+ * Instance - the non zero instance of the table, allows
+ * support for multiple tables of the same type
+ * see Acpi_gbl_Acpi_table_flag
+ * Ret_buffer - pointer to a structure containing a buffer to
+ * receive the table
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to get an ACPI table. The caller
+ * supplies an Out_buffer large enough to contain the entire ACPI
+ * table. The caller should call the Acpi_get_table_header function
+ * first to determine the buffer size needed. Upon completion
+ * the Out_buffer->Length field will indicate the number of bytes
+ * copied into the Out_buffer->Buf_ptr buffer. This table will be
+ * a complete table including the header.
+ *
+ * If the operation fails an appropriate status will be returned
+ * and the contents of Out_buffer are undefined.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_get_table (
+ ACPI_TABLE_TYPE table_type,
+ u32 instance,
+ ACPI_BUFFER *ret_buffer)
+{
+ ACPI_TABLE_HEADER *tbl_ptr;
+ ACPI_STATUS status;
+ u32 ret_buf_len;
+
+
+ status = AE_OK;
+
+ /*
+ * Must have a buffer
+ */
+ if ((instance == 0) ||
+ (!ret_buffer) ||
+ (!ret_buffer->pointer) ||
+ (!ret_buffer->length))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Check the table type and instance */
+
+ if ((table_type > ACPI_TABLE_MAX) ||
+ (acpi_gbl_acpi_table_data[table_type].flags == ACPI_TABLE_SINGLE &&
+ instance > 1))
+ {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /* Get a pointer to the entire table */
+
+ status = acpi_tb_get_table_ptr (table_type, instance, &tbl_ptr);
+ if (status != AE_OK) {
+ return (status);
+ }
+
+ /*
+ * The function will return a NULL pointer if the table is not loaded
+ */
+ if (tbl_ptr == NULL) {
+ return (AE_NOT_EXIST);
+ }
+
+ /*
+ * Got a table ptr, assume it's ok and copy it to the user's buffer
+ */
+ if (table_type == ACPI_TABLE_RSDP) {
+ /*
+ * RSD PTR is the only "table" without a header
+ */
+ ret_buf_len = sizeof (ROOT_SYSTEM_DESCRIPTOR_POINTER);
+ }
+ else {
+ ret_buf_len = tbl_ptr->length;
+ }
+
+ /*
+ * Verify we have space in the caller's buffer for the table
+ */
+ if (ret_buffer->length < ret_buf_len) {
+ ret_buffer->length = ret_buf_len;
+ return (AE_BUFFER_OVERFLOW);
+ }
+
+ ret_buffer->length = ret_buf_len;
+
+ MEMCPY ((void *) ret_buffer->pointer, (void *) tbl_ptr, ret_buf_len);
+
+ return (AE_OK);
+}
+
diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c
index 62758a297..785a0e551 100644
--- a/drivers/block/acsi_slm.c
+++ b/drivers/block/acsi_slm.c
@@ -1007,7 +1007,7 @@ int slm_init( void )
BufferP = SLMBuffer;
SLMState = IDLE;
- devfs_handle = devfs_mk_dir (NULL, "slm", 3, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "slm", NULL);
devfs_register_series (devfs_handle, "%u", MAX_SLM, DEVFS_FL_DEFAULT,
MAJOR_NR, 0, S_IFCHR | S_IRUSR | S_IWUSR,
&slm_fops, NULL);
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index b7aa4241e..33dd5b896 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -355,7 +355,7 @@ static void fd_select_side( int side );
static void fd_select_drive( int drive );
static void fd_deselect( void );
static void fd_motor_off_timer( unsigned long dummy );
-static void check_change( void );
+static void check_change( unsigned long dummy );
static __inline__ void set_head_settle_flag( void );
static __inline__ int get_head_settle_flag( void );
static void floppy_irq (int irq, void *dummy, struct pt_regs *fp);
@@ -391,14 +391,16 @@ static int floppy_release( struct inode * inode, struct file * filp );
/************************* End of Prototypes **************************/
static struct timer_list motor_off_timer =
- { NULL, NULL, 0, 0, fd_motor_off_timer };
+ { function: fd_motor_off_timer };
static struct timer_list readtrack_timer =
- { NULL, NULL, 0, 0, fd_readtrack_check };
+ { function: fd_readtrack_check };
static struct timer_list timeout_timer =
- { NULL, NULL, 0, 0, fd_times_out };
-
+ { function: fd_times_out };
+static struct timer_list fd_timer =
+ { function: check_change };
+
static inline void
start_motor_off_timer(void)
{
@@ -407,10 +409,9 @@ start_motor_off_timer(void)
}
static inline void
-start_check_change_timer(void)
+start_check_change_timer(unsigned long dummy)
{
- timer_table[FLOPPY_TIMER].expires = jiffies + CHECK_CHANGE_DELAY;
- timer_active |= (1 << FLOPPY_TIMER);
+ mod_timer(&fd_timer, jiffies + CHECK_CHANGE_DELAY);
}
static inline void
@@ -1309,12 +1310,11 @@ static void finish_fdc_done( int dummy )
stop_timeout();
NeedSeek = 0;
- if ((timer_active & (1 << FLOPPY_TIMER)) &&
- time_before(timer_table[FLOPPY_TIMER].expires, jiffies + 5))
+ if (timer_pending(&fd_timer) && time_before(fd_timer.expires, jiffies + 5))
/* If the check for a disk change is done too early after this
* last seek command, the WP bit still reads wrong :-((
*/
- timer_table[FLOPPY_TIMER].expires = jiffies + 5;
+ mod_timer(&fd_timer, jiffies + 5);
else
start_check_change_timer();
start_motor_off_timer();
@@ -1990,10 +1990,6 @@ int __init atari_floppy_init (void)
SelectedDrive = -1;
BufferDrive = -1;
- /* initialize check_change timer */
- timer_table[FLOPPY_TIMER].fn = check_change;
- timer_active &= ~(1 << FLOPPY_TIMER);
-
DMABuffer = atari_stram_alloc( BUFFER_SIZE+512, NULL, "ataflop" );
if (!DMABuffer) {
printk(KERN_ERR "atari_floppy_init: cannot get dma buffer\n");
@@ -2072,8 +2068,7 @@ void cleanup_module (void)
unregister_blkdev(MAJOR_NR, "fd");
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
- timer_active &= ~(1 << FLOPPY_TIMER);
- timer_table[FLOPPY_TIMER].fn = 0;
+ del_timer_sync(&fd_timer);
atari_stram_free( DMABuffer );
}
#endif
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 9bbe50523..9ae6fa94c 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -331,6 +331,7 @@ void cleanup_module(void)
iounmap((void*)hba[i]->vaddr);
unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
del_timer(&hba[i]->timer);
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + i));
remove_proc_entry(hba[i]->devname, proc_array);
kfree(hba[i]->cmd_pool);
kfree(hba[i]->cmd_pool_bits);
diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c
index 1eee6d545..7720c43c4 100644
--- a/drivers/block/elevator.c
+++ b/drivers/block/elevator.c
@@ -88,25 +88,25 @@ int elevator_default_merge(request_queue_t *q, struct request **req,
head = head->next;
while ((entry = entry->prev) != head && !starving) {
- *req = blkdev_entry_to_request(entry);
- latency += (*req)->nr_segments;
- if (elevator_sequence_before((*req)->elevator_sequence, sequence))
+ struct request *__rq = *req = blkdev_entry_to_request(entry);
+ latency += __rq->nr_segments;
+ if (elevator_sequence_before(__rq->elevator_sequence, sequence))
starving = 1;
if (latency < 0)
continue;
- if ((*req)->sem)
+ if (__rq->sem)
continue;
- if ((*req)->cmd != rw)
+ if (__rq->cmd != rw)
continue;
- if ((*req)->nr_sectors + count > *max_sectors)
+ if (__rq->nr_sectors + count > *max_sectors)
continue;
- if ((*req)->rq_dev != bh->b_rdev)
+ if (__rq->rq_dev != bh->b_rdev)
continue;
- if ((*req)->sector + (*req)->nr_sectors == bh->b_rsector) {
- if (latency - (*req)->nr_segments < 0)
+ if (__rq->sector + __rq->nr_sectors == bh->b_rsector) {
+ if (latency - __rq->nr_segments < 0)
break;
action = ELEVATOR_BACK_MERGE;
- } else if ((*req)->sector - count == bh->b_rsector) {
+ } else if (__rq->sector - count == bh->b_rsector) {
if (starving)
break;
action = ELEVATOR_FRONT_MERGE;
@@ -161,31 +161,45 @@ int elevator_linus_merge(request_queue_t *q, struct request **req,
int *max_sectors, int *max_segments)
{
struct list_head *entry, *head = &q->queue_head;
- unsigned int count = bh->b_size >> 9;
+ unsigned int count = bh->b_size >> 9, ret = ELEVATOR_NO_MERGE;
entry = head;
if (q->head_active && !q->plugged)
head = head->next;
while ((entry = entry->prev) != head) {
- *req = blkdev_entry_to_request(entry);
- if (!(*req)->elevator_sequence)
+ struct request *__rq = *req = blkdev_entry_to_request(entry);
+ if (!__rq->elevator_sequence)
break;
- if ((*req)->sem)
+ if (__rq->sem)
continue;
- if ((*req)->cmd != rw)
+ if (__rq->cmd != rw)
continue;
- if ((*req)->nr_sectors + count > *max_sectors)
+ if (__rq->nr_sectors + count > *max_sectors)
continue;
- if ((*req)->rq_dev != bh->b_rdev)
+ if (__rq->rq_dev != bh->b_rdev)
continue;
- if ((*req)->sector + (*req)->nr_sectors == bh->b_rsector)
- return ELEVATOR_BACK_MERGE;
- if ((*req)->sector - count == bh->b_rsector)
- return ELEVATOR_FRONT_MERGE;
- (*req)->elevator_sequence--;
+ if (__rq->sector + __rq->nr_sectors == bh->b_rsector) {
+ ret = ELEVATOR_BACK_MERGE;
+ break;
+ }
+ if (__rq->sector - count == bh->b_rsector) {
+ ret = ELEVATOR_FRONT_MERGE;
+ break;
+ }
}
- return ELEVATOR_NO_MERGE;
+
+ /*
+ * second pass scan of requests that got passed over, if any
+ */
+ if (ret != ELEVATOR_NO_MERGE && *req) {
+ while ((entry = entry->next) != &q->queue_head) {
+ struct request *tmp = blkdev_entry_to_request(entry);
+ tmp->elevator_sequence--;
+ }
+ }
+
+ return ret;
}
/*
@@ -213,18 +227,18 @@ int elevator_noop_merge(request_queue_t *q, struct request **req,
entry = head;
while ((entry = entry->prev) != head) {
- *req = blkdev_entry_to_request(entry);
- if ((*req)->sem)
+ struct request *__rq = *req = blkdev_entry_to_request(entry);
+ if (__rq->sem)
continue;
- if ((*req)->cmd != rw)
+ if (__rq->cmd != rw)
continue;
- if ((*req)->nr_sectors + count > *max_sectors)
+ if (__rq->nr_sectors + count > *max_sectors)
continue;
- if ((*req)->rq_dev != bh->b_rdev)
+ if (__rq->rq_dev != bh->b_rdev)
continue;
- if ((*req)->sector + (*req)->nr_sectors == bh->b_rsector)
+ if (__rq->sector + __rq->nr_sectors == bh->b_rsector)
return ELEVATOR_BACK_MERGE;
- if ((*req)->sector - count == bh->b_rsector)
+ if (__rq->sector - count == bh->b_rsector)
return ELEVATOR_FRONT_MERGE;
}
return ELEVATOR_NO_MERGE;
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 1fcd8b73f..18a2c6c91 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -1872,7 +1872,7 @@ static void show_floppy(void)
if (timer_pending(&fd_timer))
printk("fd_timer.function=%p\n", fd_timer.function);
if (timer_pending(&fd_timeout)){
- printk("timer_table=%p\n",fd_timeout.function);
+ printk("timer_function=%p\n",fd_timeout.function);
printk("expires=%lu\n",fd_timeout.expires-jiffies);
printk("now=%lu\n",jiffies);
}
@@ -4109,7 +4109,7 @@ int __init floppy_init(void)
raw_cmd = NULL;
- devfs_handle = devfs_mk_dir (NULL, "floppy", 0, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "floppy", NULL);
if (devfs_register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
printk("Unable to get major %d for floppy\n",MAJOR_NR);
return -EBUSY;
@@ -4143,6 +4143,7 @@ int __init floppy_init(void)
if (fdc_state[0].address == -1) {
devfs_unregister_blkdev(MAJOR_NR,"fd");
del_timer(&fd_timeout);
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
return -ENODEV;
}
#if N_FDC > 1
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 9646adbd0..7735594cb 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -148,34 +148,40 @@ request_queue_t *blk_get_queue(kdev_t dev)
return ret;
}
-/*
- * Hopefully the low level driver has finished any out standing requests
- * first...
- */
-void blk_cleanup_queue(request_queue_t * q)
+static int __block_cleanup_queue(struct list_head *head)
{
struct list_head *entry;
struct request *rq;
- int i = QUEUE_NR_REQUESTS;
+ int i = 0;
- if (list_empty(&q->request_freelist))
- return;
-
- if (q->queue_requests)
- BUG();
+ if (list_empty(head))
+ return 0;
- entry = &q->request_freelist;
- entry = entry->next;
+ entry = head->next;
do {
rq = list_entry(entry, struct request, table);
entry = entry->next;
list_del(&rq->table);
kmem_cache_free(request_cachep, rq);
- i--;
- } while (!list_empty(&q->request_freelist));
+ i++;
+ } while (!list_empty(head));
+
+ return i;
+}
+
+/*
+ * Hopefully the low level driver has finished any out standing requests
+ * first...
+ */
+void blk_cleanup_queue(request_queue_t * q)
+{
+ int count = QUEUE_NR_REQUESTS;
- if (i)
- printk("blk_cleanup_queue: leaked requests (%d)\n", i);
+ count -= __block_cleanup_queue(&q->request_freelist[READ]);
+ count -= __block_cleanup_queue(&q->request_freelist[WRITE]);
+
+ if (count)
+ printk("blk_cleanup_queue: leaked requests (%d)\n", count);
memset(q, 0, sizeof(*q));
}
@@ -280,10 +286,9 @@ static void blk_init_free_list(request_queue_t *q)
for (i = 0; i < QUEUE_NR_REQUESTS; i++) {
rq = kmem_cache_alloc(request_cachep, SLAB_KERNEL);
rq->rq_status = RQ_INACTIVE;
- list_add(&rq->table, &q->request_freelist);
+ list_add(&rq->table, &q->request_freelist[i & 1]);
}
- q->queue_requests = 0;
init_waitqueue_head(&q->wait_for_request);
spin_lock_init(&q->request_lock);
}
@@ -291,7 +296,8 @@ static void blk_init_free_list(request_queue_t *q)
void blk_init_queue(request_queue_t * q, request_fn_proc * rfn)
{
INIT_LIST_HEAD(&q->queue_head);
- INIT_LIST_HEAD(&q->request_freelist);
+ INIT_LIST_HEAD(&q->request_freelist[READ]);
+ INIT_LIST_HEAD(&q->request_freelist[WRITE]);
elevator_init(&q->elevator, ELEVATOR_LINUS);
blk_init_free_list(q);
q->request_fn = rfn;
@@ -342,19 +348,37 @@ void generic_unplug_device(void *data)
*/
static inline struct request *get_request(request_queue_t *q, int rw)
{
- register struct request *rq = NULL;
+ struct list_head *list = &q->request_freelist[rw];
+ struct request *rq;
- if (!list_empty(&q->request_freelist)) {
- if ((q->queue_requests > QUEUE_WRITES_MAX) && (rw == WRITE))
- return NULL;
+ /*
+ * Reads get preferential treatment and are allowed to steal
+ * from the write free list if necessary.
+ */
+ if (!list_empty(list)) {
+ rq = blkdev_free_rq(list);
+ goto got_rq;
+ }
- rq = blkdev_free_rq(&q->request_freelist);
- list_del(&rq->table);
- rq->rq_status = RQ_ACTIVE;
- rq->special = NULL;
- rq->q = q;
- q->queue_requests++;
+ /*
+ * if the WRITE list is non-empty, we know that rw is READ
+ * and that the READ list is empty. allow reads to 'steal'
+ * from the WRITE list.
+ */
+ if (!list_empty(&q->request_freelist[WRITE])) {
+ list = &q->request_freelist[WRITE];
+ rq = blkdev_free_rq(list);
+ goto got_rq;
}
+
+ return NULL;
+
+got_rq:
+ list_del(&rq->table);
+ rq->free_list = list;
+ rq->rq_status = RQ_ACTIVE;
+ rq->special = NULL;
+ rq->q = q;
return rq;
}
@@ -486,9 +510,9 @@ void inline blkdev_release_request(struct request *req)
/*
* Request may not have originated from ll_rw_blk
*/
- if (req->q) {
- list_add(&req->table, &req->q->request_freelist);
- req->q->queue_requests--;
+ if (req->free_list) {
+ list_add(&req->table, req->free_list);
+ req->free_list = NULL;
wake_up(&req->q->wait_for_request);
}
}
@@ -557,7 +581,7 @@ static inline void __make_request(request_queue_t * q, int rw,
int max_segments = MAX_SEGMENTS;
struct request * req = NULL;
int rw_ahead, max_sectors, el_ret;
- struct list_head *head = &q->queue_head;
+ struct list_head *head;
int latency;
elevator_t *elevator = &q->elevator;
@@ -602,12 +626,6 @@ static inline void __make_request(request_queue_t * q, int rw,
goto end_io; /* Hmmph! Nothing to write */
refile_buffer(bh);
do_write:
- /*
- * We don't allow the write-requests to fill up the
- * queue completely: we want some room for reads,
- * as they take precedence. The last third of the
- * requests are only for reads.
- */
kstat.pgpgout++;
break;
default:
@@ -646,11 +664,6 @@ static inline void __make_request(request_queue_t * q, int rw,
spin_lock_irq(&io_request_lock);
elevator_default_debug(q, bh->b_rdev);
- if (list_empty(head)) {
- q->plug_device_fn(q, bh->b_rdev); /* is atomic */
- goto get_rq;
- }
-
/*
* skip first entry, for devices with active queue head
*/
@@ -658,6 +671,11 @@ static inline void __make_request(request_queue_t * q, int rw,
if (q->head_active && !q->plugged)
head = head->next;
+ if (list_empty(head)) {
+ q->plug_device_fn(q, bh->b_rdev); /* is atomic */
+ goto get_rq;
+ }
+
el_ret = elevator->elevator_merge_fn(q, &req, bh, rw, &max_sectors, &max_segments);
switch (el_ret) {
@@ -843,7 +861,6 @@ static void __ll_rw_block(int rw, int nr, struct buffer_head * bhs[],
sorry:
for (i = 0; i < nr; i++)
buffer_IO_error(bhs[i]);
- return;
}
void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 89018e54a..ed52ee2b8 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -782,7 +782,7 @@ int __init loop_init(void)
MAJOR_NR);
return -EIO;
}
- devfs_handle = devfs_mk_dir (NULL, "loop", 0, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "loop", NULL);
devfs_register_series (devfs_handle, "%u", max_loop, DEVFS_FL_DEFAULT,
MAJOR_NR, 0,
S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
diff --git a/drivers/block/md.c b/drivers/block/md.c
index 617990e77..3fa5e5318 100644
--- a/drivers/block/md.c
+++ b/drivers/block/md.c
@@ -804,6 +804,7 @@ static void free_mddev (mddev_t *mddev)
del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev)));
md_list_del(&mddev->all_mddevs);
MD_INIT_LIST_HEAD(&mddev->all_mddevs);
+ blk_cleanup_queue(&mddev->queue);
kfree(mddev);
}
@@ -3627,7 +3628,7 @@ int md__init md_init (void)
printk (KERN_ALERT "Unable to get major %d for md\n", MD_MAJOR);
return (-1);
}
- devfs_handle = devfs_mk_dir (NULL, "md", 0, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "md", NULL);
devfs_register_series (devfs_handle, "%u",MAX_MD_DEVS,DEVFS_FL_DEFAULT,
MAJOR_NR, 0, S_IFBLK | S_IRUSR | S_IWUSR,
&md_fops, NULL);
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 222622c35..436969bb4 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -517,7 +517,7 @@ int nbd_init(void)
register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &nbd_fops,
nbd_bytesizes[i]>>9);
}
- devfs_handle = devfs_mk_dir (NULL, "nbd", 0, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "nbd", NULL);
devfs_register_series (devfs_handle, "%u", MAX_NBD,
DEVFS_FL_DEFAULT, MAJOR_NR, 0,
S_IFBLK | S_IRUSR | S_IWUSR,
@@ -530,6 +530,7 @@ int nbd_init(void)
void cleanup_module(void)
{
devfs_unregister (devfs_handle);
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
if (unregister_blkdev(MAJOR_NR, "nbd") != 0)
printk("nbd: cleanup_module failed\n");
diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
index 5c4dbbee8..c282d82a1 100644
--- a/drivers/block/paride/pg.c
+++ b/drivers/block/paride/pg.c
@@ -307,7 +307,7 @@ int pg_init (void) /* preliminary initialisation */
if (PG.present) pi_release(PI);
return -1;
}
- devfs_handle = devfs_mk_dir (NULL, "pg", 2, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "pg", NULL);
devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
major, 0, S_IFCHR | S_IRUSR | S_IWUSR,
&pg_fops, NULL);
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
index 52c67d017..0d3e81838 100644
--- a/drivers/block/paride/pt.c
+++ b/drivers/block/paride/pt.c
@@ -312,7 +312,7 @@ int pt_init (void) /* preliminary initialisation */
return -1;
}
- devfs_handle = devfs_mk_dir (NULL, "pt", 2, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "pt", NULL);
devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
major, 0, S_IFCHR | S_IRUSR | S_IWUSR,
&pt_fops, NULL);
diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
index 766ea0a18..fec570acb 100644
--- a/drivers/block/ps2esdi.c
+++ b/drivers/block/ps2esdi.c
@@ -232,6 +232,7 @@ cleanup_module(void)
free_dma(dma_arb_level);
free_irq(PS2ESDI_IRQ, NULL)
devfs_unregister_blkdev(MAJOR_NR, "ed");
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
}
#endif /* MODULE */
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 26c0509d2..727c1c543 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -408,7 +408,7 @@ int __init rd_init (void)
rd_blocksizes[i] = rd_blocksize;
rd_kbsize[i] = rd_size;
}
- devfs_handle = devfs_mk_dir (NULL, "rd", 0, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "rd", NULL);
devfs_register_series (devfs_handle, "%u", NUM_RAMDISKS,
DEVFS_FL_DEFAULT, MAJOR_NR, 0,
S_IFBLK | S_IRUSR | S_IWUSR,
@@ -436,8 +436,8 @@ int __init rd_init (void)
#ifdef MODULE
module_init(rd_init);
-#endif
module_exit(rd_cleanup);
+#endif
/* loadable module support */
MODULE_PARM (rd_size, "1i");
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index 5ac2a16a6..8bd2ec3bc 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -166,7 +166,7 @@ int __init xd_init (void)
printk("xd: Unable to get major number %d\n",MAJOR_NR);
return -1;
}
- devfs_handle = devfs_mk_dir (NULL, xd_gendisk.major_name, 0, NULL);
+ devfs_handle = devfs_mk_dir (NULL, xd_gendisk.major_name, NULL);
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */
xd_gendisk.next = gendisk_head;
diff --git a/drivers/block/xd.h b/drivers/block/xd.h
index d6fcc675a..1612f321d 100644
--- a/drivers/block/xd.h
+++ b/drivers/block/xd.h
@@ -103,9 +103,9 @@ typedef struct {
const char *name;
} XD_SIGNATURE;
-int xd_setup (char *);
+static int xd_setup (char *);
#ifndef MODULE
-int xd_manual_geo_init (char *command);
+static int xd_manual_geo_init (char *command);
#endif /* MODULE */
static u_char xd_detect (u_char *controller, unsigned int *address);
static u_char xd_initdrives (void (*init_drive)(u_char drive));
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
index 74ea30a41..88764463a 100644
--- a/drivers/block/z2ram.c
+++ b/drivers/block/z2ram.c
@@ -399,6 +399,8 @@ cleanup_module( void )
if ( unregister_blkdev( MAJOR_NR, DEVICE_NAME ) != 0 )
printk( KERN_ERR DEVICE_NAME ": unregister of device failed\n");
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+
if ( current_device != -1 )
{
i = 0;
diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
index e32238d32..b3b73f2fc 100644
--- a/drivers/cdrom/aztcd.c
+++ b/drivers/cdrom/aztcd.c
@@ -1819,12 +1819,13 @@ int __init aztcd_init(void)
void __exit aztcd_exit(void)
{
- devfs_unregister(devfs_find_handle(NULL, "aztcd", 0, 0, 0, DEVFS_SPECIAL_BLK,
+ devfs_unregister(devfs_find_handle(NULL, "aztcd", 0, 0, DEVFS_SPECIAL_BLK,
0));
if ((devfs_unregister_blkdev(MAJOR_NR, "aztcd") == -EINVAL))
{ printk("What's that: can't unregister aztcd\n");
return;
}
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
if ((azt_port==0x1f0)||(azt_port==0x170))
{ SWITCH_IDE_MASTER;
release_region(azt_port,8); /*IDE-interface*/
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index caa3900b3..4503bbfed 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -389,7 +389,7 @@ int register_cdrom(struct cdrom_device_info *cdi)
cdi->options |= (int) CDO_CHECK_TYPE;
if (!devfs_handle)
- devfs_handle = devfs_mk_dir (NULL, "cdroms", 6, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "cdroms", NULL);
sprintf (vname, "cdrom%u", cdrom_counter++);
if (cdi->de) {
int pos;
@@ -400,9 +400,9 @@ int register_cdrom(struct cdrom_device_info *cdi)
sizeof rname - 3);
if (pos >= 0) {
strncpy (rname + pos, "../", 3);
- devfs_mk_symlink (devfs_handle, vname, 0,
+ devfs_mk_symlink (devfs_handle, vname,
DEVFS_FL_DEFAULT,
- rname + pos, 0, &slave, NULL);
+ rname + pos, &slave, NULL);
devfs_auto_unregister (cdi->de, slave);
}
}
@@ -2617,7 +2617,7 @@ static int __init cdrom_init(void)
#ifdef CONFIG_SYSCTL
cdrom_sysctl_register();
#endif
- devfs_handle = devfs_mk_dir(NULL, "cdroms", 6, NULL);
+ devfs_handle = devfs_mk_dir(NULL, "cdroms", NULL);
return 0;
}
diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
index 0b8d942b4..56054ae9e 100644
--- a/drivers/cdrom/cdu31a.c
+++ b/drivers/cdrom/cdu31a.c
@@ -3544,6 +3544,7 @@ cdu31a_init(void)
}
errout0:
printk("Unable to register CDU-31a with Uniform cdrom driver\n");
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
if (devfs_unregister_blkdev(MAJOR_NR, "cdu31a"))
{
printk("Can't unregister block device for cdu31a\n");
@@ -3569,6 +3570,8 @@ cdu31a_exit(void)
return;
}
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+
if (cdu31a_irq > 0)
free_irq(cdu31a_irq, NULL);
diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
index 9e8889ac6..facf6223d 100644
--- a/drivers/cdrom/cm206.c
+++ b/drivers/cdrom/cm206.c
@@ -1285,6 +1285,7 @@ static void cleanup(int level)
printk("Can't unregister major cm206\n");
return;
}
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
case 3:
free_irq(cm206_irq, NULL);
case 2:
diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c
index b0fa47b3e..dc8870491 100644
--- a/drivers/cdrom/gscd.c
+++ b/drivers/cdrom/gscd.c
@@ -95,7 +95,7 @@ static void gscd_bin2bcd (unsigned char *p);
/* Schnittstellen zum Kern/FS */
static void do_gscd_request (request_queue_t *);
-static void __do_gscd_request (void);
+static void __do_gscd_request (unsigned long dummy);
static int gscd_ioctl (struct inode *, struct file *, unsigned int, unsigned long);
static int gscd_open (struct inode *, struct file *);
static int gscd_release (struct inode *, struct file *);
@@ -160,6 +160,7 @@ static int AudioStart_f;
static int AudioEnd_m;
static int AudioEnd_f;
+static struct timer_list gscd_timer;
static struct block_device_operations gscd_fops = {
open: gscd_open,
@@ -271,23 +272,24 @@ long offs;
static void do_gscd_request (request_queue_t * q)
{
- __do_gscd_request();
+ __do_gscd_request(0);
}
-static void __do_gscd_request (void)
+static void __do_gscd_request (unsigned long dummy)
{
unsigned int block,dev;
unsigned int nsect;
repeat:
- if (QUEUE_EMPTY || CURRENT->rq_status == RQ_INACTIVE) return;
+ if (QUEUE_EMPTY || CURRENT->rq_status == RQ_INACTIVE)
+ goto out;
INIT_REQUEST;
dev = MINOR(CURRENT->rq_dev);
block = CURRENT->sector;
nsect = CURRENT->nr_sectors;
if (QUEUE_EMPTY || CURRENT -> sector == -1)
- return;
+ goto out;
if (CURRENT -> cmd != READ)
{
@@ -318,6 +320,8 @@ repeat:
#endif
gscd_read_cmd ();
+out:
+ return;
}
@@ -992,13 +996,16 @@ long err;
void __exit exit_gscd(void)
{
- devfs_unregister(devfs_find_handle(NULL, "gscd", 0, 0, 0, DEVFS_SPECIAL_BLK,
+ del_timer_async(&gscd_timer);
+
+ devfs_unregister(devfs_find_handle(NULL, "gscd", 0, 0, DEVFS_SPECIAL_BLK,
0));
if ((devfs_unregister_blkdev(MAJOR_NR, "gscd" ) == -EINVAL))
{
printk("What's that: can't unregister GoldStar-module\n" );
return;
}
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
release_region (gscd_port,4);
printk(KERN_INFO "GoldStar-module released.\n" );
}
diff --git a/drivers/cdrom/gscd.h b/drivers/cdrom/gscd.h
index fccc742a5..9c294762b 100644
--- a/drivers/cdrom/gscd.h
+++ b/drivers/cdrom/gscd.h
@@ -74,11 +74,10 @@
#define READ_DATA(port, buf, nr) insb(port, buf, nr)
#define SET_TIMER(func, jifs) \
- ((timer_table[GSCD_TIMER].expires = jiffies + jifs), \
- (timer_table[GSCD_TIMER].fn = func), \
- (timer_active |= 1<<GSCD_TIMER))
+ ((mod_timer(&gscd_timer, jiffies + jifs)), \
+ (gscd_timer.function = func))
-#define CLEAR_TIMER timer_active &= ~(1<<GSCD_TIMER)
+#define CLEAR_TIMER del_timer_sync(&gscd_timer)
#define MAX_TRACKS 104
diff --git a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c
index 91bde1a1d..0f59831b7 100644
--- a/drivers/cdrom/mcd.c
+++ b/drivers/cdrom/mcd.c
@@ -182,7 +182,7 @@ static char tocUpToDate;
static char mcdVersion;
static void mcd_transfer(void);
-static void mcd_poll(void);
+static void mcd_poll(unsigned long dummy);
static void mcd_invalidate_buffers(void);
static void hsg2msf(long hsg, struct msf *msf);
static void bin2bcd(unsigned char *p);
@@ -203,6 +203,8 @@ int mcd_audio_ioctl(struct cdrom_device_info * cdi, unsigned int cmd,
void * arg);
int mcd_drive_status(struct cdrom_device_info * cdi, int slot_nr);
+static struct timer_list mcd_timer;
+
static struct cdrom_device_ops mcd_dops = {
mcd_open, /* open */
mcd_release, /* release */
@@ -705,7 +707,7 @@ do_mcd_request(request_queue_t * q)
static void
-mcd_poll(void)
+mcd_poll(unsigned long dummy)
{
int st;
@@ -787,7 +789,7 @@ mcd_poll(void)
#ifdef TEST3
printk("MCD_S_IDLE\n");
#endif
- return;
+ goto out;
@@ -829,7 +831,7 @@ mcd_poll(void)
mcd_state = MCD_S_IDLE;
while (CURRENT_VALID)
end_request(0);
- return;
+ goto out;
}
outb(MCMD_SET_MODE, MCDPORT(0));
@@ -869,7 +871,7 @@ mcd_poll(void)
mcd_state = MCD_S_IDLE;
while (CURRENT_VALID)
end_request(0);
- return;
+ goto out;
}
if (CURRENT_VALID) {
@@ -1071,13 +1073,13 @@ mcd_poll(void)
}
} else {
mcd_state = MCD_S_IDLE;
- return;
+ goto out;
}
break;
default:
printk("mcd: invalid state %d\n", mcd_state);
- return;
+ goto out;
}
ret:
@@ -1087,6 +1089,8 @@ mcd_poll(void)
}
SET_TIMER(mcd_poll, 1);
+out:
+ return;
}
@@ -1169,6 +1173,7 @@ static void cleanup(int level)
printk(KERN_WARNING "Can't unregister major mcd\n");
return;
}
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
default:
}
}
@@ -1369,7 +1374,7 @@ sendMcdCmd(int cmd, struct mcd_Play_msf *params)
*/
static void
-mcdStatTimer(void)
+mcdStatTimer(unsigned long dummy)
{
if (!(inb(MCDPORT(1)) & MFL_STATUS))
{
@@ -1659,6 +1664,7 @@ Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
void __exit mcd_exit(void)
{
cleanup(3);
+ del_timer_sync(&mcd_timer);
}
#ifdef MODULE
diff --git a/drivers/cdrom/mcd.h b/drivers/cdrom/mcd.h
index fffaa92a6..ce903d2f2 100644
--- a/drivers/cdrom/mcd.h
+++ b/drivers/cdrom/mcd.h
@@ -73,12 +73,13 @@
#define READ_DATA(port, buf, nr) \
insb(port, buf, nr)
-#define SET_TIMER(func, jifs) \
- ((timer_table[MCD_TIMER].expires = jiffies + jifs), \
- (timer_table[MCD_TIMER].fn = func), \
- (timer_active |= 1<<MCD_TIMER))
+#define SET_TIMER(func, jifs) \
+ do { \
+ mcd_timer.function = func; \
+ mod_timer(&mcd_timer, jiffies + jifs); \
+ } while (0)
-#define CLEAR_TIMER timer_active &= ~(1<<MCD_TIMER)
+#define CLEAR_TIMER del_timer_async(&mcd_timer);
#define MAX_TRACKS 104
diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c
index 805044841..574ee429e 100644
--- a/drivers/cdrom/mcdx.c
+++ b/drivers/cdrom/mcdx.c
@@ -1016,6 +1016,7 @@ void __exit mcdx_exit(void)
if (devfs_unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
xwarn("cleanup() unregister_blkdev() failed\n");
}
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
#if !MCDX_QUIET
else xinfo("cleanup() succeeded\n");
#endif
@@ -1143,6 +1144,7 @@ int __init mcdx_init_drive(int drive)
MCDX,
stuffp->wreg_data, stuffp->irq, stuffp->irq);
stuffp->irq = 0;
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
kfree(stuffp);
return 0;
}
@@ -1184,6 +1186,7 @@ int __init mcdx_init_drive(int drive)
kfree(stuffp);
if (devfs_unregister_blkdev(MAJOR_NR, "mcdx") != 0)
xwarn("cleanup() unregister_blkdev() failed\n");
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
return 2;
}
printk(msg);
diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c
index 480a01833..f851cd074 100644
--- a/drivers/cdrom/optcd.c
+++ b/drivers/cdrom/optcd.c
@@ -2080,12 +2080,13 @@ int __init optcd_init(void)
void __exit optcd_exit(void)
{
- devfs_unregister(devfs_find_handle(NULL, "optcd", 0, 0, 0,
+ devfs_unregister(devfs_find_handle(NULL, "optcd", 0, 0,
DEVFS_SPECIAL_BLK, 0));
if (devfs_unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
printk(KERN_ERR "optcd: what's that: can't unregister\n");
return;
}
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
release_region(optcd_port, 4);
printk(KERN_INFO "optcd: module released.\n");
}
diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
index 08400a52c..2f65bb525 100644
--- a/drivers/cdrom/sbpcd.c
+++ b/drivers/cdrom/sbpcd.c
@@ -5752,7 +5752,7 @@ int __init SBPCD_INIT(void)
request_region(CDo_command,4,major_name);
- devfs_handle = devfs_mk_dir (NULL, "sbp", 0, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "sbp", NULL);
for (j=0;j<NR_SBPCD;j++)
{
struct cdrom_device_info * sbpcd_infop;
@@ -5779,6 +5779,7 @@ int __init SBPCD_INIT(void)
printk("Can't unregister %s\n", major_name);
}
release_region(CDo_command,4);
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
return -EIO;
}
#ifdef MODULE
@@ -5794,6 +5795,7 @@ int __init SBPCD_INIT(void)
if (sbpcd_infop == NULL)
{
release_region(CDo_command,4);
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
return -ENOMEM;
}
D_S[j].sbpcd_infop = sbpcd_infop;
@@ -5845,7 +5847,7 @@ void sbpcd_exit(void)
return;
}
release_region(CDo_command,4);
-
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
devfs_unregister (devfs_handle);
for (j=0;j<NR_SBPCD;j++)
{
diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
index a867c3819..b793bac4b 100644
--- a/drivers/cdrom/sjcd.c
+++ b/drivers/cdrom/sjcd.c
@@ -1577,8 +1577,10 @@ sjcd_cleanup(void)
{
if( (devfs_unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL) )
printk( "SJCD: cannot unregister device.\n" );
- else
+ else {
release_region( sjcd_base, 4 );
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+ }
return(0);
}
@@ -1586,8 +1588,7 @@ sjcd_cleanup(void)
void __exit sjcd_exit(void)
{
- devfs_unregister(devfs_find_handle(NULL, "sjcd", 0, 0, 0, DEVFS_SPECIAL_BLK,
- 0));
+ devfs_unregister(devfs_find_handle(NULL, "sjcd", 0, 0, DEVFS_SPECIAL_BLK,0));
if ( sjcd_cleanup() )
printk( "SJCD: module: cannot be removed.\n" );
else
diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
index d85fbc01f..945facb97 100644
--- a/drivers/cdrom/sonycd535.c
+++ b/drivers/cdrom/sonycd535.c
@@ -1603,17 +1603,21 @@ sony535_init(void)
sony_toc = (struct s535_sony_toc *)
kmalloc(sizeof *sony_toc, GFP_KERNEL);
- if (sony_toc == NULL)
+ if (sony_toc == NULL) {
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
return -ENOMEM;
+ }
last_sony_subcode = (struct s535_sony_subcode *)
kmalloc(sizeof *last_sony_subcode, GFP_KERNEL);
if (last_sony_subcode == NULL) {
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
kfree(sony_toc);
return -ENOMEM;
}
sony_buffer = (Byte **)
kmalloc(4 * sony_buffer_sectors, GFP_KERNEL);
if (sony_buffer == NULL) {
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
kfree(sony_toc);
kfree(last_sony_subcode);
return -ENOMEM;
@@ -1624,6 +1628,7 @@ sony535_init(void)
if (sony_buffer[i] == NULL) {
while (--i>=0)
kfree(sony_buffer[i]);
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
kfree(sony_buffer);
kfree(sony_toc);
kfree(last_sony_subcode);
@@ -1690,7 +1695,7 @@ sony535_exit(void)
kfree_s(sony_buffer, 4 * sony_buffer_sectors);
kfree_s(last_sony_subcode, sizeof *last_sony_subcode);
kfree_s(sony_toc, sizeof *sony_toc);
- devfs_unregister(devfs_find_handle(NULL, CDU535_HANDLE, 0, 0, 0,
+ devfs_unregister(devfs_find_handle(NULL, CDU535_HANDLE, 0, 0,
DEVFS_SPECIAL_BLK, 0));
if (devfs_unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL)
printk("Uh oh, couldn't unregister " CDU535_HANDLE "\n");
diff --git a/drivers/char/console.c b/drivers/char/console.c
index 4b33e7433..6e862ec53 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -66,6 +66,9 @@
*
* Resurrected character buffers in videoram plus lots of other trickery
* by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998
+ *
+ * Removed old-style timers, introduced console_timer, made timer
+ * deletion SMP-safe. 17Jun00, Andrew Morton <andrewm@uow.edu.au>
*/
#include <linux/module.h>
@@ -139,7 +142,7 @@ static struct consw *con_driver_map[MAX_NR_CONSOLES];
static int con_open(struct tty_struct *, struct file *);
static void vc_init(unsigned int console, unsigned int rows,
unsigned int cols, int do_clear);
-static void blank_screen(void);
+static void blank_screen(unsigned long dummy);
static void gotoxy(int currcons, int new_x, int new_y);
static void save_cur(int currcons);
static void reset_terminal(int currcons, int do_clear);
@@ -147,6 +150,7 @@ static void con_flush_chars(struct tty_struct *tty);
static void set_vesa_blanking(unsigned long arg);
static void set_cursor(int currcons);
static void hide_cursor(int currcons);
+static void unblank_screen_t(unsigned long dummy);
static int printable = 0; /* Is console ready for printing? */
@@ -196,6 +200,8 @@ static int scrollback_delta = 0;
*/
int (*console_blank_hook)(int) = NULL;
+static struct timer_list console_timer;
+
/*
* Low-Level Functions
*/
@@ -2417,11 +2423,10 @@ void __init con_init(void)
if (tty_register_driver(&console_driver))
panic("Couldn't register console driver\n");
- timer_table[BLANK_TIMER].fn = blank_screen;
- timer_table[BLANK_TIMER].expires = 0;
+ init_timer(&console_timer);
+ console_timer.function = blank_screen;
if (blankinterval) {
- timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
- timer_active |= 1<<BLANK_TIMER;
+ mod_timer(&console_timer, jiffies + blankinterval);
}
/*
@@ -2589,15 +2594,14 @@ static void vesa_powerdown(void)
}
}
-static void vesa_powerdown_screen(void)
+static void vesa_powerdown_screen(unsigned long dummy)
{
- timer_active &= ~(1<<BLANK_TIMER);
- timer_table[BLANK_TIMER].fn = unblank_screen;
+ console_timer.function = unblank_screen_t; /* I don't have a clue why this is necessary */
vesa_powerdown();
}
-void do_blank_screen(int entering_gfx)
+static void timer_do_blank_screen(int entering_gfx, int from_timer_handler)
{
int currcons = fg_console;
int i;
@@ -2622,13 +2626,15 @@ void do_blank_screen(int entering_gfx)
}
hide_cursor(currcons);
+ if (!from_timer_handler)
+ del_timer_sync(&console_timer);
if (vesa_off_interval) {
- timer_table[BLANK_TIMER].fn = vesa_powerdown_screen;
- timer_table[BLANK_TIMER].expires = jiffies + vesa_off_interval;
- timer_active |= (1<<BLANK_TIMER);
+ console_timer.function = vesa_powerdown_screen;
+ mod_timer(&console_timer, jiffies + vesa_off_interval);
} else {
- timer_active &= ~(1<<BLANK_TIMER);
- timer_table[BLANK_TIMER].fn = unblank_screen;
+ if (!from_timer_handler)
+ del_timer_sync(&console_timer);
+ console_timer.function = unblank_screen_t;
}
save_screen(currcons);
@@ -2644,6 +2650,16 @@ void do_blank_screen(int entering_gfx)
sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1);
}
+void do_blank_screen(int entering_gfx)
+{
+ timer_do_blank_screen(entering_gfx, 0);
+}
+
+static void unblank_screen_t(unsigned long dummy)
+{
+ unblank_screen();
+}
+
void unblank_screen(void)
{
int currcons;
@@ -2655,10 +2671,9 @@ void unblank_screen(void)
printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
return;
}
- timer_table[BLANK_TIMER].fn = blank_screen;
+ console_timer.function = blank_screen;
if (blankinterval) {
- timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
- timer_active |= 1<<BLANK_TIMER;
+ mod_timer(&console_timer, jiffies + blankinterval);
}
currcons = fg_console;
@@ -2671,23 +2686,21 @@ void unblank_screen(void)
set_cursor(fg_console);
}
-static void blank_screen(void)
+static void blank_screen(unsigned long dummy)
{
- do_blank_screen(0);
+ timer_do_blank_screen(0, 1);
}
void poke_blanked_console(void)
{
- timer_active &= ~(1<<BLANK_TIMER);
+ del_timer(&console_timer); /* Can't use _sync here: called from tasklet */
if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
return;
if (console_blanked) {
- timer_table[BLANK_TIMER].fn = unblank_screen;
- timer_table[BLANK_TIMER].expires = jiffies; /* Now */
- timer_active |= 1<<BLANK_TIMER;
+ console_timer.function = unblank_screen_t;
+ mod_timer(&console_timer, jiffies); /* Now */
} else if (blankinterval) {
- timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
- timer_active |= 1<<BLANK_TIMER;
+ mod_timer(&console_timer, jiffies + blankinterval);
}
}
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 13656af4b..2ba24a26b 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -127,6 +127,8 @@ static struct channel digi_channels[MAX_ALLOC];
-------------------------------------------------------------------------- */
static struct channel *card_ptr[MAXCARDS];
+static struct timer_list epca_timer;
+
/* ---------------------- Begin function prototypes --------------------- */
/* ----------------------------------------------------------------------
@@ -1564,12 +1566,11 @@ void cleanup_module()
struct channel *ch;
unsigned long flags;
+ del_timer_sync(&epca_timer);
save_flags(flags);
cli();
- timer_table[DIGI_TIMER].fn = 0;
-
if ((tty_unregister_driver(&pc_driver)) ||
(tty_unregister_driver(&pc_callout)))
{
@@ -1918,12 +1919,12 @@ int __init pc_init(void)
Start up the poller to check for events on all enabled boards
---------------------------------------------------------------------- */
- timer_table[DIGI_TIMER].fn = (void *)epcapoll;
- timer_table[DIGI_TIMER].expires = 0;
+ init_timer(&epca_timer);
+ epca_timer.function = epcapoll;
+ mod_timer(&epca_timer, jiffies + HZ/25);
restore_flags(flags);
- timer_active |= 1 << DIGI_TIMER;
return 0;
} /* End pc_init */
@@ -2267,12 +2268,9 @@ static void epcapoll(unsigned long ignored)
} /* End for each card */
- timer_table[DIGI_TIMER].fn = (void *)epcapoll;
- timer_table[DIGI_TIMER].expires = jiffies + (HZ / 25);
- timer_active |= 1 << DIGI_TIMER;
+ mod_timer(&epca_timer, jiffies + (HZ / 25));
restore_flags(flags);
-
} /* End epcapoll */
/* --------------------- Begin doevent ------------------------ */
diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c
index e6cb87d1e..fd81f24ca 100644
--- a/drivers/char/ftape/zftape/zftape-init.c
+++ b/drivers/char/ftape/zftape/zftape-init.c
@@ -521,17 +521,17 @@ void cleanup_module(void)
}
for (i = 0; i < 4; i++) {
sprintf(devname, "qft%i", i);
- devfs_unregister(devfs_find_handle(NULL, devname, 0, QIC117_TAPE_MAJOR, i, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i, DEVFS_SPECIAL_CHR, 0));
sprintf(devname, "nqft%i", i);
- devfs_unregister(devfs_find_handle(NULL, devname, 0, QIC117_TAPE_MAJOR, i + 4, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i + 4, DEVFS_SPECIAL_CHR, 0));
sprintf(devname, "zqft%i", i);
- devfs_unregister(devfs_find_handle(NULL, devname, 0, QIC117_TAPE_MAJOR, i + 16, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i + 16, DEVFS_SPECIAL_CHR, 0));
sprintf(devname, "nzqft%i", i);
- devfs_unregister(devfs_find_handle(NULL, devname, 0, QIC117_TAPE_MAJOR, i + 20, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i + 20, DEVFS_SPECIAL_CHR, 0));
sprintf(devname, "rawqft%i", i);
- devfs_unregister(devfs_find_handle(NULL, devname, 0, QIC117_TAPE_MAJOR, i + 32, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i + 32, DEVFS_SPECIAL_CHR, 0));
sprintf(devname, "nrawqft%i", i);
- devfs_unregister(devfs_find_handle(NULL, devname, 0, QIC117_TAPE_MAJOR, i + 36, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i + 36, DEVFS_SPECIAL_CHR, 0));
}
zft_uninit_mem(); /* release remaining memory, if any */
printk(KERN_INFO "zftape successfully unloaded.\n");
diff --git a/drivers/char/ip2/i2ellis.c b/drivers/char/ip2/i2ellis.c
index c45509bcd..95af0a0f1 100644
--- a/drivers/char/ip2/i2ellis.c
+++ b/drivers/char/ip2/i2ellis.c
@@ -57,7 +57,7 @@ static int iiDelayed = 0; // Set when the iiResetDelay function is
// called. Cleared when ANY board is reset.
static struct timer_list * pDelayTimer; // Used by iiDelayTimer
static wait_queue_head_t pDelayWait; // Used by iiDelayTimer
-static spinlock_t Dl_spinlock;
+static rwlock_t Dl_spinlock;
//********
//* Code *
diff --git a/drivers/char/ip2/i2ellis.h b/drivers/char/ip2/i2ellis.h
index 5bbc4cca2..e249665c1 100644
--- a/drivers/char/ip2/i2ellis.h
+++ b/drivers/char/ip2/i2ellis.h
@@ -352,7 +352,7 @@ typedef struct _i2eBordStr
// Ring-buffers of channel structures whose channels have particular needs.
- spinlock_t Fbuf_spinlock;
+ rwlock_t Fbuf_spinlock;
volatile
unsigned short i2Fbuf_strip; // Strip index
volatile
@@ -360,7 +360,7 @@ typedef struct _i2eBordStr
void *i2Fbuf[CH_QUEUE_SIZE]; // An array of channel pointers
// of channels who need to send
// flow control packets.
- spinlock_t Dbuf_spinlock;
+ rwlock_t Dbuf_spinlock;
volatile
unsigned short i2Dbuf_strip; // Strip index
volatile
@@ -368,7 +368,7 @@ typedef struct _i2eBordStr
void *i2Dbuf[CH_QUEUE_SIZE]; // An array of channel pointers
// of channels who need to send
// data or in-line command packets.
- spinlock_t Bbuf_spinlock;
+ rwlock_t Bbuf_spinlock;
volatile
unsigned short i2Bbuf_strip; // Strip index
volatile
@@ -397,8 +397,8 @@ typedef struct _i2eBordStr
unsigned long debugInlineCount;
unsigned long debugBypassCount;
- spinlock_t read_fifo_spinlock;
- spinlock_t write_fifo_spinlock;
+ rwlock_t read_fifo_spinlock;
+ rwlock_t write_fifo_spinlock;
#ifdef CONFIG_DEVFS_FS
/* Device handles into devfs */
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
index 5fc1fe7a6..310044ab8 100644
--- a/drivers/char/ip2/i2lib.c
+++ b/drivers/char/ip2/i2lib.c
@@ -529,7 +529,7 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands,
unsigned short channel;
int cnt;
unsigned long flags = 0;
- spinlock_t *lock_var_p = NULL;
+ rwlock_t *lock_var_p = NULL;
// Make sure the channel exists, otherwise do nothing
if ( !i2Validate ( pCh ) ) {
diff --git a/drivers/char/ip2/i2lib.h b/drivers/char/ip2/i2lib.h
index ba5646f06..8e3f707d3 100644
--- a/drivers/char/ip2/i2lib.h
+++ b/drivers/char/ip2/i2lib.h
@@ -228,10 +228,10 @@ typedef struct _i2ChanStr
struct tq_struct tqueue_status;
struct tq_struct tqueue_hangup;
- spinlock_t Ibuf_spinlock;
- spinlock_t Obuf_spinlock;
- spinlock_t Cbuf_spinlock;
- spinlock_t Pbuf_spinlock;
+ rwlock_t Ibuf_spinlock;
+ rwlock_t Obuf_spinlock;
+ rwlock_t Cbuf_spinlock;
+ rwlock_t Pbuf_spinlock;
} i2ChanStr, *i2ChanStrPtr;
diff --git a/drivers/char/ip2/i2os.h b/drivers/char/ip2/i2os.h
index f85822c1a..8466d7747 100644
--- a/drivers/char/ip2/i2os.h
+++ b/drivers/char/ip2/i2os.h
@@ -27,6 +27,7 @@
#include "ip2types.h"
#include <asm/io.h> /* For inb, etc */
+#include <linux/version.h>
//------------------------------------
// Defines for I/O instructions:
@@ -61,7 +62,7 @@ typedef int spinlock_t;
//#define SAVE_AND_DISABLE_INTS(a,b) spin_lock_irqsave(a,b)
//#define RESTORE_INTS(a,b) spin_unlock_irqrestore(a,b)
-#define LOCK_INIT(a) spin_lock_init(a)
+#define LOCK_INIT(a) rwlock_init(a)
#define SAVE_AND_DISABLE_INTS(a,b) { \
/* printk("get_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c
index a645832c4..449bd2f76 100644
--- a/drivers/char/ip2main.c
+++ b/drivers/char/ip2main.c
@@ -329,7 +329,7 @@ static long bh_counter = 0;
* selected, the board is serviced periodically to see if anything needs doing.
*/
#define POLL_TIMEOUT (jiffies + 1)
-static struct timer_list PollTimer = { NULL, NULL, 0, 0, ip2_poll };
+static struct timer_list PollTimer = { {NULL, NULL}, 0, 0, ip2_poll };
// next, prev, expires,data, func()
static char TimerOn = 0;
@@ -862,7 +862,7 @@ old_ip2_init(void)
*/
#ifdef CONFIG_DEVFS_FS
if (!devfs_handle)
- devfs_handle = devfs_mk_dir (NULL, "ip2", 3, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "ip2", NULL);
#endif
for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
@@ -2568,10 +2568,10 @@ set_serial_info( i2ChanStrPtr pCh, struct serial_struct *new_info )
* base. Also line nunber as such is meaningless but we use it for our
* array index so it is fixed also.
*/
- if ( ns.irq != ip2config.irq
- || (int) ns.port != ((int) pCh->pMyBord->i2eBase)
- || ns.baud_base != pCh->BaudBase
- || ns.line != pCh->port_index ) {
+ if ( (ns.irq != ip2config.irq[pCh->port_index])
+ || ((int) ns.port != ((int) (pCh->pMyBord->i2eBase)))
+ || (ns.baud_base != pCh->BaudBase)
+ || (ns.line != pCh->port_index) ) {
return -EINVAL;
}
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 81421c032..bee522007 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -5307,7 +5307,7 @@ int __init stli_init(void)
if (devfs_register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stli_fsiomem))
printk("STALLION: failed to register serial memory device\n");
- devfs_handle = devfs_mk_dir (NULL, "staliomem", 9, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "staliomem", NULL);
devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
STL_SIOMEMMAJOR, 0,
S_IFCHR | S_IRUSR | S_IWUSR,
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index bbbcad9a7..5e212af34 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -771,7 +771,7 @@ int __init lp_init (void)
return -EIO;
}
- devfs_handle = devfs_mk_dir (NULL, "printers", 0, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "printers", NULL);
if (parport_register_driver (&lp_driver)) {
printk ("lp: unable to register with parport\n");
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index c26a58eea..274f3a726 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -135,8 +135,11 @@ static int misc_open(struct inode * inode, struct file * file)
old_fops = file->f_op;
file->f_op = fops_get(c->fops);
- if (file->f_op && file->f_op->open)
- err=file->f_op->open(inode,file);
+ if (file->f_op) {
+ err = 0;
+ if (file->f_op->open)
+ err=file->f_op->open(inode,file);
+ }
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);
@@ -191,7 +194,7 @@ int misc_register(struct miscdevice * misc)
if (misc->minor < DYNAMIC_MINORS)
misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
if (!devfs_handle)
- devfs_handle = devfs_mk_dir (NULL, "misc", 4, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "misc", NULL);
misc->devfs_handle =
devfs_register (devfs_handle, misc->name, DEVFS_FL_NONE,
MISC_MAJOR, misc->minor,
diff --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c
index d6fa8314b..dce40c671 100644
--- a/drivers/char/msp3400.c
+++ b/drivers/char/msp3400.c
@@ -85,7 +85,9 @@ static int amsound = 0; /* hard-wire AM sound at 6.5 Hz (france),
the autoscan seems work well only with FM... */
static int simple = -1; /* use short programming (>= msp3410 only) */
static int dolby = 0;
+#ifdef REGISTER_MIXER
static int mixer = -1;
+#endif
struct msp3400c {
int simple;
diff --git a/drivers/char/nwbutton.h b/drivers/char/nwbutton.h
index ba5067443..5f5c8ddd0 100644
--- a/drivers/char/nwbutton.h
+++ b/drivers/char/nwbutton.h
@@ -28,8 +28,6 @@ static void button_sequence_finished (unsigned long parameters);
static void button_handler (int irq, void *dev_id, struct pt_regs *regs);
static int button_read (struct file *filp, char *buffer,
size_t count, loff_t *ppos);
-static int button_open (struct inode *inode, struct file *filp);
-static int button_release (struct inode *inode, struct file *filp);
int button_init (void);
int button_add_callback (void (*callback) (void), int count);
int button_del_callback (void (*callback) (void));
diff --git a/drivers/char/pcxx.c b/drivers/char/pcxx.c
index 2e451ce17..757af9c14 100644
--- a/drivers/char/pcxx.c
+++ b/drivers/char/pcxx.c
@@ -151,9 +151,11 @@ struct tty_driver pcxe_driver;
struct tty_driver pcxe_callout;
static int pcxe_refcount;
+static struct timer_list pcxx_timer;
+
DECLARE_TASK_QUEUE(tq_pcxx);
-static void pcxxpoll(void);
+static void pcxxpoll(unsigned long dummy);
static void pcxxdelay(int);
static void fepcmd(struct channel *, int, int, int, int, int);
static void pcxe_put_char(struct tty_struct *, unsigned char);
@@ -216,9 +218,7 @@ void cleanup_module()
save_flags(flags);
cli();
- timer_active &= ~(1 << DIGI_TIMER);
- timer_table[DIGI_TIMER].fn = NULL;
- timer_table[DIGI_TIMER].expires = 0;
+ del_timer_sync(&pcxx_timer);
remove_bh(DIGI_BH);
if ((e1 = tty_unregister_driver(&pcxe_driver)))
@@ -1199,8 +1199,8 @@ int __init pcxe_init(void)
init_bh(DIGI_BH,do_pcxe_bh);
- timer_table[DIGI_TIMER].fn = pcxxpoll;
- timer_table[DIGI_TIMER].expires = 0;
+ init_timer(&pcxx_timer);
+ pcxx_timer.function = pcxxpoll;
memset(&pcxe_driver, 0, sizeof(struct tty_driver));
pcxe_driver.magic = TTY_DRIVER_MAGIC;
@@ -1620,7 +1620,7 @@ load_fep:
/*
* Start up the poller to check for events on all enabled boards
*/
- timer_active |= 1 << DIGI_TIMER;
+ mod_timer(&pcxx_timer, HZ/25);
if (verbose)
printk(KERN_NOTICE "PC/Xx: Driver with %d card(s) ready.\n", enabled_cards);
@@ -1629,7 +1629,7 @@ load_fep:
}
-static void pcxxpoll(void)
+static void pcxxpoll(unsigned long dummy)
{
unsigned long flags;
int crd;
@@ -1660,9 +1660,7 @@ static void pcxxpoll(void)
memoff(ch);
}
- timer_table[DIGI_TIMER].fn = pcxxpoll;
- timer_table[DIGI_TIMER].expires = jiffies + HZ/25;
- timer_active |= 1 << DIGI_TIMER;
+ mod_timer(&pcxx_timer, jiffies + HZ/25);
restore_flags(flags);
}
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index ae4b9e112..4e2be3c8b 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -105,9 +105,9 @@ static void pp_attach (struct parport *port)
return;
}
- add->next = pp_port_list;
add->port = port;
down (&pp_port_list_lock);
+ add->next = pp_port_list;
pp_port_list = add;
up (&pp_port_list_lock);
}
@@ -663,7 +663,7 @@ static int __init ppdev_init (void)
PP_MAJOR);
return -EIO;
}
- devfs_handle = devfs_mk_dir (NULL, "parports", 0, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "parports", NULL);
devfs_register_series (devfs_handle, "%u", PARPORT_MAX,
DEVFS_FL_DEFAULT, PP_MAJOR, 0,
S_IFCHR | S_IRUGO | S_IWUGO,
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index da6da97d7..4d11a2448 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -429,7 +429,7 @@ int __init pty_init(void)
/* Unix98 devices */
#ifdef CONFIG_UNIX98_PTYS
- devfs_mk_dir (NULL, "pts", 3, NULL);
+ devfs_mk_dir (NULL, "pts", NULL);
printk("pty: %d Unix98 ptys configured\n", UNIX98_NR_MAJORS*NR_PTYS);
for ( i = 0 ; i < UNIX98_NR_MAJORS ; i++ ) {
int j;
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 943ea6a61..af94b4b3f 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -138,13 +138,6 @@
#define _INLINE_ inline
-/*
- * Until we get a formal timer assignment
- */
-#ifndef COMTROL_TIMER
-#define COMTROL_TIMER 26
-#endif
-
#ifndef NEW_MODULES
/*
* NB. we must include the kernel idenfication string in to install the module.
@@ -165,6 +158,8 @@ static int rocket_refcount = 0;
static int rp_num_ports_open = 0;
+static struct timer_list rocket_timer;
+
unsigned long board1 = 0;
unsigned long board2 = 0;
unsigned long board3 = 0;
@@ -504,7 +499,7 @@ static _INLINE_ void rp_handle_port(struct r_port *info)
/*
* The top level polling routine.
*/
-static void rp_do_poll(void)
+static void rp_do_poll(unsigned long dummy)
{
CONTROLLER_t *ctlp;
int ctrl, aiop, ch, line;
@@ -556,7 +551,7 @@ static void rp_do_poll(void)
* Reset the timer so we get called at the next clock tick.
*/
if (rp_num_ports_open) {
- timer_active |= 1 << COMTROL_TIMER;
+ mod_timer(&rocket_timer, jiffies + 1);
}
#ifdef TIME_STAT
__asm__(".byte 0x0f,0x31"
@@ -1044,7 +1039,7 @@ static int rp_open(struct tty_struct *tty, struct file * filp)
sSetRTS(cp);
}
- timer_active |= 1 << COMTROL_TIMER;
+ mod_timer(&rocket_timer, jiffies + 1);
retval = block_til_ready(tty, filp, info);
if (retval) {
@@ -2145,13 +2140,12 @@ int __init rp_init(void)
* Set up the timer channel. If it is already in use by
* some other driver, give up.
*/
- if (timer_table[COMTROL_TIMER].fn) {
- printk("rocket.o: Timer channel %d already in use!\n",
- COMTROL_TIMER);
+ if (rocket_timer.function) {
+ printk("rocket.o: Timer already in use!\n");
return -EBUSY;
}
- timer_table[COMTROL_TIMER].fn = rp_do_poll;
- timer_table[COMTROL_TIMER].expires = 0;
+ init_timer(&rocket_timer);
+ rocket_timer.function = rp_do_poll;
/*
* Initialize the array of pointers to our own internal state
@@ -2208,7 +2202,7 @@ int __init rp_init(void)
if (max_board == 0) {
printk("No rocketport ports found; unloading driver.\n");
- timer_table[COMTROL_TIMER].fn = 0;
+ rocket_timer.function = 0;
return -ENODEV;
}
@@ -2300,7 +2294,9 @@ cleanup_module( void) {
int retval;
int i;
int released_controller = 0;
-
+
+ del_timer_sync(&rocket_timer);
+
retval = tty_unregister_driver(&callout_driver);
if (retval) {
printk("Error %d while trying to unregister "
@@ -2328,7 +2324,7 @@ cleanup_module( void) {
}
if (tmp_buf)
free_page((unsigned long) tmp_buf);
- timer_table[COMTROL_TIMER].fn = 0;
+ rocket_timer.function = 0;
}
#endif
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index 82d1bf131..fbbc8271c 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -46,6 +46,9 @@
* 5/00: Support for the RSA-DV II/S card added.
* Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
*
+ * 6/00: Remove old-style timer, use timer_list
+ * Andrew Morton <andrewm@uow.edu.au>
+ *
* This module exports the following rs232 io functions:
*
* int rs_init(void);
@@ -232,6 +235,8 @@ static DECLARE_TASK_QUEUE(tq_serial);
static struct tty_driver serial_driver, callout_driver;
static int serial_refcount;
+static struct timer_list serial_timer;
+
/* serial subtype definitions */
#ifndef SERIAL_TYPE_NORMAL
#define SERIAL_TYPE_NORMAL 1
@@ -304,11 +309,10 @@ static struct serial_state rs_table[RS_TABLE_SIZE] = {
#if (defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP))
#define NR_PCI_BOARDS 8
-#ifdef MODULE
/* We don't unregister PCI boards right now */
static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS];
static int serial_pci_board_idx = 0;
-#endif
+
#ifndef IS_PCI_REGION_IOPORT
#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \
IORESOURCE_IO)
@@ -1023,7 +1027,7 @@ static void do_softint(void *private_)
* passable results for a 16550A. (Although at the expense of much
* CPU overhead).
*/
-static void rs_timer(void)
+static void rs_timer(unsigned long dummy)
{
static unsigned long last_strobe = 0;
struct async_struct *info;
@@ -1057,8 +1061,7 @@ static void rs_timer(void)
}
}
last_strobe = jiffies;
- timer_table[RS_TIMER].expires = jiffies + RS_STROBE_TIME;
- timer_active |= 1 << RS_TIMER;
+ mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);
if (IRQ_ports[0]) {
save_flags(flags); cli();
@@ -1069,7 +1072,7 @@ static void rs_timer(void)
#endif
restore_flags(flags);
- timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0] - 2;
+ mod_timer(&serial_timer, jiffies + IRQ_timeout[0] - 2);
}
}
@@ -1380,8 +1383,7 @@ static int startup(struct async_struct * info)
/*
* Set up serial timers...
*/
- timer_table[RS_TIMER].expires = jiffies + 2*HZ/100;
- timer_active |= 1 << RS_TIMER;
+ mod_timer(&serial_timer, jiffies + 2*HZ/100);
/*
* Set up the tty->alt_speed kludge
@@ -4980,12 +4982,12 @@ static void __init probe_serial_pnp(void)
/*
* The serial driver boot-time initialization code!
*/
-int __init rs_init(void)
+static int __init rs_init(void)
{
int i;
struct serial_state * state;
- if (timer_table[RS_TIMER].fn) {
+ if (serial_timer.function) {
printk("RS_TIMER already set, another serial driver "
"already loaded?\n");
#ifdef MODULE
@@ -4996,8 +4998,9 @@ int __init rs_init(void)
}
init_bh(SERIAL_BH, do_serial_bh);
- timer_table[RS_TIMER].fn = rs_timer;
- timer_table[RS_TIMER].expires = 0;
+ init_timer(&serial_timer);
+ serial_timer.function = rs_timer;
+ mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);
for (i = 0; i < NR_IRQS; i++) {
IRQ_ports[i] = 0;
@@ -5268,8 +5271,7 @@ void unregister_serial(int line)
restore_flags(flags);
}
-#ifdef MODULE
-void rs_fini(void)
+static void __exit rs_fini(void)
{
unsigned long flags;
int e1, e2;
@@ -5277,10 +5279,8 @@ void rs_fini(void)
struct async_struct *info;
/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
+ del_timer_sync(&serial_timer);
save_flags(flags); cli();
- timer_active &= ~(1 << RS_TIMER);
- timer_table[RS_TIMER].fn = NULL;
- timer_table[RS_TIMER].expires = 0;
remove_bh(SERIAL_BH);
if ((e1 = tty_unregister_driver(&serial_driver)))
printk("serial: failed to unregister serial driver (%d)\n",
@@ -5326,7 +5326,6 @@ void rs_fini(void)
free_page(pg);
}
}
-#endif /* MODULE */
module_init(rs_init);
module_exit(rs_fini);
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 0776b5d6b..eab300d5f 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -2338,7 +2338,6 @@ int specialix_init(void)
#ifdef CONFIG_PCI
if (pci_present()) {
struct pci_dev *pdev = NULL;
- unsigned int tint;
i=0;
while (i <= SX_NBOARD) {
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 235b0f131..9600c1bad 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -3191,7 +3191,7 @@ int __init stl_init(void)
*/
if (devfs_register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem))
printk("STALLION: failed to register serial board device\n");
- devfs_handle = devfs_mk_dir (NULL, "staliomem", 9, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "staliomem", NULL);
devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
STL_SIOMEMMAJOR, 0,
S_IFCHR | S_IRUSR | S_IWUSR,
diff --git a/drivers/char/stradis.c b/drivers/char/stradis.c
index 949aa9532..03ca27a25 100644
--- a/drivers/char/stradis.c
+++ b/drivers/char/stradis.c
@@ -343,6 +343,7 @@ static u32 debiread(struct saa7146 *saa, u32 config, int addr, int count)
return result;
}
+#if 0 /* unused */
/* MUST be a multiple of 8 bytes and 8-byte aligned and < 32768 bytes */
/* data copied into saa->dmadebi buffer, caller must re-enable interrupts */
static void ibm_block_dram_read(struct saa7146 *saa, int address, int bytes)
@@ -375,6 +376,7 @@ static void ibm_block_dram_read(struct saa7146 *saa, int address, int bytes)
buf[j] = debiread(saa, debNormal, IBM_MP2_DRAM_DATA, 4);
}
}
+#endif /* unused */
static void do_irq_send_data(struct saa7146 *saa)
{
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 8eb55b500..665514727 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -373,7 +373,7 @@ struct mgsl_struct {
/*
* The size of the serial xmit buffer is 1 page, or 4096 bytes
*/
-#define SERIAL_XMIT_SIZE 4096
+/* #define SERIAL_XMIT_SIZE 4096 */ /* defined in include/linux/serial.h */
/*
@@ -7428,7 +7428,6 @@ BOOLEAN mgsl_memory_test( struct mgsl_struct *info )
} /* End Of mgsl_memory_test() */
-#pragma optimize( "", off )
/* mgsl_load_pci_memory()
*
* Load a large block of data into the PCI shared memory.
@@ -7483,7 +7482,7 @@ void mgsl_load_pci_memory( char* TargetPtr, const char* SourcePtr,
for ( Index = 0 ; Index < Intervalcount ; Index++ )
{
memcpy(TargetPtr, SourcePtr, PCI_LOAD_INTERVAL);
- Dummy = *((unsigned long *)TargetPtr);
+ Dummy = *((volatile unsigned long *)TargetPtr);
TargetPtr += PCI_LOAD_INTERVAL;
SourcePtr += PCI_LOAD_INTERVAL;
}
@@ -7491,7 +7490,6 @@ void mgsl_load_pci_memory( char* TargetPtr, const char* SourcePtr,
memcpy( TargetPtr, SourcePtr, count % PCI_LOAD_INTERVAL );
} /* End Of mgsl_load_pci_memory() */
-#pragma optimize( "", on )
void mgsl_trace_block(struct mgsl_struct *info,const char* data, int count, int xmit)
{
diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
index 09b502a72..3ca976b6e 100644
--- a/drivers/char/tpqic02.c
+++ b/drivers/char/tpqic02.c
@@ -166,6 +166,7 @@ static flag need_rewind = YES;
static kdev_t current_tape_dev;
static int extra_blocks_left = BLOCKS_BEYOND_EW;
+static struct timer_list tp_timer;
/* return_*_eof:
* NO: not at EOF,
@@ -1595,7 +1596,7 @@ static void end_dma(unsigned long * bytes_done)
* has decided to do a long rewind, just when I didn't expect it.
* Just try again.
*/
-static void qic02_tape_times_out(void)
+static void qic02_tape_times_out(unsigned long dummy)
{
printk("time-out in %s driver\n", TPQIC02_NAME);
if ((status_cmd_pending>0) || dma_mode) {
@@ -1720,7 +1721,7 @@ static void qic02_tape_interrupt(int irq, void *dev_id, struct pt_regs *regs)
wake_up(&qic02_tape_transfer);
} else {
/* start next transfer, account for track-switching time */
- timer_table[QIC02_TAPE_TIMER].expires = jiffies + 6*HZ;
+ mod_timer(&tp_timer, jiffies + 6*HZ);
dma_transfer();
}
} else {
@@ -2940,8 +2941,8 @@ int __init qic02_tape_init(void)
init_waitqueue_head(&qic02_tape_transfer);
/* prepare timer */
TIMEROFF;
- timer_table[QIC02_TAPE_TIMER].expires = 0;
- timer_table[QIC02_TAPE_TIMER].fn = qic02_tape_times_out;
+ init_timer(&tp_timer);
+ tp_timer.function = qic02_tape_times_out;
#ifndef CONFIG_QIC02_DYNCONF
if (tape_reset(0)!=TE_OK || tp_sense(TP_WRP|TP_POR|TP_CNI)!=TE_OK)
@@ -2984,14 +2985,14 @@ void cleanup_module(void)
qic02_release_resources();
}
devfs_unregister_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME);
- devfs_unregister(devfs_find_handle(NULL, "ntpqic11", 0, QIC02_TAPE_MAJOR, 2, DEVFS_SPECIAL_CHR, 0));
- devfs_unregister(devfs_find_handle(NULL, "tpqic11", 0, QIC02_TAPE_MAJOR, 3, DEVFS_SPECIAL_CHR, 0));
- devfs_unregister(devfs_find_handle(NULL, "ntpqic24", 0, QIC02_TAPE_MAJOR, 4, DEVFS_SPECIAL_CHR, 0));
- devfs_unregister(devfs_find_handle(NULL, "tpqic24", 0, QIC02_TAPE_MAJOR, 5, DEVFS_SPECIAL_CHR, 0));
- devfs_unregister(devfs_find_handle(NULL, "ntpqic120", 0, QIC02_TAPE_MAJOR, 6, DEVFS_SPECIAL_CHR, 0));
- devfs_unregister(devfs_find_handle(NULL, "tpqic120", 0, QIC02_TAPE_MAJOR, 7, DEVFS_SPECIAL_CHR, 0));
- devfs_unregister(devfs_find_handle(NULL, "ntpqic150", 0, QIC02_TAPE_MAJOR, 8, DEVFS_SPECIAL_CHR, 0));
- devfs_unregister(devfs_find_handle(NULL, "tpqic150", 0, QIC02_TAPE_MAJOR, 9, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, "ntpqic11", QIC02_TAPE_MAJOR, 2, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, "tpqic11", QIC02_TAPE_MAJOR, 3, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, "ntpqic24", QIC02_TAPE_MAJOR, 4, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, "tpqic24", QIC02_TAPE_MAJOR, 5, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, "ntpqic120", QIC02_TAPE_MAJOR, 6, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, "tpqic120", QIC02_TAPE_MAJOR, 7, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, "ntpqic150", QIC02_TAPE_MAJOR, 8, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, "tpqic150", QIC02_TAPE_MAJOR, 9, DEVFS_SPECIAL_CHR, 0));
}
int init_module(void)
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 4c0d29662..60a5c41f5 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -102,6 +102,7 @@
#ifdef CONFIG_VT
extern void con_init_devfs (void);
#endif
+extern int rio_init(void);
#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
#define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
@@ -2029,7 +2030,7 @@ void tty_unregister_devfs (struct tty_driver *driver, unsigned minor)
tty.driver = *driver;
tty.device = MKDEV(driver->major, minor);
- handle = devfs_find_handle (NULL, tty_name (&tty, buf), 0,
+ handle = devfs_find_handle (NULL, tty_name (&tty, buf),
driver->major, minor,
DEVFS_SPECIAL_CHR, 0);
devfs_unregister (handle);
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index 67ff8d856..920873d9e 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -469,9 +469,9 @@ void vcs_make_devfs (unsigned int index, int unregister)
sprintf (name, "a%u", index + 1);
if (unregister)
{
- devfs_unregister ( devfs_find_handle (devfs_handle, name + 1, 0, 0, 0,
+ devfs_unregister ( devfs_find_handle (devfs_handle, name + 1, 0, 0,
DEVFS_SPECIAL_CHR, 0) );
- devfs_unregister ( devfs_find_handle (devfs_handle, name, 0, 0, 0,
+ devfs_unregister ( devfs_find_handle (devfs_handle, name, 0, 0,
DEVFS_SPECIAL_CHR, 0) );
}
else
@@ -495,7 +495,7 @@ int __init vcs_init(void)
if (error)
printk("unable to get major %d for vcs device", VCS_MAJOR);
- devfs_handle = devfs_mk_dir (NULL, "vcc", 3, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "vcc", NULL);
devfs_register (devfs_handle, "0", DEVFS_FL_DEFAULT,
VCS_MAJOR, 0,
S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL);
diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c
index 4a3bfb859..5103433e1 100644
--- a/drivers/char/videodev.c
+++ b/drivers/char/videodev.c
@@ -330,6 +330,8 @@ static void videodev_proc_create(void)
video_dev_proc_entry->owner = THIS_MODULE;
}
+#ifdef MODULE
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
static void videodev_proc_destroy(void)
{
if (video_dev_proc_entry != NULL)
@@ -338,6 +340,8 @@ static void videodev_proc_destroy(void)
if (video_proc_entry != NULL)
remove_proc_entry("video", &proc_root);
}
+#endif
+#endif
static void videodev_proc_create_dev (struct video_device *vfd, char *name)
{
diff --git a/drivers/char/zr36120.c b/drivers/char/zr36120.c
index a46c3d056..6e860021e 100644
--- a/drivers/char/zr36120.c
+++ b/drivers/char/zr36120.c
@@ -153,6 +153,7 @@ void __init handle_chipset(void)
static void zoran_set_geo(struct zoran* ztv, struct vidinfo* i);
+#if 0 /* unused */
static
void zoran_dump(struct zoran *ztv)
{
@@ -169,6 +170,7 @@ void zoran_dump(struct zoran *ztv)
p += sprintf(p, "%08x ",zrread(i));
}
}
+#endif /* unused */
static
void reap_states(struct zoran* ztv)
diff --git a/drivers/i2o/i2o_block.c b/drivers/i2o/i2o_block.c
index 14281f55f..2dc69ae33 100644
--- a/drivers/i2o/i2o_block.c
+++ b/drivers/i2o/i2o_block.c
@@ -1664,6 +1664,7 @@ int i2o_block_init(void)
if(i2o_install_handler(&i2o_block_handler)<0)
{
unregister_blkdev(MAJOR_NR, "i2o_block");
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
printk(KERN_ERR "i2o_block: unable to register OSM.\n");
return -EINVAL;
}
@@ -1730,6 +1731,11 @@ void cleanup_module(void)
if (unregister_blkdev(MAJOR_NR, "i2o_block") != 0)
printk("i2o_block: cleanup_module failed\n");
+ /*
+ * free request queue
+ */
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+
if(evt_running) {
i = kill_proc(evt_pid, SIGTERM, 1);
if(!i) {
diff --git a/drivers/ide/hd.c b/drivers/ide/hd.c
index 6fd109c83..698112b35 100644
--- a/drivers/ide/hd.c
+++ b/drivers/ide/hd.c
@@ -105,6 +105,24 @@ static int hd_sizes[MAX_HD<<6];
static int hd_blocksizes[MAX_HD<<6];
static int hd_hardsectsizes[MAX_HD<<6];
+static struct timer_list device_timer;
+
+#define SET_TIMER \
+ do { \
+ mod_timer(&device_timer, jiffies + TIMEOUT_VALUE); \
+ } while (0)
+
+#define CLEAR_TIMER del_timer(&device_timer);
+
+#undef SET_INTR
+
+#define SET_INTR(x) \
+if ((DEVICE_INTR = (x)) != NULL) \
+ SET_TIMER; \
+else \
+ CLEAR_TIMER;
+
+
#if (HD_DELAY > 0)
unsigned long last_req;
@@ -471,7 +489,7 @@ static void recal_intr(void)
* This is another of the error-routines I don't know what to do with. The
* best idea seems to just set reset, and start all over again.
*/
-static void hd_times_out(void)
+static void hd_times_out(unsigned long dummy)
{
unsigned int dev;
@@ -527,7 +545,7 @@ static void hd_request(void)
if (DEVICE_INTR)
return;
repeat:
- timer_active &= ~(1<<HD_TIMER);
+ del_timer(&device_timer);
sti();
INIT_REQUEST;
if (reset) {
@@ -683,7 +701,7 @@ static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
void (*handler)(void) = DEVICE_INTR;
DEVICE_INTR = NULL;
- timer_active &= ~(1<<HD_TIMER);
+ del_timer(&device_timer);
if (!handler)
handler = unexpected_hd_interrupt;
handler();
@@ -814,7 +832,8 @@ int __init hd_init(void)
read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */
hd_gendisk.next = gendisk_head;
gendisk_head = &hd_gendisk;
- timer_table[HD_TIMER].fn = hd_times_out;
+ init_timer(&device_timer);
+ device_timer.function = hd_times_out;
hd_geninit();
return 0;
}
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 53f6b5a9e..e8e67d549 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -1768,6 +1768,9 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
if (stat)
toc->capacity = 0x1fffff;
+ HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] = (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9);
+ drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
+
/* Remember that we've read this stuff. */
CDROM_STATE_FLAGS (drive)->toc_valid = 1;
@@ -2066,11 +2069,11 @@ int ide_cdrom_get_last_session (struct cdrom_device_info *cdi,
struct request_sense sense;
int ret;
- toc = info->toc;
- if (!CDROM_STATE_FLAGS(drive)->toc_valid || toc == NULL)
+ if (!CDROM_STATE_FLAGS(drive)->toc_valid || info->toc == NULL)
if ((ret = cdrom_read_toc(drive, &sense)))
return ret;
+ toc = info->toc;
ms_info->addr.lba = toc->last_session_lba;
ms_info->xa_flag = toc->xa_flag;
@@ -2614,11 +2617,10 @@ static ide_module_t ide_cdrom_module = {
/* options */
char *ignore = NULL;
-#ifdef MODULE
MODULE_PARM(ignore, "s");
MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
-void __exit ide_cdrom_exit(void)
+static void __exit ide_cdrom_exit(void)
{
ide_drive_t *drive;
int failed = 0;
@@ -2630,7 +2632,6 @@ void __exit ide_cdrom_exit(void)
}
ide_unregister_module (&ide_cdrom_module);
}
-#endif /* MODULE */
int ide_cdrom_init(void)
{
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index dd5f660fe..168895fb5 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -580,6 +580,17 @@ static void save_match (ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
#endif /* MAX_HWIFS > 1 */
/*
+ * init request queue
+ */
+static void ide_init_queue(ide_drive_t *drive)
+{
+ request_queue_t *q = &drive->queue;
+
+ q->queuedata = HWGROUP(drive);
+ blk_init_queue(q, do_ide_request);
+}
+
+/*
* This routine sets up the irq for an ide interface, and creates a new
* hwgroup for the irq/hwif if none was previously assigned.
*
@@ -677,6 +688,7 @@ static int init_irq (ide_hwif_t *hwif)
hwgroup->drive = drive;
drive->next = hwgroup->drive->next;
hwgroup->drive->next = drive;
+ ide_init_queue(drive);
}
if (!hwgroup->hwif) {
hwgroup->hwif = HWIF(hwgroup->drive);
@@ -780,16 +792,13 @@ static void init_gendisk (ide_hwif_t *hwif)
(hwif->channel && hwif->mate) ? hwif->mate->index : hwif->index,
hwif->channel, unit, hwif->drives[unit].lun);
hwif->drives[unit].de =
- devfs_mk_dir (ide_devfs_handle, name, 0, NULL);
+ devfs_mk_dir (ide_devfs_handle, name, NULL);
}
}
}
static int hwif_init (ide_hwif_t *hwif)
{
- request_queue_t *q;
- unsigned int unit;
-
if (!hwif->present)
return 0;
if (!hwif->irq) {
@@ -840,12 +849,6 @@ static int hwif_init (ide_hwif_t *hwif)
read_ahead[hwif->major] = 8; /* (4kB) */
hwif->present = 1; /* success */
- for (unit = 0; unit < MAX_DRIVES; ++unit) {
- q = &hwif->drives[unit].queue;
- q->queuedata = hwif->hwgroup;
- blk_init_queue(q, do_ide_request);
- }
-
#if (DEBUG_SPINLOCK > 0)
{
static int done = 0;
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index b9aa05d4d..c9c3cb120 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -2023,6 +2023,7 @@ void ide_unregister (unsigned int index)
drive->id = NULL;
}
drive->present = 0;
+ blk_cleanup_queue(&drive->queue);
}
if (d->present)
hwgroup->drive = d;
@@ -2048,7 +2049,6 @@ void ide_unregister (unsigned int index)
kfree(blksize_size[hwif->major]);
kfree(max_sectors[hwif->major]);
kfree(max_readahead[hwif->major]);
- blk_cleanup_queue(BLK_DEFAULT_QUEUE(hwif->major));
blk_dev[hwif->major].data = NULL;
blk_dev[hwif->major].queue = NULL;
blksize_size[hwif->major] = NULL;
@@ -3594,7 +3594,7 @@ int __init ide_init (void)
if (!banner_printed) {
printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
- ide_devfs_handle = devfs_mk_dir (NULL, "ide", 3, NULL);
+ ide_devfs_handle = devfs_mk_dir (NULL, "ide", NULL);
system_bus_speed = ide_system_bus_speed();
banner_printed = 1;
}
diff --git a/drivers/ieee1394/Config.in b/drivers/ieee1394/Config.in
index df0e3cfd2..bdb3002d2 100644
--- a/drivers/ieee1394/Config.in
+++ b/drivers/ieee1394/Config.in
@@ -4,18 +4,20 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
mainmenu_option next_comment
comment 'IEEE 1394 (FireWire) support'
- tristate 'IEEE 1394 (FireWire) support (EXPERIMENTAL)' CONFIG_IEEE1394 $CONFIG_PCI
+ dep_tristate 'IEEE 1394 (FireWire) support (EXPERIMENTAL)' CONFIG_IEEE1394 $CONFIG_PCI
if [ "$CONFIG_IEEE1394" != "n" ]; then
dep_tristate 'Texas Instruments PCILynx support' CONFIG_IEEE1394_PCILYNX $CONFIG_IEEE1394
if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then
bool ' Use PCILynx local RAM' CONFIG_IEEE1394_PCILYNX_LOCALRAM
+ bool ' Support for non-IEEE1394 local ports' CONFIG_IEEE1394_PCILYNX_PORTS
fi
dep_tristate 'Adaptec AIC-5800 (AHA-89xx) support' CONFIG_IEEE1394_AIC5800 $CONFIG_IEEE1394
dep_tristate 'OHCI (Open Host Controller Interface) support' CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394
+ dep_tristate 'Video1394 support' CONFIG_IEEE1394_VIDEO1394 $CONFIG_IEEE1394_OHCI1394
dep_tristate 'Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394
diff --git a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile
index c89374f45..cc6b40ee4 100644
--- a/drivers/ieee1394/Makefile
+++ b/drivers/ieee1394/Makefile
@@ -53,13 +53,20 @@ else
endif
ifeq ($(CONFIG_IEEE1394_OHCI1394),y)
-L_OBJS += ohci1394.o
+LX_OBJS += ohci1394.o
else
ifeq ($(CONFIG_IEEE1394_OHCI1394),m)
- M_OBJS += ohci1394.o
+ MX_OBJS += ohci1394.o
endif
endif
+ifeq ($(CONFIG_IEEE1394_VIDEO1394),y)
+L_OBJS += video1394.o
+else
+ ifeq ($(CONFIG_IEEE1394_VIDEO1394),m)
+ M_OBJS += video1394.o
+ endif
+endif
ifeq ($(CONFIG_IEEE1394_RAWIO),y)
L_OBJS += raw1394.o
diff --git a/drivers/ieee1394/aic5800.c b/drivers/ieee1394/aic5800.c
index 6cf3779d5..2748c21b6 100644
--- a/drivers/ieee1394/aic5800.c
+++ b/drivers/ieee1394/aic5800.c
@@ -646,7 +646,7 @@ static void aic_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
phyid = phyid & 0x3F;
handle_selfid(aic, host, phyid, isroot, rcv_bytes);
} else {
- hpsb_packet_received(host, aic->rcv_page, rcv_bytes);
+ hpsb_packet_received(host, aic->rcv_page, rcv_bytes, 0);
};
} else {
PRINT(KERN_ERR, aic->id,
diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c
index a884f2a1c..486ad1ad4 100644
--- a/drivers/ieee1394/csr.c
+++ b/drivers/ieee1394/csr.c
@@ -4,6 +4,9 @@
* CSR implementation, iso/bus manager implementation.
*
* Copyright (C) 1999 Andreas E. Bombe
+ *
+ * This code is licensed under the GPL. See the file COPYING in the root
+ * directory of the kernel sources for details.
*/
#include <linux/string.h>
diff --git a/drivers/ieee1394/guid.c b/drivers/ieee1394/guid.c
index 36ac332c5..1aa453292 100644
--- a/drivers/ieee1394/guid.c
+++ b/drivers/ieee1394/guid.c
@@ -4,6 +4,9 @@
* GUID collection and management
*
* Copyright (C) 2000 Andreas E. Bombe
+ *
+ * This code is licensed under the GPL. See the file COPYING in the root
+ * directory of the kernel sources for details.
*/
#include <linux/kernel.h>
diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c
index 3e20824aa..130a40527 100644
--- a/drivers/ieee1394/highlevel.c
+++ b/drivers/ieee1394/highlevel.c
@@ -2,6 +2,9 @@
* IEEE 1394 for Linux
*
* Copyright (C) 1999 Andreas E. Bombe
+ *
+ * This code is licensed under the GPL. See the file COPYING in the root
+ * directory of the kernel sources for details.
*/
#include <linux/config.h>
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
index 9a9951204..8e0e80da1 100644
--- a/drivers/ieee1394/hosts.c
+++ b/drivers/ieee1394/hosts.c
@@ -5,6 +5,9 @@
*
* Copyright (C) 1999 Andreas E. Bombe
* Copyright (C) 1999 Emanuel Pirker
+ *
+ * This code is licensed under the GPL. See the file COPYING in the root
+ * directory of the kernel sources for details.
*/
#include <linux/config.h>
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index ffcfc7f52..e0641271b 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -5,6 +5,9 @@
* highlevel or lowlevel code
*
* Copyright (C) 1999, 2000 Andreas E. Bombe
+ *
+ * This code is licensed under the GPL. See the file COPYING in the root
+ * directory of the kernel sources for details.
*/
#include <linux/config.h>
@@ -534,7 +537,7 @@ struct hpsb_packet *create_reply_packet(struct hpsb_host *host, quadlet_t *data,
if (packet == NULL) break
void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
- size_t size)
+ size_t size, int write_acked)
{
struct hpsb_packet *packet;
int length, rcode, extcode;
@@ -548,7 +551,8 @@ void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
rcode = highlevel_write(host, source, data+3, addr, 4);
- if (((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
+ if (!write_acked
+ && ((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
/* not a broadcast write, reply */
PREP_REPLY_PACKET(0);
fill_async_write_resp(packet, rcode);
@@ -561,7 +565,8 @@ void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
rcode = highlevel_write(host, source, data+4, addr,
data[3]>>16);
- if (((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
+ if (!write_acked
+ && ((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
/* not a broadcast write, reply */
PREP_REPLY_PACKET(0);
fill_async_write_resp(packet, rcode);
@@ -644,7 +649,8 @@ void handle_incoming_packet(struct hpsb_host *host, int tcode, quadlet_t *data,
#undef PREP_REPLY_PACKET
-void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size)
+void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
+ int write_acked)
{
int tcode;
@@ -672,7 +678,7 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size)
case TCODE_READQ:
case TCODE_READB:
case TCODE_LOCK_REQUEST:
- handle_incoming_packet(host, tcode, data, size);
+ handle_incoming_packet(host, tcode, data, size, write_acked);
break;
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
index 636aef40e..faeeca45d 100644
--- a/drivers/ieee1394/ieee1394_core.h
+++ b/drivers/ieee1394/ieee1394_core.h
@@ -52,8 +52,7 @@ struct hpsb_packet {
* overwritten to allow in-place byte swapping. Neither of these is
* CRCed (the sizes also don't include CRC), but contain space for at
* least one additional quadlet to allow in-place CRCing. The memory is
- * also guaranteed to have physical mapping (virt_to_bus() is meaningful
- * on these pointers).
+ * also guaranteed to be DMA mappable.
*/
quadlet_t *header;
quadlet_t *data;
@@ -145,7 +144,12 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
* immediately), with the header (i.e. the first four quadlets) in machine byte
* order and the data block in big endian. *data can be safely overwritten
* after this call.
+ *
+ * If the packet is a write request, write_acked is to be set to true if it was
+ * ack_complete'd already, false otherwise. This arg is ignored for any other
+ * packet type.
*/
-void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size);
+void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
+ int write_acked);
#endif /* _IEEE1394_CORE_H */
diff --git a/drivers/ieee1394/ieee1394_syms.c b/drivers/ieee1394/ieee1394_syms.c
index c1ebadd10..39a61a01b 100644
--- a/drivers/ieee1394/ieee1394_syms.c
+++ b/drivers/ieee1394/ieee1394_syms.c
@@ -4,6 +4,9 @@
* Exported symbols for module usage.
*
* Copyright (C) 1999 Andreas E. Bombe
+ *
+ * This code is licensed under the GPL. See the file COPYING in the root
+ * directory of the kernel sources for details.
*/
#include <linux/types.h>
diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
index c5c5cc4ad..179834ac7 100644
--- a/drivers/ieee1394/ieee1394_transactions.c
+++ b/drivers/ieee1394/ieee1394_transactions.c
@@ -4,6 +4,9 @@
* Transaction support.
*
* Copyright (C) 1999 Andreas E. Bombe
+ *
+ * This code is licensed under the GPL. See the file COPYING in the root
+ * directory of the kernel sources for details.
*/
#include <linux/sched.h>
@@ -152,38 +155,58 @@ void fill_iso_packet(struct hpsb_packet *packet, int length, int channel,
* Return value: The allocated transaction label or -1 if there was no free
* tlabel and @wait is false.
*/
+static int __get_tlabel(struct hpsb_host *host, nodeid_t nodeid)
+{
+ int tlabel;
+
+ if (host->tlabel_count) {
+ host->tlabel_count--;
+
+ if (host->tlabel_pool[0] != ~0) {
+ tlabel = ffz(host->tlabel_pool[0]);
+ host->tlabel_pool[0] |= 1 << tlabel;
+ } else {
+ tlabel = ffz(host->tlabel_pool[1]);
+ host->tlabel_pool[1] |= 1 << tlabel;
+ tlabel += 32;
+ }
+ return tlabel;
+ }
+ return -1;
+}
+
int get_tlabel(struct hpsb_host *host, nodeid_t nodeid, int wait)
{
unsigned long flags;
int tlabel;
-
- while (1) {
- spin_lock_irqsave(&host->tlabel_lock, flags);
-
- if (host->tlabel_count) {
- host->tlabel_count--;
-
- if (host->tlabel_pool[0] != ~0) {
- tlabel = ffz(host->tlabel_pool[0]);
- host->tlabel_pool[0] |= 1 << tlabel;
- } else {
- tlabel = ffz(host->tlabel_pool[1]);
- host->tlabel_pool[1] |= 1 << tlabel;
- tlabel += 32;
- }
-
- spin_unlock_irqrestore(&host->tlabel_lock, flags);
- return tlabel;
- }
-
- spin_unlock_irqrestore(&host->tlabel_lock, flags);
-
- if (wait) {
- sleep_on(&host->tlabel_wait);
- } else {
- return -1;
- }
- }
+ wait_queue_t wq;
+
+ spin_lock_irqsave(&host->tlabel_lock, flags);
+
+ tlabel = __get_tlabel(host, nodeid);
+ if (tlabel != -1 || !wait) {
+ spin_unlock_irqrestore(&host->tlabel_lock, flags);
+ return tlabel;
+ }
+
+ init_waitqueue_entry(&wq, current);
+ add_wait_queue(&host->tlabel_wait, &wq);
+
+ for (;;) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ tlabel = __get_tlabel(host, nodeid);
+ if (tlabel != -1) break;
+
+ spin_unlock_irqrestore(&host->tlabel_lock, flags);
+ schedule();
+ spin_lock_irqsave(&host->tlabel_lock, flags);
+ }
+
+ spin_unlock_irqrestore(&host->tlabel_lock, flags);
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&host->tlabel_wait, &wq);
+
+ return tlabel;
}
/**
diff --git a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h
index 411b79b36..84be6aa05 100644
--- a/drivers/ieee1394/ieee1394_types.h
+++ b/drivers/ieee1394/ieee1394_types.h
@@ -11,15 +11,23 @@
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#include <linux/wait.h>
#define DECLARE_WAITQUEUE(name, task) struct wait_queue name = { task, NULL }
typedef struct wait_queue *wait_queue_head_t;
+typedef struct wait_queue wait_queue_t;
inline static void init_waitqueue_head(wait_queue_head_t *wh)
{
*wh = NULL;
}
+inline static void init_waitqueue_entry(wait_queue_t *wq, struct task_struct *p)
+{
+ wq->task = p;
+ wq->next = NULL;
+}
+
static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
@@ -30,6 +38,22 @@ static __inline__ void list_add_tail(struct list_head *new, struct list_head *he
#define set_current_state(state_value) \
do { current->state = (state_value); } while (0)
+
+#include <asm/page.h>
+/* Pure 2^n version of get_order */
+extern __inline__ int get_order(unsigned long size)
+{
+ int order;
+ size = (size-1) >> (PAGE_SHIFT-1);
+ order = -1;
+ do {
+ size >>= 1;
+ order++;
+ } while (size);
+ return order;
+}
+
+
#include <linux/pci.h>
inline static int pci_enable_device(struct pci_dev *dev)
{
@@ -39,8 +63,134 @@ inline static int pci_enable_device(struct pci_dev *dev)
return 0;
}
+#define PCI_DMA_BIDIRECTIONAL 0
+#define PCI_DMA_TODEVICE 1
+#define PCI_DMA_FROMDEVICE 2
+#define PCI_DMA_NONE 3
+#define PCI_ROM_RESOURCE 6
+#define pci_resource_start(dev, bar) ((bar) == PCI_ROM_RESOURCE \
+ ? (dev)->rom_address \
+ : (dev)->base_address[(bar)])
+#define BUG() *(int *)0 = 0
+
+#include <asm/io.h>
+typedef u32 dma_addr_t;
+
+extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+{
+ return 1;
+}
+
+extern inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+ dma_addr_t *dma_handle)
+{
+ void *ret;
+ ret = (void *)__get_free_pages(GFP_ATOMIC, get_order(size));
+ if (ret) {
+ memset(ret, 0, size);
+ *dma_handle = virt_to_bus(ret);
+ }
+ return ret;
+}
+
+extern inline void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
+{
+ free_pages((unsigned long)vaddr, get_order(size));
+}
+
+extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+ size_t size, int direction)
+{
+ if (direction == PCI_DMA_NONE)
+ BUG();
+ return virt_to_bus(ptr);
+}
+
+extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+ size_t size, int direction)
+{
+ if (direction == PCI_DMA_NONE)
+ BUG();
+}
+
+struct scatterlist {};
+extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+ int nents, int direction)
+{
+ if (direction == PCI_DMA_NONE)
+ BUG();
+ return nents;
+}
+
+extern inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+ int nents, int direction)
+{
+ if (direction == PCI_DMA_NONE)
+ BUG();
+}
+
+extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
+ dma_addr_t dma_handle,
+ size_t size, int direction)
+{
+ if (direction == PCI_DMA_NONE)
+ BUG();
+}
+
+extern inline void pci_dma_sync_sg(struct pci_dev *hwdev,
+ struct scatterlist *sg,
+ int nelems, int direction)
+{
+ if (direction == PCI_DMA_NONE)
+ BUG();
+}
+
+
+#ifndef _LINUX_DEVFS_FS_KERNEL_H
+typedef struct devfs_entry * devfs_handle_t;
+#define DEVFS_FL_NONE 0
+
+static inline devfs_handle_t devfs_register (devfs_handle_t dir,
+ const char *name,
+ unsigned int flags,
+ unsigned int major,
+ unsigned int minor,
+ umode_t mode,
+ void *ops, void *info)
+{
+ return NULL;
+}
+static inline void devfs_unregister (devfs_handle_t de)
+{
+ return;
+}
+static inline int devfs_register_chrdev (unsigned int major, const char *name,
+ struct file_operations *fops)
+{
+ return register_chrdev (major, name, fops);
+}
+static inline int devfs_unregister_chrdev (unsigned int major,const char *name)
+{
+ return unregister_chrdev (major, name);
+}
+#endif /* _LINUX_DEVFS_FS_KERNEL_H */
+
+
+#define V22_COMPAT_MOD_INC_USE_COUNT MOD_INC_USE_COUNT
+#define V22_COMPAT_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT
+#define OWNER_THIS_MODULE
+
+#else /* Linux version < 2.3 */
+
+#define V22_COMPAT_MOD_INC_USE_COUNT do {} while (0)
+#define V22_COMPAT_MOD_DEC_USE_COUNT do {} while (0)
+#define OWNER_THIS_MODULE owner: THIS_MODULE,
+
#endif /* Linux version < 2.3 */
+
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18)
#include <asm/spinlock.h>
#else
@@ -55,9 +205,9 @@ inline static int pci_enable_device(struct pci_dev *dev)
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
-typedef __u32 quadlet_t;
-typedef __u64 octlet_t;
-typedef __u16 nodeid_t;
+typedef u32 quadlet_t;
+typedef u64 octlet_t;
+typedef u16 nodeid_t;
#define BUS_MASK 0xffc0
#define NODE_MASK 0x003f
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index a0933c3e4..05e1063d7 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -25,10 +25,10 @@
* . Async Request Receive
* . Async Response Transmit
* . Iso Receive
+ * . DMA mmap for iso receive
*
* Things not implemented:
* . Iso Transmit
- * . DMA to user's space in iso receive mode
* . DMA error recovery
*
* Things to be fixed:
@@ -38,7 +38,6 @@
* . Self-id are sometimes not received properly
* if card is initialized with no other nodes
* on the bus
- * . SONY CXD3222 chip is not working properly
* . Apple PowerBook detected but not working yet
*/
@@ -56,7 +55,7 @@
* Albrecht Dress <ad@mpifr-bonn.mpg.de>
* . Apple PowerBook detection
* Daniel Kobras <daniel.kobras@student.uni-tuebingen.de>
- * . Reset the board properly before leaving
+ * . Reset the board properly before leaving + misc cleanups
*/
#include <linux/config.h>
@@ -130,6 +129,8 @@ int supported_chips[][2] = {
{ PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72870 },
{ PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_UPD72871 },
{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW },
+ { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_ALI_OHCI1394_M5251 },
+ { PCI_VENDOR_ID_LUCENT, PCI_DEVICE_ID_LUCENT_FW323 },
{ -1, -1 }
};
@@ -142,617 +143,6 @@ static int init_driver(void);
static void dma_trm_bh(void *data);
static void dma_rcv_bh(void *data);
static void dma_trm_reset(struct dma_trm_ctx *d);
-static void stop_context(struct ti_ohci *ohci, int reg, char *msg);
-
-#ifdef _VIDEO_1394_H
-
-/* Taken from bttv.c */
-/*******************************/
-/* Memory management functions */
-/*******************************/
-
-#define MDEBUG(x) do { } while(0) /* Debug memory management */
-
-/* [DaveM] I've recoded most of this so that:
- * 1) It's easier to tell what is happening
- * 2) It's more portable, especially for translating things
- * out of vmalloc mapped areas in the kernel.
- * 3) Less unnecessary translations happen.
- *
- * The code used to assume that the kernel vmalloc mappings
- * existed in the page tables of every process, this is simply
- * not guarenteed. We now use pgd_offset_k which is the
- * defined way to get at the kernel page tables.
- */
-
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
- unsigned long ret = 0UL;
- pmd_t *pmd;
- pte_t *ptep, pte;
-
- if (!pgd_none(*pgd)) {
- pmd = pmd_offset(pgd, adr);
- if (!pmd_none(*pmd)) {
- ptep = pte_offset(pmd, adr);
- pte = *ptep;
- if(pte_present(pte))
- ret = (pte_page(pte)|(adr&(PAGE_SIZE-1)));
- }
- }
- MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
- return ret;
-}
-
-static inline unsigned long uvirt_to_bus(unsigned long adr)
-{
- unsigned long kva, ret;
-
- kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
- ret = virt_to_bus((void *)kva);
- MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
- return ret;
-}
-
-static inline unsigned long kvirt_to_bus(unsigned long adr)
-{
- unsigned long va, kva, ret;
-
- va = VMALLOC_VMADDR(adr);
- kva = uvirt_to_kva(pgd_offset_k(va), va);
- ret = virt_to_bus((void *)kva);
- MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
- return ret;
-}
-
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the
- * area and marking the pages as reserved.
- */
-static inline unsigned long kvirt_to_pa(unsigned long adr)
-{
- unsigned long va, kva, ret;
-
- va = VMALLOC_VMADDR(adr);
- kva = uvirt_to_kva(pgd_offset_k(va), va);
- ret = __pa(kva);
- MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
- return ret;
-}
-
-static void * rvmalloc(unsigned long size)
-{
- void * mem;
- unsigned long adr, page;
-
- mem=vmalloc(size);
- if (mem)
- {
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr=(unsigned long) mem;
- while (size > 0)
- {
- page = kvirt_to_pa(adr);
- mem_map_reserve(MAP_NR(__va(page)));
- adr+=PAGE_SIZE;
- size-=PAGE_SIZE;
- }
- }
- return mem;
-}
-
-static void rvfree(void * mem, unsigned long size)
-{
- unsigned long adr, page;
-
- if (mem)
- {
- adr=(unsigned long) mem;
- while (size > 0)
- {
- page = kvirt_to_pa(adr);
- mem_map_unreserve(MAP_NR(__va(page)));
- adr+=PAGE_SIZE;
- size-=PAGE_SIZE;
- }
- vfree(mem);
- }
-}
-
-static int free_dma_fbuf_ctx(struct dma_fbuf_ctx **d)
-{
- int i;
- struct ti_ohci *ohci;
-
- if ((*d)==NULL) return -1;
-
- ohci = (struct ti_ohci *)(*d)->ohci;
-
- DBGMSG(ohci->id, "Freeing dma_fbuf_ctx %d", (*d)->ctx);
-
- stop_context(ohci, (*d)->ctrlClear, NULL);
-
- if ((*d)->buf) rvfree((void *)(*d)->buf,
- (*d)->num_desc * (*d)->buf_size);
-
- if ((*d)->prg) {
- for (i=0;i<(*d)->num_desc;i++)
- if ((*d)->prg[i]) kfree((*d)->prg[i]);
- kfree((*d)->prg);
- }
-
- if ((*d)->buffer_status)
- kfree((*d)->buffer_status);
-
- kfree(*d);
- *d = NULL;
-
- return 0;
-}
-
-static struct dma_fbuf_ctx *
-alloc_dma_fbuf_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
- int buf_size, int channel)
-{
- struct dma_fbuf_ctx *d=NULL;
- int i;
-
- d = (struct dma_fbuf_ctx *)kmalloc(sizeof(struct dma_fbuf_ctx),
- GFP_KERNEL);
-
- if (d==NULL) {
- PRINT(KERN_ERR, ohci->id, "failed to allocate dma_fbuf_ctx");
- return NULL;
- }
-
- d->ohci = (void *)ohci;
- d->ctx = ctx;
- d->channel = channel;
- d->num_desc = num_desc;
- d->frame_size = buf_size;
- if (buf_size%PAGE_SIZE)
- d->buf_size = buf_size + PAGE_SIZE - (buf_size%PAGE_SIZE);
- else
- d->buf_size = buf_size;
- d->ctrlSet = OHCI1394_IrRcvContextControlSet+32*d->ctx;
- d->ctrlClear = OHCI1394_IrRcvContextControlClear+32*d->ctx;
- d->cmdPtr = OHCI1394_IrRcvCommandPtr+32*d->ctx;
- d->ctxMatch = OHCI1394_IrRcvContextMatch+32*d->ctx;
- d->nb_cmd = d->buf_size / PAGE_SIZE + 1;
- d->last_buffer = 0;
- d->buf = NULL;
- d->prg = NULL;
- init_waitqueue_head(&d->waitq);
-
- d->buf = rvmalloc(d->num_desc * d->buf_size);
-
- if (d->buf == NULL) {
- PRINT(KERN_ERR, ohci->id, "failed to allocate dma fbuffer");
- free_dma_fbuf_ctx(&d);
- return NULL;
- }
- memset(d->buf, 0, d->num_desc * d->buf_size);
-
- d->prg = kmalloc(d->num_desc * sizeof(struct dma_cmd *),
- GFP_KERNEL);
-
- if (d->prg == NULL) {
- PRINT(KERN_ERR, ohci->id, "failed to allocate dma fbuf prg");
- free_dma_fbuf_ctx(&d);
- return NULL;
- }
- memset(d->prg, 0, d->num_desc * sizeof(struct dma_cmd *));
-
- for (i=0;i<d->num_desc;i++) {
- d->prg[i] = kmalloc(d->nb_cmd * sizeof(struct dma_cmd),
- GFP_KERNEL);
- if (d->prg[i] == NULL) {
- PRINT(KERN_ERR, ohci->id,
- "failed to allocate dma fbuf prg");
- free_dma_fbuf_ctx(&d);
- return NULL;
- }
- }
-
- d->buffer_status = kmalloc(d->num_desc * sizeof(unsigned int),
- GFP_KERNEL);
-
- if (d->buffer_status == NULL) {
- PRINT(KERN_ERR, ohci->id, "failed to allocate dma fbuf prg");
- free_dma_fbuf_ctx(&d);
- return NULL;
- }
- memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int));
-
- PRINT(KERN_INFO, ohci->id, "Iso DMA to User's Space: %d buffers "
- "of size %d allocated for a frame size %d, each with %d prgs",
- d->num_desc, d->buf_size, d->frame_size, d->nb_cmd);
-
- return d;
-}
-
-static void initialize_dma_fbuf_prg(struct dma_cmd *prg, int n,
- int frame_size, unsigned long buf)
-{
- int i;
- int leftsize = (frame_size%PAGE_SIZE) ?
- frame_size%PAGE_SIZE : PAGE_SIZE;
-
- /* the first descriptor will sync and read only 4 bytes */
- prg[0].control = (0x280F << 16) | 4;
- prg[0].address = kvirt_to_bus(buf);
- prg[0].branchAddress = (virt_to_bus(&(prg[1].control))
- & 0xfffffff0) | 0x1;
- prg[0].status = 0;
-
- /* the second descriptor will read PAGE_SIZE-4 bytes */
- prg[1].control = (0x280C << 16) | (PAGE_SIZE-4);
- prg[1].address = kvirt_to_bus(buf+4);
- prg[1].branchAddress = (virt_to_bus(&(prg[2].control))
- & 0xfffffff0) | 0x1;
- prg[1].status = 0;
-
- for (i=2;i<n-1;i++) {
- prg[i].control = (0x280C << 16) | PAGE_SIZE;
- prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE);
-
- prg[i].branchAddress =
- (virt_to_bus(&(prg[i+1].control))
- & 0xfffffff0) | 0x1;
-
- prg[i].status = 0;
- }
-
- /* the last descriptor will generate an interrupt */
- prg[i].control = (0x283C << 16) | leftsize;
- prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE);
- prg[i].status = 0;
-}
-
-static void initialize_dma_fbuf_ctx(struct dma_fbuf_ctx *d, int tag)
-{
- struct ti_ohci *ohci = (struct ti_ohci *)d->ohci;
- int i;
-
- stop_context(ohci, d->ctrlClear, NULL);
-
- for (i=0;i<d->num_desc;i++) {
- initialize_dma_fbuf_prg(d->prg[i], d->nb_cmd, d->frame_size,
- (unsigned long)d->buf+i*d->buf_size);
- }
-
- /* Set bufferFill, no header */
- reg_write(ohci, d->ctrlSet, 0x80000000);
-
- /* Set the context match register to match on all tags,
- sync for sync tag, and listen to d->channel */
- reg_write(ohci, d->ctxMatch, 0xf0000000|((tag&0xf)<<8)|d->channel);
-
- /* Set up isoRecvIntMask to generate interrupts */
- reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1<<d->ctx);
-}
-
-/* find which context is listening to this channel */
-int fbuf_ctx_listening(struct ti_ohci *ohci, int channel)
-{
- int i;
- for (i=0;i<ohci->nb_iso_ctx-1;i++)
- if (ohci->fbuf_context[i]) {
- if (ohci->fbuf_context[i]->channel==channel)
- return i;
- }
-
- PRINT(KERN_ERR, ohci->id,
- "no iso context is listening to channel %d",
- channel);
- return -1;
-}
-
-static int ohci_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct ti_ohci *ohci=&cards[MINOR(inode->i_rdev)];
-
- switch(cmd)
- {
- case VIDEO1394_LISTEN_CHANNEL:
- {
- struct video1394_mmap v;
- int i;
-
- if(copy_from_user(&v, (void *)arg, sizeof(v)))
- return -EFAULT;
- if (v.channel<0 || v.channel>(ISO_CHANNELS-1)) {
- PRINT(KERN_ERR, ohci->id,
- "iso channel %d out of bound", v.channel);
- return -EFAULT;
- }
- if (test_and_set_bit(v.channel, &ohci->IR_channel_usage)) {
- PRINT(KERN_ERR, ohci->id,
- "channel %d is already taken", v.channel);
- return -EFAULT;
- }
-
- /* find a free iso context */
- for (i=0;i<ohci->nb_iso_ctx-1;i++)
- if (ohci->fbuf_context[i]==NULL) break;
-
- if (i==(ohci->nb_iso_ctx-1)) {
- PRINT(KERN_ERR, ohci->id, "no iso context available");
- return -EFAULT;
- }
-
- if (v.nb_buffers * v.buf_size > VIDEO1394_MAX_SIZE) {
- PRINT(KERN_ERR, ohci->id,
- "%d buffers of size %d bytes is too big",
- v.nb_buffers, v.buf_size);
- return -EFAULT;
- }
-
- ohci->fbuf_context[i] =
- alloc_dma_fbuf_ctx(ohci, i+1, v.nb_buffers,
- v.buf_size, v.channel);
-
- if (ohci->fbuf_context[i] == NULL) {
- PRINT(KERN_ERR, ohci->id,
- "Couldn't allocate fbuf context");
- return -EFAULT;
- }
- initialize_dma_fbuf_ctx(ohci->fbuf_context[i], v.sync_tag);
-
- ohci->current_fbuf_ctx = ohci->fbuf_context[i];
-
- v.buf_size = ohci->fbuf_context[i]->buf_size;
-
- PRINT(KERN_INFO, ohci->id,
- "iso context %d listen on channel %d", i+1,
- v.channel);
-
- if(copy_to_user((void *)arg, &v, sizeof(v)))
- return -EFAULT;
-
- return 0;
- }
- case VIDEO1394_UNLISTEN_CHANNEL:
- {
- int channel;
- int i;
-
- if(copy_from_user(&channel, (void *)arg, sizeof(int)))
- return -EFAULT;
-
- if (!test_and_clear_bit(channel, &ohci->IR_channel_usage)) {
- PRINT(KERN_ERR, ohci->id,
- "channel %d is not being used", channel);
- return -EFAULT;
- }
-
- i = fbuf_ctx_listening(ohci, channel);
- if (i<0) return -EFAULT;
-
- free_dma_fbuf_ctx(&ohci->fbuf_context[i]);
-
- PRINT(KERN_INFO, ohci->id,
- "iso context %d stop listening on channel %d",
- i+1, channel);
-
- return 0;
- }
- case VIDEO1394_QUEUE_BUFFER:
- {
- struct video1394_wait v;
- struct dma_fbuf_ctx *d;
- int i;
-
- if(copy_from_user(&v, (void *)arg, sizeof(v)))
- return -EFAULT;
-
- i = fbuf_ctx_listening(ohci, v.channel);
- if (i<0) return -EFAULT;
- d = ohci->fbuf_context[i];
-
- if ((v.buffer<0) || (v.buffer>d->num_desc)) {
- PRINT(KERN_ERR, ohci->id,
- "buffer %d out of range",v.buffer);
- return -EFAULT;
- }
-
- if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) {
- PRINT(KERN_ERR, ohci->id,
- "buffer %d is already used",v.buffer);
- return -EFAULT;
- }
-
- d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
-
- d->prg[d->last_buffer][d->nb_cmd-1].branchAddress =
- (virt_to_bus(&(d->prg[v.buffer][0].control))
- & 0xfffffff0) | 0x1;
-
- d->last_buffer = v.buffer;
-
- if (!(reg_read(ohci, d->ctrlSet) & 0x8000))
- {
- DBGMSG(ohci->id, "Starting iso DMA ctx=%d",d->ctx);
-
- /* Tell the controller where the first program is */
- reg_write(ohci, d->cmdPtr,
- virt_to_bus(&(d->prg[v.buffer][0])) | 0x1 );
-
- /* Run IR context */
- reg_write(ohci, d->ctrlSet, 0x8000);
- }
- else {
- /* Wake up dma context if necessary */
- if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
- PRINT(KERN_INFO, ohci->id,
- "Waking up iso dma ctx=%d", d->ctx);
- reg_write(ohci, d->ctrlSet, 0x1000);
- }
- }
- return 0;
-
- }
- case VIDEO1394_WAIT_BUFFER:
- {
- struct video1394_wait v;
- struct dma_fbuf_ctx *d;
- int i;
-
- if(copy_from_user(&v, (void *)arg, sizeof(v)))
- return -EFAULT;
-
- i = fbuf_ctx_listening(ohci, v.channel);
- if (i<0) return -EFAULT;
- d = ohci->fbuf_context[i];
-
- if ((v.buffer<0) || (v.buffer>d->num_desc)) {
- PRINT(KERN_ERR, ohci->id,
- "buffer %d out of range",v.buffer);
- return -EFAULT;
- }
-
- switch(d->buffer_status[v.buffer]) {
- case VIDEO1394_BUFFER_READY:
- d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
- return 0;
- case VIDEO1394_BUFFER_QUEUED:
- while(d->buffer_status[v.buffer]!=
- VIDEO1394_BUFFER_READY) {
- interruptible_sleep_on(&d->waitq);
- if(signal_pending(current)) return -EINTR;
- }
- d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
- return 0;
- default:
- PRINT(KERN_ERR, ohci->id,
- "buffer %d is not queued",v.buffer);
- return -EFAULT;
- }
- }
- default:
- return -EINVAL;
- }
-}
-
-/*
- * This maps the vmalloced and reserved fbuffer to user space.
- *
- * FIXME:
- * - PAGE_READONLY should suffice!?
- * - remap_page_range is kind of inefficient for page by page remapping.
- * But e.g. pte_alloc() does not work in modules ... :-(
- */
-
-static int do_fbuf_mmap(struct ti_ohci *ohci, struct dma_fbuf_ctx *d,
- const char *adr, unsigned long size)
-{
- unsigned long start=(unsigned long) adr;
- unsigned long page,pos;
-
- if (size>d->num_desc * d->buf_size) {
- PRINT(KERN_ERR, ohci->id,
- "fbuf context %d buf size is different from mmap size",
- d->ctx);
- return -EINVAL;
- }
- if (!d->buf) {
- PRINT(KERN_ERR, ohci->id,
- "fbuf context %d is not allocated", d->ctx);
- return -EINVAL;
- }
-
- pos=(unsigned long) d->buf;
- while (size > 0) {
- page = kvirt_to_pa(pos);
- if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
- return -EAGAIN;
- start+=PAGE_SIZE;
- pos+=PAGE_SIZE;
- size-=PAGE_SIZE;
- }
- return 0;
-}
-
-int ohci_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct ti_ohci *ohci=&cards[MINOR(file->f_dentry->d_inode->i_rdev)];
- PRINT(KERN_INFO, ohci->id, "mmap");
- if (ohci->current_fbuf_ctx == NULL) {
- PRINT(KERN_ERR, ohci->id, "current fbuf context not set");
- return -EINVAL;
- }
-
- return do_fbuf_mmap(ohci, ohci->current_fbuf_ctx,
- (char *)vma->vm_start,
- (unsigned long)(vma->vm_end-vma->vm_start));
- return 0;
-}
-
-static int ohci_open(struct inode *inode, struct file *file)
-{
- struct ti_ohci *ohci=&cards[MINOR(inode->i_rdev)];
- PRINT(KERN_INFO, ohci->id, "open");
- return 0;
-}
-
-static int ohci_release(struct inode *inode, struct file *file)
-{
- struct ti_ohci *ohci=&cards[MINOR(inode->i_rdev)];
- int i;
-
- PRINT(KERN_INFO, ohci->id, "release");
- for (i=0;i<ohci->nb_iso_ctx-1;i++)
- if (ohci->fbuf_context[i]) {
- if (!test_and_clear_bit(ohci->fbuf_context[i]->channel,
- &ohci->IR_channel_usage)) {
- PRINT(KERN_ERR, ohci->id,
- "channel %d is not being used",
- ohci->fbuf_context[i]->channel);
- }
- PRINT(KERN_INFO, ohci->id,
- "iso context %d stop listening on channel %d",
- i+1, ohci->fbuf_context[i]->channel);
- free_dma_fbuf_ctx(&ohci->fbuf_context[i]);
- }
- return 0;
-}
-
-static struct file_operations ohci_fops=
-{
- owner: THIS_MODULE,
- ioctl: ohci_ioctl,
- mmap: ohci_mmap,
- open: ohci_open,
- release: ohci_release
-};
-
-int wakeup_dma_fbuf_ctx(struct ti_ohci *ohci, struct dma_fbuf_ctx *d)
-{
- int i;
-
- if (d==NULL) {
- PRINT(KERN_ERR, ohci->id, "Iso receive event received but "
- "context not allocated");
- return -EFAULT;
- }
-
- for (i=0;i<d->num_desc;i++) {
- if (d->prg[i][d->nb_cmd-1].status) {
- d->prg[i][d->nb_cmd-1].status=0;
- d->buffer_status[i] = VIDEO1394_BUFFER_READY;
- }
- }
- if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq);
- return 0;
-}
-
-#endif
-
-
/***********************************
* IEEE-1394 functionality section *
@@ -827,14 +217,14 @@ static int set_phy_reg(struct ti_ohci *ohci, int addr, unsigned char data) {
inline static int handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,
int phyid, int isroot)
{
- quadlet_t *q = ohci->self_id_buffer;
+ quadlet_t *q = ohci->selfid_buf_cpu;
quadlet_t self_id_count=reg_read(ohci, OHCI1394_SelfIDCount);
size_t size;
quadlet_t lsid;
/* Self-id handling seems much easier than for the aic5800 chip.
All the self-id packets, including this device own self-id,
- should be correctly arranged in the self_id_buffer at this
+ should be correctly arranged in the selfid buffer at this
stage */
/* Check status of self-id reception */
@@ -952,55 +342,36 @@ static int run_context(struct ti_ohci *ohci, int reg, char *msg)
return 0;
}
-static void stop_context(struct ti_ohci *ohci, int reg, char *msg)
-{
- int i=0;
-
- /* stop the channel program if it's still running */
- reg_write(ohci, reg, 0x8000);
-
- /* Wait until it effectively stops */
- while (reg_read(ohci, reg) & 0x400) {
- i++;
- if (i>5000) {
- PRINT(KERN_ERR, ohci->id,
- "runaway loop while stopping context...");
- break;
- }
- }
- if (msg) PRINT(KERN_ERR, ohci->id, "%s\n dma prg stopped\n", msg);
-}
-
/* Generate the dma receive prgs and start the context */
static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d)
{
struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
int i;
- stop_context(ohci, d->ctrlClear, NULL);
+ ohci1394_stop_context(ohci, d->ctrlClear, NULL);
for (i=0; i<d->num_desc; i++) {
/* end of descriptor list? */
if ((i+1) < d->num_desc) {
- d->prg[i]->control = (0x283C << 16) | d->buf_size;
- d->prg[i]->branchAddress =
- (virt_to_bus(d->prg[i+1]) & 0xfffffff0) | 0x1;
+ d->prg_cpu[i]->control = (0x283C << 16) | d->buf_size;
+ d->prg_cpu[i]->branchAddress =
+ (d->prg_bus[i+1] & 0xfffffff0) | 0x1;
} else {
- d->prg[i]->control = (0x283C << 16) | d->buf_size;
- d->prg[i]->branchAddress =
- (virt_to_bus(d->prg[0]) & 0xfffffff0);
+ d->prg_cpu[i]->control = (0x283C << 16) | d->buf_size;
+ d->prg_cpu[i]->branchAddress =
+ d->prg_bus[0] & 0xfffffff0;
}
- d->prg[i]->address = virt_to_bus(d->buf[i]);
- d->prg[i]->status = d->buf_size;
+ d->prg_cpu[i]->address = d->buf_bus[i];
+ d->prg_cpu[i]->status = d->buf_size;
}
d->buf_ind = 0;
d->buf_offset = 0;
/* Tell the controller where the first AR program is */
- reg_write(ohci, d->cmdPtr, virt_to_bus(d->prg[0]) | 0x1);
+ reg_write(ohci, d->cmdPtr, d->prg_bus[0] | 0x1);
/* Run AR context */
reg_write(ohci, d->ctrlSet, 0x00008000);
@@ -1014,26 +385,30 @@ static void initialize_dma_trm_ctx(struct dma_trm_ctx *d)
struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
/* Stop the context */
- stop_context(ohci, d->ctrlClear, NULL);
+ ohci1394_stop_context(ohci, d->ctrlClear, NULL);
d->prg_ind = 0;
d->sent_ind = 0;
d->free_prgs = d->num_desc;
d->branchAddrPtr = NULL;
- d->first = NULL;
- d->last = NULL;
+ d->fifo_first = NULL;
+ d->fifo_last = NULL;
+ d->pending_first = NULL;
+ d->pending_last = NULL;
PRINT(KERN_INFO, ohci->id, "AT dma ctx=%d initialized", d->ctx);
}
/* Count the number of available iso contexts */
-static int get_nb_iso_ctx(struct ti_ohci *ohci)
+static int get_nb_iso_ctx(struct ti_ohci *ohci, int reg)
{
int i,ctx=0;
u32 tmp;
- reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0xffffffff);
- tmp = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
+ reg_write(ohci, reg, 0xffffffff);
+ tmp = reg_read(ohci, reg);
+
+ DBGMSG(ohci->id,"Iso contexts reg: %08x implemented: %08x", reg, tmp);
/* Count the number of contexts */
for(i=0; i<32; i++) {
@@ -1062,7 +437,7 @@ static int ohci_initialize(struct hpsb_host *host)
if ((retval=ohci_soft_reset(ohci))<0) return retval;
/*
- *Delay aftger soft reset to make sure everything has settled
+ * Delay after soft reset to make sure everything has settled
* down (sanity)
*/
mdelay(100);
@@ -1089,31 +464,33 @@ static int ohci_initialize(struct hpsb_host *host)
reg_write(ohci, OHCI1394_LinkControlSet, 0x00300000);
/* Clear interrupt registers */
- reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
+ reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
/* Set up self-id dma buffer */
- reg_write(ohci, OHCI1394_SelfIDBuffer,
- virt_to_bus(ohci->self_id_buffer));
+ reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus);
/* enable self-id dma */
reg_write(ohci, OHCI1394_LinkControlSet, 0x00000200);
/* Set the configuration ROM mapping register */
- reg_write(ohci, OHCI1394_ConfigROMmap,
- virt_to_bus(ohci->csr_config_rom));
-
- /* Write the config ROM header */
- reg_write(ohci, OHCI1394_ConfigROMhdr,
- cpu_to_be32(ohci->csr_config_rom[0]));
+ reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus);
/* Set bus options */
reg_write(ohci, OHCI1394_BusOptions,
- cpu_to_be32(ohci->csr_config_rom[2]));
-
+ cpu_to_be32(ohci->csr_config_rom_cpu[2]));
+
+#if 0
/* Write the GUID into the csr config rom */
- ohci->csr_config_rom[3] = be32_to_cpu(reg_read(ohci, OHCI1394_GUIDHi));
- ohci->csr_config_rom[4] = be32_to_cpu(reg_read(ohci, OHCI1394_GUIDLo));
+ ohci->csr_config_rom_cpu[3] =
+ be32_to_cpu(reg_read(ohci, OHCI1394_GUIDHi));
+ ohci->csr_config_rom_cpu[4] =
+ be32_to_cpu(reg_read(ohci, OHCI1394_GUIDLo));
+#endif
+
+ /* Write the config ROM header */
+ reg_write(ohci, OHCI1394_ConfigROMhdr,
+ cpu_to_be32(ohci->csr_config_rom_cpu[0]));
ohci->max_packet_size =
1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
@@ -1124,39 +501,56 @@ static int ohci_initialize(struct hpsb_host *host)
reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
/* Initialize IR dma */
- ohci->nb_iso_ctx = get_nb_iso_ctx(ohci);
- PRINT(KERN_INFO, ohci->id, "%d iso contexts available",
- ohci->nb_iso_ctx);
- for (i=0;i<ohci->nb_iso_ctx;i++) {
- reg_write(ohci, OHCI1394_IrRcvContextControlClear+32*i,
+ ohci->nb_iso_rcv_ctx =
+ get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);
+ PRINT(KERN_INFO, ohci->id, "%d iso receive contexts available",
+ ohci->nb_iso_rcv_ctx);
+ for (i=0;i<ohci->nb_iso_rcv_ctx;i++) {
+ reg_write(ohci, OHCI1394_IsoRcvContextControlClear+32*i,
0xffffffff);
- reg_write(ohci, OHCI1394_IrRcvContextMatch+32*i, 0);
- reg_write(ohci, OHCI1394_IrRcvCommandPtr+32*i, 0);
- }
-#ifdef _VIDEO_1394_H
- ohci->fbuf_context = (struct dma_fbuf_ctx **)
- kmalloc((ohci->nb_iso_ctx-1)*sizeof(struct dma_fbuf_ctx *),
- GFP_KERNEL);
- if (ohci->fbuf_context)
- memset(ohci->fbuf_context, 0,
- (ohci->nb_iso_ctx-1)*sizeof(struct dma_fbuf_ctx *));
- else {
- PRINT(KERN_ERR, ohci->id, "Cannot allocate fbuf_context");
- return -1;
+ reg_write(ohci, OHCI1394_IsoRcvContextMatch+32*i, 0);
+ reg_write(ohci, OHCI1394_IsoRcvCommandPtr+32*i, 0);
}
-#endif
+
/* Set bufferFill, isochHeader, multichannel for IR context */
- reg_write(ohci, OHCI1394_IrRcvContextControlSet, 0xd0000000);
+ reg_write(ohci, OHCI1394_IsoRcvContextControlSet, 0xd0000000);
/* Set the context match register to match on all tags */
- reg_write(ohci, OHCI1394_IrRcvContextMatch, 0xf0000000);
+ reg_write(ohci, OHCI1394_IsoRcvContextMatch, 0xf0000000);
+
+ /* Clear the interrupt mask */
+ reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
+ reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
+
+ /* Initialize IT dma */
+ ohci->nb_iso_xmit_ctx =
+ get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);
+ PRINT(KERN_INFO, ohci->id, "%d iso transmit contexts available",
+ ohci->nb_iso_xmit_ctx);
+ for (i=0;i<ohci->nb_iso_xmit_ctx;i++) {
+ reg_write(ohci, OHCI1394_IsoXmitContextControlClear+32*i,
+ 0xffffffff);
+ reg_write(ohci, OHCI1394_IsoXmitCommandPtr+32*i, 0);
+ }
+
+ /* Clear the interrupt mask */
+ reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
+ reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
/* Clear the multi channel mask high and low registers */
reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff);
reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);
- /* Clear the interrupt mask */
- reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
+ /* Initialize AR dma */
+ initialize_dma_rcv_ctx(ohci->ar_req_context);
+ initialize_dma_rcv_ctx(ohci->ar_resp_context);
+
+ /* Initialize AT dma */
+ initialize_dma_trm_ctx(ohci->at_req_context);
+ initialize_dma_trm_ctx(ohci->at_resp_context);
+
+ /* Initialize IR dma */
+ initialize_dma_rcv_ctx(ohci->ir_context);
/* Set up isoRecvIntMask to generate interrupts for context 0
(thanks to Michael Greger for seeing that I forgot this) */
@@ -1193,23 +587,13 @@ static int ohci_initialize(struct hpsb_host *host)
OHCI1394_ARRQ |
OHCI1394_respTxComplete |
OHCI1394_reqTxComplete |
- OHCI1394_isochRx
+ OHCI1394_isochRx |
+ OHCI1394_isochTx
);
/* Enable link */
reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
- /* Initialize AR dma */
- initialize_dma_rcv_ctx(ohci->ar_req_context);
- initialize_dma_rcv_ctx(ohci->ar_resp_context);
-
- /* Initialize AT dma */
- initialize_dma_trm_ctx(ohci->at_req_context);
- initialize_dma_trm_ctx(ohci->at_resp_context);
-
- /* Initialize IR dma */
- initialize_dma_rcv_ctx(ohci->ir_context);
-
return 1;
}
@@ -1223,74 +607,132 @@ static void ohci_remove(struct hpsb_host *host)
}
}
-/* Insert a packet in the AT DMA fifo and generate the DMA prg */
+/*
+ * Insert a packet in the AT DMA fifo and generate the DMA prg
+ * FIXME: rewrite the program in order to accept packets crossing
+ * page boundaries.
+ * check also that a single dma descriptor doesn't cross a
+ * page boundary.
+ */
static void insert_packet(struct ti_ohci *ohci,
struct dma_trm_ctx *d, struct hpsb_packet *packet)
{
u32 cycleTimer;
int idx = d->prg_ind;
- d->prg[idx].begin.address = 0;
- d->prg[idx].begin.branchAddress = 0;
+ d->prg_cpu[idx]->begin.address = 0;
+ d->prg_cpu[idx]->begin.branchAddress = 0;
if (d->ctx==1) {
/*
* For response packets, we need to put a timeout value in
* the 16 lower bits of the status... let's try 1 sec timeout
*/
cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
- d->prg[idx].begin.status =
+ d->prg_cpu[idx]->begin.status =
(((((cycleTimer>>25)&0x7)+1)&0x7)<<13) |
((cycleTimer&0x01fff000)>>12);
DBGMSG(ohci->id, "cycleTimer: %08x timeStamp: %08x",
- cycleTimer, d->prg[idx].begin.status);
+ cycleTimer, d->prg_cpu[idx]->begin.status);
}
else
- d->prg[idx].begin.status = 0;
+ d->prg_cpu[idx]->begin.status = 0;
- d->prg[idx].data[0] = packet->speed_code<<16 |
+ d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
(packet->header[0] & 0xFFFF);
- d->prg[idx].data[1] = (packet->header[1] & 0xFFFF) |
+ d->prg_cpu[idx]->data[1] = (packet->header[1] & 0xFFFF) |
(packet->header[0] & 0xFFFF0000);
- d->prg[idx].data[2] = packet->header[2];
- d->prg[idx].data[3] = packet->header[3];
+ d->prg_cpu[idx]->data[2] = packet->header[2];
+ d->prg_cpu[idx]->data[3] = packet->header[3];
if (packet->data_size) { /* block transmit */
- d->prg[idx].begin.control = OUTPUT_MORE_IMMEDIATE | 0x10;
- d->prg[idx].end.control = OUTPUT_LAST | packet->data_size;
- d->prg[idx].end.address = virt_to_bus(packet->data);
- d->prg[idx].end.branchAddress = 0;
- d->prg[idx].end.status = 0x4000;
+ d->prg_cpu[idx]->begin.control = OUTPUT_MORE_IMMEDIATE | 0x10;
+ d->prg_cpu[idx]->end.control = OUTPUT_LAST | packet->data_size;
+ /*
+ * FIXME: check that the packet data buffer
+ * do not cross a page boundary
+ */
+ d->prg_cpu[idx]->end.address =
+ pci_map_single(ohci->dev, packet->data,
+ packet->data_size, PCI_DMA_TODEVICE);
+ d->prg_cpu[idx]->end.branchAddress = 0;
+ d->prg_cpu[idx]->end.status = 0;
if (d->branchAddrPtr)
- *(d->branchAddrPtr) = virt_to_bus(d->prg+idx) | 0x3;
- d->branchAddrPtr = &(d->prg[idx].end.branchAddress);
+ *(d->branchAddrPtr) = d->prg_bus[idx] | 0x3;
+ d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress);
}
else { /* quadlet transmit */
- d->prg[idx].begin.control =
+ d->prg_cpu[idx]->begin.control =
OUTPUT_LAST_IMMEDIATE | packet->header_size;
if (d->branchAddrPtr)
- *(d->branchAddrPtr) = virt_to_bus(d->prg+idx) | 0x2;
- d->branchAddrPtr = &(d->prg[idx].begin.branchAddress);
+ *(d->branchAddrPtr) = d->prg_bus[idx] | 0x2;
+ d->branchAddrPtr = &(d->prg_cpu[idx]->begin.branchAddress);
}
d->free_prgs--;
/* queue the packet in the appropriate context queue */
- if (d->last) {
- d->last->xnext = packet;
- d->last = packet;
+ if (d->fifo_last) {
+ d->fifo_last->xnext = packet;
+ d->fifo_last = packet;
+ }
+ else {
+ d->fifo_first = packet;
+ d->fifo_last = packet;
+ }
+ d->prg_ind = (d->prg_ind+1)%d->num_desc;
+}
+
+/*
+ * This function fills the AT FIFO with the (eventual) pending packets
+ * and runs or wake up the AT DMA prg if necessary.
+ * The function MUST be called with the d->lock held.
+ */
+static int dma_trm_flush(struct ti_ohci *ohci, struct dma_trm_ctx *d)
+{
+ int idx,z;
+
+ if (d->pending_first == NULL || d->free_prgs == 0)
+ return 0;
+
+ idx = d->prg_ind;
+ z = (d->pending_first->data_size) ? 3 : 2;
+
+ /* insert the packets into the at dma fifo */
+ while (d->free_prgs>0 && d->pending_first) {
+ insert_packet(ohci, d, d->pending_first);
+ d->pending_first = d->pending_first->xnext;
+ }
+ if (d->pending_first == NULL)
+ d->pending_last = NULL;
+ else
+ PRINT(KERN_INFO, ohci->id,
+ "AT DMA FIFO ctx=%d full... waiting",d->ctx);
+
+ /* Is the context running ? (should be unless it is
+ the first packet to be sent in this context) */
+ if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) {
+ DBGMSG(ohci->id,"Starting AT DMA ctx=%d",d->ctx);
+ reg_write(ohci, d->cmdPtr, d->prg_bus[idx]|z);
+ run_context(ohci, d->ctrlSet, NULL);
}
else {
- d->first = packet;
- d->last = packet;
+ DBGMSG(ohci->id,"Waking AT DMA ctx=%d",d->ctx);
+ /* wake up the dma context if necessary */
+ if (!(reg_read(ohci, d->ctrlSet) & 0x400))
+ reg_write(ohci, d->ctrlSet, 0x1000);
}
+ return 1;
}
+/*
+ * Transmission of an async packet
+ */
static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
{
struct ti_ohci *ohci = host->hostdata;
struct dma_trm_ctx *d;
unsigned char tcode;
- int timeout=50;
+ unsigned long flags;
if (packet->data_size >= ohci->max_packet_size) {
PRINT(KERN_ERR, ohci->id,
@@ -1305,48 +747,21 @@ static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
if (tcode & 0x02) d = ohci->at_resp_context;
else d = ohci->at_req_context;
- spin_lock(&d->lock);
+ spin_lock_irqsave(&d->lock,flags);
- if (d->free_prgs<1) {
- PRINT(KERN_INFO, ohci->id,
- "AT DMA ctx=%d Running out of prgs... waiting",d->ctx);
- }
- while (d->free_prgs<1) {
- spin_unlock(&d->lock);
- interruptible_sleep_on(&d->waitq);
- if(signal_pending(current)) return -EINTR;
- if (timeout--<0) {
- stop_context(ohci, d->ctrlClear,
- "AT DMA runaway loop... bailing out");
- return 0;
- }
- spin_lock(&d->lock);
- }
-
- insert_packet(ohci, d, packet);
-
- /* Is the context running ? (should be unless it is
- the first packet to be sent in this context) */
- if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) {
- DBGMSG(ohci->id,"Starting AT DMA ctx=%d",d->ctx);
- if (packet->data_size)
- reg_write(ohci, d->cmdPtr,
- virt_to_bus(&(d->prg[d->prg_ind])) | 0x3);
- else
- reg_write(ohci, d->cmdPtr,
- virt_to_bus(&(d->prg[d->prg_ind])) | 0x2);
-
- run_context(ohci, d->ctrlSet, NULL);
+ /* queue the packet for later insertion into to dma fifo */
+ if (d->pending_last) {
+ d->pending_last->xnext = packet;
+ d->pending_last = packet;
}
else {
- DBGMSG(ohci->id,"Waking AT DMA ctx=%d",d->ctx);
- /* wake up the dma context if necessary */
- if (!(reg_read(ohci, d->ctrlSet) & 0x400))
- reg_write(ohci, d->ctrlSet, 0x1000);
+ d->pending_first = packet;
+ d->pending_last = packet;
}
+
+ dma_trm_flush(ohci, d);
- d->prg_ind = (d->prg_ind+1)%d->num_desc;
- spin_unlock(&d->lock);
+ spin_unlock_irqrestore(&d->lock,flags);
return 1;
}
@@ -1359,7 +774,10 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
switch (cmd) {
case RESET_BUS:
- host->attempt_root=1;
+ /*
+ * FIXME: this flag might be necessary in some case
+ */
+ /* host->attempt_root = 1; */
PRINT(KERN_INFO, ohci->id, "resetting bus on request%s",
(host->attempt_root ? " and attempting to become root"
: ""));
@@ -1415,14 +833,9 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
spin_lock_irqsave(&ohci->IR_channel_lock, flags);
-#if 0
- PRINT(KERN_INFO, ohci->id, "!!! try listen on channel %d !!!",
- arg);
-#endif
-
if (!test_and_set_bit(arg, &ohci->IR_channel_usage)) {
- PRINT(KERN_INFO, ohci->id,
- "listening enabled on channel %d", arg);
+ DBGMSG(ohci->id,
+ "listening enabled on channel %d", arg);
if (arg > 31) {
u32 setMask= 0x00000001;
@@ -1447,8 +860,8 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
spin_lock_irqsave(&ohci->IR_channel_lock, flags);
if (test_and_clear_bit(arg, &ohci->IR_channel_usage)) {
- PRINT(KERN_INFO, ohci->id,
- "listening disabled on iso channel %d", arg);
+ DBGMSG(ohci->id,
+ "listening disabled on iso channel %d", arg);
if (arg > 31) {
u32 clearMask= 0x00000001;
@@ -1490,29 +903,42 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
static void dma_trm_reset(struct dma_trm_ctx *d)
{
struct ti_ohci *ohci;
+ unsigned long flags;
if (d==NULL) {
PRINT_G(KERN_ERR, "dma_trm_reset called with NULL arg");
return;
}
ohci = (struct ti_ohci *)(d->ohci);
- stop_context(ohci, d->ctrlClear, NULL);
+ ohci1394_stop_context(ohci, d->ctrlClear, NULL);
- spin_lock(&d->lock);
+ spin_lock_irqsave(&d->lock,flags);
+
+ /* is there still any packet pending in the fifo ? */
+ while(d->fifo_first) {
+ PRINT(KERN_INFO, ohci->id,
+ "AT dma reset ctx=%d, aborting transmission",
+ d->ctx);
+ hpsb_packet_sent(ohci->host, d->fifo_first, ACKX_ABORTED);
+ d->fifo_first = d->fifo_first->xnext;
+ }
+ d->fifo_first = d->fifo_last = NULL;
/* is there still any packet pending ? */
- while(d->first) {
+ while(d->pending_first) {
PRINT(KERN_INFO, ohci->id,
"AT dma reset ctx=%d, aborting transmission",
d->ctx);
- hpsb_packet_sent(ohci->host, d->first, ACKX_ABORTED);
- d->first = d->first->xnext;
+ hpsb_packet_sent(ohci->host, d->pending_first,
+ ACKX_ABORTED);
+ d->pending_first = d->pending_first->xnext;
}
- d->first = d->last = NULL;
+ d->pending_first = d->pending_last = NULL;
+
d->branchAddrPtr=NULL;
d->sent_ind = d->prg_ind;
d->free_prgs = d->num_desc;
- spin_unlock(&d->lock);
+ spin_unlock_irqrestore(&d->lock,flags);
}
static void ohci_irq_handler(int irq, void *dev_id,
@@ -1528,10 +954,10 @@ static void ohci_irq_handler(int irq, void *dev_id,
/* read the interrupt event register */
event=reg_read(ohci, OHCI1394_IntEventClear);
- DBGMSG(ohci->id, "IntEvent: %08x",event);
-
if (!event) return;
+ DBGMSG(ohci->id, "IntEvent: %08x",event);
+
/* clear the interrupt event register */
reg_write(ohci, OHCI1394_IntEventClear, event);
@@ -1560,7 +986,7 @@ static void ohci_irq_handler(int irq, void *dev_id,
DBGMSG(ohci->id, "Got reqTxComplete interrupt "
"status=0x%08X", reg_read(ohci, d->ctrlSet));
if (reg_read(ohci, d->ctrlSet) & 0x800)
- stop_context(ohci, d->ctrlClear,
+ ohci1394_stop_context(ohci, d->ctrlClear,
"reqTxComplete");
else
dma_trm_bh((void *)d);
@@ -1570,7 +996,7 @@ static void ohci_irq_handler(int irq, void *dev_id,
DBGMSG(ohci->id, "Got respTxComplete interrupt "
"status=0x%08X", reg_read(ohci, d->ctrlSet));
if (reg_read(ohci, d->ctrlSet) & 0x800)
- stop_context(ohci, d->ctrlClear,
+ ohci1394_stop_context(ohci, d->ctrlClear,
"respTxComplete");
else
dma_trm_bh((void *)d);
@@ -1580,9 +1006,9 @@ static void ohci_irq_handler(int irq, void *dev_id,
DBGMSG(ohci->id, "Got RQPkt interrupt status=0x%08X",
reg_read(ohci, d->ctrlSet));
if (reg_read(ohci, d->ctrlSet) & 0x800)
- stop_context(ohci, d->ctrlClear, "RQPkt");
+ ohci1394_stop_context(ohci, d->ctrlClear, "RQPkt");
else {
-#if 1
+#if IEEE1394_USE_BOTTOM_HALVES
queue_task(&d->task, &tq_immediate);
mark_bh(IMMEDIATE_BH);
#else
@@ -1595,9 +1021,9 @@ static void ohci_irq_handler(int irq, void *dev_id,
DBGMSG(ohci->id, "Got RSPkt interrupt status=0x%08X",
reg_read(ohci, d->ctrlSet));
if (reg_read(ohci, d->ctrlSet) & 0x800)
- stop_context(ohci, d->ctrlClear, "RSPkt");
+ ohci1394_stop_context(ohci, d->ctrlClear, "RSPkt");
else {
-#if 1
+#if IEEE1394_USE_BOTTOM_HALVES
queue_task(&d->task, &tq_immediate);
mark_bh(IMMEDIATE_BH);
#else
@@ -1608,9 +1034,6 @@ static void ohci_irq_handler(int irq, void *dev_id,
if (event & OHCI1394_isochRx) {
quadlet_t isoRecvIntEvent;
struct dma_rcv_ctx *d = ohci->ir_context;
-#ifdef _VIDEO_1394_H
- int i;
-#endif
isoRecvIntEvent =
reg_read(ohci, OHCI1394_IsoRecvIntEventSet);
reg_write(ohci, OHCI1394_IsoRecvIntEventClear,
@@ -1620,10 +1043,10 @@ static void ohci_irq_handler(int irq, void *dev_id,
reg_read(ohci, d->ctrlSet), isoRecvIntEvent);
if (isoRecvIntEvent & 0x1) {
if (reg_read(ohci, d->ctrlSet) & 0x800)
- stop_context(ohci, d->ctrlClear,
+ ohci1394_stop_context(ohci, d->ctrlClear,
"isochRx");
else {
-#if 1
+#if IEEE1394_USE_BOTTOM_HALVES
queue_task(&d->task, &tq_immediate);
mark_bh(IMMEDIATE_BH);
#else
@@ -1631,12 +1054,21 @@ static void ohci_irq_handler(int irq, void *dev_id,
#endif
}
}
-#ifdef _VIDEO_1394_H
- for (i=0;i<ohci->nb_iso_ctx-1;i++)
- if (isoRecvIntEvent & (1<<(i+1)))
- wakeup_dma_fbuf_ctx(
- ohci,ohci->fbuf_context[i]);
-#endif
+ if (ohci->video_tmpl)
+ ohci->video_tmpl->irq_handler(ohci->id,
+ isoRecvIntEvent,
+ 0);
+ }
+ if (event & OHCI1394_isochTx) {
+ quadlet_t isoXmitIntEvent;
+ isoXmitIntEvent =
+ reg_read(ohci, OHCI1394_IsoXmitIntEventSet);
+ reg_write(ohci, OHCI1394_IsoXmitIntEventClear,
+ isoXmitIntEvent);
+ DBGMSG(ohci->id, "Got isochTx interrupt");
+ if (ohci->video_tmpl)
+ ohci->video_tmpl->irq_handler(ohci->id, 0,
+ isoXmitIntEvent);
}
if (event & OHCI1394_selfIDComplete) {
if (host->in_bus_reset) {
@@ -1703,10 +1135,10 @@ static void insert_dma_buffer(struct dma_rcv_ctx *d, int idx)
struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
DBGMSG(ohci->id, "Inserting dma buf ctx=%d idx=%d", d->ctx, idx);
- d->prg[idx]->status = d->buf_size;
- d->prg[idx]->branchAddress &= 0xfffffff0;
+ d->prg_cpu[idx]->status = d->buf_size;
+ d->prg_cpu[idx]->branchAddress &= 0xfffffff0;
idx = (idx + d->num_desc - 1 ) % d->num_desc;
- d->prg[idx]->branchAddress |= 0x1;
+ d->prg_cpu[idx]->branchAddress |= 0x1;
/* wake up the dma context if necessary */
if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
@@ -1724,7 +1156,7 @@ static int block_length(struct dma_rcv_ctx *d, int idx,
/* Where is the data length ? */
if (offset+12>=d->buf_size)
- length = (d->buf[(idx+1)%d->num_desc]
+ length = (d->buf_cpu[(idx+1)%d->num_desc]
[3-(d->buf_size-offset)/4]>>16);
else
length = (buf_ptr[3]>>16);
@@ -1769,7 +1201,7 @@ static void dma_rcv_bh(void *data)
struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
unsigned int split_left, idx, offset, rescount;
unsigned char tcode;
- int length, bytes_left;
+ int length, bytes_left, ack;
quadlet_t *buf_ptr;
char *split_ptr;
char msg[256];
@@ -1778,9 +1210,9 @@ static void dma_rcv_bh(void *data)
idx = d->buf_ind;
offset = d->buf_offset;
- buf_ptr = d->buf[idx] + offset/4;
+ buf_ptr = d->buf_cpu[idx] + offset/4;
- rescount = d->prg[idx]->status&0xffff;
+ rescount = d->prg_cpu[idx]->status&0xffff;
bytes_left = d->buf_size - rescount - offset;
while (bytes_left>0) {
@@ -1790,21 +1222,22 @@ static void dma_rcv_bh(void *data)
if (length<4) { /* something is wrong */
sprintf(msg,"unexpected tcode 0x%X in AR ctx=%d",
tcode, d->ctx);
- stop_context(ohci, d->ctrlClear, msg);
+ ohci1394_stop_context(ohci, d->ctrlClear, msg);
spin_unlock(&d->lock);
return;
}
if ((offset+length)>d->buf_size) { /* Split packet */
if (length>d->split_buf_size) {
- stop_context(ohci, d->ctrlClear,
+ ohci1394_stop_context(ohci, d->ctrlClear,
"split packet size exceeded");
d->buf_ind = idx;
d->buf_offset = offset;
spin_unlock(&d->lock);
return;
}
- if (d->prg[(idx+1)%d->num_desc]->status==d->buf_size) {
+ if (d->prg_cpu[(idx+1)%d->num_desc]->status
+ ==d->buf_size) {
/* other part of packet not written yet */
/* this should never happen I think */
/* anyway we'll get it on the next call */
@@ -1822,7 +1255,7 @@ static void dma_rcv_bh(void *data)
split_ptr += d->buf_size-offset;
insert_dma_buffer(d, idx);
idx = (idx+1) % d->num_desc;
- buf_ptr = d->buf[idx];
+ buf_ptr = d->buf_cpu[idx];
offset=0;
while (split_left >= d->buf_size) {
memcpy(split_ptr,buf_ptr,d->buf_size);
@@ -1830,7 +1263,7 @@ static void dma_rcv_bh(void *data)
split_left -= d->buf_size;
insert_dma_buffer(d, idx);
idx = (idx+1) % d->num_desc;
- buf_ptr = d->buf[idx];
+ buf_ptr = d->buf_cpu[idx];
}
if (split_left>0) {
memcpy(split_ptr, buf_ptr, split_left);
@@ -1838,17 +1271,6 @@ static void dma_rcv_bh(void *data)
buf_ptr += offset/4;
}
- /*
- * Tip by James Goodwin <jamesg@Filanet.com>
- * We need to handle write requests that are received
- * to our middle address space (posted writes).
- * In this case, the hardware generates an
- * ack_complete... but, if we pass the packet up to
- * the subsystem, it will try and send a response
- * (which it shouldn't), because it assumes we
- * returned ack_pending.
- */
-
/*
* We get one phy packet for each bus reset.
* we know that from now on the bus topology may
@@ -1862,22 +1284,12 @@ static void dma_rcv_bh(void *data)
(d->spb[length/4-1]>>16)&0x1f,
(d->spb[length/4-1]>>21)&0x3,
tcode, length, d->spb[3], d->ctx);
+
+ ack = (((d->spb[length/4-1]>>16)&0x1f)
+ == 0x11) ? 1 : 0;
- /*
- * Tip by James Goodwin <jamesg@Filanet.com>
- * Handle case of posted writes. If we receive
- * an ack_complete, we should not send a
- * response. Fake out upper layers by turning
- * the packet into a broadcast packet... we
- * should really modify the core stack to
- * accept an ack received argument and figure
- * out whether to reply.
- */
- if (((d->spb[length/4-1]>>16)&0x1f) == 0x11) {
- d->spb[0] |= (ALL_NODES<<16);
- }
hpsb_packet_received(ohci->host, d->spb,
- length);
+ length, ack);
}
else
PRINT(KERN_INFO, ohci->id,
@@ -1899,21 +1311,11 @@ static void dma_rcv_bh(void *data)
(buf_ptr[length/4-1]>>21)&0x3,
tcode, length, buf_ptr[3], d->ctx);
- /*
- * Tip by James Goodwin <jamesg@Filanet.com>
- * Handle case of posted writes. If we receive
- * an ack_complete, we should not send a
- * response. Fake out upper layers by turning
- * the packet into a broadcast packet... we
- * should really modify the core stack to
- * accept an ack received argument and figure
- * out whether to reply.
- */
- if (((d->spb[length/4-1]>>16)&0x1f) == 0x11) {
- buf_ptr[0] |= (ALL_NODES<<16);
- }
+ ack = (((buf_ptr[length/4-1]>>16)&0x1f)
+ == 0x11) ? 1 : 0;
+
hpsb_packet_received(ohci->host, buf_ptr,
- length);
+ length, ack);
}
else
PRINT(KERN_INFO, ohci->id,
@@ -1924,11 +1326,11 @@ static void dma_rcv_bh(void *data)
if (offset==d->buf_size) {
insert_dma_buffer(d, idx);
idx = (idx+1) % d->num_desc;
- buf_ptr = d->buf[idx];
+ buf_ptr = d->buf_cpu[idx];
offset=0;
}
}
- rescount = d->prg[idx]->status & 0xffff;
+ rescount = d->prg_cpu[idx]->status & 0xffff;
bytes_left = d->buf_size - rescount - offset;
}
@@ -1945,32 +1347,51 @@ static void dma_trm_bh(void *data)
struct dma_trm_ctx *d = (struct dma_trm_ctx*)data;
struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
struct hpsb_packet *packet;
+ unsigned long flags;
u32 ack;
- spin_lock(&d->lock);
+ spin_lock_irqsave(&d->lock, flags);
- if (d->first==NULL) {
- stop_context(ohci, d->ctrlClear,
+ if (d->fifo_first==NULL) {
+#if 0
+ ohci1394_stop_context(ohci, d->ctrlClear,
"Packet sent ack received but queue is empty");
- spin_unlock(&d->lock);
+#endif
+ spin_unlock_irqrestore(&d->lock, flags);
return;
}
- packet = d->first;
- d->first = d->first->xnext;
- if (d->first==NULL) d->last=NULL;
- if (packet->data_size)
- ack = d->prg[d->sent_ind].end.status>>16;
- else
- ack = d->prg[d->sent_ind].begin.status>>16;
- d->sent_ind = (d->sent_ind+1)%d->num_desc;
- d->free_prgs++;
- spin_unlock(&d->lock);
- if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq);
+ while (d->fifo_first) {
+ packet = d->fifo_first;
+ if (packet->data_size)
+ ack = d->prg_cpu[d->sent_ind]->end.status>>16;
+ else
+ ack = d->prg_cpu[d->sent_ind]->begin.status>>16;
+
+ if (ack==0)
+ /* this packet hasn't been sent yet*/
+ break;
+
+ DBGMSG(ohci->id,
+ "Packet sent to node %d ack=0x%X spd=%d ctx=%d",
+ (packet->header[0]>>16)&0x3f, ack&0x1f, (ack>>5)&0x3,
+ d->ctx);
+ hpsb_packet_sent(ohci->host, packet, ack&0xf);
+
+ if (packet->data_size)
+ pci_unmap_single(ohci->dev,
+ d->prg_cpu[d->sent_ind]->end.address,
+ packet->data_size, PCI_DMA_TODEVICE);
+
+ d->sent_ind = (d->sent_ind+1)%d->num_desc;
+ d->free_prgs++;
+ d->fifo_first = d->fifo_first->xnext;
+ }
+ if (d->fifo_first==NULL) d->fifo_last=NULL;
+
+ dma_trm_flush(ohci, d);
- DBGMSG(ohci->id, "Packet sent to node %d ack=0x%X spd=%d ctx=%d",
- (packet->header[0]>>16)&0x3f, ack&0x1f, (ack>>5)&0x3, d->ctx);
- hpsb_packet_sent(ohci->host, packet, ack&0xf);
+ spin_unlock_irqrestore(&d->lock, flags);
}
static int free_dma_rcv_ctx(struct dma_rcv_ctx **d)
@@ -1984,17 +1405,25 @@ static int free_dma_rcv_ctx(struct dma_rcv_ctx **d)
DBGMSG(ohci->id, "Freeing dma_rcv_ctx %d",(*d)->ctx);
- stop_context(ohci, (*d)->ctrlClear, NULL);
+ ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL);
- if ((*d)->buf) {
- for (i=0; i<(*d)->num_desc; i++)
- if ((*d)->buf[i]) kfree((*d)->buf[i]);
- kfree((*d)->buf);
- }
- if ((*d)->prg) {
+ if ((*d)->buf_cpu) {
for (i=0; i<(*d)->num_desc; i++)
- if ((*d)->prg[i]) kfree((*d)->prg[i]);
- kfree((*d)->prg);
+ if ((*d)->buf_cpu[i] && (*d)->buf_bus[i])
+ pci_free_consistent(
+ ohci->dev, (*d)->buf_size,
+ (*d)->buf_cpu[i], (*d)->buf_bus[i]);
+ kfree((*d)->buf_cpu);
+ kfree((*d)->buf_bus);
+ }
+ if ((*d)->prg_cpu) {
+ for (i=0; i<(*d)->num_desc; i++)
+ if ((*d)->prg_cpu[i] && (*d)->prg_bus[i])
+ pci_free_consistent(
+ ohci->dev, sizeof(struct dma_cmd),
+ (*d)->prg_cpu[i], (*d)->prg_bus[i]);
+ kfree((*d)->prg_cpu);
+ kfree((*d)->prg_bus);
}
if ((*d)->spb) kfree((*d)->spb);
@@ -2030,27 +1459,34 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
d->ctrlClear = ctrlClear;
d->cmdPtr = cmdPtr;
- d->buf = NULL;
- d->prg = NULL;
+ d->buf_cpu = NULL;
+ d->buf_bus = NULL;
+ d->prg_cpu = NULL;
+ d->prg_bus = NULL;
d->spb = NULL;
- d->buf = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL);
+ d->buf_cpu = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL);
+ d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);
- if (d->buf == NULL) {
+ if (d->buf_cpu == NULL || d->buf_bus == NULL) {
PRINT(KERN_ERR, ohci->id, "failed to allocate dma buffer");
free_dma_rcv_ctx(&d);
return NULL;
}
- memset(d->buf, 0, d->num_desc * sizeof(quadlet_t*));
+ memset(d->buf_cpu, 0, d->num_desc * sizeof(quadlet_t*));
+ memset(d->buf_bus, 0, d->num_desc * sizeof(dma_addr_t));
- d->prg = kmalloc(d->num_desc * sizeof(struct dma_cmd*), GFP_KERNEL);
+ d->prg_cpu = kmalloc(d->num_desc * sizeof(struct dma_cmd*),
+ GFP_KERNEL);
+ d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);
- if (d->prg == NULL) {
+ if (d->prg_cpu == NULL || d->prg_bus == NULL) {
PRINT(KERN_ERR, ohci->id, "failed to allocate dma prg");
free_dma_rcv_ctx(&d);
return NULL;
}
- memset(d->prg, 0, d->num_desc * sizeof(struct dma_cmd*));
+ memset(d->prg_cpu, 0, d->num_desc * sizeof(struct dma_cmd*));
+ memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t));
d->spb = kmalloc(d->split_buf_size, GFP_KERNEL);
@@ -2061,10 +1497,12 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
}
for (i=0; i<d->num_desc; i++) {
- d->buf[i] = kmalloc(d->buf_size, GFP_KERNEL);
+ d->buf_cpu[i] = pci_alloc_consistent(ohci->dev,
+ d->buf_size,
+ d->buf_bus+i);
- if (d->buf[i] != NULL) {
- memset(d->buf[i], 0, d->buf_size);
+ if (d->buf_cpu[i] != NULL) {
+ memset(d->buf_cpu[i], 0, d->buf_size);
} else {
PRINT(KERN_ERR, ohci->id,
"failed to allocate dma buffer");
@@ -2072,10 +1510,13 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
return NULL;
}
- d->prg[i]= kmalloc(sizeof(struct dma_cmd), GFP_KERNEL);
+
+ d->prg_cpu[i] = pci_alloc_consistent(ohci->dev,
+ sizeof(struct dma_cmd),
+ d->prg_bus+i);
- if (d->prg[i] != NULL) {
- memset(d->prg[i], 0, sizeof(struct dma_cmd));
+ if (d->prg_cpu[i] != NULL) {
+ memset(d->prg_cpu[i], 0, sizeof(struct dma_cmd));
} else {
PRINT(KERN_ERR, ohci->id,
"failed to allocate dma prg");
@@ -2098,6 +1539,7 @@ alloc_dma_rcv_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
static int free_dma_trm_ctx(struct dma_trm_ctx **d)
{
struct ti_ohci *ohci;
+ int i;
if (*d==NULL) return -1;
@@ -2105,9 +1547,18 @@ static int free_dma_trm_ctx(struct dma_trm_ctx **d)
DBGMSG(ohci->id, "Freeing dma_trm_ctx %d",(*d)->ctx);
- stop_context(ohci, (*d)->ctrlClear, NULL);
+ ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL);
+
+ if ((*d)->prg_cpu) {
+ for (i=0; i<(*d)->num_desc; i++)
+ if ((*d)->prg_cpu[i] && (*d)->prg_bus[i])
+ pci_free_consistent(
+ ohci->dev, sizeof(struct at_dma_prg),
+ (*d)->prg_cpu[i], (*d)->prg_bus[i]);
+ kfree((*d)->prg_cpu);
+ kfree((*d)->prg_bus);
+ }
- if ((*d)->prg) kfree((*d)->prg);
kfree(*d);
*d = NULL;
return 0;
@@ -2118,6 +1569,7 @@ alloc_dma_trm_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
int ctrlSet, int ctrlClear, int cmdPtr)
{
struct dma_trm_ctx *d=NULL;
+ int i;
d = (struct dma_trm_ctx *)kmalloc(sizeof(struct dma_trm_ctx),
GFP_KERNEL);
@@ -2133,16 +1585,35 @@ alloc_dma_trm_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
d->ctrlSet = ctrlSet;
d->ctrlClear = ctrlClear;
d->cmdPtr = cmdPtr;
- d->prg = NULL;
+ d->prg_cpu = NULL;
+ d->prg_bus = NULL;
- d->prg = kmalloc(d->num_desc * sizeof(struct at_dma_prg), GFP_KERNEL);
+ d->prg_cpu = kmalloc(d->num_desc * sizeof(struct at_dma_prg*),
+ GFP_KERNEL);
+ d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);
- if (d->prg == NULL) {
+ if (d->prg_cpu == NULL || d->prg_bus == NULL) {
PRINT(KERN_ERR, ohci->id, "failed to allocate at dma prg");
free_dma_trm_ctx(&d);
return NULL;
}
- memset(d->prg, 0, d->num_desc * sizeof(struct at_dma_prg));
+ memset(d->prg_cpu, 0, d->num_desc * sizeof(struct at_dma_prg*));
+ memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t));
+
+ for (i=0; i<d->num_desc; i++) {
+ d->prg_cpu[i] = pci_alloc_consistent(ohci->dev,
+ sizeof(struct at_dma_prg),
+ d->prg_bus+i);
+
+ if (d->prg_cpu[i] != NULL) {
+ memset(d->prg_cpu[i], 0, sizeof(struct at_dma_prg));
+ } else {
+ PRINT(KERN_ERR, ohci->id,
+ "failed to allocate at dma prg");
+ free_dma_trm_ctx(&d);
+ return NULL;
+ }
+ }
spin_lock_init(&d->lock);
@@ -2150,15 +1621,42 @@ alloc_dma_trm_ctx(struct ti_ohci *ohci, int ctx, int num_desc,
d->task.routine = dma_trm_bh;
d->task.data = (void*)d;
- init_waitqueue_head(&d->waitq);
-
return d;
}
+static u32 ohci_crc16(unsigned *data, int length)
+{
+ int check=0, i;
+ int shift, sum, next=0;
+
+ for (i = length; i; i--) {
+ for (next = check, shift = 28; shift >= 0; shift -= 4 ) {
+ sum = ((next >> 12) ^ (*data >> shift)) & 0xf;
+ next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
+ }
+ check = next & 0xffff;
+ data++;
+ }
+
+ return check;
+}
+
+static void ohci_init_config_rom(struct ti_ohci *ohci)
+{
+ int i;
+
+ ohci_csr_rom[3] = reg_read(ohci, OHCI1394_GUIDHi);
+ ohci_csr_rom[4] = reg_read(ohci, OHCI1394_GUIDLo);
+
+ ohci_csr_rom[0] = 0x04040000 | ohci_crc16(ohci_csr_rom+1, 4);
+
+ for (i=0;i<sizeof(ohci_csr_rom)/4;i++)
+ ohci->csr_config_rom_cpu[i] = cpu_to_be32(ohci_csr_rom[i]);
+}
+
static int add_card(struct pci_dev *dev)
{
struct ti_ohci *ohci; /* shortcut to currently handled device */
- int i;
if (num_of_cards == MAX_OHCI1394_CARDS) {
PRINT_G(KERN_WARNING, "cannot handle more than %d cards. "
@@ -2182,21 +1680,29 @@ static int add_card(struct pci_dev *dev)
ohci->state = 0;
/* csr_config rom allocation */
- ohci->csr_config_rom = kmalloc(1024, GFP_KERNEL);
- if (ohci->csr_config_rom == NULL) {
+ ohci->csr_config_rom_cpu =
+ pci_alloc_consistent(ohci->dev, sizeof(ohci_csr_rom),
+ &ohci->csr_config_rom_bus);
+ if (ohci->csr_config_rom_cpu == NULL) {
FAIL("failed to allocate buffer config rom");
}
- for (i=0;i<sizeof(ohci_csr_rom)/4;i++)
- ohci->csr_config_rom[i] = cpu_to_be32(ohci_csr_rom[i]);
DBGMSG(ohci->id, "The 1st byte at offset 0x404 is: 0x%02x",
- *((char *)ohci->csr_config_rom+4));
+ *((char *)ohci->csr_config_rom_cpu+4));
- /* self-id dma buffer allocation */
- ohci->self_id_buffer = kmalloc(2048, GFP_KERNEL);
- if (ohci->self_id_buffer == NULL) {
+ /*
+ * self-id dma buffer allocation
+ * FIXME: some early chips may need 8KB alignment for the
+ * selfid buffer
+ */
+ ohci->selfid_buf_cpu =
+ pci_alloc_consistent(ohci->dev, 2048, &ohci->selfid_buf_bus);
+ if (ohci->selfid_buf_cpu == NULL) {
FAIL("failed to allocate DMA buffer for self-id packets");
}
+ if ((unsigned long)ohci->selfid_buf_cpu & 0xfff)
+ PRINT(KERN_INFO, ohci->id, "Selfid buffer %p not aligned on "
+ "8Kb boundary", ohci->selfid_buf_cpu);
ohci->ar_req_context =
alloc_dma_rcv_ctx(ohci, 0, AR_REQ_NUM_DESC,
@@ -2241,9 +1747,9 @@ static int add_card(struct pci_dev *dev)
ohci->ir_context =
alloc_dma_rcv_ctx(ohci, 2, IR_NUM_DESC,
IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
- OHCI1394_IrRcvContextControlSet,
- OHCI1394_IrRcvContextControlClear,
- OHCI1394_IrRcvCommandPtr);
+ OHCI1394_IsoRcvContextControlSet,
+ OHCI1394_IsoRcvContextControlClear,
+ OHCI1394_IsoRcvCommandPtr);
if (ohci->ir_context == NULL) {
FAIL("failed to allocate IR context");
@@ -2274,6 +1780,8 @@ static int add_card(struct pci_dev *dev)
FAIL("failed to allocate shared interrupt %d", dev->irq);
}
+ ohci_init_config_rom(ohci);
+
return 0;
#undef FAIL
}
@@ -2297,12 +1805,9 @@ int ohci_get_info(char *buf, char **start, off_t fpos,
//unsigned char phyreg;
//int i, nports;
int i;
+
struct dma_rcv_ctx *d=NULL;
struct dma_trm_ctx *dt=NULL;
-#ifdef _VIDEO_1394_H
- int j;
- struct dma_fbuf_ctx *f=ohci->fbuf_context[0];
-#endif
p += sprintf(p,"IEEE-1394 OHCI Driver status report:\n");
p += sprintf(p," bus number: 0x%x Node ID: 0x%x\n",
@@ -2332,26 +1837,6 @@ int ohci_get_info(char *buf, char **start, off_t fpos,
p += sprintf(p,"\n---Iso Receive DMA---\n");
-#ifdef _VIDEO_1394_H
-
-#if 0
- if (f!=NULL) {
- for (i=0; i<f->num_desc; i++) {
- for (j=0;j<f->nb_cmd;j++) {
- p += sprintf(p,
- "prg[%d][%d]: %p %08x %08x %08x %08x\n",
- i,j,virt_to_bus(&(f->prg[i][j])),
- f->prg[i][j].control,
- f->prg[i][j].address,
- f->prg[i][j].branchAddress,
- f->prg[i][j].status);
- }
- }
- }
-#endif
-
-#else
-
d = ohci->ir_context;
#if 0
for (i=0; i<d->num_desc; i++) {
@@ -2389,7 +1874,7 @@ int ohci_get_info(char *buf, char **start, off_t fpos,
dt->prg_ind, dt->sent_ind, dt->free_prgs,
dt->branchAddrPtr);
p += sprintf(p, "AT req queue: first: %p last: %p\n",
- dt->first, dt->last);
+ dt->fifo_first, dt->fifo_last);
dt = ohci->at_resp_context;
#if 0
for (i=0; i<dt->num_desc; i++) {
@@ -2437,15 +1922,14 @@ int ohci_get_info(char *buf, char **start, off_t fpos,
dt->prg_ind, dt->sent_ind, dt->free_prgs,
dt->branchAddrPtr);
p += sprintf(p, "AT resp queue: first: %p last: %p\n",
- dt->first, dt->last);
-#endif
+ dt->fifo_first, dt->fifo_last);
/* ----- Register Dump ----- */
p += sprintf(p,"\n### HC Register dump ###\n");
SR("Version : %08x GUID_ROM : %08x ATRetries : %08x\n",
OHCI1394_Version, OHCI1394_GUID_ROM, OHCI1394_ATRetries);
- SR("CSRReadData : %08x CSRCompData : %08x CSRControl : %08x\n",
- OHCI1394_CSRReadData, OHCI1394_CSRCompareData, OHCI1394_CSRControl);
+ SR("CSRData : %08x CSRCompData : %08x CSRControl : %08x\n",
+ OHCI1394_CSRData, OHCI1394_CSRCompareData, OHCI1394_CSRControl);
SR("ConfigROMhdr: %08x BusID : %08x BusOptions : %08x\n",
OHCI1394_ConfigROMhdr, OHCI1394_BusID, OHCI1394_BusOptions);
SR("GUIDHi : %08x GUIDLo : %08x ConfigROMmap: %08x\n",
@@ -2481,14 +1965,21 @@ int ohci_get_info(char *buf, char **start, off_t fpos,
SR("AsRsRvCtxCtl: %08x AsRsRvCmdPtr: %08x IntEvent : %08x\n",
OHCI1394_AsRspRcvContextControlSet, OHCI1394_AsRspRcvCommandPtr,
OHCI1394_IntEventSet);
- for (i=0;i<4;i++) {
+ for (i=0;i<ohci->nb_iso_rcv_ctx;i++) {
p += sprintf(p,"IsoRCtxCtl%02d: %08x IsoRCmdPtr%02d: %08x"
" IsoRCxtMch%02d: %08x\n", i,
reg_read(ohci,
- OHCI1394_IrRcvContextControlSet+32*i),
- i,reg_read(ohci, OHCI1394_IrRcvCommandPtr+32*i),
+ OHCI1394_IsoRcvContextControlSet+32*i),
+ i,reg_read(ohci, OHCI1394_IsoRcvCommandPtr+32*i),
i,reg_read(ohci,
- OHCI1394_IrRcvContextMatch+32*i));
+ OHCI1394_IsoRcvContextMatch+32*i));
+ }
+ for (i=0;i<ohci->nb_iso_xmit_ctx;i++) {
+ p += sprintf(p,"IsoTCtxCtl%02d: %08x IsoTCmdPtr%02d: %08x\n",
+ i,
+ reg_read(ohci,
+ OHCI1394_IsoXmitContextControlSet+32*i),
+ i,reg_read(ohci,OHCI1394_IsoXmitCommandPtr+32*i));
}
#if 0
@@ -2554,9 +2045,11 @@ struct proc_dir_entry ohci_proc_entry =
static void remove_card(struct ti_ohci *ohci)
{
-#ifdef _VIDEO_1394_H
- int i;
-#endif
+ /*
+ * Reset the board properly before leaving
+ * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de>
+ */
+ ohci_soft_reset(ohci);
/* Free AR dma */
free_dma_rcv_ctx(&ohci->ar_req_context);
@@ -2569,28 +2062,18 @@ static void remove_card(struct ti_ohci *ohci)
/* Free IR dma */
free_dma_rcv_ctx(&ohci->ir_context);
-#ifdef _VIDEO_1394_H
- /* Free the frame buffer context */
- if (ohci->fbuf_context)
- for (i=0;i<ohci->nb_iso_ctx-1;i++) {
- free_dma_fbuf_ctx(&ohci->fbuf_context[i]);
- }
-#endif
-
- /*
- * Reset the board properly before leaving
- * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de>
- */
- ohci_soft_reset(ohci);
-
/* Free self-id buffer */
- if (ohci->self_id_buffer)
- kfree(ohci->self_id_buffer);
+ if (ohci->selfid_buf_cpu)
+ pci_free_consistent(ohci->dev, 2048,
+ ohci->selfid_buf_cpu,
+ ohci->selfid_buf_bus);
/* Free config rom */
- if (ohci->csr_config_rom)
- kfree(ohci->csr_config_rom);
-
+ if (ohci->csr_config_rom_cpu)
+ pci_free_consistent(ohci->dev, sizeof(ohci_csr_rom),
+ ohci->csr_config_rom_cpu,
+ ohci->csr_config_rom_bus);
+
/* Free the IRQ */
free_irq(ohci->dev->irq, ohci);
@@ -2646,9 +2129,9 @@ static size_t get_ohci_rom(struct hpsb_host *host, const quadlet_t **ptr)
struct ti_ohci *ohci=host->hostdata;
DBGMSG(ohci->id, "request csr_rom address: %08X",
- (u32)ohci->csr_config_rom);
+ (u32)ohci->csr_config_rom_cpu);
- *ptr = ohci->csr_config_rom;
+ *ptr = ohci->csr_config_rom_cpu;
return sizeof(ohci_csr_rom);
}
@@ -2675,6 +2158,118 @@ struct hpsb_host_template *get_ohci_template(void)
return &tmpl;
}
+void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg)
+{
+ int i=0;
+
+ /* stop the channel program if it's still running */
+ reg_write(ohci, reg, 0x8000);
+
+ /* Wait until it effectively stops */
+ while (reg_read(ohci, reg) & 0x400) {
+ i++;
+ if (i>5000) {
+ PRINT(KERN_ERR, ohci->id,
+ "runaway loop while stopping context...");
+ break;
+ }
+ }
+ if (msg) PRINT(KERN_ERR, ohci->id, "%s\n dma prg stopped\n", msg);
+}
+
+struct ti_ohci *ohci1394_get_struct(int card_num)
+{
+ if (card_num>=0 && card_num<num_of_cards)
+ return &cards[card_num];
+ return NULL;
+}
+
+int ohci1394_register_video(struct ti_ohci *ohci,
+ struct video_template *tmpl)
+{
+ if (ohci->video_tmpl)
+ return -ENFILE;
+ ohci->video_tmpl = tmpl;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+void ohci1394_unregister_video(struct ti_ohci *ohci,
+ struct video_template *tmpl)
+{
+ if (ohci->video_tmpl != tmpl) {
+ PRINT(KERN_ERR, ohci->id,
+ "Trying to unregister wrong video device");
+ }
+ else {
+ ohci->video_tmpl = NULL;
+ MOD_DEC_USE_COUNT;
+ }
+}
+
+#if 0
+int ohci_compare_swap(struct ti_ohci *ohci, quadlet_t *data,
+ quadlet_t compare, int sel)
+{
+ int timeout = 255;
+ reg_write(ohci, OHCI1394_CSRData, *data);
+ reg_write(ohci, OHCI1394_CSRCompareData, compare);
+ reg_write(ohci, OHCI1394_CSRControl, sel);
+ while(!(reg_read(ohci, OHCI1394_CSRControl)&0x80000000)) {
+ if (timeout--) {
+ PRINT(KERN_INFO, ohci->id, "request_channel timeout");
+ return -1;
+ }
+ }
+ *data = reg_read(ohci, OHCI1394_CSRData);
+ return 0;
+}
+
+int ohci1394_request_channel(struct ti_ohci *ohci, int channel)
+{
+ int csrSel;
+ quadlet_t chan, data1=0, data2=0;
+ int timeout = 32;
+
+ if (channel<32) {
+ chan = 1<<channel;
+ csrSel = 2;
+ }
+ else {
+ chan = 1<<(channel-32);
+ csrSel = 3;
+ }
+ if (ohci_compare_swap(ohci, &data1, 0, csrSel)<0) {
+ PRINT(KERN_INFO, ohci->id, "request_channel timeout");
+ return -1;
+ }
+ while (timeout--) {
+ if (data1 & chan) {
+ PRINT(KERN_INFO, ohci->id,
+ "request channel %d failed", channel);
+ return -1;
+ }
+ data2 = data1;
+ data1 |= chan;
+ if (ohci_compare_swap(ohci, &data1, data2, csrSel)<0) {
+ PRINT(KERN_INFO, ohci->id, "request_channel timeout");
+ return -1;
+ }
+ if (data1==data2) {
+ PRINT(KERN_INFO, ohci->id,
+ "request channel %d succeded", channel);
+ return 0;
+ }
+ }
+ PRINT(KERN_INFO, ohci->id, "request channel %d failed", channel);
+ return -1;
+}
+#endif
+
+EXPORT_SYMBOL(ohci1394_stop_context);
+EXPORT_SYMBOL(ohci1394_get_struct);
+EXPORT_SYMBOL(ohci1394_register_video);
+EXPORT_SYMBOL(ohci1394_unregister_video);
#ifdef MODULE
@@ -2695,10 +2290,6 @@ void cleanup_module(void)
#endif
#endif
-#ifdef _VIDEO_1394_H
- unregister_chrdev(OHCI1394_MAJOR, "ohci1394");
-#endif
-
PRINT_G(KERN_INFO, "removed " OHCI1394_DRIVER_NAME " module\n");
}
@@ -2709,17 +2300,8 @@ int init_module(void)
if (hpsb_register_lowlevel(get_ohci_template())) {
PRINT_G(KERN_ERR, "registering failed\n");
return -ENXIO;
- } else {
-#ifdef _VIDEO_1394_H
- if (register_chrdev(OHCI1394_MAJOR, "ohci1394", &ohci_fops))
- {
- printk("ohci1394: unable to get major %d\n",
- OHCI1394_MAJOR);
- return -EIO;
- }
-#endif
- return 0;
- }
+ }
+ return 0;
}
#endif /* MODULE */
diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h
index d778cbe7d..af1aeb2a6 100644
--- a/drivers/ieee1394/ohci1394.h
+++ b/drivers/ieee1394/ohci1394.h
@@ -22,8 +22,8 @@
#define _OHCI1394_H
#include "ieee1394_types.h"
-/* include this for the video frame grabber */
-/* #include "video1394.h" */
+
+#define IEEE1394_USE_BOTTOM_HALVES 0
#define OHCI1394_DRIVER_NAME "ohci1394"
@@ -71,6 +71,18 @@
#define PCI_DEVICE_ID_APPLE_UNI_N_FW 0x0018
#endif
+#ifndef PCI_DEVICE_ID_ALI_OHCI1394_M5251
+#define PCI_DEVICE_ID_ALI_OHCI1394_M5251 0x5251
+#endif
+
+#ifndef PCI_VENDOR_ID_LUCENT
+#define PCI_VENDOR_ID_LUCENT 0x11c1
+#endif
+
+#ifndef PCI_DEVICE_ID_LUCENT_FW323
+#define PCI_DEVICE_ID_LUCENT_FW323 0x5811
+#endif
+
#define MAX_OHCI1394_CARDS 4
#define OHCI1394_MAX_AT_REQ_RETRIES 0x2
@@ -87,8 +99,8 @@
#define AR_RESP_SPLIT_BUF_SIZE 4096 /* split packet buffer */
#define IR_NUM_DESC 16 /* number of IR descriptors */
-#define IR_BUF_SIZE 6480 /* 6480 bytes/buffer */
-#define IR_SPLIT_BUF_SIZE 8192 /* split packet buffer */
+#define IR_BUF_SIZE 4096 /* 6480 bytes/buffer */
+#define IR_SPLIT_BUF_SIZE 4096 /* split packet buffer */
#define AT_REQ_NUM_DESC 32 /* number of AT req descriptors */
#define AT_RESP_NUM_DESC 32 /* number of AT resp descriptors */
@@ -113,8 +125,15 @@ struct dma_rcv_ctx {
unsigned int num_desc;
unsigned int buf_size;
unsigned int split_buf_size;
- struct dma_cmd **prg;
- quadlet_t **buf;
+
+ /* dma block descriptors */
+ struct dma_cmd **prg_cpu;
+ dma_addr_t *prg_bus;
+
+ /* dma buffers */
+ quadlet_t **buf_cpu;
+ dma_addr_t *buf_bus;
+
unsigned int buf_ind;
unsigned int buf_offset;
quadlet_t *spb;
@@ -130,45 +149,37 @@ struct dma_trm_ctx {
void *ohci;
int ctx;
unsigned int num_desc;
- struct at_dma_prg *prg;
+
+ /* dma block descriptors */
+ struct at_dma_prg **prg_cpu;
+ dma_addr_t *prg_bus;
+
unsigned int prg_ind;
unsigned int sent_ind;
int free_prgs;
quadlet_t *branchAddrPtr;
- struct hpsb_packet *first;
- struct hpsb_packet *last;
+
+ /* list of packets inserted in the AT FIFO */
+ struct hpsb_packet *fifo_first;
+ struct hpsb_packet *fifo_last;
+
+ /* list of pending packets to be inserted in the AT FIFO */
+ struct hpsb_packet *pending_first;
+ struct hpsb_packet *pending_last;
+
spinlock_t lock;
struct tq_struct task;
int ctrlClear;
int ctrlSet;
int cmdPtr;
- wait_queue_head_t waitq;
};
-#ifdef _VIDEO_1394_H
-
-#define OHCI1394_MAJOR 172
-#define ISO_CHANNELS 64
-
-struct dma_fbuf_ctx {
- void *ohci;
- int ctx;
- int channel;
- int last_buffer;
- unsigned int num_desc;
- unsigned int buf_size;
- unsigned int frame_size;
- unsigned int nb_cmd;
- unsigned char *buf;
- struct dma_cmd **prg;
- unsigned int *buffer_status;
- int ctrlClear;
- int ctrlSet;
- int cmdPtr;
- int ctxMatch;
- wait_queue_head_t waitq;
+/* video device template */
+struct video_template {
+ void (*irq_handler) (int card, quadlet_t isoRecvEvent,
+ quadlet_t isoXmitEvent);
};
-#endif
+
struct ti_ohci {
int id; /* sequential card number */
@@ -180,8 +191,13 @@ struct ti_ohci {
/* remapped memory spaces */
void *registers;
- quadlet_t *self_id_buffer; /* dma buffer for self-id packets */
- quadlet_t *csr_config_rom; /* buffer for csr config rom */
+ /* dma buffer for self-id packets */
+ quadlet_t *selfid_buf_cpu;
+ dma_addr_t selfid_buf_bus;
+
+ /* buffer for csr config rom */
+ quadlet_t *csr_config_rom_cpu;
+ dma_addr_t csr_config_rom_bus;
unsigned int max_packet_size;
@@ -197,13 +213,10 @@ struct ti_ohci {
struct dma_rcv_ctx *ir_context;
u64 IR_channel_usage;
spinlock_t IR_channel_lock;
- int nb_iso_ctx;
+ int nb_iso_rcv_ctx;
-#ifdef _VIDEO_1394_H
- /* frame buffer context */
- struct dma_fbuf_ctx **fbuf_context;
- struct dma_fbuf_ctx *current_fbuf_ctx;
-#endif
+ /* iso transmit */
+ int nb_iso_xmit_ctx;
/* IEEE-1394 part follows */
struct hpsb_host *host;
@@ -214,8 +227,23 @@ struct ti_ohci {
int self_id_errors;
int NumBusResets;
+
+ /* video device */
+ struct video_template *video_tmpl;
};
+inline static int cross_bound(unsigned long addr, unsigned int size)
+{
+ int cross=0;
+ if (size>PAGE_SIZE) {
+ cross = size/PAGE_SIZE;
+ size -= cross*PAGE_SIZE;
+ }
+ if ((PAGE_SIZE-addr%PAGE_SIZE)<size)
+ cross++;
+ return cross;
+}
+
/*
* Register read and write helper functions.
*/
@@ -310,7 +338,7 @@ quadlet_t ohci_csr_rom[] = {
#define OHCI1394_Version 0x000
#define OHCI1394_GUID_ROM 0x004
#define OHCI1394_ATRetries 0x008
-#define OHCI1394_CSRReadData 0x00C
+#define OHCI1394_CSRData 0x00C
#define OHCI1394_CSRCompareData 0x010
#define OHCI1394_CSRControl 0x014
#define OHCI1394_ConfigROMhdr 0x018
@@ -370,12 +398,18 @@ quadlet_t ohci_csr_rom[] = {
#define OHCI1394_AsRspRcvContextControlClear 0x1E4
#define OHCI1394_AsRspRcvCommandPtr 0x1EC
+/* Isochronous transmit registers */
+/* Add (32 * n) for context n */
+#define OHCI1394_IsoXmitContextControlSet 0x200
+#define OHCI1394_IsoXmitContextControlClear 0x204
+#define OHCI1394_IsoXmitCommandPtr 0x20C
+
/* Isochronous receive registers */
/* Add (32 * n) for context n */
-#define OHCI1394_IrRcvContextControlSet 0x400
-#define OHCI1394_IrRcvContextControlClear 0x404
-#define OHCI1394_IrRcvCommandPtr 0x40C
-#define OHCI1394_IrRcvContextMatch 0x410
+#define OHCI1394_IsoRcvContextControlSet 0x400
+#define OHCI1394_IsoRcvContextControlClear 0x404
+#define OHCI1394_IsoRcvCommandPtr 0x40C
+#define OHCI1394_IsoRcvContextMatch 0x410
/* Interrupts Mask/Events */
@@ -410,5 +444,12 @@ quadlet_t ohci_csr_rom[] = {
#define DMA_SPEED_200 0x1
#define DMA_SPEED_400 0x2
+void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg);
+struct ti_ohci *ohci1394_get_struct(int card_num);
+int ohci1394_register_video(struct ti_ohci *ohci,
+ struct video_template *tmpl);
+void ohci1394_unregister_video(struct ti_ohci *ohci,
+ struct video_template *tmpl);
+
#endif
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
index 368c5137b..16aeaa92d 100644
--- a/drivers/ieee1394/pcilynx.c
+++ b/drivers/ieee1394/pcilynx.c
@@ -82,7 +82,7 @@ static pcl_t alloc_pcl(struct ti_lynx *lynx)
spin_lock(&lynx->lock);
/* FIXME - use ffz() to make this readable */
- for (i = 0; i < LOCALRAM_SIZE; i++) {
+ for (i = 0; i < (LOCALRAM_SIZE / 1024); i++) {
m = lynx->pcl_bmap[i];
for (j = 0; j < 8; j++) {
if (m & 1<<j) {
@@ -385,11 +385,22 @@ static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host, size_t s
-/* This must be called with the async_queue_lock held. */
+/* This must be called with the async.queue_lock held. */
static void send_next_async(struct ti_lynx *lynx)
{
struct ti_pcl pcl;
- struct hpsb_packet *packet = lynx->async_queue;
+ struct hpsb_packet *packet = lynx->async.queue;
+
+ lynx->async.header_dma = pci_map_single(lynx->dev, packet->header,
+ packet->header_size,
+ PCI_DMA_TODEVICE);
+ if (packet->data_size) {
+ lynx->async.data_dma = pci_map_single(lynx->dev, packet->data,
+ packet->data_size,
+ PCI_DMA_TODEVICE);
+ } else {
+ lynx->async.data_dma = 0;
+ }
pcl.next = PCL_NEXT_INVALID;
pcl.async_error_next = PCL_NEXT_INVALID;
@@ -400,16 +411,16 @@ static void send_next_async(struct ti_lynx *lynx)
pcl.buffer[0].control = PCL_CMD_XMT | packet->speed_code << 14
| packet->header_size | PCL_BIGENDIAN;
#endif
- pcl.buffer[0].pointer = virt_to_bus(packet->header);
+ pcl.buffer[0].pointer = lynx->async.header_dma;
pcl.buffer[1].control = PCL_LAST_BUFF | packet->data_size;
- pcl.buffer[1].pointer = virt_to_bus(packet->data);
+ pcl.buffer[1].pointer = lynx->async.data_dma;
if (!packet->data_be) {
pcl.buffer[1].control |= PCL_BIGENDIAN;
}
- put_pcl(lynx, lynx->async_pcl, &pcl);
- run_pcl(lynx, lynx->async_pcl_start, 3);
+ put_pcl(lynx, lynx->async.pcl, &pcl);
+ run_pcl(lynx, lynx->async.pcl_start, 3);
}
@@ -440,8 +451,8 @@ static int lynx_initialize(struct hpsb_host *host)
int i;
u32 *pcli;
- lynx->async_queue = NULL;
- spin_lock_init(&lynx->async_queue_lock);
+ lynx->async.queue = NULL;
+ spin_lock_init(&lynx->async.queue_lock);
spin_lock_init(&lynx->phy_reg_lock);
pcl.next = pcl_bus(lynx, lynx->rcv_pcl);
@@ -456,13 +467,13 @@ static int lynx_initialize(struct hpsb_host *host)
pcl.buffer[0].control = PCL_CMD_RCV | PCL_BIGENDIAN | 16;
pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
#endif
- pcl.buffer[0].pointer = virt_to_bus(lynx->rcv_page);
- pcl.buffer[1].pointer = virt_to_bus(lynx->rcv_page) + 16;
+ pcl.buffer[0].pointer = lynx->rcv_page_dma;
+ pcl.buffer[1].pointer = lynx->rcv_page_dma + 16;
put_pcl(lynx, lynx->rcv_pcl, &pcl);
- pcl.next = pcl_bus(lynx, lynx->async_pcl);
- pcl.async_error_next = pcl_bus(lynx, lynx->async_pcl);
- put_pcl(lynx, lynx->async_pcl_start, &pcl);
+ pcl.next = pcl_bus(lynx, lynx->async.pcl);
+ pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl);
+ put_pcl(lynx, lynx->async.pcl_start, &pcl);
pcl.next = PCL_NEXT_INVALID;
pcl.async_error_next = PCL_NEXT_INVALID;
@@ -476,7 +487,7 @@ static int lynx_initialize(struct hpsb_host *host)
int page = i / ISORCV_PER_PAGE;
int sec = i % ISORCV_PER_PAGE;
- pcl.buffer[0].pointer = virt_to_bus(lynx->iso_rcv.page[page])
+ pcl.buffer[0].pointer = lynx->iso_rcv.page_dma[page]
+ sec * MAX_ISORCV_SIZE;
pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4;
put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);
@@ -542,7 +553,9 @@ static void lynx_release(struct hpsb_host *host)
lynx = host->hostdata;
remove_card(lynx);
} else {
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
unregister_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME);
+#endif
}
}
@@ -568,13 +581,13 @@ static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
cpu_to_be32s(&packet->header[3]);
}
- spin_lock_irqsave(&lynx->async_queue_lock, flags);
+ spin_lock_irqsave(&lynx->async.queue_lock, flags);
- if (lynx->async_queue == NULL) {
- lynx->async_queue = packet;
+ if (lynx->async.queue == NULL) {
+ lynx->async.queue = packet;
send_next_async(lynx);
} else {
- p = lynx->async_queue;
+ p = lynx->async.queue;
while (p->xnext != NULL) {
p = p->xnext;
}
@@ -582,7 +595,7 @@ static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
p->xnext = packet;
}
- spin_unlock_irqrestore(&lynx->async_queue_lock, flags);
+ spin_unlock_irqrestore(&lynx->async.queue_lock, flags);
return 1;
}
@@ -637,13 +650,13 @@ static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
break;
case CANCEL_REQUESTS:
- spin_lock_irqsave(&lynx->async_queue_lock, flags);
+ spin_lock_irqsave(&lynx->async.queue_lock, flags);
reg_write(lynx, DMA3_CHAN_CTRL, 0);
- packet = lynx->async_queue;
- lynx->async_queue = NULL;
+ packet = lynx->async.queue;
+ lynx->async.queue = NULL;
- spin_unlock_irqrestore(&lynx->async_queue_lock, flags);
+ spin_unlock_irqrestore(&lynx->async.queue_lock, flags);
while (packet != NULL) {
lastpacket = packet;
@@ -696,7 +709,7 @@ static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
* IEEE-1394 functionality section END *
***************************************/
-
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
/* VFS functions for local bus / aux device access. Access to those
* is implemented as a character device instead of block devices
* because buffers are not wanted for this. Therefore llseek (from
@@ -710,7 +723,7 @@ static ssize_t mem_write(struct file*, const char*, size_t, loff_t*);
static struct file_operations aux_ops = {
- owner: THIS_MODULE,
+ OWNER_THIS_MODULE
/* FIXME: should have custom llseek with bounds checking */
read: mem_read,
write: mem_write,
@@ -735,18 +748,23 @@ static int mem_open(struct inode *inode, struct file *file)
enum { rom, aux, ram } type;
struct memdata *md;
+ V22_COMPAT_MOD_INC_USE_COUNT;
+
if (cid < PCILYNX_MINOR_AUX_START) {
/* just for completeness */
+ V22_COMPAT_MOD_DEC_USE_COUNT;
return -ENXIO;
} else if (cid < PCILYNX_MINOR_ROM_START) {
cid -= PCILYNX_MINOR_AUX_START;
if (cid >= num_of_cards || !cards[cid].aux_port) {
+ V22_COMPAT_MOD_DEC_USE_COUNT;
return -ENXIO;
}
type = aux;
} else if (cid < PCILYNX_MINOR_RAM_START) {
cid -= PCILYNX_MINOR_ROM_START;
if (cid >= num_of_cards || !cards[cid].local_rom) {
+ V22_COMPAT_MOD_DEC_USE_COUNT;
return -ENXIO;
}
type = rom;
@@ -755,6 +773,7 @@ static int mem_open(struct inode *inode, struct file *file)
* It is currently used inside the driver! */
cid -= PCILYNX_MINOR_RAM_START;
if (cid >= num_of_cards || !cards[cid].local_ram) {
+ V22_COMPAT_MOD_DEC_USE_COUNT;
return -ENXIO;
}
type = ram;
@@ -762,6 +781,7 @@ static int mem_open(struct inode *inode, struct file *file)
md = (struct memdata *)vmalloc(sizeof(struct memdata));
if (md == NULL) {
+ V22_COMPAT_MOD_DEC_USE_COUNT;
return -ENOMEM;
}
@@ -793,6 +813,7 @@ static int mem_release(struct inode *inode, struct file *file)
vfree(md);
+ V22_COMPAT_MOD_DEC_USE_COUNT;
return 0;
}
@@ -801,16 +822,15 @@ static unsigned int aux_poll(struct file *file, poll_table *pt)
struct memdata *md = (struct memdata *)file->private_data;
int cid = md->cid;
unsigned int mask;
- int intr_seen;
/* reading and writing is always allowed */
mask = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
if (md->type == aux) {
poll_wait(file, &cards[cid].aux_intr_wait, pt);
- intr_seen = atomic_read(&cards[cid].aux_intr_seen);
- if (atomic_read(&md->aux_intr_last_seen) != intr_seen) {
+ if (atomic_read(&md->aux_intr_last_seen)
+ != atomic_read(&cards[cid].aux_intr_seen)) {
mask |= POLLPRI;
atomic_inc(&md->aux_intr_last_seen);
}
@@ -956,7 +976,7 @@ static ssize_t mem_read(struct file *file, char *buffer, size_t count,
}
while (bcount >= 4) {
- retval = mem_dmaread(md, virt_to_phys(md->lynx->mem_dma_buffer)
+ retval = mem_dmaread(md, md->lynx->mem_dma_buffer_dma
+ count - bcount, bcount, off);
if (retval < 0) return retval;
@@ -1008,7 +1028,7 @@ static ssize_t mem_write(struct file *file, const char *buffer, size_t count,
file->f_pos += count;
return count;
}
-
+#endif /* CONFIG_IEEE1394_PCILYNX_PORTS */
/********************************************************
@@ -1028,6 +1048,7 @@ static void lynx_irq_handler(int irq, void *dev_id,
reg_write(lynx, LINK_INT_STATUS, linkint);
//printk("-%d- one interrupt: 0x%08x / 0x%08x\n", lynx->id, intmask, linkint);
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
if (intmask & PCI_INT_AUX_INT) {
atomic_inc(&lynx->aux_intr_seen);
wake_up_interruptible(&lynx->aux_intr_wait);
@@ -1036,6 +1057,7 @@ static void lynx_irq_handler(int irq, void *dev_id,
if (intmask & PCI_INT_DMA0_HLT) {
wake_up_interruptible(&lynx->mem_dma_intr_wait);
}
+#endif
if (intmask & PCI_INT_1394) {
@@ -1108,17 +1130,24 @@ static void lynx_irq_handler(int irq, void *dev_id,
u32 ack;
struct hpsb_packet *packet;
- spin_lock(&lynx->async_queue_lock);
+ spin_lock(&lynx->async.queue_lock);
ack = reg_read(lynx, DMA3_CHAN_STAT);
- packet = lynx->async_queue;
- lynx->async_queue = packet->xnext;
+ packet = lynx->async.queue;
+ lynx->async.queue = packet->xnext;
+
+ pci_unmap_single(lynx->dev, lynx->async.header_dma,
+ packet->header_size, PCI_DMA_TODEVICE);
+ if (packet->data_size) {
+ pci_unmap_single(lynx->dev, lynx->async.data_dma,
+ packet->data_size, PCI_DMA_TODEVICE);
+ }
- if (lynx->async_queue != NULL) {
+ if (lynx->async.queue != NULL) {
send_next_async(lynx);
}
- spin_unlock(&lynx->async_queue_lock);
+ spin_unlock(&lynx->async.queue_lock);
if (ack & DMA_CHAN_STAT_SPECIALACK) {
ack = (ack >> 15) & 0xf;
@@ -1150,7 +1179,7 @@ static void lynx_irq_handler(int irq, void *dev_id,
|| (*q_data >> 4 & 0xf) == TCODE_WRITEQ) {
cpu_to_be32s(q_data + 3);
}
- hpsb_packet_received(host, q_data, stat & 0x1fff);
+ hpsb_packet_received(host, q_data, stat & 0x1fff, 0);
}
run_pcl(lynx, lynx->rcv_pcl_start, 1);
@@ -1184,7 +1213,8 @@ static void iso_rcv_bh(struct ti_lynx *lynx)
"iso receive error on %d to 0x%p", idx, data);
} else {
hpsb_packet_received(lynx->host, data,
- lynx->iso_rcv.stat[idx] & 0x1fff);
+ lynx->iso_rcv.stat[idx] & 0x1fff,
+ 0);
}
spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
@@ -1210,12 +1240,11 @@ static int add_card(struct pci_dev *dev)
} while (0)
struct ti_lynx *lynx; /* shortcut to currently handled device */
- unsigned long page;
unsigned int i;
if (num_of_cards == MAX_PCILYNX_CARDS) {
PRINT_G(KERN_WARNING, "cannot handle more than %d cards. "
- "Adjust MAX_PCILYNX_CARDS in ti_pcilynx.h.",
+ "Adjust MAX_PCILYNX_CARDS in pcilynx.h.",
MAX_PCILYNX_CARDS);
return 1;
}
@@ -1225,6 +1254,10 @@ static int add_card(struct pci_dev *dev)
lynx->id = num_of_cards-1;
lynx->dev = dev;
+ if (!pci_dma_supported(dev, 0xffffffff)) {
+ FAIL("DMA address limits not supported for PCILynx hardware %d",
+ lynx->id);
+ }
if (pci_enable_device(dev)) {
FAIL("failed to enable PCILynx hardware %d", lynx->id);
}
@@ -1239,61 +1272,50 @@ static int add_card(struct pci_dev *dev)
}
#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
- lynx->pcl_mem = kmalloc(8 * sizeof(lynx->pcl_bmap)
- * sizeof(struct ti_pcl), GFP_KERNEL);
+ lynx->pcl_mem = pci_alloc_consistent(dev, LOCALRAM_SIZE,
+ &lynx->pcl_mem_dma);
if (lynx->pcl_mem != NULL) {
lynx->state = have_pcl_mem;
PRINT(KERN_INFO, lynx->id,
- "allocated PCL memory %d Bytes @ 0x%p",
- 8 * sizeof(lynx->pcl_bmap) * sizeof(struct ti_pcl),
+ "allocated PCL memory %d Bytes @ 0x%p", LOCALRAM_SIZE,
lynx->pcl_mem);
} else {
FAIL("failed to allocate PCL memory area");
}
#endif
- lynx->mem_dma_buffer = kmalloc(65536, GFP_KERNEL);
- if (lynx->mem_dma_buffer != NULL) {
- lynx->state = have_aux_buf;
- } else {
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+ lynx->mem_dma_buffer = pci_alloc_consistent(dev, 65536,
+ &lynx->mem_dma_buffer_dma);
+ if (lynx->mem_dma_buffer == NULL) {
FAIL("failed to allocate DMA buffer for aux");
}
+ lynx->state = have_aux_buf;
+#endif
- page = get_free_page(GFP_KERNEL);
- if (page != 0) {
- lynx->rcv_page = (void *)page;
- lynx->state = have_1394_buffers;
- } else {
+ lynx->rcv_page = pci_alloc_consistent(dev, PAGE_SIZE,
+ &lynx->rcv_page_dma);
+ if (lynx->rcv_page == NULL) {
FAIL("failed to allocate receive buffer");
}
+ lynx->state = have_1394_buffers;
for (i = 0; i < ISORCV_PAGES; i++) {
- page = get_free_page(GFP_KERNEL);
- if (page != 0) {
- lynx->iso_rcv.page[i] = (void *)page;
- } else {
+ lynx->iso_rcv.page[i] =
+ pci_alloc_consistent(dev, PAGE_SIZE,
+ &lynx->iso_rcv.page_dma[i]);
+ if (lynx->iso_rcv.page[i] == NULL) {
FAIL("failed to allocate iso receive buffers");
}
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
- lynx->registers = ioremap_nocache(dev->base_address[0],
- PCILYNX_MAX_REGISTER);
- lynx->local_ram = ioremap(dev->base_address[1], PCILYNX_MAX_MEMORY);
- lynx->aux_port = ioremap(dev->base_address[2], PCILYNX_MAX_MEMORY);
-#else
lynx->registers = ioremap_nocache(pci_resource_start(dev,0),
PCILYNX_MAX_REGISTER);
lynx->local_ram = ioremap(pci_resource_start(dev,1), PCILYNX_MAX_MEMORY);
- lynx->aux_port = ioremap(pci_resource_start(dev,2), PCILYNX_MAX_MEMORY);
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,15)
- lynx->local_rom = ioremap(dev->rom_address, PCILYNX_MAX_MEMORY);
-#else
+ lynx->aux_port = ioremap(pci_resource_start(dev,2), PCILYNX_MAX_MEMORY);
lynx->local_rom = ioremap(pci_resource_start(dev,PCI_ROM_RESOURCE),
PCILYNX_MAX_MEMORY);
-#endif
lynx->state = have_iomappings;
if (lynx->registers == NULL) {
@@ -1309,15 +1331,17 @@ static int add_card(struct pci_dev *dev)
/* alloc_pcl return values are not checked, it is expected that the
* provided PCL space is sufficient for the initial allocations */
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
if (lynx->aux_port != NULL) {
lynx->dmem_pcl = alloc_pcl(lynx);
aux_setup_pcls(lynx);
sema_init(&lynx->mem_dma_mutex, 1);
}
+#endif
lynx->rcv_pcl = alloc_pcl(lynx);
lynx->rcv_pcl_start = alloc_pcl(lynx);
- lynx->async_pcl = alloc_pcl(lynx);
- lynx->async_pcl_start = alloc_pcl(lynx);
+ lynx->async.pcl = alloc_pcl(lynx);
+ lynx->async.pcl_start = alloc_pcl(lynx);
for (i = 0; i < NUM_ISORCV_PCL; i++) {
lynx->iso_rcv.pcl[i] = alloc_pcl(lynx);
@@ -1330,8 +1354,10 @@ static int add_card(struct pci_dev *dev)
reg_write(lynx, PCI_INT_ENABLE, PCI_INT_AUX_INT | PCI_INT_DMA_ALL);
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
init_waitqueue_head(&lynx->mem_dma_intr_wait);
init_waitqueue_head(&lynx->aux_intr_wait);
+#endif
lynx->iso_rcv.tq.routine = (void (*)(void*))iso_rcv_bh;
lynx->iso_rcv.tq.data = lynx;
@@ -1372,15 +1398,22 @@ static void remove_card(struct ti_lynx *lynx)
case have_1394_buffers:
for (i = 0; i < ISORCV_PAGES; i++) {
if (lynx->iso_rcv.page[i]) {
- free_page((unsigned long)lynx->iso_rcv.page[i]);
+ pci_free_consistent(lynx->dev, PAGE_SIZE,
+ lynx->iso_rcv.page[i],
+ lynx->iso_rcv.page_dma[i]);
}
}
- free_page((unsigned long)lynx->rcv_page);
+ pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page,
+ lynx->rcv_page_dma);
case have_aux_buf:
- kfree(lynx->mem_dma_buffer);
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
+ pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer,
+ lynx->mem_dma_buffer_dma);
+#endif
case have_pcl_mem:
#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
- kfree(lynx->pcl_mem);
+ pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem,
+ lynx->pcl_mem_dma);
#endif
case have_intr:
free_irq(lynx->dev->irq, lynx);
@@ -1416,11 +1449,13 @@ static int init_driver()
return -ENXIO;
}
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
if (register_chrdev(PCILYNX_MAJOR, PCILYNX_DRIVER_NAME, &aux_ops)) {
PRINT_G(KERN_ERR, "allocation of char major number %d failed",
PCILYNX_MAJOR);
return -EBUSY;
}
+#endif
return 0;
}
diff --git a/drivers/ieee1394/pcilynx.h b/drivers/ieee1394/pcilynx.h
index cf45d8d0a..ccb5a9f0b 100644
--- a/drivers/ieee1394/pcilynx.h
+++ b/drivers/ieee1394/pcilynx.h
@@ -12,7 +12,7 @@
#define PCI_DEVICE_ID_TI_PCILYNX 0x8000
#define MAX_PCILYNX_CARDS 4
-#define LOCALRAM_SIZE 64
+#define LOCALRAM_SIZE 4096
#define NUM_ISORCV_PCL 4
#define MAX_ISORCV_SIZE 2048
@@ -50,23 +50,27 @@ struct ti_lynx {
void *aux_port;
+#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
atomic_t aux_intr_seen;
wait_queue_head_t aux_intr_wait;
void *mem_dma_buffer;
+ dma_addr_t mem_dma_buffer_dma;
struct semaphore mem_dma_mutex;
wait_queue_head_t mem_dma_intr_wait;
+#endif
/*
- * use local RAM of LOCALRAM_SIZE (in kB) for PCLs, which allows for
+ * use local RAM of LOCALRAM_SIZE bytes for PCLs, which allows for
* LOCALRAM_SIZE * 8 PCLs (each sized 128 bytes);
* the following is an allocation bitmap
*/
- u8 pcl_bmap[LOCALRAM_SIZE];
+ u8 pcl_bmap[LOCALRAM_SIZE / 1024];
-#ifndef CONFIG_IEEE1394_LYNXRAM
+#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM
/* point to PCLs memory area if needed */
void *pcl_mem;
+ dma_addr_t pcl_mem_dma;
#endif
/* PCLs for local mem / aux transfers */
@@ -81,16 +85,21 @@ struct ti_lynx {
pcl_t rcv_pcl_start, rcv_pcl;
void *rcv_page;
+ dma_addr_t rcv_page_dma;
int rcv_active;
- pcl_t async_pcl_start, async_pcl;
- struct hpsb_packet *async_queue;
- spinlock_t async_queue_lock;
+ struct {
+ pcl_t pcl_start, pcl;
+ struct hpsb_packet *queue;
+ spinlock_t queue_lock;
+ dma_addr_t header_dma, data_dma;
+ } async;
struct {
pcl_t pcl[NUM_ISORCV_PCL];
u32 stat[NUM_ISORCV_PCL];
void *page[ISORCV_PAGES];
+ dma_addr_t page_dma[ISORCV_PAGES];
pcl_t pcl_start;
int chan_count;
int next, last, used, running;
@@ -381,11 +390,7 @@ inline static void get_pcl(const struct ti_lynx *lynx, pcl_t pclid,
inline static u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid)
{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
- return lynx->dev->base_address[1] + pclid * sizeof(struct ti_pcl);
-#else
- return lynx->dev->resource[1].start + pclid * sizeof(struct ti_pcl);
-#endif
+ return pci_resource_start(lynx->dev, 1) + pclid * sizeof(struct ti_pcl);
}
#else /* CONFIG_IEEE1394_PCILYNX_LOCALRAM */
@@ -407,7 +412,7 @@ inline static void get_pcl(const struct ti_lynx *lynx, pcl_t pclid,
inline static u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid)
{
- return virt_to_bus(lynx->pcl_mem) + pclid * sizeof(struct ti_pcl);
+ return lynx->pcl_mem_dma + pclid * sizeof(struct ti_pcl);
}
#endif /* CONFIG_IEEE1394_PCILYNX_LOCALRAM */
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index 523f5d393..83c1169fe 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -4,6 +4,9 @@
* Raw interface to the bus
*
* Copyright (C) 1999, 2000 Andreas E. Bombe
+ *
+ * This code is licensed under the GPL. See the file COPYING in the root
+ * directory of the kernel sources for details.
*/
#include <linux/kernel.h>
@@ -13,8 +16,13 @@
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/module.h>
+#include <linux/version.h>
#include <asm/uaccess.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
+#include <linux/devfs_fs_kernel.h>
+#endif
+
#include "ieee1394.h"
#include "ieee1394_types.h"
#include "ieee1394_core.h"
@@ -24,6 +32,8 @@
#include "raw1394.h"
+static devfs_handle_t devfs_handle = NULL;
+
LIST_HEAD(host_info_list);
static int host_count = 0;
spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
@@ -257,7 +267,7 @@ static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
req->req.type = RAW1394_REQ_ISO_RECEIVE;
req->req.generation = get_hpsb_generation();
req->req.misc = 0;
- req->req.recvb = fi->iso_buffer;
+ req->req.recvb = (u64)fi->iso_buffer;
req->req.length = MIN(length, fi->iso_buffer_length);
list_add_tail(&req->list, &reqs);
@@ -326,7 +336,7 @@ static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
req->req.type = RAW1394_REQ_FCP_REQUEST;
req->req.generation = get_hpsb_generation();
req->req.misc = nodeid | (direction << 16);
- req->req.recvb = (quadlet_t *)fi->fcp_buffer;
+ req->req.recvb = (u64)fi->fcp_buffer;
req->req.length = length;
list_add_tail(&req->list, &reqs);
@@ -343,7 +353,7 @@ static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
}
-static int dev_read(struct file *file, char *buffer, size_t count,
+static ssize_t dev_read(struct file *file, char *buffer, size_t count,
loff_t *offset_is_ignored)
{
struct file_info *fi = (struct file_info *)file->private_data;
@@ -376,7 +386,8 @@ static int dev_read(struct file *file, char *buffer, size_t count,
req = list_entry(lh, struct pending_request, list);
if (req->req.length) {
- if (copy_to_user(req->req.recvb, req->data, req->req.length)) {
+ if (copy_to_user((void *)req->req.recvb, req->data,
+ req->req.length)) {
req->req.error = RAW1394_ERROR_MEMFAULT;
}
}
@@ -507,7 +518,7 @@ static void handle_iso_listen(struct file_info *fi, struct pending_request *req)
} else {
fi->listen_channels |= 1ULL << channel;
hpsb_listen_channel(hl_handle, fi->host, channel);
- fi->iso_buffer = req->req.recvb;
+ fi->iso_buffer = (void *)req->req.recvb;
fi->iso_buffer_length = req->req.length;
}
} else {
@@ -563,7 +574,7 @@ static int handle_local_request(struct file_info *fi,
break;
case RAW1394_REQ_ASYNC_WRITE:
- if (copy_from_user(req->data, req->req.sendb,
+ if (copy_from_user(req->data, (void *)req->req.sendb,
req->req.length)) {
req->req.error = RAW1394_ERROR_MEMFAULT;
break;
@@ -588,7 +599,7 @@ static int handle_local_request(struct file_info *fi,
}
}
- if (copy_from_user(req->data, req->req.sendb,
+ if (copy_from_user(req->data, (void *)req->req.sendb,
req->req.length)) {
req->req.error = RAW1394_ERROR_MEMFAULT;
break;
@@ -646,7 +657,7 @@ static int handle_remote_request(struct file_info *fi,
if (req->req.length == 4) {
quadlet_t x;
- if (copy_from_user(&x, req->req.sendb, 4)) {
+ if (copy_from_user(&x, (void *)req->req.sendb, 4)) {
req->req.error = RAW1394_ERROR_MEMFAULT;
}
@@ -658,7 +669,7 @@ static int handle_remote_request(struct file_info *fi,
req->req.length);
if (!packet) return -ENOMEM;
- if (copy_from_user(packet->data, req->req.sendb,
+ if (copy_from_user(packet->data, (void *)req->req.sendb,
req->req.length)) {
req->req.error = RAW1394_ERROR_MEMFAULT;
}
@@ -684,7 +695,7 @@ static int handle_remote_request(struct file_info *fi,
req->req.misc);
if (!packet) return -ENOMEM;
- if (copy_from_user(packet->data, req->req.sendb,
+ if (copy_from_user(packet->data, (void *)req->req.sendb,
req->req.length)) {
req->req.error = RAW1394_ERROR_MEMFAULT;
break;
@@ -761,12 +772,12 @@ static int state_connected(struct file_info *fi, struct pending_request *req)
}
-static int dev_write(struct file *file, const char *buffer, size_t count,
+static ssize_t dev_write(struct file *file, const char *buffer, size_t count,
loff_t *offset_is_ignored)
{
struct file_info *fi = (struct file_info *)file->private_data;
struct pending_request *req;
- int retval = 0;
+ ssize_t retval = 0;
if (count != sizeof(struct raw1394_request)) {
return -EINVAL;
@@ -828,8 +839,11 @@ static int dev_open(struct inode *inode, struct file *file)
return -ENXIO;
}
+ V22_COMPAT_MOD_INC_USE_COUNT;
+
fi = kmalloc(sizeof(struct file_info), SLAB_KERNEL);
if (fi == NULL) {
+ V22_COMPAT_MOD_DEC_USE_COUNT;
return -ENOMEM;
}
@@ -898,6 +912,7 @@ static int dev_release(struct inode *inode, struct file *file)
kfree(fi);
+ V22_COMPAT_MOD_DEC_USE_COUNT;
return 0;
}
@@ -910,7 +925,7 @@ static struct hpsb_highlevel_ops hl_ops = {
};
static struct file_operations file_ops = {
- owner: THIS_MODULE,
+ OWNER_THIS_MODULE
read: dev_read,
write: dev_write,
poll: dev_poll,
@@ -926,18 +941,24 @@ int init_raw1394(void)
return -ENOMEM;
}
- if (register_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME,
- &file_ops)) {
- HPSB_ERR("raw1394 failed to allocate device major");
+ devfs_handle = devfs_register(NULL, RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
+ RAW1394_DEVICE_MAJOR, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR, &file_ops,
+ NULL);
+
+ if (devfs_register_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME,
+ &file_ops)) {
+ HPSB_ERR("raw1394 failed to register /dev/raw1394 device");
return -EBUSY;
}
-
+ printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME);
return 0;
}
void cleanup_raw1394(void)
{
- unregister_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME);
+ devfs_unregister_chrdev(RAW1394_DEVICE_MAJOR, RAW1394_DEVICE_NAME);
+ devfs_unregister(devfs_handle);
hpsb_unregister_highlevel(hl_handle);
}
diff --git a/drivers/ieee1394/raw1394.h b/drivers/ieee1394/raw1394.h
index f23bfc051..b0d819429 100644
--- a/drivers/ieee1394/raw1394.h
+++ b/drivers/ieee1394/raw1394.h
@@ -1,11 +1,10 @@
-
#ifndef IEEE1394_RAW1394_H
#define IEEE1394_RAW1394_H
#define RAW1394_DEVICE_MAJOR 171
#define RAW1394_DEVICE_NAME "raw1394"
-#define RAW1394_KERNELAPI_VERSION 2
+#define RAW1394_KERNELAPI_VERSION 3
/* state: opened */
#define RAW1394_REQ_INITIALIZE 1
@@ -45,24 +44,27 @@
#define RAW1394_ERROR_TIMEOUT (-1102)
+#include <asm/types.h>
+
struct raw1394_request {
- int type;
- int error;
- int misc;
+ __u32 type;
+ __s32 error;
+ __u32 misc;
+
+ __u32 generation;
+ __u32 length;
- unsigned int generation;
- octlet_t address;
+ __u64 address;
- unsigned long tag;
+ __u64 tag;
- size_t length;
- quadlet_t *sendb;
- quadlet_t *recvb;
+ __u64 sendb;
+ __u64 recvb;
};
struct raw1394_khost_list {
- int nodes;
- char name[32];
+ __u32 nodes;
+ __u8 name[32];
};
#ifdef __KERNEL__
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
new file mode 100644
index 000000000..9f00fd3f0
--- /dev/null
+++ b/drivers/ieee1394/video1394.c
@@ -0,0 +1,1266 @@
+/*
+ * video1394.c - video driver for OHCI 1394 boards
+ * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <asm/byteorder.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+#include <linux/tqueue.h>
+#include <linux/delay.h>
+
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <linux/types.h>
+#include <linux/wrapper.h>
+#include <linux/vmalloc.h>
+
+#include "ieee1394.h"
+#include "ieee1394_types.h"
+#include "hosts.h"
+#include "ieee1394_core.h"
+#include "video1394.h"
+
+#include "ohci1394.h"
+
+#define VIDEO1394_MAJOR 172
+#define ISO_CHANNELS 64
+#define ISO_RECEIVE 0
+#define ISO_TRANSMIT 1
+
+struct it_dma_prg {
+ struct dma_cmd begin;
+ quadlet_t data[4];
+ struct dma_cmd end;
+ quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */
+};
+
+struct dma_iso_ctx {
+ struct ti_ohci *ohci;
+ int ctx;
+ int channel;
+ int last_buffer;
+ unsigned int num_desc;
+ unsigned int buf_size;
+ unsigned int frame_size;
+ unsigned int packet_size;
+ unsigned int left_size;
+ unsigned int nb_cmd;
+ unsigned char *buf;
+ struct dma_cmd **ir_prg;
+ struct it_dma_prg **it_prg;
+ unsigned int *buffer_status;
+ int ctrlClear;
+ int ctrlSet;
+ int cmdPtr;
+ int ctxMatch;
+ wait_queue_head_t waitq;
+};
+
+struct video_card {
+ struct ti_ohci *ohci;
+
+ struct dma_iso_ctx **ir_context;
+ struct dma_iso_ctx **it_context;
+ struct dma_iso_ctx *current_ctx;
+};
+
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+#define VIDEO1394_DEBUG
+#endif
+
+#ifdef DBGMSG
+#undef DBGMSG
+#endif
+
+#ifdef VIDEO1394_DEBUG
+#define DBGMSG(card, fmt, args...) \
+printk(KERN_INFO "video1394_%d: " fmt "\n" , card , ## args)
+#else
+#define DBGMSG(card, fmt, args...)
+#endif
+
+/* print general (card independent) information */
+#define PRINT_G(level, fmt, args...) \
+printk(level "video1394: " fmt "\n" , ## args)
+
+/* print card specific information */
+#define PRINT(level, card, fmt, args...) \
+printk(level "video1394_%d: " fmt "\n" , card , ## args)
+
+void irq_handler(int card, quadlet_t isoRecvIntEvent,
+ quadlet_t isoXmitIntEvent);
+
+static struct video_card video_cards[MAX_OHCI1394_CARDS];
+static int num_of_video_cards = 0;
+static struct video_template video_tmpl = { irq_handler };
+
+/* Taken from bttv.c */
+/*******************************/
+/* Memory management functions */
+/*******************************/
+
+#define MDEBUG(x) do { } while(0) /* Debug memory management */
+
+/* [DaveM] I've recoded most of this so that:
+ * 1) It's easier to tell what is happening
+ * 2) It's more portable, especially for translating things
+ * out of vmalloc mapped areas in the kernel.
+ * 3) Less unnecessary translations happen.
+ *
+ * The code used to assume that the kernel vmalloc mappings
+ * existed in the page tables of every process, this is simply
+ * not guarenteed. We now use pgd_offset_k which is the
+ * defined way to get at the kernel page tables.
+ */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#define page_address(x) (x)
+#endif
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
+{
+ unsigned long ret = 0UL;
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+
+ if (!pgd_none(*pgd)) {
+ pmd = pmd_offset(pgd, adr);
+ if (!pmd_none(*pmd)) {
+ ptep = pte_offset(pmd, adr);
+ pte = *ptep;
+ if(pte_present(pte))
+ ret = (page_address(pte_page(pte))|
+ (adr&(PAGE_SIZE-1)));
+ }
+ }
+ MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
+ return ret;
+}
+
+static inline unsigned long uvirt_to_bus(unsigned long adr)
+{
+ unsigned long kva, ret;
+
+ kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
+ ret = virt_to_bus((void *)kva);
+ MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
+ return ret;
+}
+
+static inline unsigned long kvirt_to_bus(unsigned long adr)
+{
+ unsigned long va, kva, ret;
+
+ va = VMALLOC_VMADDR(adr);
+ kva = uvirt_to_kva(pgd_offset_k(va), va);
+ ret = virt_to_bus((void *)kva);
+ MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
+ return ret;
+}
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+ unsigned long va, kva, ret;
+
+ va = VMALLOC_VMADDR(adr);
+ kva = uvirt_to_kva(pgd_offset_k(va), va);
+ ret = __pa(kva);
+ MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
+ return ret;
+}
+
+static void * rvmalloc(unsigned long size)
+{
+ void * mem;
+ unsigned long adr, page;
+
+ mem=vmalloc(size);
+ if (mem)
+ {
+ memset(mem, 0, size); /* Clear the ram out,
+ no junk to the user */
+ adr=(unsigned long) mem;
+ while (size > 0)
+ {
+ page = kvirt_to_pa(adr);
+ mem_map_reserve(MAP_NR(__va(page)));
+ adr+=PAGE_SIZE;
+ size-=PAGE_SIZE;
+ }
+ }
+ return mem;
+}
+
+static void rvfree(void * mem, unsigned long size)
+{
+ unsigned long adr, page;
+
+ if (mem)
+ {
+ adr=(unsigned long) mem;
+ while (size > 0)
+ {
+ page = kvirt_to_pa(adr);
+ mem_map_unreserve(MAP_NR(__va(page)));
+ adr+=PAGE_SIZE;
+ size-=PAGE_SIZE;
+ }
+ vfree(mem);
+ }
+}
+
+static int free_dma_iso_ctx(struct dma_iso_ctx **d)
+{
+ int i;
+ struct ti_ohci *ohci;
+
+ if ((*d)==NULL) return -1;
+
+ ohci = (struct ti_ohci *)(*d)->ohci;
+
+ DBGMSG(ohci->id, "Freeing dma_iso_ctx %d", (*d)->ctx);
+
+ ohci1394_stop_context(ohci, (*d)->ctrlClear, NULL);
+
+ if ((*d)->buf) rvfree((void *)(*d)->buf,
+ (*d)->num_desc * (*d)->buf_size);
+
+ if ((*d)->ir_prg) {
+ for (i=0;i<(*d)->num_desc;i++)
+ if ((*d)->ir_prg[i]) kfree((*d)->ir_prg[i]);
+ kfree((*d)->ir_prg);
+ }
+
+ if ((*d)->it_prg) {
+ for (i=0;i<(*d)->num_desc;i++)
+ if ((*d)->it_prg[i]) kfree((*d)->it_prg[i]);
+ kfree((*d)->it_prg);
+ }
+
+ if ((*d)->buffer_status)
+ kfree((*d)->buffer_status);
+
+ kfree(*d);
+ *d = NULL;
+
+ return 0;
+}
+
+static struct dma_iso_ctx *
+alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int ctx, int num_desc,
+ int buf_size, int channel, unsigned int packet_size)
+{
+ struct dma_iso_ctx *d=NULL;
+ int i;
+
+ d = (struct dma_iso_ctx *)kmalloc(sizeof(struct dma_iso_ctx),
+ GFP_KERNEL);
+ memset(d, 0, sizeof(struct dma_iso_ctx));
+
+ if (d==NULL) {
+ PRINT(KERN_ERR, ohci->id, "failed to allocate dma_iso_ctx");
+ return NULL;
+ }
+
+ d->ohci = (void *)ohci;
+ d->ctx = ctx;
+ d->channel = channel;
+ d->num_desc = num_desc;
+ d->frame_size = buf_size;
+ if (buf_size%PAGE_SIZE)
+ d->buf_size = buf_size + PAGE_SIZE - (buf_size%PAGE_SIZE);
+ else
+ d->buf_size = buf_size;
+ d->last_buffer = -1;
+ d->buf = NULL;
+ d->ir_prg = NULL;
+ init_waitqueue_head(&d->waitq);
+
+ d->buf = rvmalloc(d->num_desc * d->buf_size);
+
+ if (d->buf == NULL) {
+ PRINT(KERN_ERR, ohci->id, "failed to allocate dma buffer");
+ free_dma_iso_ctx(&d);
+ return NULL;
+ }
+ memset(d->buf, 0, d->num_desc * d->buf_size);
+
+ if (type == ISO_RECEIVE) {
+ d->ctrlSet = OHCI1394_IsoRcvContextControlSet+32*d->ctx;
+ d->ctrlClear = OHCI1394_IsoRcvContextControlClear+32*d->ctx;
+ d->cmdPtr = OHCI1394_IsoRcvCommandPtr+32*d->ctx;
+ d->ctxMatch = OHCI1394_IsoRcvContextMatch+32*d->ctx;
+
+ d->ir_prg = kmalloc(d->num_desc * sizeof(struct dma_cmd *),
+ GFP_KERNEL);
+
+ if (d->ir_prg == NULL) {
+ PRINT(KERN_ERR, ohci->id,
+ "failed to allocate dma ir prg");
+ free_dma_iso_ctx(&d);
+ return NULL;
+ }
+ memset(d->ir_prg, 0, d->num_desc * sizeof(struct dma_cmd *));
+
+ d->nb_cmd = d->buf_size / PAGE_SIZE + 1;
+ d->left_size = (d->frame_size % PAGE_SIZE) ?
+ d->frame_size % PAGE_SIZE : PAGE_SIZE;
+
+ for (i=0;i<d->num_desc;i++) {
+ d->ir_prg[i] = kmalloc(d->nb_cmd *
+ sizeof(struct dma_cmd),
+ GFP_KERNEL);
+ if (d->ir_prg[i] == NULL) {
+ PRINT(KERN_ERR, ohci->id,
+ "failed to allocate dma ir prg");
+ free_dma_iso_ctx(&d);
+ return NULL;
+ }
+ }
+ }
+ else { /* ISO_TRANSMIT */
+ d->ctrlSet = OHCI1394_IsoXmitContextControlSet+16*d->ctx;
+ d->ctrlClear = OHCI1394_IsoXmitContextControlClear+16*d->ctx;
+ d->cmdPtr = OHCI1394_IsoXmitCommandPtr+16*d->ctx;
+
+ d->it_prg = kmalloc(d->num_desc * sizeof(struct it_dma_prg *),
+ GFP_KERNEL);
+
+ if (d->it_prg == NULL) {
+ PRINT(KERN_ERR, ohci->id,
+ "failed to allocate dma it prg");
+ free_dma_iso_ctx(&d);
+ return NULL;
+ }
+ memset(d->it_prg, 0, d->num_desc*sizeof(struct it_dma_prg *));
+
+ d->packet_size = packet_size;
+
+ if (PAGE_SIZE % packet_size || packet_size>2048) {
+ PRINT(KERN_ERR, ohci->id,
+ "Packet size %d not yet supported\n",
+ packet_size);
+ free_dma_iso_ctx(&d);
+ return NULL;
+ }
+
+ d->nb_cmd = d->frame_size / d->packet_size;
+ if (d->frame_size % d->packet_size) {
+ d->nb_cmd++;
+ d->left_size = d->frame_size % d->packet_size;
+ }
+ else
+ d->left_size = d->packet_size;
+
+ for (i=0;i<d->num_desc;i++) {
+ d->it_prg[i] = kmalloc(d->nb_cmd *
+ sizeof(struct it_dma_prg),
+ GFP_KERNEL);
+ if (d->it_prg[i] == NULL) {
+ PRINT(KERN_ERR, ohci->id,
+ "failed to allocate dma it prg");
+ free_dma_iso_ctx(&d);
+ return NULL;
+ }
+ }
+ }
+
+ d->buffer_status = kmalloc(d->num_desc * sizeof(unsigned int),
+ GFP_KERNEL);
+
+ if (d->buffer_status == NULL) {
+ PRINT(KERN_ERR, ohci->id, "failed to allocate dma ir prg");
+ free_dma_iso_ctx(&d);
+ return NULL;
+ }
+ memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int));
+
+ PRINT(KERN_INFO, ohci->id, "Iso %s DMA: %d buffers "
+ "of size %d allocated for a frame size %d, each with %d prgs",
+ (type==ISO_RECEIVE) ? "receive" : "transmit",
+ d->num_desc, d->buf_size, d->frame_size, d->nb_cmd);
+
+ return d;
+}
+
+static void reset_ir_status(struct dma_iso_ctx *d, int n)
+{
+ int i;
+ d->ir_prg[n][0].status = 4;
+ d->ir_prg[n][1].status = PAGE_SIZE-4;
+ for (i=2;i<d->nb_cmd-1;i++)
+ d->ir_prg[n][i].status = PAGE_SIZE;
+ d->ir_prg[n][i].status = d->left_size;
+}
+
+static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n)
+{
+ struct dma_cmd *ir_prg = d->ir_prg[n];
+ unsigned long buf = (unsigned long)d->buf+n*d->buf_size;
+ int i;
+
+ /* the first descriptor will sync and read only 4 bytes */
+ ir_prg[0].control = (0x280F << 16) | 4;
+ ir_prg[0].address = kvirt_to_bus(buf);
+ ir_prg[0].branchAddress = (virt_to_bus(&(ir_prg[1].control))
+ & 0xfffffff0) | 0x1;
+
+ /* the second descriptor will read PAGE_SIZE-4 bytes */
+ ir_prg[1].control = (0x280C << 16) | (PAGE_SIZE-4);
+ ir_prg[1].address = kvirt_to_bus(buf+4);
+ ir_prg[1].branchAddress = (virt_to_bus(&(ir_prg[2].control))
+ & 0xfffffff0) | 0x1;
+
+ for (i=2;i<d->nb_cmd-1;i++) {
+ ir_prg[i].control = (0x280C << 16) | PAGE_SIZE;
+ ir_prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE);
+
+ ir_prg[i].branchAddress =
+ (virt_to_bus(&(ir_prg[i+1].control))
+ & 0xfffffff0) | 0x1;
+ }
+
+ /* the last descriptor will generate an interrupt */
+ ir_prg[i].control = (0x283C << 16) | d->left_size;
+ ir_prg[i].address = kvirt_to_bus(buf+(i-1)*PAGE_SIZE);
+}
+
+static void initialize_dma_ir_ctx(struct dma_iso_ctx *d, int tag)
+{
+ struct ti_ohci *ohci = (struct ti_ohci *)d->ohci;
+ int i;
+
+ ohci1394_stop_context(ohci, d->ctrlClear, NULL);
+
+ for (i=0;i<d->num_desc;i++) {
+ initialize_dma_ir_prg(d, i);
+ reset_ir_status(d, i);
+ }
+
+ /* Set bufferFill, no header */
+ reg_write(ohci, d->ctrlSet, 0x80000000);
+
+ /* Set the context match register to match on all tags,
+ sync for sync tag, and listen to d->channel */
+ reg_write(ohci, d->ctxMatch, 0xf0000000|((tag&0xf)<<8)|d->channel);
+
+ /* Set up isoRecvIntMask to generate interrupts */
+ reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1<<d->ctx);
+}
+
+/* find which context is listening to this channel */
+int ir_ctx_listening(struct video_card *video, int channel)
+{
+ int i;
+ struct ti_ohci *ohci = video->ohci;
+
+ for (i=0;i<ohci->nb_iso_rcv_ctx-1;i++)
+ if (video->ir_context[i]) {
+ if (video->ir_context[i]->channel==channel)
+ return i;
+ }
+
+ PRINT(KERN_ERR, ohci->id,
+ "no iso context is listening to channel %d",
+ channel);
+ return -1;
+}
+
+int it_ctx_talking(struct video_card *video, int channel)
+{
+ int i;
+ struct ti_ohci *ohci = video->ohci;
+
+ for (i=0;i<ohci->nb_iso_xmit_ctx;i++)
+ if (video->it_context[i]) {
+ if (video->it_context[i]->channel==channel)
+ return i;
+ }
+
+ PRINT(KERN_ERR, ohci->id,
+ "no iso context is talking to channel %d",
+ channel);
+ return -1;
+}
+
+int wakeup_dma_ir_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d)
+{
+ int i;
+
+ if (d==NULL) {
+ PRINT(KERN_ERR, ohci->id, "Iso receive event received but "
+ "context not allocated");
+ return -EFAULT;
+ }
+
+ for (i=0;i<d->num_desc;i++) {
+ if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) {
+ reset_ir_status(d, i);
+ d->buffer_status[i] = VIDEO1394_BUFFER_READY;
+ }
+ }
+ if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq);
+ return 0;
+}
+
+int wakeup_dma_it_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d)
+{
+ int i;
+
+ if (d==NULL) {
+ PRINT(KERN_ERR, ohci->id, "Iso transmit event received but "
+ "context not allocated");
+ return -EFAULT;
+ }
+
+ for (i=0;i<d->num_desc;i++) {
+ if (d->it_prg[i][d->nb_cmd-1].end.status & 0xFFFF0000) {
+ d->it_prg[i][d->nb_cmd-1].end.status = 0;
+ d->buffer_status[i] = VIDEO1394_BUFFER_READY;
+ }
+ }
+ if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq);
+ return 0;
+}
+
+static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag)
+{
+ struct it_dma_prg *it_prg = d->it_prg[n];
+ unsigned long buf = (unsigned long)d->buf+n*d->buf_size;
+ int i;
+
+ for (i=0;i<d->nb_cmd;i++) {
+
+ it_prg[i].begin.control = OUTPUT_MORE_IMMEDIATE | 8 ;
+ it_prg[i].begin.address = 0;
+
+ it_prg[i].begin.status = 0;
+
+ /* FIXME: what is the tag value + speed selection */
+ it_prg[i].data[0] =
+ (DMA_SPEED_400<<16) | (d->channel<<8) | 0xa0;
+ if (i==0) it_prg[i].data[0] |= sync_tag;
+ it_prg[i].data[1] = d->packet_size << 16;
+ it_prg[i].data[2] = 0;
+ it_prg[i].data[3] = 0;
+
+ it_prg[i].end.control = 0x100c0000;
+ it_prg[i].end.address =
+ kvirt_to_bus(buf+i*d->packet_size);
+
+ if (i<d->nb_cmd-1) {
+ it_prg[i].end.control |= d->packet_size;
+ it_prg[i].begin.branchAddress =
+ (virt_to_bus(&(it_prg[i+1].begin.control))
+ & 0xfffffff0) | 0x3;
+ it_prg[i].end.branchAddress =
+ (virt_to_bus(&(it_prg[i+1].begin.control))
+ & 0xfffffff0) | 0x3;
+ }
+ else {
+ /* the last prg generates an interrupt */
+ it_prg[i].end.control |= 0x08300000 | d->left_size;
+ /* the last prg doesn't branch */
+ it_prg[i].begin.branchAddress = 0;
+ it_prg[i].end.branchAddress = 0;
+ }
+ it_prg[i].end.status = 0;
+
+#if 0
+ printk("%d:%d: %08x-%08x ctrl %08x brch %08x d0 %08x d1 %08x\n",n,i,
+ virt_to_bus(&(it_prg[i].begin.control)),
+ virt_to_bus(&(it_prg[i].end.control)),
+ it_prg[i].end.control,
+ it_prg[i].end.branchAddress,
+ it_prg[i].data[0], it_prg[i].data[1]);
+#endif
+ }
+}
+
+static void initialize_dma_it_ctx(struct dma_iso_ctx *d, int sync_tag)
+{
+ struct ti_ohci *ohci = (struct ti_ohci *)d->ohci;
+ int i;
+
+ ohci1394_stop_context(ohci, d->ctrlClear, NULL);
+
+ for (i=0;i<d->num_desc;i++)
+ initialize_dma_it_prg(d, i, sync_tag);
+
+ /* Set up isoRecvIntMask to generate interrupts */
+ reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx);
+}
+
+static int do_iso_mmap(struct ti_ohci *ohci, struct dma_iso_ctx *d,
+ const char *adr, unsigned long size)
+{
+ unsigned long start=(unsigned long) adr;
+ unsigned long page,pos;
+
+ if (size>d->num_desc * d->buf_size) {
+ PRINT(KERN_ERR, ohci->id,
+ "iso context %d buf size is different from mmap size",
+ d->ctx);
+ return -EINVAL;
+ }
+ if (!d->buf) {
+ PRINT(KERN_ERR, ohci->id,
+ "iso context %d is not allocated", d->ctx);
+ return -EINVAL;
+ }
+
+ pos=(unsigned long) d->buf;
+ while (size > 0) {
+ page = kvirt_to_pa(pos);
+ if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+ return -EAGAIN;
+ start+=PAGE_SIZE;
+ pos+=PAGE_SIZE;
+ size-=PAGE_SIZE;
+ }
+ return 0;
+}
+
+static int video1394_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct video_card *video = &video_cards[MINOR(inode->i_rdev)];
+ struct ti_ohci *ohci= video->ohci;
+
+ switch(cmd)
+ {
+ case VIDEO1394_LISTEN_CHANNEL:
+ case VIDEO1394_TALK_CHANNEL:
+ {
+ struct video1394_mmap v;
+ int i;
+
+ if(copy_from_user(&v, (void *)arg, sizeof(v)))
+ return -EFAULT;
+ if (v.channel<0 || v.channel>(ISO_CHANNELS-1)) {
+ PRINT(KERN_ERR, ohci->id,
+ "iso channel %d out of bound", v.channel);
+ return -EFAULT;
+ }
+ if (test_and_set_bit(v.channel, &ohci->IR_channel_usage)) {
+ PRINT(KERN_ERR, ohci->id,
+ "channel %d is already taken", v.channel);
+ return -EFAULT;
+ }
+
+ if (v.buf_size<=0) {
+ PRINT(KERN_ERR, ohci->id,
+ "Invalid %d length buffer requested",v.buf_size);
+ return -EFAULT;
+ }
+
+ if (v.nb_buffers<=0) {
+ PRINT(KERN_ERR, ohci->id,
+ "Invalid %d buffers requested",v.nb_buffers);
+ return -EFAULT;
+ }
+
+ if (v.nb_buffers * v.buf_size > VIDEO1394_MAX_SIZE) {
+ PRINT(KERN_ERR, ohci->id,
+ "%d buffers of size %d bytes is too big",
+ v.nb_buffers, v.buf_size);
+ return -EFAULT;
+ }
+
+ if (cmd == VIDEO1394_LISTEN_CHANNEL) {
+ /* find a free iso receive context */
+ for (i=0;i<ohci->nb_iso_rcv_ctx-1;i++)
+ if (video->ir_context[i]==NULL) break;
+
+ if (i==(ohci->nb_iso_rcv_ctx-1)) {
+ PRINT(KERN_ERR, ohci->id,
+ "no iso context available");
+ return -EFAULT;
+ }
+
+ video->ir_context[i] =
+ alloc_dma_iso_ctx(ohci, ISO_RECEIVE, i+1,
+ v.nb_buffers, v.buf_size,
+ v.channel, 0);
+
+ if (video->ir_context[i] == NULL) {
+ PRINT(KERN_ERR, ohci->id,
+ "Couldn't allocate ir context");
+ return -EFAULT;
+ }
+ initialize_dma_ir_ctx(video->ir_context[i],
+ v.sync_tag);
+
+ video->current_ctx = video->ir_context[i];
+
+ v.buf_size = video->ir_context[i]->buf_size;
+
+ PRINT(KERN_INFO, ohci->id,
+ "iso context %d listen on channel %d", i+1,
+ v.channel);
+ }
+ else {
+ /* find a free iso transmit context */
+ for (i=0;i<ohci->nb_iso_xmit_ctx;i++)
+ if (video->it_context[i]==NULL) break;
+
+ if (i==ohci->nb_iso_xmit_ctx) {
+ PRINT(KERN_ERR, ohci->id,
+ "no iso context available");
+ return -EFAULT;
+ }
+
+ video->it_context[i] =
+ alloc_dma_iso_ctx(ohci, ISO_TRANSMIT, i,
+ v.nb_buffers, v.buf_size,
+ v.channel, v.packet_size);
+
+ if (video->it_context[i] == NULL) {
+ PRINT(KERN_ERR, ohci->id,
+ "Couldn't allocate it context");
+ return -EFAULT;
+ }
+ initialize_dma_it_ctx(video->it_context[i],
+ v.sync_tag);
+
+ video->current_ctx = video->it_context[i];
+
+ v.buf_size = video->it_context[i]->buf_size;
+
+ PRINT(KERN_INFO, ohci->id,
+ "iso context %d talk on channel %d", i,
+ v.channel);
+ }
+
+ if(copy_to_user((void *)arg, &v, sizeof(v)))
+ return -EFAULT;
+
+ return 0;
+ }
+ case VIDEO1394_UNLISTEN_CHANNEL:
+ case VIDEO1394_UNTALK_CHANNEL:
+ {
+ int channel;
+ int i;
+
+ if(copy_from_user(&channel, (void *)arg, sizeof(int)))
+ return -EFAULT;
+
+ if (!test_and_clear_bit(channel, &ohci->IR_channel_usage)) {
+ PRINT(KERN_ERR, ohci->id,
+ "channel %d is not being used", channel);
+ return -EFAULT;
+ }
+
+ if (cmd == VIDEO1394_UNLISTEN_CHANNEL) {
+ i = ir_ctx_listening(video, channel);
+ if (i<0) return -EFAULT;
+
+ free_dma_iso_ctx(&video->ir_context[i]);
+
+ PRINT(KERN_INFO, ohci->id,
+ "iso context %d stop listening on channel %d",
+ i+1, channel);
+ }
+ else {
+ i = it_ctx_talking(video, channel);
+ if (i<0) return -EFAULT;
+
+ free_dma_iso_ctx(&video->it_context[i]);
+
+ PRINT(KERN_INFO, ohci->id,
+ "iso context %d stop talking on channel %d",
+ i, channel);
+ }
+
+ return 0;
+ }
+ case VIDEO1394_LISTEN_QUEUE_BUFFER:
+ {
+ struct video1394_wait v;
+ struct dma_iso_ctx *d;
+ int i;
+
+ if(copy_from_user(&v, (void *)arg, sizeof(v)))
+ return -EFAULT;
+
+ i = ir_ctx_listening(video, v.channel);
+ if (i<0) return -EFAULT;
+ d = video->ir_context[i];
+
+ if ((v.buffer<0) || (v.buffer>d->num_desc)) {
+ PRINT(KERN_ERR, ohci->id,
+ "buffer %d out of range",v.buffer);
+ return -EFAULT;
+ }
+
+ if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) {
+ PRINT(KERN_ERR, ohci->id,
+ "buffer %d is already used",v.buffer);
+ return -EFAULT;
+ }
+
+ d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
+
+ if (d->last_buffer>=0)
+ d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress =
+ (virt_to_bus(&(d->ir_prg[v.buffer][0].control))
+ & 0xfffffff0) | 0x1;
+
+ d->last_buffer = v.buffer;
+
+ d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = 0;
+
+ if (!(reg_read(ohci, d->ctrlSet) & 0x8000))
+ {
+ DBGMSG(ohci->id, "Starting iso DMA ctx=%d",d->ctx);
+
+ /* Tell the controller where the first program is */
+ reg_write(ohci, d->cmdPtr,
+ virt_to_bus(&(d->ir_prg[v.buffer][0]))|0x1);
+
+ /* Run IR context */
+ reg_write(ohci, d->ctrlSet, 0x8000);
+ }
+ else {
+ /* Wake up dma context if necessary */
+ if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
+ PRINT(KERN_INFO, ohci->id,
+ "Waking up iso dma ctx=%d", d->ctx);
+ reg_write(ohci, d->ctrlSet, 0x1000);
+ }
+ }
+ return 0;
+
+ }
+ case VIDEO1394_LISTEN_WAIT_BUFFER:
+ {
+ struct video1394_wait v;
+ struct dma_iso_ctx *d;
+ int i;
+
+ if(copy_from_user(&v, (void *)arg, sizeof(v)))
+ return -EFAULT;
+
+ i = ir_ctx_listening(video, v.channel);
+ if (i<0) return -EFAULT;
+ d = video->ir_context[i];
+
+ if ((v.buffer<0) || (v.buffer>d->num_desc)) {
+ PRINT(KERN_ERR, ohci->id,
+ "buffer %d out of range",v.buffer);
+ return -EFAULT;
+ }
+
+ switch(d->buffer_status[v.buffer]) {
+ case VIDEO1394_BUFFER_READY:
+ d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
+ return 0;
+ case VIDEO1394_BUFFER_QUEUED:
+#if 1
+ while(d->buffer_status[v.buffer]!=
+ VIDEO1394_BUFFER_READY) {
+ interruptible_sleep_on(&d->waitq);
+ if(signal_pending(current)) return -EINTR;
+ }
+#else
+ if (wait_event_interruptible(d->waitq,
+ d->buffer_status[v.buffer]
+ == VIDEO1394_BUFFER_READY)
+ == -ERESTARTSYS)
+ return -EINTR;
+#endif
+ d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
+ return 0;
+ default:
+ PRINT(KERN_ERR, ohci->id,
+ "buffer %d is not queued",v.buffer);
+ return -EFAULT;
+ }
+ }
+ case VIDEO1394_TALK_QUEUE_BUFFER:
+ {
+ struct video1394_wait v;
+ struct dma_iso_ctx *d;
+ int i;
+
+ if(copy_from_user(&v, (void *)arg, sizeof(v)))
+ return -EFAULT;
+
+ i = it_ctx_talking(video, v.channel);
+ if (i<0) return -EFAULT;
+ d = video->it_context[i];
+
+ if ((v.buffer<0) || (v.buffer>d->num_desc)) {
+ PRINT(KERN_ERR, ohci->id,
+ "buffer %d out of range",v.buffer);
+ return -EFAULT;
+ }
+
+ if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) {
+ PRINT(KERN_ERR, ohci->id,
+ "buffer %d is already used",v.buffer);
+ return -EFAULT;
+ }
+
+ d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
+
+ if (d->last_buffer>=0) {
+ d->it_prg[d->last_buffer]
+ [d->nb_cmd-1].end.branchAddress =
+ (virt_to_bus(&(d->it_prg[v.buffer][0].begin.control))
+ & 0xfffffff0) | 0x3;
+
+ d->it_prg[d->last_buffer]
+ [d->nb_cmd-1].begin.branchAddress =
+ (virt_to_bus(&(d->it_prg[v.buffer][0].begin.control))
+ & 0xfffffff0) | 0x3;
+ }
+ d->last_buffer = v.buffer;
+
+ d->it_prg[d->last_buffer][d->nb_cmd-1].end.branchAddress = 0;
+
+ if (!(reg_read(ohci, d->ctrlSet) & 0x8000))
+ {
+ DBGMSG(ohci->id, "Starting iso transmit DMA ctx=%d",
+ d->ctx);
+
+ /* Tell the controller where the first program is */
+ reg_write(ohci, d->cmdPtr,
+ virt_to_bus(&(d->it_prg[v.buffer][0]))|0x3);
+
+ /* Run IT context */
+ reg_write(ohci, d->ctrlSet, 0x8000);
+ }
+ else {
+ /* Wake up dma context if necessary */
+ if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
+ PRINT(KERN_INFO, ohci->id,
+ "Waking up iso transmit dma ctx=%d",
+ d->ctx);
+ reg_write(ohci, d->ctrlSet, 0x1000);
+ }
+ }
+ return 0;
+
+ }
+ case VIDEO1394_TALK_WAIT_BUFFER:
+ {
+ struct video1394_wait v;
+ struct dma_iso_ctx *d;
+ int i;
+
+ if(copy_from_user(&v, (void *)arg, sizeof(v)))
+ return -EFAULT;
+
+ i = it_ctx_talking(video, v.channel);
+ if (i<0) return -EFAULT;
+ d = video->it_context[i];
+
+ if ((v.buffer<0) || (v.buffer>d->num_desc)) {
+ PRINT(KERN_ERR, ohci->id,
+ "buffer %d out of range",v.buffer);
+ return -EFAULT;
+ }
+
+ switch(d->buffer_status[v.buffer]) {
+ case VIDEO1394_BUFFER_READY:
+ d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
+ return 0;
+ case VIDEO1394_BUFFER_QUEUED:
+#if 1
+ while(d->buffer_status[v.buffer]!=
+ VIDEO1394_BUFFER_READY) {
+ interruptible_sleep_on(&d->waitq);
+ if(signal_pending(current)) return -EINTR;
+ }
+#else
+ if (wait_event_interruptible(d->waitq,
+ d->buffer_status[v.buffer]
+ == VIDEO1394_BUFFER_READY)
+ == -ERESTARTSYS)
+ return -EINTR;
+#endif
+ d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
+ return 0;
+ default:
+ PRINT(KERN_ERR, ohci->id,
+ "buffer %d is not queued",v.buffer);
+ return -EFAULT;
+ }
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * This maps the vmalloced and reserved buffer to user space.
+ *
+ * FIXME:
+ * - PAGE_READONLY should suffice!?
+ * - remap_page_range is kind of inefficient for page by page remapping.
+ * But e.g. pte_alloc() does not work in modules ... :-(
+ */
+
+int video1394_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct video_card *video =
+ &video_cards[MINOR(file->f_dentry->d_inode->i_rdev)];
+ struct ti_ohci *ohci= video->ohci;
+
+ PRINT(KERN_INFO, ohci->id, "mmap");
+ if (video->current_ctx == NULL) {
+ PRINT(KERN_ERR, ohci->id, "current iso context not set");
+ return -EINVAL;
+ }
+
+ return do_iso_mmap(ohci, video->current_ctx,
+ (char *)vma->vm_start,
+ (unsigned long)(vma->vm_end-vma->vm_start));
+ return 0;
+}
+
+static int video1394_open(struct inode *inode, struct file *file)
+{
+ int i = MINOR(inode->i_rdev);
+
+ if (i<0 || i>=num_of_video_cards) {
+ PRINT(KERN_ERR, i, "ohci card %d not found", i);
+ return -EIO;
+ }
+
+ V22_COMPAT_MOD_INC_USE_COUNT;
+
+ PRINT(KERN_INFO, i, "open");
+
+ return 0;
+}
+
+static int video1394_release(struct inode *inode, struct file *file)
+{
+ struct video_card *video = &video_cards[MINOR(inode->i_rdev)];
+ struct ti_ohci *ohci= video->ohci;
+ int i;
+
+ for (i=0;i<ohci->nb_iso_rcv_ctx-1;i++)
+ if (video->ir_context[i]) {
+ if (!test_and_clear_bit(
+ video->ir_context[i]->channel,
+ &ohci->IR_channel_usage)) {
+ PRINT(KERN_ERR, ohci->id,
+ "channel %d is not being used",
+ video->ir_context[i]->channel);
+ }
+ PRINT(KERN_INFO, ohci->id,
+ "iso receive context %d stop listening "
+ "on channel %d", i+1,
+ video->ir_context[i]->channel);
+ free_dma_iso_ctx(&video->ir_context[i]);
+ }
+
+ for (i=0;i<ohci->nb_iso_xmit_ctx;i++)
+ if (video->it_context[i]) {
+ if (!test_and_clear_bit(
+ video->it_context[i]->channel,
+ &ohci->IR_channel_usage)) {
+ PRINT(KERN_ERR, ohci->id,
+ "channel %d is not being used",
+ video->it_context[i]->channel);
+ }
+ PRINT(KERN_INFO, ohci->id,
+ "iso transmit context %d stop talking "
+ "on channel %d", i+1,
+ video->it_context[i]->channel);
+ free_dma_iso_ctx(&video->it_context[i]);
+ }
+
+
+ V22_COMPAT_MOD_DEC_USE_COUNT;
+
+ PRINT(KERN_INFO, ohci->id, "release");
+ return 0;
+}
+
+void irq_handler(int card, quadlet_t isoRecvIntEvent,
+ quadlet_t isoXmitIntEvent)
+{
+ int i;
+ struct video_card *video = &video_cards[card];
+
+ DBGMSG(card, "Iso event Recv: %08x Xmit: %08x",
+ isoRecvIntEvent, isoXmitIntEvent);
+
+ for (i=0;i<video->ohci->nb_iso_rcv_ctx-1;i++)
+ if (isoRecvIntEvent & (1<<(i+1)))
+ wakeup_dma_ir_ctx(video->ohci,
+ video->ir_context[i]);
+
+ for (i=0;i<video->ohci->nb_iso_xmit_ctx;i++)
+ if (isoXmitIntEvent & (1<<i))
+ wakeup_dma_it_ctx(video->ohci,
+ video->it_context[i]);
+}
+
+static struct file_operations video1394_fops=
+{
+ OWNER_THIS_MODULE
+ ioctl: video1394_ioctl,
+ mmap: video1394_mmap,
+ open: video1394_open,
+ release: video1394_release
+};
+
+static int video1394_init(int i, struct ti_ohci *ohci)
+{
+ struct video_card *video = &video_cards[i];
+
+ if (ohci1394_register_video(ohci, &video_tmpl)<0) {
+ PRINT(KERN_ERR, i, "register_video failed");
+ return -1;
+ }
+
+ video->ohci = ohci;
+
+ /* Iso receive dma contexts */
+ video->ir_context = (struct dma_iso_ctx **)
+ kmalloc((ohci->nb_iso_rcv_ctx-1)*
+ sizeof(struct dma_iso_ctx *), GFP_KERNEL);
+ if (video->ir_context)
+ memset(video->ir_context, 0,
+ (ohci->nb_iso_rcv_ctx-1)*sizeof(struct dma_iso_ctx *));
+ else {
+ PRINT(KERN_ERR, ohci->id, "Cannot allocate ir_context");
+ return -1;
+ }
+
+ /* Iso transmit dma contexts */
+ video->it_context = (struct dma_iso_ctx **)
+ kmalloc(ohci->nb_iso_xmit_ctx *
+ sizeof(struct dma_iso_ctx *), GFP_KERNEL);
+ if (video->it_context)
+ memset(video->it_context, 0,
+ ohci->nb_iso_xmit_ctx * sizeof(struct dma_iso_ctx *));
+ else {
+ PRINT(KERN_ERR, ohci->id, "Cannot allocate it_context");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void remove_card(struct video_card *video)
+{
+ int i;
+
+ ohci1394_unregister_video(video->ohci, &video_tmpl);
+
+ /* Free the iso receive contexts */
+ if (video->ir_context) {
+ for (i=0;i<video->ohci->nb_iso_rcv_ctx-1;i++) {
+ free_dma_iso_ctx(&video->ir_context[i]);
+ }
+ kfree(video->ir_context);
+ }
+
+ /* Free the iso transmit contexts */
+ if (video->it_context) {
+ for (i=0;i<video->ohci->nb_iso_xmit_ctx;i++) {
+ free_dma_iso_ctx(&video->it_context[i]);
+ }
+ kfree(video->it_context);
+ }
+}
+
+#ifdef MODULE
+
+/* EXPORT_NO_SYMBOLS; */
+
+MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
+MODULE_DESCRIPTION("driver for digital video on OHCI board");
+MODULE_SUPPORTED_DEVICE("video1394");
+
+void cleanup_module(void)
+{
+ int i;
+ unregister_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME);
+
+ for (i=0; i<num_of_video_cards; i++)
+ remove_card(&video_cards[i]);
+
+ printk(KERN_INFO "removed " VIDEO1394_DRIVER_NAME " module\n");
+}
+
+int init_module(void)
+{
+ struct ti_ohci *ohci;
+ int i;
+
+ memset(video_cards, 0, MAX_OHCI1394_CARDS * sizeof(struct video_card));
+ num_of_video_cards = 0;
+
+ for (i=0; i<MAX_OHCI1394_CARDS; i++) {
+ ohci=ohci1394_get_struct(i);
+ if (ohci) {
+ num_of_video_cards++;
+ video1394_init(i, ohci);
+ }
+ }
+
+ if (!num_of_video_cards) {
+ PRINT_G(KERN_INFO, "no ohci card found... init failed");
+ return -EIO;
+ }
+
+ if (register_chrdev(VIDEO1394_MAJOR, VIDEO1394_DRIVER_NAME,
+ &video1394_fops)) {
+ printk("video1394: unable to get major %d\n",
+ VIDEO1394_MAJOR);
+ return -EIO;
+ }
+
+ PRINT_G(KERN_INFO, "initialized with %d ohci cards",
+ num_of_video_cards);
+
+ return 0;
+}
+
+#endif /* MODULE */
+
+
diff --git a/drivers/ieee1394/video1394.h b/drivers/ieee1394/video1394.h
index 47b8e64a2..dc6e5c981 100644
--- a/drivers/ieee1394/video1394.h
+++ b/drivers/ieee1394/video1394.h
@@ -20,6 +20,8 @@
#ifndef _VIDEO_1394_H
#define _VIDEO_1394_H
+#define VIDEO1394_DRIVER_NAME "video1394"
+
#define VIDEO1394_MAX_SIZE 0x400000
enum {
@@ -31,8 +33,12 @@ enum {
enum {
VIDEO1394_LISTEN_CHANNEL = 0,
VIDEO1394_UNLISTEN_CHANNEL,
- VIDEO1394_QUEUE_BUFFER,
- VIDEO1394_WAIT_BUFFER
+ VIDEO1394_LISTEN_QUEUE_BUFFER,
+ VIDEO1394_LISTEN_WAIT_BUFFER,
+ VIDEO1394_TALK_CHANNEL,
+ VIDEO1394_UNTALK_CHANNEL,
+ VIDEO1394_TALK_QUEUE_BUFFER,
+ VIDEO1394_TALK_WAIT_BUFFER
};
struct video1394_mmap {
@@ -40,6 +46,8 @@ struct video1394_mmap {
int sync_tag;
int nb_buffers;
int buf_size;
+ int packet_size;
+ int fps;
};
struct video1394_wait {
@@ -47,4 +55,5 @@ struct video1394_wait {
int buffer;
};
-#endif
+
+#endif
diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c
index 610c20b6d..009010896 100644
--- a/drivers/isdn/avmb1/capi.c
+++ b/drivers/isdn/avmb1/capi.c
@@ -2089,7 +2089,7 @@ int capi_init(void)
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
devfs_unregister_chrdev(capi_rawmajor, "capi/r%d");
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
- devfs_unregister(devfs_find_handle(NULL, "capi20", 0,
+ devfs_unregister(devfs_find_handle(NULL, "capi20",
capi_major, 0,
DEVFS_SPECIAL_CHR, 0));
return -EIO;
@@ -2112,13 +2112,13 @@ int capi_init(void)
for (j = 0; j < CAPINC_NR_PORTS; j++) {
char devname[32];
sprintf(devname, "capi/r%u", j);
- devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_rawmajor, j, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, devname, capi_rawmajor, j, DEVFS_SPECIAL_CHR, 0));
}
capinc_tty_exit();
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
(void) detach_capi_interface(&cuser);
devfs_unregister_chrdev(capi_major, "capi20");
- devfs_unregister(devfs_find_handle(NULL, "capi20", 0,
+ devfs_unregister(devfs_find_handle(NULL, "capi20",
capi_major, 0,
DEVFS_SPECIAL_CHR, 0));
MOD_DEC_USE_COUNT;
@@ -2144,7 +2144,7 @@ void cleanup_module(void)
(void)proc_exit();
devfs_unregister_chrdev(capi_major, "capi20");
- devfs_unregister(devfs_find_handle(NULL, "isdn/capi20", 0, capi_major, 0, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, "isdn/capi20", capi_major, 0, DEVFS_SPECIAL_CHR, 0));
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
capinc_tty_exit();
@@ -2152,7 +2152,7 @@ void cleanup_module(void)
for (j = 0; j < CAPINC_NR_PORTS; j++) {
char devname[32];
sprintf(devname, "capi/r%u", j);
- devfs_unregister(devfs_find_handle(NULL, devname, 0, capi_rawmajor, j, DEVFS_SPECIAL_CHR, 0));
+ devfs_unregister(devfs_find_handle(NULL, devname, capi_rawmajor, j, DEVFS_SPECIAL_CHR, 0));
}
#endif
(void) detach_capi_interface(&cuser);
diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c
index fa5a3d844..f6c326301 100644
--- a/drivers/isdn/isdn_common.c
+++ b/drivers/isdn/isdn_common.c
@@ -2603,7 +2603,7 @@ static void isdn_init_devfs(void)
int i;
# endif
- devfs_handle = devfs_mk_dir (NULL, "isdn", 4, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "isdn", NULL);
# ifdef CONFIG_ISDN_PPP
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
char buf[8];
diff --git a/drivers/mtd/.cvsignore b/drivers/mtd/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/drivers/mtd/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/drivers/mtd/Config.in b/drivers/mtd/Config.in
new file mode 100644
index 000000000..26fcfe517
--- /dev/null
+++ b/drivers/mtd/Config.in
@@ -0,0 +1,43 @@
+mainmenu_option next_comment
+comment 'Memory Technology Devices (MTD)'
+
+tristate 'Memory Technology Device (MTD) support' CONFIG_MTD
+
+if [ "$CONFIG_MTD" != "n" ]; then
+ dep_tristate 'Common Flash Interface (CFI) support' CONFIG_MTD_CFI $CONFIG_MTD
+ dep_tristate 'CFI support for Intel/Sharp Extended Command Set chips' CONFIG_MTD_CFI_INTELEXT $CONFIG_CFI
+ dep_tristate 'CFI chips in virtual memory map' CONFIG_MTD_NORA $CONFIG_MTD_CFI
+ dep_tristate 'CFI chips in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_CFI
+ dep_tristate 'CFI chips on RPXLite PPC board' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI
+ dep_tristate 'M-Systems Disk-On-Chip 1000 support' CONFIG_MTD_DOC1000 $CONFIG_MTD
+ dep_tristate 'M-Systems Disk-On-Chip 2000' CONFIG_MTD_DOC2000 $CONFIG_MTD
+ dep_tristate 'M-Systems Disk-On-Chip Millennium' CONFIG_MTD_DOC2001 $CONFIG_MTD
+ if [ "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" ]; then
+ define_bool CONFIG_MTD_DOCPROBE y
+ else
+ if [ "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" ]; then
+ define_bool CONFIG_MTD_DOCPROBE m
+ else
+ define_bool CONFIG_MTD_DOCPROBE n
+ fi
+ fi
+ dep_tristate 'Use extra onboard system memory as MTD device' CONFIG_MTD_SLRAM $CONFIG_MTD
+ dep_tristate 'Octagon 5066 SBC onboard flash support' CONFIG_MTD_OCTAGON $CONFIG_MTD
+ dep_tristate 'Tempustech VMAX SBC301 onboard flash support' CONFIG_MTD_VMAX $CONFIG_MTD
+ dep_tristate 'Mixcom piggyback flash card support' CONFIG_MTD_MIXMEM $CONFIG_MTD
+ dep_tristate 'Ramix PMC551 PCI Mezzanine ram card support' CONFIG_MTD_PMC551 $CONFIG_MTD
+ if [ "$CONFIG_MTD_PMC551" != "n" ]; then
+ bool 'PMC551 256M DRAM Bugfix' CONFIG_MTD_PMC551_BUGFIX
+ fi
+ dep_tristate 'Debugging RAM test driver' CONFIG_MTD_MTDRAM $CONFIG_MTD
+
+ dep_tristate 'FTL (Flash Translation Layer) support' CONFIG_FTL $CONFIG_MTD
+ dep_tristate 'NFTL (NAND Flash Translation Layer) support' CONFIG_NFTL $CONFIG_MTD
+ if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_NFTL" != "n" ]; then
+ bool 'Write support for NFTL (EXPERIMENTAL)' CONFIG_NFTL_RW
+ fi
+ dep_tristate 'Direct blockdevice access to MTD devices' CONFIG_MTD_BLOCK $CONFIG_MTD
+ dep_tristate 'Direct chardevice access to MTD devices' CONFIG_MTD_CHAR $CONFIG_MTD
+fi
+
+endmenu
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
new file mode 100644
index 000000000..53a3906f8
--- /dev/null
+++ b/drivers/mtd/Makefile
@@ -0,0 +1,190 @@
+# $Id: Makefile,v 1.20 2000/07/04 08:58:10 dwmw2 Exp $
+
+# Uncomment this to enable the DBG macro (see mtd.h)
+#CFLAGS+= -DZDBG
+
+ifndef CONFIG_MTD
+# We're being invoked outside a normal kernel build. Fake it
+EXTRA_CFLAGS= -I$(shell pwd)/../include
+
+HWDRIVERS = slram.o docprobe.o doc1000.o nora.o physmap.o rpxlite.o vmax301.o octagon-5066.o pmc551.o mtdram.o
+USERDRIVERS = ftl.o nftl.o mtdblock.o mtdchar.o
+MIX_OBJS = mtdcore.o mapped.o doc2000.o doc2001.o cfi_probe.o cfi_cmdset_0001.o
+MI_OBJS = $(HWDRIVERS) $(USERDRIVERS)
+CFLAGS_nftl.o := -DCONFIG_NFTL_RW
+else
+
+O_TARGET := mtdlink.o
+SUB_DIRS :=
+ALL_SUB_DIRS :=
+MOD_LIST_NAME := MTD_MODULES
+
+
+ifeq ($(CONFIG_MTD),y)
+ OX_OBJS += mtdcore.o mapped.o
+else
+ ifeq ($(CONFIG_MTD),m)
+ MX_OBJS += mtdcore.o mapped.o
+ endif
+endif
+
+ifeq ($(CONFIG_MTD_NORA),y)
+ O_OBJS += nora.o
+else
+ ifeq ($(CONFIG_MTD_NORA),m)
+ M_OBJS += nora.o
+ endif
+endif
+
+ifeq ($(CONFIG_MTD_RPXLITE),y)
+ O_OBJS += rpxlite.o
+else
+ ifeq ($(CONFIG_MTD_RPXLITE),m)
+ M_OBJS += rpxlite.o
+ endif
+endif
+
+ifeq ($(CONFIG_MTD_PHYSMAP),y)
+ O_OBJS += physmap.o
+else
+ ifeq ($(CONFIG_MTD_PHYSMAP),m)
+ M_OBJS += physmap.o
+ endif
+endif
+
+ifeq ($(CONFIG_MTD_CFI),y)
+ OX_OBJS += cfi_probe.o
+else
+ ifeq ($(CONFIG_MTD_CFI),m)
+ MX_OBJS += cfi_probe.o
+ endif
+endif
+
+ifeq ($(CONFIG_MTD_CFI_INTELEXT),y)
+ OX_OBJS += cfi_cmdset_0001.o
+else
+ ifeq ($(CONFIG_MTD_CFI_INTELEXT),m)
+ MX_OBJS += cfi_cmdset_0001.o
+ endif
+endif
+
+ifeq ($(CONFIG_MTD_DOC1000),y)
+ O_OBJS += doc1000.o
+else
+ ifeq ($(CONFIG_MTD_DOC1000),m)
+ M_OBJS += doc1000.o
+ endif
+endif
+
+ifeq ($(CONFIG_MTD_DOC2000),y)
+ OX_OBJS += doc2000.o
+else
+ ifeq ($(CONFIG_MTD_DOC2000),m)
+ MX_OBJS += doc2000.o
+ endif
+endif
+
+ifeq ($(CONFIG_MTD_DOC2001),y)
+ OX_OBJS += doc2001.o
+else
+ ifeq ($(CONFIG_MTD_DOC2001),m)
+ MX_OBJS += doc2001.o
+ endif
+endif
+
+ifeq ($(CONFIG_MTD_DOCPROBE),y)
+ O_OBJS += docprobe.o
+else
+ ifeq ($(CONFIG_MTD_DOCPROBE),m)
+ M_OBJS += docprobe.o
+ endif
+endif
+
+ifeq ($(CONFIG_MTD_SLRAM),y)
+ O_OBJS += slram.o
+else
+ ifeq ($(CONFIG_MTD_SLRAM),m)
+ M_OBJS += slram.o
+ endif
+endif
+
+ifeq ($(CONFIG_MTD_OCTAGON),y)
+ O_OBJS += octagon-5066.o
+else
+ ifeq ($(CONFIG_MTD_OCTAGON),m)
+ M_OBJS += octagon-5066.o
+ endif
+endif
+
+ifeq ($(CONFIG_MTD_PMC551),y)
+ O_OBJS += pmc551.o
+else
+ ifeq ($(CONFIG_MTD_PMC551),m)
+ M_OBJS += pmc551.o
+ endif
+endif
+
+ifeq ($(CONFIG_MTD_PMC551_BUGFIX),y)
+ CFLAGS_pmc551.o += -DPMC551_DRAM_BUG
+endif
+
+ifeq ($(CONFIG_MTD_VMAX),y)
+ O_OBJS += vmax301.o
+else
+ ifeq ($(CONFIG_MTD_VMAX),m)
+ M_OBJS += vmax301.o
+ endif
+endif
+
+ifeq ($(CONFIG_MTD_MIXMEM),y)
+ O_OBJS += mixmem.o
+else
+ ifeq ($(CONFIG_MTD_MIXMEM),m)
+ M_OBJS += mixmem.o
+ endif
+endif
+
+ifeq ($(CONFIG_MTD_MTDRAM),y)
+ O_OBJS += mtdram.o
+else
+ ifeq ($(CONFIG_MTD_MTDRAM),m)
+ M_OBJS += mtdram.o
+ endif
+endif
+
+ifeq ($(CONFIG_FTL),y)
+ O_OBJS += ftl.o
+else
+ ifeq ($(CONFIG_FTL),m)
+ M_OBJS += ftl.o
+ endif
+endif
+
+ifeq ($(CONFIG_NFTL),y)
+ O_OBJS += nftl.o
+else
+ ifeq ($(CONFIG_NFTL),m)
+ M_OBJS += nftl.o
+ endif
+endif
+
+ifeq ($(CONFIG_MTD_BLOCK),y)
+ O_OBJS += mtdblock.o
+else
+ ifeq ($(CONFIG_MTD_BLOCK),m)
+ M_OBJS += mtdblock.o
+ endif
+endif
+
+
+ifeq ($(CONFIG_MTD_CHAR),y)
+ O_OBJS += mtdchar.o
+else
+ ifeq ($(CONFIG_MTD_CHAR),m)
+ M_OBJS += mtdchar.o
+ endif
+endif
+
+endif
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/mtd/cfi_cmdset_0001.c b/drivers/mtd/cfi_cmdset_0001.c
new file mode 100644
index 000000000..713d8ab05
--- /dev/null
+++ b/drivers/mtd/cfi_cmdset_0001.c
@@ -0,0 +1,871 @@
+/*
+ * Common Flash Interface support:
+ * Intel Extended Vendor Command Set (ID 0x0001)
+ *
+ * (C) 2000 Red Hat. GPL'd
+ *
+ * $Id: cfi_cmdset_0001.c,v 1.20 2000/07/04 07:36:43 dwmw2 Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+
+#if LINUX_VERSION_CODE < 0x20300
+#define set_current_state(x) current->state = (x);
+#endif
+static int cfi_intelext_read_1_by_16 (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_write_1_by_16(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+static int cfi_intelext_erase_1_by_16 (struct mtd_info *, struct erase_info *);
+static void cfi_intelext_sync (struct mtd_info *);
+static int cfi_intelext_suspend (struct mtd_info *);
+static void cfi_intelext_resume (struct mtd_info *);
+
+static void cfi_intelext_destroy(struct mtd_info *);
+
+void cfi_cmdset_0001(struct map_info *, int, unsigned long);
+EXPORT_SYMBOL(cfi_cmdset_0001);
+
+struct mtd_info *cfi_intelext_setup (struct map_info *);
+
+void cfi_cmdset_0001(struct map_info *map, int primary, unsigned long base)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ int i;
+ struct cfi_pri_intelext *extp;
+
+ __u16 adr = primary?cfi->cfiq.P_ADR:cfi->cfiq.A_ADR;
+
+ printk(" Intel/Sharp Extended Query Table at 0x%4.4X\n", adr);
+
+ if (!adr)
+ return;
+
+ /* Switch it into Query Mode */
+ switch(map->buswidth) {
+ case 1:
+ map->write8(map, 0x98, 0x55);
+ break;
+ case 2:
+ map->write16(map, 0x9898, 0xaa);
+ break;
+ case 4:
+ map->write32(map, 0x98989898, 0x154);
+ break;
+ }
+
+ extp = kmalloc(sizeof(*extp), GFP_KERNEL);
+ if (!extp) {
+ printk("Failed to allocate memory\n");
+ return;
+ }
+
+ /* Read in the Extended Query Table */
+ for (i=0; i<sizeof(*extp); i++) {
+ ((unsigned char *)extp)[i] =
+ map->read8(map, (base+((adr+i)*map->buswidth)));
+ }
+
+ if (extp->MajorVersion != '1' ||
+ (extp->MinorVersion < '0' || extp->MinorVersion > '2')) {
+ printk(" Unknown IntelExt Extended Query version %c.%c.\n",
+ extp->MajorVersion, extp->MinorVersion);
+ kfree(extp);
+ return;
+ }
+
+ /* Do some byteswapping if necessary */
+ extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
+ extp->BlkStatusRegMask = le32_to_cpu(extp->BlkStatusRegMask);
+
+
+ /* Tell the user about it in lots of lovely detail */
+#if 0
+ printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport);
+ printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported");
+ printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported");
+ printk(" - Suspend Program: %s\n", extp->FeatureSupport&4?"supported":"unsupported");
+ printk(" - Legacy Lock/Unlock: %s\n", extp->FeatureSupport&8?"supported":"unsupported");
+ printk(" - Queued Erase: %s\n", extp->FeatureSupport&16?"supported":"unsupported");
+ printk(" - Instant block lock: %s\n", extp->FeatureSupport&32?"supported":"unsupported");
+ printk(" - Protection Bits: %s\n", extp->FeatureSupport&64?"supported":"unsupported");
+ printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported");
+ printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported");
+ for (i=9; i<32; i++) {
+ if (extp->FeatureSupport & (1<<i))
+ printk(" - Unknown Bit %X: supported\n", i);
+ }
+
+ printk(" Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport);
+ printk(" - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported");
+ for (i=1; i<8; i++) {
+ if (extp->SuspendCmdSupport & (1<<i))
+ printk(" - Unknown Bit %X: supported\n", i);
+ }
+
+ printk(" Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask);
+ printk(" - Lock Bit Active: %s\n", extp->BlkStatusRegMask&1?"yes":"no");
+ printk(" - Valid Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no");
+ for (i=2; i<16; i++) {
+ if (extp->BlkStatusRegMask & (1<<i))
+ printk(" - Unknown Bit %X Active: yes\n",i);
+ }
+
+ printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n",
+ extp->VccOptimal >> 8, extp->VccOptimal & 0xf);
+ if (extp->VppOptimal)
+ printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n",
+ extp->VppOptimal >> 8, extp->VppOptimal & 0xf);
+#endif
+ /* OK. We like it. Take over the control of it. */
+
+ /* Switch it into Read Mode */
+ switch(map->buswidth) {
+ case 1:
+ map->write8(map, 0xff, 0x55);
+ break;
+ case 2:
+ map->write16(map, 0xffff, 0xaa);
+ break;
+ case 4:
+ map->write32(map, 0xffffffff, 0x154);
+ break;
+ }
+
+
+ /* If there was an old setup function, decrease its use count */
+ if (cfi->cmdset_setup)
+ put_module_symbol((unsigned long)cfi->cmdset_setup);
+ if (cfi->cmdset_priv)
+ kfree(cfi->cmdset_priv);
+
+ for (i=0; i< cfi->numchips; i++) {
+ cfi->chips[i].word_write_time = 128;
+ cfi->chips[i].buffer_write_time = 128;
+ cfi->chips[i].erase_time = 1024;
+ }
+
+
+ cfi->cmdset_setup = cfi_intelext_setup;
+ cfi->cmdset_priv = extp;
+ MOD_INC_USE_COUNT; /* So the setup function is still there
+ * by the time it's called */
+
+ return;
+}
+
+struct mtd_info *cfi_intelext_setup(struct map_info *map)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ struct mtd_info *mtd;
+
+ mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+ printk("number of CFI chips: %d\n", cfi->numchips);
+
+ if (!mtd) {
+ printk("Failed to allocate memory for MTD device\n");
+ kfree(cfi->cmdset_priv);
+ return NULL;
+ }
+
+ memset(mtd, 0, sizeof(*mtd));
+ mtd->priv = map;
+ mtd->type = MTD_NORFLASH;
+ mtd->erasesize = 0x20000; /* FIXME */
+ /* Also select the correct geometry setup too */
+ mtd->size = (1 << cfi->cfiq.DevSize) * cfi->numchips;
+ mtd->erase = cfi_intelext_erase_1_by_16;
+ mtd->read = cfi_intelext_read_1_by_16;
+ mtd->write = cfi_intelext_write_1_by_16;
+ mtd->sync = cfi_intelext_sync;
+ mtd->suspend = cfi_intelext_suspend;
+ mtd->resume = cfi_intelext_resume;
+ mtd->flags = MTD_CAP_NORFLASH;
+ map->fldrv_destroy = cfi_intelext_destroy;
+ mtd->name = map->name;
+ return mtd;
+}
+
+static inline int do_read_1_by_16_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
+{
+ __u16 status;
+ unsigned long timeo = jiffies + HZ;
+ DECLARE_WAITQUEUE(wait, current);
+
+ adr += chip->start;
+
+ retry:
+ spin_lock_bh(chip->mutex);
+
+ /* Check that the chip's ready to talk to us.
+ * Later, we can actually think about interrupting it
+ * if it's in FL_ERASING or FL_WRITING state.
+ * Not just yet, though.
+ */
+ switch (chip->state) {
+#if 0
+ case FL_ERASING:
+ case FL_WRITING:
+ /* Suspend the operation, set state to FL_xxx_SUSPENDED */
+#endif
+
+ case FL_CFI_QUERY:
+ case FL_JEDEC_QUERY:
+ case FL_READY:
+ map->write16(map, cpu_to_le16(0x0070), adr);
+ chip->state = FL_STATUS;
+
+ case FL_STATUS:
+ status = le16_to_cpu(map->read16(map, adr));
+
+ if (!(status & (1<<7))) {
+ static int z=0;
+ /* Urgh. Chip not yet ready to talk to us. */
+ if (time_after(jiffies, timeo)) {
+ spin_unlock_bh(chip->mutex);
+ printk("waiting for chip to be ready timed out in read");
+ return -EIO;
+ }
+
+ /* Latency issues. Drop the lock, wait a while and retry */
+ spin_unlock_bh(chip->mutex);
+
+ z++;
+ if ( 0 && !(z % 100 ))
+ printk("chip not ready yet before read. looping\n");
+
+ udelay(1);
+
+ goto retry;
+ }
+ break;
+
+ default:
+ printk("Waiting for chip, status = %d\n", chip->state);
+
+ /* Stick ourselves on a wait queue to be woken when
+ someone changes the status */
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&chip->wq, &wait);
+
+ spin_unlock_bh(chip->mutex);
+
+ schedule();
+ remove_wait_queue(&chip->wq, &wait);
+
+ if(signal_pending(current))
+ return -EINTR;
+
+
+ timeo = jiffies + HZ;
+
+ goto retry;
+ }
+
+ map->write16(map, cpu_to_le16(0x00ff), adr);
+ chip->state = FL_READY;
+
+ map->copy_from(map, buf, adr, len);
+
+ if (chip->state == FL_ERASE_SUSPENDED ||
+ chip->state == FL_WRITE_SUSPENDED) {
+ printk("Who in hell suspended the pending operation? I didn't write that code yet!\n");
+ /* Restart it and set the state accordingly */
+ }
+
+ wake_up(&chip->wq);
+ spin_unlock_bh(chip->mutex);
+
+ return 0;
+}
+
+static int cfi_intelext_read_1_by_16 (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ unsigned long ofs;
+ int chipnum;
+ int ret = 0;
+
+ /* ofs: offset within the first chip that the first read should start */
+ chipnum = (from >> cfi->chipshift);
+ ofs = from - (chipnum << cfi->chipshift);
+
+ *retlen = 0;
+
+ while (len) {
+ unsigned long thislen;
+
+ if (chipnum >= cfi->numchips)
+ break;
+
+ if ((len + ofs -1) >> cfi->chipshift)
+ thislen = (1<<cfi->chipshift) - ofs;
+ else
+ thislen = len;
+
+ ret = do_read_1_by_16_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
+ if (ret)
+ break;
+
+ *retlen += thislen;
+ len -= thislen;
+ buf += thislen;
+
+ ofs = 0;
+ chipnum++;
+ }
+ return ret;
+}
+
+static inline int do_write_1_by_16_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u16 datum)
+{
+ __u16 status;
+ unsigned long timeo = jiffies + HZ;
+ DECLARE_WAITQUEUE(wait, current);
+ int z = 0;
+ adr += chip->start;
+
+ retry:
+ spin_lock_bh(chip->mutex);
+
+ /* Check that the chip's ready to talk to us.
+ * Later, we can actually think about interrupting it
+ * if it's in FL_ERASING state.
+ * Not just yet, though.
+ */
+ switch (chip->state) {
+ case FL_CFI_QUERY:
+ case FL_JEDEC_QUERY:
+ case FL_READY:
+ map->write16(map, cpu_to_le16(0x0070), adr);
+ chip->state = FL_STATUS;
+ timeo = jiffies + HZ;
+
+ case FL_STATUS:
+ status = le16_to_cpu(map->read16(map, adr));
+
+ if (!(status & (1<<7))) {
+
+ /* Urgh. Chip not yet ready to talk to us. */
+ if (time_after(jiffies, timeo)) {
+ spin_unlock_bh(chip->mutex);
+ printk("waiting for chip to be ready timed out in read");
+ return -EIO;
+ }
+
+ /* Latency issues. Drop the lock, wait a while and retry */
+ spin_unlock_bh(chip->mutex);
+
+ z++;
+ if ( 0 && !(z % 100 ))
+ printk("chip not ready yet before write. looping\n");
+
+ udelay(1);
+
+ goto retry;
+ }
+ break;
+
+ default:
+ printk("Waiting for chip, status = %d\n", chip->state);
+
+ /* Stick ourselves on a wait queue to be woken when
+ someone changes the status */
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&chip->wq, &wait);
+
+ spin_unlock_bh(chip->mutex);
+
+ schedule();
+ remove_wait_queue(&chip->wq, &wait);
+
+ if(signal_pending(current))
+ return -EINTR;
+
+ timeo = jiffies + HZ;
+
+ goto retry;
+ }
+
+ map->write16(map, cpu_to_le16(0x0040), adr);
+ map->write16(map, datum, adr);
+ chip->state = FL_WRITING;
+
+ timeo = jiffies + (HZ/2);
+
+ spin_unlock_bh(chip->mutex);
+ udelay(chip->word_write_time);
+ spin_lock_bh(chip->mutex);
+
+ z = 0;
+ while ( !( (status = le16_to_cpu(map->read16(map, adr))) & 0x80 ) ) {
+
+ if (chip->state != FL_WRITING) {
+ /* Someone's suspended the write. Sleep */
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&chip->wq, &wait);
+
+ spin_unlock_bh(chip->mutex);
+
+ schedule();
+ remove_wait_queue(&chip->wq, &wait);
+
+ if (signal_pending(current))
+ return -EINTR;
+
+ timeo = jiffies + (HZ / 2); /* FIXME */
+
+ spin_lock_bh(chip->mutex);
+ continue;
+ }
+
+ /* OK Still waiting */
+ if (time_after(jiffies, timeo)) {
+ chip->state = FL_STATUS;
+ spin_unlock_bh(chip->mutex);
+ printk("waiting for chip to be ready timed out in read");
+ return -EIO;
+ }
+
+ /* Latency issues. Drop the lock, wait a while and retry */
+ spin_unlock_bh(chip->mutex);
+
+ z++;
+ if ( 0 && !(z % 100 ))
+ printk("chip not ready yet after write. looping\n");
+
+ udelay(1);
+
+ spin_lock_bh(chip->mutex);
+ continue;
+ }
+ if (!z) {
+ chip->word_write_time--;
+ if (!chip->word_write_time)
+ chip->word_write_time++;
+ else
+ printk("decreasing word_write_time to %d µs\n", chip->word_write_time);
+ }
+ if (z > 100) {
+ chip->word_write_time++;
+ printk("increasing word_write_time to %d µs\n", chip->word_write_time);
+ }
+
+ /* Done and happy. */
+ chip->state = FL_STATUS;
+ wake_up(&chip->wq);
+ spin_unlock_bh(chip->mutex);
+ // printk("write ret OK at %lx\n", adr);
+ return 0;
+}
+
+
+/* This version only uses the 'word write' instruction. We should update it
+ * to write using 'buffer write' if it's available
+ */
+static int cfi_intelext_write_1_by_16 (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ int ret = 0;
+ int chipnum;
+ unsigned long ofs;
+
+ *retlen = 0;
+ chipnum = to >> cfi->chipshift;
+ ofs = to - (chipnum << cfi->chipshift);
+
+ /* If it's not word-aligned, do the first byte write */
+ if (ofs & 1) {
+#if defined(__LITTLE_ENDIAN)
+ ret = do_write_1_by_16_oneword(map, &cfi->chips[chipnum],
+ ofs, 0xFF | (*buf << 8));
+#elif defined(__BIG_ENDIAN)
+ ret = do_write_1_by_16_oneword(map, &cfi->chips[chipnum],
+ ofs, 0xFF00 | (*buf));
+#else
+#error define a sensible endianness
+#endif
+ if (ret)
+ return ret;
+
+ ofs++;
+ buf++;
+ (*retlen)++;
+ len--;
+
+ if (ofs >> cfi->chipshift) {
+ chipnum ++;
+ ofs = 0;
+ if (chipnum == cfi->numchips)
+ return 0;
+ }
+ }
+
+ while(len > 1) {
+ ret = do_write_1_by_16_oneword(map, &cfi->chips[chipnum],
+ ofs, *(__u16 *)buf);
+ if (ret)
+ return ret;
+
+ ofs += 2;
+ buf += 2;
+ (*retlen) += 2;
+ len -= 2;
+
+ if (ofs >> cfi->chipshift) {
+ chipnum ++;
+ ofs = 0;
+ if (chipnum == cfi->numchips)
+ return 0;
+ }
+ }
+
+ if (len) {
+ /* Final byte to write */
+#if defined(__LITTLE_ENDIAN)
+ ret = do_write_1_by_16_oneword(map, &cfi->chips[chipnum],
+ ofs, 0xFF00 | (*buf));
+#elif defined(__BIG_ENDIAN)
+ ret = do_write_1_by_16_oneword(map, &cfi->chips[chipnum],
+ ofs, 0xFF | (*buf << 8));
+#else
+#error define a sensible endianness
+#endif
+ if (ret)
+ return ret;
+
+ (*retlen)++;
+ }
+
+ return 0;
+}
+
+
+static inline int do_erase_1_by_16_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+{
+ __u16 status;
+ unsigned long timeo = jiffies + HZ;
+ DECLARE_WAITQUEUE(wait, current);
+
+ adr += chip->start;
+
+ retry:
+ spin_lock_bh(chip->mutex);
+
+ /* Check that the chip's ready to talk to us. */
+ switch (chip->state) {
+ case FL_CFI_QUERY:
+ case FL_JEDEC_QUERY:
+ case FL_READY:
+ map->write16(map, cpu_to_le16(0x0070), adr);
+ chip->state = FL_STATUS;
+ timeo = jiffies + HZ;
+
+ case FL_STATUS:
+ status = le16_to_cpu(map->read16(map, adr));
+
+ if (!(status & (1<<7))) {
+ static int z=0;
+ /* Urgh. Chip not yet ready to talk to us. */
+ if (time_after(jiffies, timeo)) {
+ spin_unlock_bh(chip->mutex);
+ printk("waiting for chip to be ready timed out in erase");
+ return -EIO;
+ }
+
+ /* Latency issues. Drop the lock, wait a while and retry */
+ spin_unlock_bh(chip->mutex);
+
+ z++;
+ if ( 0 && !(z % 100 ))
+ printk("chip not ready yet before erase. looping\n");
+
+ udelay(1);
+
+ goto retry;
+ }
+ break;
+
+ default:
+ printk("Waiting for chip, status = %d\n", chip->state);
+
+ /* Stick ourselves on a wait queue to be woken when
+ someone changes the status */
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&chip->wq, &wait);
+
+ spin_unlock_bh(chip->mutex);
+
+ schedule();
+ remove_wait_queue(&chip->wq, &wait);
+
+ if(signal_pending(current))
+ return -EINTR;
+
+ timeo = jiffies + HZ;
+
+ goto retry;
+ }
+
+ map->write16(map, cpu_to_le16(0x0020), adr);
+ map->write16(map, cpu_to_le16(0x00D0), adr);
+
+ chip->state = FL_ERASING;
+
+ timeo = jiffies + (HZ*2);
+ spin_unlock_bh(chip->mutex);
+ schedule_timeout(HZ);
+ spin_lock_bh(chip->mutex);
+
+ /* FIXME. Use a timer to check this, and return immediately. */
+ /* Once the state machine's known to be working I'll do that */
+
+ while ( !( (status = le16_to_cpu(map->read16(map, adr))) & 0x80 ) ) {
+ static int z=0;
+
+ if (chip->state != FL_ERASING) {
+ /* Someone's suspended the erase. Sleep */
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&chip->wq, &wait);
+
+ spin_unlock_bh(chip->mutex);
+ printk("erase suspended. Sleeping\n");
+
+ schedule();
+ remove_wait_queue(&chip->wq, &wait);
+
+ if (signal_pending(current))
+ return -EINTR;
+
+ timeo = jiffies + (HZ*2); /* FIXME */
+ spin_lock_bh(chip->mutex);
+ continue;
+ }
+
+ /* OK Still waiting */
+ if (time_after(jiffies, timeo)) {
+ chip->state = FL_STATUS;
+ spin_unlock_bh(chip->mutex);
+ printk("waiting for erase to complete timed out.");
+ return -EIO;
+ }
+
+ /* Latency issues. Drop the lock, wait a while and retry */
+ spin_unlock_bh(chip->mutex);
+
+ z++;
+ if ( 0 && !(z % 100 ))
+ printk("chip not ready yet after erase. looping\n");
+
+ udelay(1);
+
+ spin_lock_bh(chip->mutex);
+ continue;
+ }
+
+ /* Done and happy. */
+ chip->state = FL_STATUS;
+ wake_up(&chip->wq);
+ spin_unlock_bh(chip->mutex);
+ //printk("erase ret OK\n");
+ return 0;
+}
+
+static int cfi_intelext_erase_1_by_16 (struct mtd_info *mtd, struct erase_info *instr)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ unsigned long adr, len;
+ int chipnum, ret = 0;
+
+ if (instr->addr & (mtd->erasesize - 1))
+ return -EINVAL;
+
+ if (instr->len & (mtd->erasesize -1))
+ return -EINVAL;
+
+ if ((instr->len + instr->addr) > mtd->size)
+ return -EINVAL;
+
+ chipnum = instr->addr >> cfi->chipshift;
+ adr = instr->addr - (chipnum << cfi->chipshift);
+ len = instr->len;
+
+ while(len) {
+ ret = do_erase_1_by_16_oneblock(map, &cfi->chips[chipnum], adr);
+
+ if (ret)
+ return ret;
+
+ adr += mtd->erasesize;
+ len -= mtd->erasesize;
+
+ if (adr >> cfi->chipshift) {
+ adr = 0;
+ chipnum++;
+
+ if (chipnum >= cfi->numchips)
+ break;
+ }
+ }
+
+ if (instr->callback)
+ instr->callback(instr);
+
+ return 0;
+}
+
+
+
+static void cfi_intelext_sync (struct mtd_info *mtd)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ int i;
+ struct flchip *chip;
+ int ret = 0;
+ DECLARE_WAITQUEUE(wait, current);
+
+ for (i=0; !ret && i<cfi->numchips; i++) {
+ chip = &cfi->chips[i];
+
+ retry:
+ spin_lock_bh(chip->mutex);
+
+ switch(chip->state) {
+ case FL_READY:
+ case FL_STATUS:
+ case FL_CFI_QUERY:
+ case FL_JEDEC_QUERY:
+ chip->oldstate = chip->state;
+ chip->state = FL_SYNCING;
+ /* No need to wake_up() on this state change -
+ * as the whole point is that nobody can do anything
+ * with the chip now anyway.
+ */
+ spin_unlock_bh(chip->mutex);
+ break;
+
+ default:
+ /* Not an idle state */
+ add_wait_queue(&chip->wq, &wait);
+
+ spin_unlock_bh(chip->mutex);
+ schedule();
+
+ goto retry;
+ }
+ }
+
+ /* Unlock the chips again */
+
+ for (i--; i >=0; i--) {
+ chip = &cfi->chips[i];
+
+ spin_lock_bh(chip->mutex);
+
+ if (chip->state == FL_SYNCING) {
+ chip->state = chip->oldstate;
+ wake_up(&chip->wq);
+ }
+ spin_unlock_bh(chip->mutex);
+ }
+}
+
+
+static int cfi_intelext_suspend(struct mtd_info *mtd)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ int i;
+ struct flchip *chip;
+ int ret = 0;
+
+ for (i=0; !ret && i<cfi->numchips; i++) {
+ chip = &cfi->chips[i];
+
+ spin_lock_bh(chip->mutex);
+
+ switch(chip->state) {
+ case FL_READY:
+ case FL_STATUS:
+ case FL_CFI_QUERY:
+ case FL_JEDEC_QUERY:
+ chip->oldstate = chip->state;
+ chip->state = FL_PM_SUSPENDED;
+ /* No need to wake_up() on this state change -
+ * as the whole point is that nobody can do anything
+ * with the chip now anyway.
+ */
+ spin_unlock_bh(chip->mutex);
+ break;
+
+ default:
+ ret = -EAGAIN;
+ break;
+ }
+ }
+
+ /* Unlock the chips again */
+
+ for (i--; i >=0; i--) {
+ chip = &cfi->chips[i];
+
+ spin_lock_bh(chip->mutex);
+
+ if (chip->state == FL_PM_SUSPENDED) {
+ chip->state = chip->oldstate;
+ wake_up(&chip->wq);
+ }
+ spin_unlock_bh(chip->mutex);
+ }
+
+ return ret;
+}
+
+static void cfi_intelext_resume(struct mtd_info *mtd)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ int i;
+ struct flchip *chip;
+
+ for (i=0; i<cfi->numchips; i++) {
+
+ chip = &cfi->chips[i];
+
+ spin_lock_bh(chip->mutex);
+
+ if (chip->state == FL_PM_SUSPENDED) {
+ chip->state = chip->oldstate;
+ wake_up(&chip->wq);
+ }
+ else
+ printk("Argh. Chip not in PM_SUSPENDED state upon resume()\n");
+
+ spin_unlock_bh(chip->mutex);
+ }
+}
+
+static void cfi_intelext_destroy(struct mtd_info *mtd)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ kfree(cfi->cmdset_priv);
+ kfree(cfi);
+}
+
diff --git a/drivers/mtd/cfi_probe.c b/drivers/mtd/cfi_probe.c
new file mode 100644
index 000000000..ccd33fb3c
--- /dev/null
+++ b/drivers/mtd/cfi_probe.c
@@ -0,0 +1,501 @@
+/*
+ Common Flash Interface probe code.
+ (C) 2000 Red Hat. GPL'd.
+ $Id: cfi_probe.c,v 1.12 2000/07/03 13:29:16 dwmw2 Exp $
+*/
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+
+#include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+
+
+struct mtd_info *cfi_probe(struct map_info *);
+EXPORT_SYMBOL(cfi_probe);
+
+static void print_cfi_ident(struct cfi_ident *);
+static void check_cmd_set(struct map_info *, int, unsigned long);
+static struct cfi_private *cfi_cfi_probe(struct map_info *);
+
+struct mtd_info *cfi_probe(struct map_info *map)
+{
+ struct mtd_info *mtd = NULL;
+ struct cfi_private *cfi;
+ /* First probe the map to see if we have CFI stuff there. */
+ cfi = cfi_cfi_probe(map);
+
+ if (!cfi)
+ return NULL;
+
+ map->fldrv_priv = cfi;
+
+ /* OK we liked it. Now find a driver for the command set it talks */
+
+ check_cmd_set(map, 1, cfi->chips[0].start); /* First the primary cmdset */
+ check_cmd_set(map, 0, cfi->chips[0].start); /* Then the secondary */
+
+ /* check_cmd_set() will have used get_module_symbol to increase
+ the use count of the module which provides the command set
+ driver. If we're quitting, we have to decrease it again.
+ */
+
+ if(cfi->cmdset_setup) {
+ mtd = cfi->cmdset_setup(map);
+
+ if (mtd)
+ return mtd;
+ put_module_symbol((unsigned long)cfi->cmdset_setup);
+ }
+ printk("No supported Vendor Command Set found\n");
+
+ kfree(cfi);
+ map->fldrv_priv = NULL;
+ return NULL;
+
+}
+
+static int cfi_probe_new_chip(struct map_info *map, unsigned long base,
+ struct flchip *chips, struct cfi_private *cfi)
+{
+ switch (map->buswidth) {
+
+ case 1: {
+ unsigned char tmp = map->read8(map, base + 0x55);
+
+ /* If there's a device there, put it in Query Mode */
+ map->write8(map, 0x98, base+0x55);
+
+ if (map->read8(map,base+0x10) == 'Q' &&
+ map->read8(map,base+0x11) == 'R' &&
+ map->read8(map,base+0x12) == 'Y') {
+ printk("%s: Found a CFI device at 0x%lx in 8 bit mode\n", map->name, base);
+ if (chips) {
+ /* Check previous chips for aliases */
+ printk("FIXME: Do alias check at line %d of cfi_probe.c\n", __LINE__);
+ /* Put it back into Read Mode */
+ map->write8(map, 0x98, base+0x55);
+ }
+ return 1;
+ } else {
+ if (map->read8(map, base + 0x55) == 0x98) {
+ /* It looks like RAM. Put back the stuff we overwrote */
+ map->write8(map, tmp, base+0x55);
+ }
+ return 0;
+ }
+ }
+
+ case 2: {
+ __u16 tmp = map->read16(map, base + 0xaa);
+
+ /* If there's a device there, put it into Query Mode */
+ map->write16(map, 0x9898, base+0xAA);
+
+ if (map->read16(map, base+0x20) == cpu_to_le16(0x0051) &&
+ map->read16(map, base+0x22) == cpu_to_le16(0x0052) &&
+ map->read16(map, base+0x24) == cpu_to_le16(0x0059)) {
+ printk("%s: Found a CFI device at 0x%lx in 16 bit mode\n", map->name, base);
+ if (chips) {
+ /* Check previous chips for aliases */
+ int i;
+
+ for (i=0; i < cfi->numchips; i++) {
+ /* This chip should be in read mode if it's one
+ we've already touched. */
+ if (map->read16(map, chips[i].start+0x20) == cpu_to_le16(0x0051) &&
+ map->read16(map, chips[i].start+0x22) == cpu_to_le16(0x0052) &&
+ map->read16(map, chips[i].start+0x24) == cpu_to_le16(0x0059)){
+ /* Either the old chip has got 'Q''R''Y' in a most
+ unfortunate place, or it's an alias of the new
+ chip. Double-check that it's in read mode, and check. */
+ map->write16(map, 0xffff, chips[i].start+0x20);
+ if (map->read16(map, chips[i].start+0x20) == cpu_to_le16(0x0051) &&
+ map->read16(map, chips[i].start+0x22) == cpu_to_le16(0x0052) &&
+ map->read16(map, chips[i].start+0x24) == cpu_to_le16(0x0059)) {
+ /* Yes it's got QRY for data. Most unfortunate.
+ Stick the old one in read mode too. */
+ map->write16(map, 0xffff, base);
+ if (map->read16(map, base+0x20) == cpu_to_le16(0x0051) &&
+ map->read16(map, base+0x22) == cpu_to_le16(0x0052) &&
+ map->read16(map, base+0x24) == cpu_to_le16(0x0059)) {
+ /* OK, so has the new one. Assume it's an alias */
+ printk("T'was probably an alias for the chip at 0x%lx\n", chips[i].start);
+ return 1;
+ } /* else no, they're different, fall through. */
+ } else {
+ /* No the old one hasn't got QRY for data. Therefore,
+ it's an alias of the new one. */
+ map->write16(map, 0xffff, base+0xaa);
+ /* Just to be paranoid. */
+ map->write16(map, 0xffff, chips[i].start+0xaa);
+ printk("T'was an alias for the chip at 0x%lx\n", chips[i].start);
+ return 1;
+ }
+ }
+ /* No, the old one didn't look like it's in query mode. Next. */
+ }
+
+ /* OK, if we got to here, then none of the previous chips appear to
+ be aliases for the current one. */
+ if (cfi->numchips == MAX_CFI_CHIPS) {
+ printk("%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS);
+ /* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */
+ return 1;
+ }
+ printk("Not an alias. Adding\n");
+ chips[cfi->numchips].start = base;
+ chips[cfi->numchips].state = FL_READY;
+ chips[cfi->numchips].mutex = &chips[cfi->numchips]._spinlock;
+ cfi->numchips++;
+
+ /* Put it back into Read Mode */
+ map->write16(map, 0xffff, base+0xaa);
+ }
+
+ return 1;
+ }
+ else if (map->read16(map, base+0x20) == 0x5151 &&
+ map->read16(map, base+0x22) == 0x5252 &&
+ map->read16(map, base+0x24) == 0x5959) {
+ printk("%s: Found a coupled pair of CFI devices at %lx in 8 bit mode\n",
+ map->name, base);
+ if (chips) {
+ /* Check previous chips for aliases */
+ printk("FIXME: Do alias check at line %d of cfi_probe.c\n", __LINE__);
+
+ /* Put it back into Read Mode */
+ map->write16(map, 0xffff, base+0xaa);
+ }
+
+ return 2;
+ } else {
+ if (map->read16(map, base+0xaa) == 0x9898) {
+ /* It looks like RAM. Put back the stuff we overwrote */
+ map->write16(map, tmp, base+0xaa);
+ }
+ return 0;
+ }
+ }
+
+
+ case 4: {
+ __u32 tmp = map->read32(map, base+0x154);
+
+ /* If there's a device there, put it into Query Mode */
+ map->write32(map, 0x98989898, base+0x154);
+
+ if (map->read32(map, base+0x40) == cpu_to_le32(0x00000051) &&
+ map->read32(map, base+0x44) == cpu_to_le32(0x00000052) &&
+ map->read32(map, base+0x48) == cpu_to_le32(0x00000059)) {
+ /* This isn't actually in the CFI spec - only x8 and x16 are. */
+ printk("%s: Found a CFI device at %lx in 32 bit mode\n", map->name, base);
+ if (chips) {
+ /* Check previous chips for aliases */
+ printk("FIXME: Do alias check at line %d of cfi_probe.c\n", __LINE__);
+
+ /* Put it back into read mode */
+ map->write32(map, 0xffffffff, base+0x154);
+ }
+ return 1;
+ }
+ else if (map->read32(map, base+0x40) == cpu_to_le32(0x00510051) &&
+ map->read32(map, base+0x44) == cpu_to_le32(0x00520052) &&
+ map->read32(map, base+0x48) == cpu_to_le32(0x00590059)) {
+ printk("%s: Found a coupled pair of CFI devices at location %lx in 16 bit mode\n", map->name, base);
+ if (chips) {
+ /* Check previous chips for aliases */
+ printk("FIXME: Do alias check at line %d of cfi_probe.c\n", __LINE__);
+
+ /* Put it back into read mode */
+ map->write32(map, 0xffffffff, base+0x154);
+ }
+ return 2;
+ }
+ else if (map->read32(map, base+0x40) == 0x51515151 &&
+ map->read32(map, base+0x44) == 0x52525252 &&
+ map->read32(map, base+0x48) == 0x59595959) {
+ printk("%s: Found four side-by-side CFI devices at location %lx in 8 bit mode\n", map->name, base);
+ if (chips) {
+ /* Check previous chips for aliases */
+ printk("FIXME: Do alias check at line %d of cfi_probe.c\n", __LINE__);
+
+ /* Put it back into read mode */
+ map->write32(map, 0xffffffff, base+0x154);
+ }
+ return 4;
+ } else {
+ if (map->read32(map, base+0x154) == 0x98989898) {
+ /* It looks like RAM. Put back the stuff we overwrote */
+ map->write32(map, tmp, base+0x154);
+ }
+ return 0;
+ }
+ }
+ default:
+ printk(KERN_WARNING "cfi_cfi_probe called with strange buswidth %d\n", map->buswidth);
+ return 0;
+ }
+}
+
+static struct cfi_private *cfi_cfi_probe(struct map_info *map)
+{
+ unsigned long base=0;
+ struct cfi_private cfi;
+ struct cfi_private *retcfi;
+ struct flchip chip[MAX_CFI_CHIPS];
+ int i;
+
+ memset(&cfi, 0, sizeof(cfi));
+
+ /* The first invocation (with chips == NULL) leaves the device in Query Mode */
+ cfi.interleave = cfi_probe_new_chip(map, 0, NULL, NULL);
+
+ if (!cfi.interleave) {
+ printk("%s: Found no CFI device at location zero\n", map->name);
+ /* Doesn't appear to be CFI-compliant at all */
+ return NULL;
+ }
+
+ /* Read the Basic Query Structure from the device */
+
+ for (i=0; i<sizeof(struct cfi_ident); i++) {
+ ((unsigned char *)&cfi.cfiq)[i] = map->read8(map,base + ((0x10 + i)*map->buswidth));
+ }
+
+ /* Do any necessary byteswapping */
+ cfi.cfiq.P_ID = le16_to_cpu(cfi.cfiq.P_ID);
+ cfi.cfiq.P_ADR = le16_to_cpu(cfi.cfiq.P_ADR);
+ cfi.cfiq.A_ID = le16_to_cpu(cfi.cfiq.A_ID);
+ cfi.cfiq.A_ADR = le16_to_cpu(cfi.cfiq.A_ADR);
+ cfi.cfiq.InterfaceDesc = le16_to_cpu(cfi.cfiq.InterfaceDesc);
+ cfi.cfiq.MaxBufWriteSize = le16_to_cpu(cfi.cfiq.MaxBufWriteSize);
+
+#if 1
+ /* Dump the information therein */
+ print_cfi_ident(&cfi.cfiq);
+
+ for (i=0; i<cfi.cfiq.NumEraseRegions; i++) {
+ __u16 EraseRegionInfoNum = (map->read8(map,base + ((0x2d + (4*i))*map->buswidth))) +
+ (((map->read8(map,(0x2e + (4*i))*map->buswidth)) << 8));
+ __u16 EraseRegionInfoSize = (map->read8(map, base + ((0x2f + (4*i))*map->buswidth))) +
+ (map->read8(map, base + ((0x30 + (4*i))*map->buswidth)) << 8);
+
+ printk(" Erase Region #%d: BlockSize 0x%4.4X bytes, %d blocks\n",
+ i, EraseRegionInfoSize * 256, EraseRegionInfoNum+1);
+ }
+
+ printk("\n");
+#endif
+
+ /* Switch the chip back into Read Mode, to make the alias detection work */
+ switch(map->buswidth) {
+ case 1:
+ map->write8(map, 0xff, 0x55);
+ break;
+ case 2:
+ map->write16(map, 0xffff, 0xaa);
+ break;
+ case 4:
+ map->write32(map, 0xffffffff, 0x154);
+ break;
+ }
+
+ /* OK. We've worked out what it is and we're happy with it. Now see if there are others */
+
+ chip[0].start = 0;
+ chip[0].state = FL_READY;
+ chip[0].mutex = &chip[0]._spinlock;
+
+ cfi.chipshift = cfi.cfiq.DevSize;
+ cfi.numchips = 1;
+
+ if (!cfi.chipshift) {
+ printk("cfi.chipsize is zero. This is bad. cfi.cfiq.DevSize is %d\n", cfi.cfiq.DevSize);
+ return NULL;
+ }
+
+ for (base = (1<<cfi.chipshift); base < map->size; base += (1<<cfi.chipshift))
+ cfi_probe_new_chip(map, base, &chip[0], &cfi);
+
+ retcfi = kmalloc(sizeof(struct cfi_private) + cfi.numchips * sizeof(struct flchip), GFP_KERNEL);
+
+ if (!retcfi)
+ return NULL;
+
+ memcpy(retcfi, &cfi, sizeof(cfi));
+ memcpy(&retcfi->chips[0], chip, sizeof(struct flchip) * cfi.numchips);
+ for (i=0; i< retcfi->numchips; i++) {
+ init_waitqueue_head(&retcfi->chips[i].wq);
+ spin_lock_init(&retcfi->chips[i]._spinlock);
+ }
+ return retcfi;
+}
+
+static char *vendorname(__u16 vendor)
+{
+ switch (vendor) {
+ case P_ID_NONE:
+ return "None";
+
+ case P_ID_INTEL_EXT:
+ return "Intel/Sharp Extended";
+
+ case P_ID_AMD_STD:
+ return "AMD/Fujitsu Standard";
+
+ case P_ID_INTEL_STD:
+ return "Intel/Sharp Standard";
+
+ case P_ID_AMD_EXT:
+ return "AMD/Fujitsu Extended";
+
+ case P_ID_MITSUBISHI_STD:
+ return "Mitsubishi Standard";
+
+ case P_ID_MITSUBISHI_EXT:
+ return "Mitsubishi Extended";
+
+ case P_ID_RESERVED:
+ return "Not Allowed / Reserved for Future Use";
+
+ default:
+ return "Unknown";
+ }
+}
+
+
+static void print_cfi_ident(struct cfi_ident *cfip)
+{
+ if (cfip->qry[0] != 'Q' || cfip->qry[1] != 'R' || cfip->qry[2] != 'Y') {
+ printk("Invalid CFI ident structure.\n");
+ return;
+ }
+
+ printk("Primary Vendor Command Set: %4.4X (%s)\n", cfip->P_ID, vendorname(cfip->P_ID));
+ if (cfip->P_ADR)
+ printk("Primary Algorithm Table at %4.4X\n", cfip->P_ADR);
+ else
+ printk("No Primary Algorithm Table\n");
+
+ printk("Alternative Vendor Command Set: %4.4X (%s)\n", cfip->A_ID, vendorname(cfip->A_ID));
+ if (cfip->A_ADR)
+ printk("Alternate Algorithm Table at %4.4X\n", cfip->A_ADR);
+ else
+ printk("No Alternate Algorithm Table\n");
+
+
+ printk("Vcc Minimum: %x.%x V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf);
+ printk("Vcc Maximum: %x.%x V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf);
+ if (cfip->VppMin) {
+ printk("Vpp Minimum: %x.%x V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf);
+ printk("Vpp Maximum: %x.%x V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf);
+ }
+ else
+ printk("No Vpp line\n");
+
+ printk("Typical byte/word write timeout: %d µs\n", 1<<cfip->WordWriteTimeoutTyp);
+ printk("Maximum byte/word write timeout: %d µs\n", (1<<cfip->WordWriteTimeoutMax) * (1<<cfip->WordWriteTimeoutTyp));
+
+ if (cfip->BufWriteTimeoutTyp || cfip->BufWriteTimeoutMax) {
+ printk("Typical full buffer write timeout: %d µs\n", 1<<cfip->BufWriteTimeoutTyp);
+ printk("Maximum full buffer write timeout: %d µs\n", (1<<cfip->BufWriteTimeoutMax) * (1<<cfip->BufWriteTimeoutTyp));
+ }
+ else
+ printk("Full buffer write not supported\n");
+
+ printk("Typical block erase timeout: %d µs\n", 1<<cfip->BlockEraseTimeoutTyp);
+ printk("Maximum block erase timeout: %d µs\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp));
+ if (cfip->ChipEraseTimeoutTyp || cfip->ChipEraseTimeoutMax) {
+ printk("Typical chip erase timeout: %d µs\n", 1<<cfip->ChipEraseTimeoutTyp);
+ printk("Maximum chip erase timeout: %d µs\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp));
+ }
+ else
+ printk("Chip erase not supported\n");
+
+ printk("Device size: 0x%X bytes (%d Mb)\n", 1 << cfip->DevSize, 1<< (cfip->DevSize - 20));
+ printk("Flash Device Interface description: 0x%4.4X\n", cfip->InterfaceDesc);
+ switch(cfip->InterfaceDesc) {
+ case 0:
+ printk(" - x8-only asynchronous interface\n");
+ break;
+
+ case 1:
+ printk(" - x16-only asynchronous interface\n");
+ break;
+
+ case 2:
+ printk(" - supports x8 and x16 via BYTE# with asynchronous interface\n");
+ break;
+
+ case 3:
+ printk(" - x32-only asynchronous interface\n");
+ break;
+
+ case 65535:
+ printk(" - Not Allowed / Reserved\n");
+ break;
+
+ default:
+ printk(" - Unknown\n");
+ break;
+ }
+
+ printk("Max. bytes in buffer write: 0x%x\n", 1<< cfip->MaxBufWriteSize);
+ printk("Number of Erase Block Regions: %d\n", cfip->NumEraseRegions);
+
+}
+
+static void check_cmd_set(struct map_info *map, int primary, unsigned long base)
+{
+ __u16 adr;
+ struct cfi_private *cfi = map->fldrv_priv;
+ __u16 type = primary?cfi->cfiq.P_ID:cfi->cfiq.A_ID;
+ char probename[32];
+ void (*probe_function)(struct map_info *, int, unsigned long);
+
+ if (type == P_ID_NONE || type == P_ID_RESERVED)
+ return;
+
+ sprintf(probename, "cfi_cmdset_%4.4X", type);
+
+ probe_function = (void *)get_module_symbol(NULL, probename);
+ if (!probe_function) {
+ request_module(probename);
+
+ probe_function = (void *)get_module_symbol(NULL, probename);
+ }
+
+ if (probe_function) {
+ (*probe_function)(map, primary, base);
+ put_module_symbol((unsigned long)probe_function);
+ return;
+ }
+
+ /* This was a command set we don't know about. Print only the basic info */
+ adr = primary?cfi->cfiq.P_ADR:cfi->cfiq.A_ADR;
+
+ if (!adr) {
+ printk(" No Extended Query Table\n");
+ }
+ else if (map->read8(map,base+(adr*map->buswidth)) != (primary?'P':'A') ||
+ map->read8(map,base+((adr+1)*map->buswidth)) != (primary?'R':'L') ||
+ map->read8(map,base+((adr+2)*map->buswidth)) != (primary?'I':'T')) {
+ printk ("Invalid Extended Query Table at %4.4X: %2.2X %2.2X %2.2X\n",
+ adr,
+ map->read8(map,base+(adr*map->buswidth)),
+ map->read8(map,base+((adr+1)*map->buswidth)),
+ map->read8(map,base+((adr+2)*map->buswidth)));
+ }
+ else {
+ printk(" Extended Query Table version %c.%c\n",
+ map->read8(map,base+((adr+3)*map->buswidth)),
+ map->read8(map,base+((adr+4)*map->buswidth)));
+ }
+}
diff --git a/drivers/mtd/doc1000.c b/drivers/mtd/doc1000.c
new file mode 100644
index 000000000..3b288b129
--- /dev/null
+++ b/drivers/mtd/doc1000.c
@@ -0,0 +1,601 @@
+/*======================================================================
+
+ $Id: doc1000.c,v 1.8 2000/07/03 10:01:38 dwmw2 Exp $
+
+ A general driver for accessing PCMCIA card memory via Bulk
+ Memory Services.
+
+ This driver provides the equivalent of /dev/mem for a PCMCIA
+ card's attribute and common memory. It includes character
+ and block devices.
+
+ Written by David Hinds, dhinds@allegro.stanford.edu
+
+======================================================================*/
+
+
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <stdarg.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/iflash.h>
+
+/* Parameters that can be set with 'insmod' */
+
+static u_long base = 0xe0000;
+static int erase_timeout = 10*HZ; /* in ticks */
+static int retry_limit = 4; /* write retries */
+static u_long max_tries = 4096; /* status polling */
+
+MODULE_PARM(base,"l");
+MODULE_PARM(erase_timeout, "i");
+MODULE_PARM(retry_limit, "i");
+MODULE_PARM(max_tries, "i");
+
+#define WINDOW_SIZE 0x2000
+#define WINDOW_MASK (WINDOW_SIZE - 1)
+#define PAGEREG_LO (WINDOW_SIZE)
+#define PAGEREG_HI (WINDOW_SIZE + 2)
+
+static struct mtd_info *mymtd;
+static struct timer_list flashcard_timer;
+
+#define MAX_CELLS 32
+#define MAX_FLASH_DEVICES 8
+
+/* A flash region is composed of one or more "cells", where we allow
+ simultaneous erases if they are in different cells */
+
+
+
+struct mypriv {
+ u_char *baseaddr;
+ u_short curpage;
+ u_char locked;
+ u_short numdevices;
+ u_char interleave;
+ struct erase_info *cur_erases;
+ wait_queue_head_t wq;
+ u_char devstat[MAX_FLASH_DEVICES];
+ u_long devshift;
+};
+
+
+static void flashcard_periodic(u_long data);
+static int flashcard_erase (struct mtd_info *mtd, struct erase_info *instr);
+static int flashcard_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+static int flashcard_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
+static void flashcard_sync (struct mtd_info *mtd);
+
+static inline void resume_erase(volatile u_char *addr);
+static inline int suspend_erase(volatile u_char *addr);
+static inline int byte_write (volatile u_char *addr, u_char byte);
+static inline int word_write (volatile u_char *addr, __u16 word);
+static inline int check_write(volatile u_char *addr);
+static inline void block_erase (volatile u_char *addr);
+static inline int check_erase(volatile u_char *addr);
+
+#ifdef __SMP__
+#warning This is definitely not SMP safe. Lock the paging mechanism.
+#endif
+
+static u_char *pagein(struct mtd_info *mtd, u_long addr)
+{
+ struct mypriv *priv=mtd->priv;
+ u_short page = addr >> 13;
+
+ priv->baseaddr[PAGEREG_LO] = page & 0xff;
+ priv->baseaddr[PAGEREG_HI] = page >> 8;
+ priv->curpage = page;
+
+ return &priv->baseaddr[addr & WINDOW_MASK];
+}
+
+
+void flashcard_sync (struct mtd_info *mtd)
+{
+ struct mypriv *priv=mtd->priv;
+
+ flashcard_periodic((u_long) mtd);
+ printk("sync...");
+ if (priv->cur_erases)
+ interruptible_sleep_on(&priv->wq);
+ printk("Done.\n");
+}
+
+int flashcard_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+ u_char *pageaddr;
+ struct mypriv *priv=mtd->priv;
+ struct erase_info **tmp=&priv->cur_erases;
+
+ if (instr->len != mtd->erasesize)
+ return -EINVAL;
+ if (instr->addr + instr->len > mtd->size)
+ return -EINVAL;
+
+ pageaddr=pagein(mtd,instr->addr);
+ instr->mtd = mtd;
+ instr->dev = instr->addr >> priv->devshift;
+ instr->cell = (instr->addr - (instr->dev << priv->devshift)) / mtd->erasesize;
+ instr->next = NULL;
+ instr->state = MTD_ERASE_PENDING;
+
+ while (*tmp)
+ {
+ tmp = &((*tmp) -> next);
+ }
+
+ *tmp = instr;
+ flashcard_periodic((u_long)mtd);
+ return 0;
+}
+
+
+int flashcard_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+ u_char *pageaddr=pagein(mtd,from);
+ struct mypriv *priv=mtd->priv;
+ u_char device = from >> priv->devshift;
+ u_char cell = (int) (from - (device << priv->devshift)) / mtd->erasesize;
+ int ret = 0, timeron = 0;
+
+ if ((from & WINDOW_MASK) + len <= WINDOW_SIZE)
+ *retlen = len;
+ else
+ *retlen = WINDOW_SIZE - (from & WINDOW_MASK);
+
+ if (priv->devstat[device])
+ {
+
+ /* There is an erase in progress or pending for this device. Stop it */
+ timeron = del_timer(&flashcard_timer);
+
+ if (priv->cur_erases && priv->cur_erases->cell == cell)
+
+ {
+ /* The erase is on the current cell. Just return all 0xff */
+ add_timer(&flashcard_timer);
+
+
+ printk("Cell %d currently erasing. Setting to all 0xff\n",cell);
+ memset(buf, 0xff, *retlen);
+ return 0;
+ }
+ if (priv->devstat[device] == MTD_ERASING)
+ {
+ ret = suspend_erase(pageaddr);
+ priv->devstat[device] = MTD_ERASE_SUSPEND;
+
+ if (ret)
+ {
+ printk("flashcard: failed to suspend erase\n");
+ add_timer (&flashcard_timer);
+ return ret;
+ }
+ }
+
+ }
+
+ writew(IF_READ_ARRAY, (u_long)pageaddr & ~1);
+
+ ret = 0;
+ memcpy (buf, pageaddr, *retlen);
+
+ writew(IF_READ_CSR, (u_long)pageaddr & ~1);
+
+
+ if (priv->devstat[device] & MTD_ERASE_SUSPEND)
+ {
+ resume_erase(pageaddr);
+ priv->devstat[device]=MTD_ERASING;
+ }
+
+
+ if (timeron) add_timer (&flashcard_timer);
+
+ return ret;
+}
+
+
+int flashcard_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
+{
+ struct mypriv *priv = (struct mypriv *)mtd->priv;
+ u_char *endaddr, *startaddr;
+ register u_char *pageaddr;
+ u_char device = to >> priv->devshift;
+/* jiffies_t oldj=jiffies;*/
+ int ret;
+
+ while (priv->devstat[device])
+ {
+ flashcard_sync(mtd);
+ }
+
+ if ((to & WINDOW_MASK) + len <= WINDOW_SIZE)
+ *retlen = len;
+ else
+ *retlen = WINDOW_SIZE - (to & WINDOW_MASK);
+
+ pageaddr = pagein(mtd, to);
+ startaddr = (u_char *)((u_long) pageaddr & ~1);
+ endaddr = pageaddr+(*retlen);
+
+
+
+ /* Set up to read */
+ writew(IF_READ_CSR, startaddr);
+
+ /* Make sure it's aligned by reading the first byte if necessary */
+ if (to & 1)
+ {
+ /* Unaligned access */
+
+ u_char cbuf;
+
+ cbuf = *buf;
+
+ if (!((u_long)pageaddr & 0xf))
+ schedule();
+
+ ret = byte_write(pageaddr, cbuf);
+ if (ret) return ret;
+
+ pageaddr++; buf++;
+ }
+
+
+ for ( ; pageaddr + 1 < endaddr; buf += 2, pageaddr += 2)
+ {
+ /* if ((u_long)pageaddr & 0xf) schedule();*/
+
+ ret = word_write(pageaddr, *(__u16 *)buf);
+ if (ret)
+ return ret;
+ }
+
+ if (pageaddr != endaddr)
+ {
+ /* One more byte to write at the end. */
+ u_char cbuf;
+
+ cbuf = *buf;
+
+ ret = byte_write(pageaddr, cbuf);
+
+ if (ret) return ret;
+ }
+
+ return check_write(startaddr);
+/* printk("Time taken in flashcard_write: %lx jiffies\n",jiffies - oldj);*/
+}
+
+
+
+
+/*====================================================================*/
+
+static inline int byte_write (volatile u_char *addr, u_char byte)
+{
+ register u_char status;
+ register u_short i;
+
+ for (i = 0; i < max_tries; i++)
+ {
+ status = readb(addr);
+ if (status & CSR_WR_READY)
+ {
+ writeb(IF_WRITE & 0xff, addr);
+ writeb(byte, addr);
+ return 0;
+ }
+ }
+
+ printk(KERN_NOTICE "flashcard: byte_write timed out, status 0x%x\n",status);
+ return -EIO;
+}
+
+static inline int word_write (volatile u_char *addr, __u16 word)
+{
+ register u_short status = 0;
+ register u_short i;
+
+ for (i = 0; i < max_tries; i++)
+ {
+ status = readw(addr);
+ if ((status & CSR_WR_READY) == CSR_WR_READY)
+ {
+ writew(IF_WRITE, addr);
+ writew(word, addr);
+ return 0;
+ }
+ }
+
+ printk(KERN_NOTICE "flashcard: word_write timed out at %p, status 0x%x\n", addr, status);
+ return -EIO;
+}
+
+static inline void block_erase (volatile u_char *addr)
+{
+ writew(IF_BLOCK_ERASE, addr);
+ writew(IF_CONFIRM, addr);
+}
+
+
+static inline int check_erase(volatile u_char *addr)
+{
+ __u16 status;
+
+/* writew(IF_READ_CSR, addr);*/
+ status = readw(addr);
+
+
+ if ((status & CSR_WR_READY) != CSR_WR_READY)
+ return -EBUSY;
+
+ if (status & (CSR_ERA_ERR | CSR_VPP_LOW | CSR_WR_ERR))
+ {
+ printk(KERN_NOTICE "flashcard: erase failed, status 0x%x\n",
+ status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static inline int suspend_erase(volatile u_char *addr)
+{
+ __u16 status = 0;
+ u_long i;
+
+ writew(IF_ERASE_SUSPEND, addr);
+ writew(IF_READ_CSR, addr);
+
+ for (i = 0; i < max_tries; i++)
+ {
+ status = readw(addr);
+ if ((status & CSR_WR_READY) == CSR_WR_READY) break;
+ }
+ if (i == max_tries)
+ {
+ printk(KERN_NOTICE "flashcard: suspend_erase timed out, status 0x%x\n", status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static inline void resume_erase(volatile u_char *addr)
+{
+ __u16 status;
+
+ writew(IF_READ_CSR, addr);
+ status = readw(addr);
+
+ /* Only give resume signal if the erase is really suspended */
+ if (status & CSR_ERA_SUSPEND)
+ writew(IF_CONFIRM, addr);
+}
+
+static inline void reset_block(volatile u_char *addr)
+{
+ u_short i;
+ __u16 status;
+
+ writew(IF_CLEAR_CSR, addr);
+
+ for (i = 0; i < 100; i++) {
+ writew(IF_READ_CSR, addr);
+ status = readw(addr);
+ if (status != 0xffff) break;
+ udelay(1000);
+ }
+
+ writew(IF_READ_CSR, addr);
+}
+
+static inline int check_write(volatile u_char *addr)
+{
+ u_short status = 0, i;
+
+ writew(IF_READ_CSR, addr);
+
+ for (i=0; i < max_tries; i++)
+ {
+ status = readw(addr);
+ if (status & (CSR_WR_ERR | CSR_VPP_LOW))
+ {
+ printk(KERN_NOTICE "flashcard: write failure at %p, status 0x%x\n", addr, status);
+ reset_block(addr);
+ return -EIO;
+ }
+ if ((status & CSR_WR_READY) == CSR_WR_READY)
+ return 0;
+ }
+ printk(KERN_NOTICE "flashcard: write timed out at %p, status 0x%x\n", addr, status);
+ return -EIO;
+}
+
+
+/*====================================================================*/
+
+
+
+static void flashcard_periodic(unsigned long data)
+{
+ register struct mtd_info *mtd = (struct mtd_info *)data;
+ register struct mypriv *priv = mtd->priv;
+ struct erase_info *erase = priv->cur_erases;
+ u_char *pageaddr;
+
+ del_timer (&flashcard_timer);
+
+ if (!erase)
+ return;
+
+ pageaddr = pagein(mtd, erase->addr);
+
+ if (erase->state == MTD_ERASE_PENDING)
+ {
+ block_erase(pageaddr);
+ priv->devstat[erase->dev] = erase->state = MTD_ERASING;
+ erase->time = jiffies;
+ erase->retries = 0;
+ }
+ else if (erase->state == MTD_ERASING)
+ {
+ /* It's trying to erase. Check whether it's finished */
+
+ int ret = check_erase(pageaddr);
+
+ if (!ret)
+ {
+ /* It's finished OK */
+ priv->devstat[erase->dev] = 0;
+ priv->cur_erases = erase->next;
+ erase->state = MTD_ERASE_DONE;
+ if (erase->callback)
+ (*(erase->callback))(erase);
+ else
+ kfree(erase);
+ }
+ else if (ret == -EIO)
+ {
+ if (++erase->retries > retry_limit)
+ {
+ printk("Failed too many times. Giving up\n");
+ priv->cur_erases = erase->next;
+ priv->devstat[erase->dev] = 0;
+ erase->state = MTD_ERASE_FAILED;
+ if (erase->callback)
+ (*(erase->callback))(erase);
+ else
+ kfree(erase);
+ }
+ else
+ priv->devstat[erase->dev] = erase->state = MTD_ERASE_PENDING;
+ }
+ else if (erase->time + erase_timeout < jiffies)
+ {
+ printk("Flash erase timed out. The world is broken.\n");
+
+ /* Just ignore and hope it goes away. For a while, read ops will give the CSR
+ and writes won't work. */
+
+ priv->cur_erases = erase->next;
+ priv->devstat[erase->dev] = 0;
+ erase->state = MTD_ERASE_FAILED;
+ if (erase->callback)
+ (*(erase->callback))(erase);
+ else
+ kfree(erase);
+ }
+ }
+
+ if (priv->cur_erases)
+ {
+ flashcard_timer.expires = jiffies + HZ;
+ add_timer (&flashcard_timer);
+ }
+ else
+ wake_up_interruptible(&priv->wq);
+
+}
+
+#if defined (MODULE) && LINUX_VERSION_CODE < 0x20300
+#define init_doc1000 init_module
+#define cleanup_doc1000 cleanup_module
+#endif
+
+int __init init_doc1000(void)
+{
+ struct mypriv *priv;
+
+ if (!base)
+ {
+ printk(KERN_NOTICE "flashcard: No start address for memory device.\n");
+ return -EINVAL;
+ }
+
+ mymtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+
+ if (!mymtd)
+ {
+ printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device.\n");
+ return -ENOMEM;
+ }
+
+ memset(mymtd,0,sizeof(struct mtd_info));
+
+ mymtd->priv = (void *) kmalloc (sizeof(struct mypriv), GFP_KERNEL);
+ if (!mymtd->priv)
+ {
+ kfree(mymtd);
+ printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device's private data.\n");
+ return -ENOMEM;
+ }
+
+
+
+
+ priv=mymtd->priv;
+ init_waitqueue_head(&priv->wq);
+
+ memset (priv,0,sizeof(struct mypriv));
+
+ priv->baseaddr = phys_to_virt(base);
+ priv->numdevices = 4;
+
+ mymtd->name = "M-Systems DiskOnChip 1000";
+
+ mymtd->size = 0x100000;
+ mymtd->flags = MTD_CLEAR_BITS | MTD_ERASEABLE;
+ mymtd->erase = flashcard_erase;
+ mymtd->point = NULL;
+ mymtd->unpoint = NULL;
+ mymtd->read = flashcard_read;
+ mymtd->write = flashcard_write;
+
+ mymtd->sync = flashcard_sync;
+ mymtd->erasesize = 0x10000;
+ // mymtd->interleave = 2;
+ priv->devshift = 24;
+ mymtd->type = MTD_NORFLASH;
+
+ if (add_mtd_device(mymtd))
+ {
+ printk(KERN_NOTICE "MTD device registration failed!\n");
+ kfree(mymtd->priv);
+ kfree(mymtd);
+ return -EAGAIN;
+ }
+
+ init_timer(&flashcard_timer);
+ flashcard_timer.function = flashcard_periodic;
+ flashcard_timer.data = (u_long)mymtd;
+ return 0;
+}
+
+static void __init cleanup_doc1000(void)
+{
+ kfree (mymtd->priv);
+ del_mtd_device(mymtd);
+ kfree(mymtd);
+}
+
diff --git a/drivers/mtd/doc2000.c b/drivers/mtd/doc2000.c
new file mode 100644
index 000000000..8385648d1
--- /dev/null
+++ b/drivers/mtd/doc2000.c
@@ -0,0 +1,837 @@
+
+/* Linux driver for Disk-On-Chip 2000 */
+/* (c) 1999 Machine Vision Holdings, Inc. */
+/* Author: David Woodhouse <dwmw2@mvhi.com> */
+/* $Id: doc2000.c,v 1.23 2000/07/03 10:01:38 dwmw2 Exp $ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/doc2000.h>
+
+//#define PRERELEASE
+
+static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+static int doc_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
+static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eecbuf);
+static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf);
+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, u_char *buf);
+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, const u_char *buf);
+static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
+
+
+static struct mtd_info *doc2klist = NULL;
+
+/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
+
+int _DoC_WaitReady (unsigned long docptr)
+{
+ //long c=-1;
+ short c=-1;
+
+ DEBUG(2,"_DoC_WaitReady called for out-of-line wait\n");
+
+ /* Out-of-line routine to wait for chip response */
+ while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B) && --c)
+ ;
+
+ if (c == 0)
+ DEBUG(2, "_DoC_WaitReady timed out.\n");
+
+ return (c==0);
+}
+
+static inline int DoC_WaitReady(unsigned long docptr)
+{
+ /* This is inline, to optimise the common case, where it's ready instantly */
+ volatile char dummy;
+ int ret = 0;
+
+ /* Out-of-line routine to wait for chip response */
+ /* TPW: Add 4 reads - see Software Requirement 2.3.2 */
+ dummy = ReadDOC(docptr, CDSNControl);
+ dummy = ReadDOC(docptr, CDSNControl);
+ dummy = ReadDOC(docptr, CDSNControl);
+ dummy = ReadDOC(docptr, CDSNControl);
+
+ if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
+ ret = _DoC_WaitReady(docptr); /* Call the out-of-line routine to wait */
+
+ /* TPW: Add 2 reads - see Software Requirement 2.3.2 */
+ dummy = ReadDOC(docptr, CDSNControl);
+ dummy = ReadDOC(docptr, CDSNControl);
+
+ return ret;
+}
+
+
+/* DoC_Command: Send a flash command to the flash chip */
+
+static inline int DoC_Command(unsigned long docptr, unsigned char command, unsigned char xtraflags)
+{
+ /* Assert the CLE (Command Latch Enable) line to the flash chip */
+ WriteDOC( CDSN_CTRL_FLASH_IO | xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE,
+ docptr, CDSNControl);
+
+ /* Send the command */
+ WriteDOC(command, docptr, 2k_CDSN_IO);
+
+ /* Lower the CLE line */
+ WriteDOC( CDSN_CTRL_FLASH_IO | xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
+
+ /* Wait for the chip to respond */
+ return DoC_WaitReady(docptr);
+}
+
+/* DoC_Address: Set the current address for the flash chip */
+
+static inline int DoC_Address (unsigned long docptr, int numbytes, unsigned long ofs,
+ unsigned char xtraflags1, unsigned char xtraflags2)
+{
+ /* Assert the ALE (Address Latch Enable line to the flash chip */
+ WriteDOC( CDSN_CTRL_FLASH_IO | xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE,
+ docptr, CDSNControl);
+
+ /* Send the address */
+ /* Three cases:
+ numbytes == 1: Send single byte, bits 0-7.
+ numbytes == 2: Send bits 9-16 followed by 17-23
+ numbytes == 3: Send 0-7, 9-16, then 17-23
+ */
+ if (numbytes != 2)
+ WriteDOC(ofs & 0xff, docptr, 2k_CDSN_IO);
+
+ if (numbytes != 1) {
+ WriteDOC((ofs >> 9) & 0xff, docptr, 2k_CDSN_IO);
+ WriteDOC((ofs >> 17) & 0xff, docptr, 2k_CDSN_IO);
+ }
+ /* Lower the ALE line */
+ WriteDOC( CDSN_CTRL_FLASH_IO | xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr, CDSNControl);
+
+ /* Wait for the chip to respond */
+ return DoC_WaitReady(docptr);
+}
+
+/* DoC_SelectChip: Select a given flash chip within the current floor */
+
+static inline int DoC_SelectChip(unsigned long docptr, int chip)
+{
+ /* Select the individual flash chip requested */
+ WriteDOC( chip, docptr, CDSNDeviceSelect);
+
+ /* Wait for it to be ready */
+ return DoC_WaitReady(docptr);
+}
+
+/* DoC_SelectFloor: Select a given floor (bank of flash chips) */
+
+static inline int DoC_SelectFloor(unsigned long docptr, int floor)
+{
+ /* Select the floor (bank) of chips required */
+ WriteDOC( floor, docptr, FloorSelect);
+
+ /* Wait for the chip to be ready */
+ return DoC_WaitReady(docptr);
+}
+
+/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */
+
+int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
+{
+ int mfr, id, chipshift=0;
+ char *mfrname=NULL, *idname=NULL;
+
+ /* Page in the required floor/chip */
+ DoC_SelectFloor(doc->virtadr, floor);
+ DoC_SelectChip(doc->virtadr, chip);
+
+ /* Reset the chip */
+ if (DoC_Command(doc->virtadr, NAND_CMD_RESET, CDSN_CTRL_WP)) {
+ DEBUG(2, "DoC_Command (reset) for %d,%d returned true\n", floor,chip);
+ return 0;
+ }
+
+ /* Read the NAND chip ID: 1. Send ReadID command */
+ if(DoC_Command(doc->virtadr, NAND_CMD_READID, CDSN_CTRL_WP)) {
+ DEBUG(2,"DoC_Command (ReadID) for %d,%d returned true\n", floor,chip);
+ return 0;
+ }
+
+ /* Read the NAND chip ID: 2. Send address byte zero
+ */
+ DoC_Address(doc->virtadr, 1, 0, CDSN_CTRL_WP, 0);
+
+ /* Read the manufacturer and device id codes from the device */
+ mfr = ReadDOC(doc->virtadr, 2k_CDSN_IO);
+ id = ReadDOC(doc->virtadr, 2k_CDSN_IO);
+
+ /* No response - return failure */
+ if (mfr == 0xff || mfr == 0)
+ return 0;
+
+ /* Check it's the same as the first chip we identified.
+ * M-Systems say that any given DiskOnChip device should only
+ * contain _one_ type of flash part, although that's not a
+ * hardware restriction. */
+ if (doc->mfr) {
+ if (doc->mfr == mfr && doc->id == id)
+ return 1; /* This is another the same the first */
+ else
+ printk(KERN_WARNING "Flash chip at floor %d, chip %d is different:\n",
+ floor, chip);
+ }
+
+ /* Print (and store if first time) the manufacturer and ID codes. */
+
+ switch(mfr) {
+ case NAND_MFR_TOSHIBA: /* Toshiba */
+ mfrname = "Toshiba";
+
+ switch(id) {
+ case 0x64:
+ idname = "TC5816BDC";
+ chipshift = 21;
+ break;
+
+ case 0x6b:
+ idname = "TC5832DC";
+ chipshift = 22;
+ break;
+
+ case 0x73:
+ idname = "TH58V128DC";
+ chipshift = 24;
+ break;
+
+ case 0x75:
+ idname = "TC58256FT/DC";
+ chipshift = 25;
+ break;
+
+ case 0xe5:
+ idname = "TC58V32DC";
+ chipshift = 22;
+ break;
+
+ case 0xe6:
+ idname = "TC58V64DC";
+ chipshift = 23;
+ break;
+
+ case 0xea:
+ idname = "TC58V16BDC";
+ chipshift = 21;
+ break;
+ }
+ break; /* End of Toshiba parts */
+
+ case NAND_MFR_SAMSUNG: /* Samsung */
+ mfrname = "Samsung";
+
+ switch(id) {
+ case 0x64:
+ idname = "KM29N16000";
+ chipshift = 21;
+
+ case 0x73:
+ idname = "KM29U128T";
+ chipshift = 24;
+ break;
+
+ case 0x75:
+ idname = "KM29U256T";
+ chipshift = 25;
+ break;
+
+ case 0xe3:
+ idname = "KM29W32000";
+ chipshift = 22;
+ break;
+
+ case 0xe6:
+ idname = "KM29U64000";
+ chipshift = 23;
+ break;
+
+ case 0xea:
+ idname = "KM29W16000";
+ chipshift = 21;
+ break;
+ }
+ break; /* End of Samsung parts */
+ }
+
+ /* If we've identified it fully, print the full names */
+ if (idname) {
+#ifdef PRERELEASE
+ DEBUG(1, "Flash chip found: %2.2X %2.2X (%s %s)\n",
+ mfr,id,mfrname,idname);
+#endif
+ /* If this is the first chip, store the id codes */
+ if (!doc->mfr) {
+ doc->mfr = mfr;
+ doc->id = id;
+ doc->chipshift = chipshift;
+ return 1;
+ }
+ return 0;
+ }
+
+ /* We haven't fully identified the chip. Print as much as we know. */
+ if (mfrname)
+ printk(KERN_WARNING "Unknown %s flash chip found: %2.2X %2.2X\n", mfrname,
+ id, mfr);
+ else
+ printk(KERN_WARNING "Unknown flash chip found: %2.2X %2.2X\n", id, mfr);
+
+ printk(KERN_WARNING "Please report to David.Woodhouse@mvhi.com\n");
+ return 0;
+}
+
+/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
+
+void DoC_ScanChips(struct DiskOnChip *this)
+{
+ int floor, chip;
+ int numchips[MAX_FLOORS];
+ int ret = 1;
+
+ this->numchips = 0;
+ this->mfr = 0;
+ this->id = 0;
+
+ /* For each floor, find the number of valid chips it contains */
+ for (floor = 0 ; floor < MAX_FLOORS ; floor++) {
+ ret = 1;
+ numchips[floor]=0;
+ for (chip = 0 ; chip < MAX_CHIPS && ret != 0; chip++ ) {
+
+ ret = DoC_IdentChip(this, floor, chip);
+ if (ret) {
+ numchips[floor]++;
+ this->numchips++;
+ }
+ }
+ }
+
+ /* If there are none at all that we recognise, bail */
+ if (!this->numchips) {
+ printk("No flash chips recognised.\n");
+ return;
+ }
+
+ /* Allocate an array to hold the information for each chip */
+ this->chips = kmalloc(sizeof(struct Nand) * this->numchips, GFP_KERNEL);
+ if (!this->chips){
+ printk("No memory for allocating chip info structures\n");
+ return;
+ }
+
+ ret = 0;
+
+ /* Fill out the chip array with {floor, chipno} for each
+ * detected chip in the device. */
+ for (floor = 0; floor < MAX_FLOORS; floor++) {
+ for (chip = 0 ; chip < numchips[floor] ; chip++) {
+ this->chips[ret].floor = floor;
+ this->chips[ret].chip = chip;
+ this->chips[ret].curadr = 0;
+ this->chips[ret].curmode = 0x50;
+ ret++;
+ }
+ }
+
+ /* Calculate and print the total size of the device */
+ this->totlen = this->numchips * (1 << this->chipshift);
+
+ printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld Mb\n", this->numchips ,
+ this->totlen >> 20);
+}
+
+
+static int DoC2k_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
+{
+ int tmp1, tmp2, retval;
+ if (doc1->physadr == doc2->physadr)
+ return 1;
+
+ /* Use the alias resolution register which was set aside for this
+ * purpose. If it's value is the same on both chips, they might
+ * be the same chip, and we write to one and check for a change in
+ * the other. It's unclear if this register is usuable in the
+ * DoC 2000 (it's in the Millenium docs), but it seems to work. */
+ tmp1 = ReadDOC(doc1->virtadr, AliasResolution);
+ tmp2 = ReadDOC(doc2->virtadr, AliasResolution);
+ if (tmp1 != tmp2)
+ return 0;
+
+ WriteDOC((tmp1+1) % 0xff, doc1->virtadr, AliasResolution);
+ tmp2 = ReadDOC(doc2->virtadr, AliasResolution);
+ if (tmp2 == (tmp1+1) % 0xff)
+ retval = 1;
+ else
+ retval = 0;
+
+ /* Restore register contents. May not be necessary, but do it just to
+ * be safe. */
+ WriteDOC(tmp1, doc1->virtadr, AliasResolution);
+
+ return retval;
+}
+
+
+void DoC2k_init(struct mtd_info *mtd)
+{
+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ struct DiskOnChip *old = NULL;
+
+ /* We must avoid being called twice for the same device. */
+
+ if (doc2klist)
+ old = (struct DiskOnChip *)doc2klist->priv;
+
+ while (old) {
+ if (DoC2k_is_alias(old, this)) {
+ printk(KERN_NOTICE "Ignoring DiskOnChip 2000 at 0x%lX - already configured\n",
+ this->physadr);
+ iounmap((void *)this->virtadr);
+ kfree(mtd);
+ return;
+ }
+ if (old->nextdoc)
+ old = (struct DiskOnChip *)old->nextdoc->priv;
+ else
+ old = NULL;
+ }
+
+
+ mtd->name = "DiskOnChip 2000";
+ printk(KERN_NOTICE "DiskOnChip 2000 found at address 0x%lX\n",this->physadr);
+
+ mtd->type = MTD_NANDFLASH;
+ mtd->flags = MTD_CAP_NANDFLASH;
+ mtd->size = 0;
+ mtd->erasesize = 0x2000;
+ mtd->oobblock = 512;
+ mtd->oobsize = 16;
+ mtd->module = THIS_MODULE;
+ mtd->erase = doc_erase;
+ mtd->point = NULL;
+ mtd->unpoint = NULL;
+ mtd->read = doc_read;
+ mtd->write = doc_write;
+ mtd->read_ecc = doc_read_ecc;
+ mtd->write_ecc = doc_write_ecc;
+ mtd->read_oob = doc_read_oob;
+ mtd->write_oob = doc_write_oob;
+ mtd->sync = NULL;
+
+ this->totlen = 0;
+ this->numchips = 0;
+
+ this->curfloor = -1;
+ this->curchip = -1;
+
+ /* Ident all the chips present. */
+ DoC_ScanChips(this);
+
+ if (!this->totlen) {
+ kfree(mtd);
+ iounmap((void *)this->virtadr);
+ } else {
+ this->nextdoc = doc2klist;
+ doc2klist = mtd;
+ mtd->size = this->totlen;
+ add_mtd_device(mtd);
+ return;
+ }
+}
+
+
+EXPORT_SYMBOL(DoC2k_init);
+
+static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+ /* Just a special case of doc_read_ecc */
+ return doc_read_ecc(mtd, from, len, retlen, buf, NULL);
+}
+
+static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf)
+{
+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ int di=0; /* Yes, DI is a hangover from when I was disassembling the binary driver */
+ unsigned long docptr;
+ struct Nand *mychip;
+
+ docptr = this->virtadr;
+
+ /* Don't allow read past end of device */
+ if (from >= this->totlen)
+ return -EINVAL;
+
+ /* Don't allow a single read to cross a 512-byte block boundary */
+ if (from + len > ( (from | 0x1ff) + 1))
+ len = ((from | 0x1ff) + 1) - from;
+
+ /* Find the chip which is to be used and select it */
+ mychip = &this->chips[from >> (this->chipshift)];
+
+ if (this->curfloor != mychip->floor) {
+ DoC_SelectFloor(docptr, mychip->floor);
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+ else if (this->curchip != mychip->chip) {
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+
+ this->curfloor = mychip->floor;
+ this->curchip = mychip->chip;
+
+
+ if (eccbuf) {
+ /* Prime the ECC engine */
+ WriteDOC ( DOC_ECC_RESET, docptr, ECCConf);
+ WriteDOC ( DOC_ECC_EN, docptr, ECCConf);
+ }
+
+ DoC_Command(docptr, (from >> 8) & 1, CDSN_CTRL_WP);
+ DoC_Address(docptr, 3, from, CDSN_CTRL_WP , CDSN_CTRL_ECC_IO);
+
+ for (di=0; di < len ; di++) {
+ buf[di] = ReadDOC(docptr, 2k_CDSN_IO);
+ }
+
+ /* Let the caller know we completed it */
+ *retlen = len;
+
+ if (eccbuf) {
+ /* Read the ECC data through the DiskOnChip ECC logic */
+ for (di=0; di<6; di++) {
+ eccbuf[di] = ReadDOC(docptr, 2k_CDSN_IO);
+ }
+
+ /* Flush the pipeline */
+ (void) ReadDOC(docptr, 2k_ECCStatus);
+ (void) ReadDOC(docptr, 2k_ECCStatus);
+
+ /* Check the ECC Status */
+ if (ReadDOC(docptr, 2k_ECCStatus) & 0x80) {
+ /* There was an ECC error */
+ printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
+
+ /* FIXME: Implement ECC error correction, don't just whinge */
+
+ /* We return error, but have actually done the read. Not that
+ this can be told to user-space, via sys_read(), but at least
+ MTD-aware stuff can know about it by checking *retlen */
+ return -EIO;
+ }
+#ifdef PSYCHO_DEBUG
+ else
+ printk("ECC OK at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+ (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], eccbuf[4],
+ eccbuf[5]);
+#endif
+
+ /* Reset the ECC engine */
+ WriteDOC(DOC_ECC_RESV, docptr , ECCConf);
+
+ }
+
+ return 0;
+}
+
+static int doc_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
+{
+ static char as[6];
+ return doc_write_ecc(mtd, to, len, retlen, buf, as);
+}
+
+static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf)
+{
+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ int di=0;
+ unsigned long docptr;
+ struct Nand *mychip;
+
+ docptr = this->virtadr;
+
+ /* Don't allow write past end of device */
+ if (to >= this->totlen)
+ return -EINVAL;
+#if 0
+ /* Don't allow a single write to cross a 512-byte block boundary */
+ if (to + len > ( (to | 0x1ff) + 1))
+ len = ((to | 0x1ff) + 1) - to;
+
+#else
+ /* Don't allow writes which aren't exactly one block */
+ if (to & 0x1ff || len != 0x200)
+ return -EINVAL;
+#endif
+
+ /* Find the chip which is to be used and select it */
+ mychip = &this->chips[to >> (this->chipshift)];
+
+ if (this->curfloor != mychip->floor) {
+ DoC_SelectFloor(docptr, mychip->floor);
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+ else if (this->curchip != mychip->chip) {
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+
+ this->curfloor = mychip->floor;
+ this->curchip = mychip->chip;
+
+ /* Set device to main plane of flash */
+ DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP);
+ DoC_Command(docptr, NAND_CMD_READ0, CDSN_CTRL_WP);
+
+ if (eccbuf) {
+ /* Prime the ECC engine */
+ WriteDOC ( DOC_ECC_RESET, docptr, ECCConf);
+ WriteDOC ( DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
+ }
+
+ DoC_Command(docptr, NAND_CMD_SEQIN, 0);
+ DoC_Address(docptr, 3, to, 0, CDSN_CTRL_ECC_IO);
+
+ for (di=0; di < len ; di++) {
+ WriteDOC(buf[di], docptr, 2k_CDSN_IO);
+ }
+
+
+ if (eccbuf) {
+ WriteDOC( CDSN_CTRL_ECC_IO | CDSN_CTRL_CE , docptr, CDSNControl );
+
+#if 1
+ /* eduardp@m-sys.com says this shouldn't be necessary,
+ * but it doesn't actually work without it, so I've
+ * left it in for now. dwmw2.
+ */
+
+ WriteDOC( 0, docptr, 2k_CDSN_IO);
+ WriteDOC( 0, docptr, 2k_CDSN_IO);
+ WriteDOC( 0, docptr, 2k_CDSN_IO);
+#endif
+ /* Read the ECC data through the DiskOnChip ECC logic */
+ for (di=0; di<6; di++) {
+ eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
+ }
+#ifdef PSYCHO_DEBUG
+ printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+ (long) to, eccbuf[0], eccbuf[1], eccbuf[2],
+ eccbuf[3], eccbuf[4], eccbuf[5] );
+#endif
+ /* Reset the ECC engine */
+ WriteDOC(DOC_ECC_RESV, docptr , ECCConf);
+
+ }
+
+ DoC_Command(docptr, NAND_CMD_PAGEPROG, 0);
+
+ DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP);
+ /* There's an implicit DoC_WaitReady() in DoC_Command */
+
+ if (ReadDOC(docptr, 2k_CDSN_IO) & 1) {
+ printk("Error programming flash\n");
+ /* Error in programming */
+ *retlen = 0;
+ return -EIO;
+ }
+
+ /* Let the caller know we completed it */
+ *retlen = len;
+
+ return 0;
+}
+
+
+
+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, u_char *buf)
+{
+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ int i;
+ unsigned long docptr;
+ struct Nand *mychip;
+
+ docptr = this->virtadr;
+
+ mychip = &this->chips[ofs >> this->chipshift];
+
+ if (this->curfloor != mychip->floor) {
+ DoC_SelectFloor(docptr, mychip->floor);
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+ else if (this->curchip != mychip->chip) {
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+ this->curfloor = mychip->floor;
+ this->curchip = mychip->chip;
+
+
+
+ DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP);
+ DoC_Address(docptr, 3, ofs, CDSN_CTRL_WP, 0);
+
+ for (i=0; i<len; i++)
+ buf[i] = ReadDOC(docptr, 2k_CDSN_IO);
+
+ *retlen = len;
+ return 0;
+
+}
+
+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, const u_char *buf)
+{
+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ int i;
+ unsigned long docptr;
+ struct Nand *mychip;
+
+ // printk("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",(long)ofs, len,
+ // buf[0], buf[1], buf[2], buf[3], buf[8], buf[9], buf[14],buf[15]);
+
+ docptr = this->virtadr;
+
+ mychip = &this->chips[ofs >> this->chipshift];
+
+ if (this->curfloor != mychip->floor) {
+ DoC_SelectFloor(docptr, mychip->floor);
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+ else if (this->curchip != mychip->chip) {
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+ this->curfloor = mychip->floor;
+ this->curchip = mychip->chip;
+
+ DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP);
+ DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP);
+
+ DoC_Command(docptr, NAND_CMD_SEQIN, 0);
+ DoC_Address(docptr, 3, ofs, 0, 0);
+
+ for (i=0; i<len; i++)
+ WriteDOC(buf[i], docptr, 2k_CDSN_IO);
+
+ DoC_Command(docptr, NAND_CMD_PAGEPROG, 0);
+ DoC_Command(docptr, NAND_CMD_STATUS, 0);
+ /* DoC_WaitReady() is implicit in DoC_Command */
+
+ if (ReadDOC(docptr, 2k_CDSN_IO) & 1) {
+ printk("Error programming oob data\n");
+ /* There was an error */
+ *retlen = 0;
+ return -EIO;
+ }
+
+ *retlen = len;
+ return 0;
+
+}
+
+
+int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ unsigned long ofs = instr->addr;
+ unsigned long len = instr->len;
+ unsigned long docptr;
+ struct Nand *mychip;
+
+ if(len != mtd->erasesize)
+ printk(KERN_WARNING "Erase not right size (%lx != %lx)n", len, mtd->erasesize);
+
+
+ docptr = this->virtadr;
+
+ mychip = &this->chips[ofs >> this->chipshift];
+
+ if (this->curfloor != mychip->floor) {
+ DoC_SelectFloor(docptr, mychip->floor);
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+ else if (this->curchip != mychip->chip) {
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+ this->curfloor = mychip->floor;
+ this->curchip = mychip->chip;
+
+ instr->state = MTD_ERASE_PENDING;
+
+ DoC_Command(docptr, NAND_CMD_ERASE1, 0);
+ DoC_Address(docptr, 2, ofs, 0, 0);
+ DoC_Command(docptr, NAND_CMD_ERASE2, 0);
+
+ instr->state = MTD_ERASING;
+
+ DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP);
+
+ if (ReadDOC(docptr, 2k_CDSN_IO) & 1) {
+ printk("Error writing\n");
+ /* There was an error */
+ instr->state = MTD_ERASE_FAILED;
+ }
+ else
+ instr->state = MTD_ERASE_DONE;
+
+ if (instr->callback)
+ instr->callback(instr);
+
+ return 0;
+}
+
+
+
+
+
+/****************************************************************************
+ *
+ * Module stuff
+ *
+ ****************************************************************************/
+
+#if LINUX_VERSION_CODE < 0x20300
+#ifdef MODULE
+#define cleanup_doc2000 cleanup_module
+#endif
+#define __exit
+#endif
+
+
+static void __exit cleanup_doc2000(void)
+{
+ struct mtd_info *mtd;
+ struct DiskOnChip *this;
+
+ while((mtd=doc2klist)) {
+ this = (struct DiskOnChip *)mtd->priv;
+ doc2klist = this->nextdoc;
+
+ del_mtd_device(mtd);
+
+ iounmap((void *)this->virtadr);
+ kfree(this->chips);
+ kfree(mtd);
+ }
+
+}
+
+#if LINUX_VERSION_CODE > 0x20300
+module_exit(cleanup_doc2000);
+#endif
+
diff --git a/drivers/mtd/doc2001.c b/drivers/mtd/doc2001.c
new file mode 100644
index 000000000..9f63b0b22
--- /dev/null
+++ b/drivers/mtd/doc2001.c
@@ -0,0 +1,844 @@
+
+/* Linux driver for Disk-On-Chip Millennium */
+/* (c) 1999 Machine Vision Holdings, Inc. */
+/* Author: David Woodhouse <dwmw2@mvhi.com> */
+/* $Id: doc2001.c,v 1.4 2000/07/03 10:01:38 dwmw2 Exp $ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/doc2000.h>
+
+
+
+//#define PRERELEASE
+#if 0
+static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+static int doc_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
+static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eecbuf);
+static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf);
+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, u_char *buf);
+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, const u_char *buf);
+static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
+#endif
+
+static struct mtd_info *docmillist = NULL;
+
+/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
+
+int _DoC_WaitReady (unsigned long docptr)
+{
+ //long c=-1;
+ short c=-1;
+
+ DEBUG(2,"_DoC_WaitReady called for out-of-line wait\n");
+
+ /* Out-of-line routine to wait for chip response */
+ while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B) && --c)
+ ;
+
+ if (c == 0)
+ DEBUG(2, "_DoC_WaitReady timed out.\n");
+
+ return (c==0);
+}
+
+static inline int DoC_WaitReady(unsigned long docptr)
+{
+ /* This is inline, to optimise the common case, where it's ready instantly */
+ volatile char dummy;
+ int ret = 0;
+
+ /* Out-of-line routine to wait for chip response */
+ /* TPW: Add 4 reads - see Software Requirement 2.3.2 */
+ dummy = ReadDOC(docptr, CDSNControl);
+ dummy = ReadDOC(docptr, CDSNControl);
+ dummy = ReadDOC(docptr, CDSNControl);
+ dummy = ReadDOC(docptr, CDSNControl);
+
+ if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
+ ret = _DoC_WaitReady(docptr); /* Call the out-of-line routine to wait */
+
+ /* TPW: Add 2 reads - see Software Requirement 2.3.2 */
+ dummy = ReadDOC(docptr, CDSNControl);
+ dummy = ReadDOC(docptr, CDSNControl);
+
+ return ret;
+}
+
+
+/* DoC_Command: Send a flash command to the flash chip */
+
+static inline int DoC_Command(unsigned long docptr, unsigned char command, unsigned char xtraflags)
+{
+ /* Assert the CLE (Command Latch Enable) line to the flash chip */
+ WriteDOC( CDSN_CTRL_FLASH_IO | xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE,
+ docptr, CDSNControl);
+
+ /* Send the command */
+ WriteDOC(command, docptr, 2k_CDSN_IO);
+
+ /* Lower the CLE line */
+ WriteDOC( CDSN_CTRL_FLASH_IO | xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
+
+ /* Wait for the chip to respond */
+ return DoC_WaitReady(docptr);
+}
+
+/* DoC_Address: Set the current address for the flash chip */
+
+static inline int DoC_Address (unsigned long docptr, int numbytes, unsigned long ofs,
+ unsigned char xtraflags1, unsigned char xtraflags2)
+{
+ /* Assert the ALE (Address Latch Enable line to the flash chip */
+ WriteDOC( CDSN_CTRL_FLASH_IO | xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE,
+ docptr, CDSNControl);
+
+ /* Send the address */
+ /* Three cases:
+ numbytes == 1: Send single byte, bits 0-7.
+ numbytes == 2: Send bits 9-16 followed by 17-23
+ numbytes == 3: Send 0-7, 9-16, then 17-23
+ */
+ if (numbytes != 2)
+ WriteDOC(ofs & 0xff, docptr, 2k_CDSN_IO);
+
+ if (numbytes != 1) {
+ WriteDOC((ofs >> 9) & 0xff, docptr, 2k_CDSN_IO);
+ WriteDOC((ofs >> 17) & 0xff, docptr, 2k_CDSN_IO);
+ }
+ /* Lower the ALE line */
+ WriteDOC( CDSN_CTRL_FLASH_IO | xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr, CDSNControl);
+
+ /* Wait for the chip to respond */
+ return DoC_WaitReady(docptr);
+}
+
+/* DoC_SelectChip: Select a given flash chip within the current floor */
+
+static inline int DoC_SelectChip(unsigned long docptr, int chip)
+{
+ /* Select the individual flash chip requested */
+ WriteDOC( chip, docptr, CDSNDeviceSelect);
+
+ /* Wait for it to be ready */
+ return DoC_WaitReady(docptr);
+}
+
+/* DoC_SelectFloor: Select a given floor (bank of flash chips) */
+
+static inline int DoC_SelectFloor(unsigned long docptr, int floor)
+{
+ /* Select the floor (bank) of chips required */
+ WriteDOC( floor, docptr, FloorSelect);
+
+ /* Wait for the chip to be ready */
+ return DoC_WaitReady(docptr);
+}
+
+/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */
+
+int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
+{
+ int mfr, id, chipshift=0;
+ char *mfrname=NULL, *idname=NULL;
+
+ /* Page in the required floor/chip */
+ DoC_SelectFloor(doc->virtadr, floor);
+ DoC_SelectChip(doc->virtadr, chip);
+
+ /* Reset the chip */
+ if (DoC_Command(doc->virtadr, NAND_CMD_RESET, CDSN_CTRL_WP)) {
+ DEBUG(2, "DoC_Command (reset) for %d,%d returned true\n", floor,chip);
+ return 0;
+ }
+
+ /* Read the NAND chip ID: 1. Send ReadID command */
+ if(DoC_Command(doc->virtadr, NAND_CMD_READID, CDSN_CTRL_WP)) {
+ DEBUG(2,"DoC_Command (ReadID) for %d,%d returned true\n", floor,chip);
+ return 0;
+ }
+
+ /* Read the NAND chip ID: 2. Send address byte zero
+ */
+ DoC_Address(doc->virtadr, 1, 0, CDSN_CTRL_WP, 0);
+
+ /* Read the manufacturer and device id codes from the device */
+ mfr = ReadDOC(doc->virtadr, 2k_CDSN_IO);
+ id = ReadDOC(doc->virtadr, 2k_CDSN_IO);
+
+ /* No response - return failure */
+ if (mfr == 0xff || mfr == 0)
+ return 0;
+
+ /* Check it's the same as the first chip we identified.
+ * M-Systems say that any given DiskOnChip device should only
+ * contain _one_ type of flash part, although that's not a
+ * hardware restriction. */
+ if (doc->mfr) {
+ if (doc->mfr == mfr && doc->id == id)
+ return 1; /* This is another the same the first */
+ else
+ printk(KERN_WARNING "Flash chip at floor %d, chip %d is different:\n",
+ floor, chip);
+ }
+
+ /* Print (and store if first time) the manufacturer and ID codes. */
+
+ switch(mfr) {
+ case NAND_MFR_TOSHIBA: /* Toshiba */
+ mfrname = "Toshiba";
+
+ switch(id) {
+ case 0x64:
+ idname = "TC5816BDC";
+ chipshift = 21;
+ break;
+
+ case 0x6b:
+ idname = "TC5832DC";
+ chipshift = 22;
+ break;
+
+ case 0x73:
+ idname = "TH58V128DC";
+ chipshift = 24;
+ break;
+
+ case 0x75:
+ idname = "TC58256FT/DC";
+ chipshift = 25;
+ break;
+
+ case 0xe5:
+ idname = "TC58V32DC";
+ chipshift = 22;
+ break;
+
+ case 0xe6:
+ idname = "TC58V64DC";
+ chipshift = 23;
+ break;
+
+ case 0xea:
+ idname = "TC58V16BDC";
+ chipshift = 21;
+ break;
+ }
+ break; /* End of Toshiba parts */
+
+ case NAND_MFR_SAMSUNG: /* Samsung */
+ mfrname = "Samsung";
+
+ switch(id) {
+ case 0x64:
+ idname = "KM29N16000";
+ chipshift = 21;
+
+ case 0x73:
+ idname = "KM29U128T";
+ chipshift = 24;
+ break;
+
+ case 0x75:
+ idname = "KM29U256T";
+ chipshift = 25;
+ break;
+
+ case 0xe3:
+ idname = "KM29W32000";
+ chipshift = 22;
+ break;
+
+ case 0xe6:
+ idname = "KM29U64000";
+ chipshift = 23;
+ break;
+
+ case 0xea:
+ idname = "KM29W16000";
+ chipshift = 21;
+ break;
+ }
+ break; /* End of Samsung parts */
+ }
+
+ /* If we've identified it fully, print the full names */
+ if (idname) {
+#ifdef PRERELEASE
+ DEBUG(1, "Flash chip found: %2.2X %2.2X (%s %s)\n",
+ mfr,id,mfrname,idname);
+#endif
+ /* If this is the first chip, store the id codes */
+ if (!doc->mfr) {
+ doc->mfr = mfr;
+ doc->id = id;
+ doc->chipshift = chipshift;
+ return 1;
+ }
+ return 0;
+ }
+
+ /* We haven't fully identified the chip. Print as much as we know. */
+ if (mfrname)
+ printk(KERN_WARNING "Unknown %s flash chip found: %2.2X %2.2X\n", mfrname,
+ id, mfr);
+ else
+ printk(KERN_WARNING "Unknown flash chip found: %2.2X %2.2X\n", id, mfr);
+
+ printk(KERN_WARNING "Please report to David.Woodhouse@mvhi.com\n");
+ return 0;
+}
+
+/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
+
+void DoC_ScanChips(struct DiskOnChip *this)
+{
+ int floor, chip;
+ int numchips[MAX_FLOORS];
+ int ret = 1;
+
+ this->numchips = 0;
+ this->mfr = 0;
+ this->id = 0;
+
+ /* For each floor, find the number of valid chips it contains */
+ for (floor = 0 ; floor < MAX_FLOORS ; floor++) {
+ ret = 1;
+ numchips[floor]=0;
+ for (chip = 0 ; chip < MAX_CHIPS && ret != 0; chip++ ) {
+
+ ret = DoC_IdentChip(this, floor, chip);
+ if (ret) {
+ numchips[floor]++;
+ this->numchips++;
+ }
+ }
+ }
+
+ /* If there are none at all that we recognise, bail */
+ if (!this->numchips) {
+ printk("No flash chips recognised.\n");
+ return;
+ }
+
+ /* Allocate an array to hold the information for each chip */
+ this->chips = kmalloc(sizeof(struct Nand) * this->numchips, GFP_KERNEL);
+ if (!this->chips){
+ printk("No memory for allocating chip info structures\n");
+ return;
+ }
+
+ ret = 0;
+
+ /* Fill out the chip array with {floor, chipno} for each
+ * detected chip in the device. */
+ for (floor = 0; floor < MAX_FLOORS; floor++) {
+ for (chip = 0 ; chip < numchips[floor] ; chip++) {
+ this->chips[ret].floor = floor;
+ this->chips[ret].chip = chip;
+ this->chips[ret].curadr = 0;
+ this->chips[ret].curmode = 0x50;
+ ret++;
+ }
+ }
+
+ /* Calculate and print the total size of the device */
+ this->totlen = this->numchips * (1 << this->chipshift);
+
+ printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld Mb\n", this->numchips ,
+ this->totlen >> 20);
+}
+
+static int DoCMil_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
+{
+ int tmp1, tmp2, retval;
+ if (doc1->physadr == doc2->physadr)
+ return 1;
+
+ /* Use the alias resolution register which was set aside for this
+ * purpose. If it's value is the same on both chips, they might
+ * be the same chip, and we write to one and check for a change in
+ * the other. It's unclear if this register is usuable in the
+ * DoC 2000 (it's in the Millenium docs), but it seems to work. */
+ tmp1 = ReadDOC(doc1->virtadr, AliasResolution);
+ tmp2 = ReadDOC(doc2->virtadr, AliasResolution);
+ if (tmp1 != tmp2)
+ return 0;
+
+ WriteDOC((tmp1+1) % 0xff, doc1->virtadr, AliasResolution);
+ tmp2 = ReadDOC(doc2->virtadr, AliasResolution);
+ if (tmp2 == (tmp1+1) % 0xff)
+ retval = 1;
+ else
+ retval = 0;
+
+ /* Restore register contents. May not be necessary, but do it just to
+ * be safe. */
+ WriteDOC(tmp1, doc1->virtadr, AliasResolution);
+
+ return retval;
+}
+
+
+void DoCMil_init(struct mtd_info *mtd)
+{
+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ struct DiskOnChip *old = NULL;
+
+ /* We must avoid being called twice for the same device. */
+
+ if (docmillist)
+ old = (struct DiskOnChip *)docmillist->priv;
+
+ while (old) {
+ if (DoCMil_is_alias(this, old)) {
+ printk(KERN_NOTICE "Ignoring DiskOnChip Millennium at 0x%lX - already configured\n",
+ this->physadr);
+ iounmap((void *)this->virtadr);
+ kfree(mtd);
+ return;
+ }
+ if (old->nextdoc)
+ old = (struct DiskOnChip *)old->nextdoc->priv;
+ else
+ old = NULL;
+ }
+
+ mtd->name = "DiskOnChip Millennium";
+ printk(KERN_NOTICE "DiskOnChip Millennium found at address 0x%lX\n",this->physadr);
+
+#if 1
+ printk("Unfortunately, we don't have support for the DiskOnChip Millennium yet.\n");
+ iounmap((void *)this->virtadr);
+ kfree(mtd);
+ return;
+#else
+ mtd->type = MTD_NANDFLASH;
+ mtd->flags = MTD_CAP_NANDFLASH;
+ mtd->size = 0;
+ mtd->erasesize = 0x2000;
+ mtd->oobblock = 512;
+ mtd->oobsize = 16;
+ mtd->module = THIS_MODULE;
+ mtd->erase = doc_erase;
+ mtd->point = NULL;
+ mtd->unpoint = NULL;
+ mtd->read = doc_read;
+ mtd->write = doc_write;
+ mtd->read_ecc = doc_read_ecc;
+ mtd->write_ecc = doc_write_ecc;
+ mtd->read_oob = doc_read_oob;
+ mtd->write_oob = doc_write_oob;
+ mtd->sync = NULL;
+
+ this->totlen = 0;
+ this->numchips = 0;
+
+ this->curfloor = -1;
+ this->curchip = -1;
+
+ /* Ident all the chips present. */
+ DoC_ScanChips(this);
+
+ if (!this->totlen) {
+ kfree(mtd);
+ iounmap((void *)this->virtadr);
+ } else {
+ this->nextdoc = docmillist;
+ docmillist = mtd;
+ mtd->size = this->totlen;
+ add_mtd_device(mtd);
+ return;
+ }
+#endif
+}
+
+
+EXPORT_SYMBOL(DoCMil_init);
+#if 0
+static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+ /* Just a special case of doc_read_ecc */
+ return doc_read_ecc(mtd, from, len, retlen, buf, NULL);
+}
+
+static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf)
+{
+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ int di=0; /* Yes, DI is a hangover from when I was disassembling the binary driver */
+ unsigned long docptr;
+ struct Nand *mychip;
+
+ docptr = this->virtadr;
+
+ /* Don't allow read past end of device */
+ if (from >= this->totlen)
+ return -EINVAL;
+
+ /* Don't allow a single read to cross a 512-byte block boundary */
+ if (from + len > ( (from | 0x1ff) + 1))
+ len = ((from | 0x1ff) + 1) - from;
+
+ /* Find the chip which is to be used and select it */
+ mychip = &this->chips[from >> (this->chipshift)];
+
+ if (this->curfloor != mychip->floor) {
+ DoC_SelectFloor(docptr, mychip->floor);
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+ else if (this->curchip != mychip->chip) {
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+
+ this->curfloor = mychip->floor;
+ this->curchip = mychip->chip;
+
+
+ if (eccbuf) {
+ /* Prime the ECC engine */
+ WriteDOC ( DOC_ECC_RESET, docptr, ECCConf);
+ WriteDOC ( DOC_ECC_EN, docptr, ECCConf);
+ }
+
+ DoC_Command(docptr, (from >> 8) & 1, CDSN_CTRL_WP);
+ DoC_Address(docptr, 3, from, CDSN_CTRL_WP , CDSN_CTRL_ECC_IO);
+
+ for (di=0; di < len ; di++) {
+ buf[di] = ReadDOC(docptr, 2k_CDSN_IO);
+ }
+
+ /* Let the caller know we completed it */
+ *retlen = len;
+
+ if (eccbuf) {
+ /* Read the ECC data through the DiskOnChip ECC logic */
+ for (di=0; di<6; di++) {
+ eccbuf[di] = ReadDOC(docptr, 2k_CDSN_IO);
+ }
+
+ /* Flush the pipeline */
+ (void) ReadDOC(docptr, 2k_ECCStatus);
+ (void) ReadDOC(docptr, 2k_ECCStatus);
+
+ /* Check the ECC Status */
+ if (ReadDOC(docptr, 2k_ECCStatus) & 0x80) {
+ /* There was an ECC error */
+ printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
+
+ /* FIXME: Implement ECC error correction, don't just whinge */
+
+ /* We return error, but have actually done the read. Not that
+ this can be told to user-space, via sys_read(), but at least
+ MTD-aware stuff can know about it by checking *retlen */
+ return -EIO;
+ }
+#ifdef PSYCHO_DEBUG
+ else
+ printk("ECC OK at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+ (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], eccbuf[4],
+ eccbuf[5]);
+#endif
+
+ /* Reset the ECC engine */
+ WriteDOC(DOC_ECC_RESV, docptr , ECCConf);
+
+ }
+
+ return 0;
+}
+
+static int doc_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
+{
+ static char as[6];
+ return doc_write_ecc(mtd, to, len, retlen, buf, as);
+}
+
+static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf)
+{
+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ int di=0;
+ unsigned long docptr;
+ struct Nand *mychip;
+
+ docptr = this->virtadr;
+
+ /* Don't allow write past end of device */
+ if (to >= this->totlen)
+ return -EINVAL;
+#if 0
+ /* Don't allow a single write to cross a 512-byte block boundary */
+ if (to + len > ( (to | 0x1ff) + 1))
+ len = ((to | 0x1ff) + 1) - to;
+
+#else
+ /* Don't allow writes which aren't exactly one block */
+ if (to & 0x1ff || len != 0x200)
+ return -EINVAL;
+#endif
+
+ /* Find the chip which is to be used and select it */
+ mychip = &this->chips[to >> (this->chipshift)];
+
+ if (this->curfloor != mychip->floor) {
+ DoC_SelectFloor(docptr, mychip->floor);
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+ else if (this->curchip != mychip->chip) {
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+
+ this->curfloor = mychip->floor;
+ this->curchip = mychip->chip;
+
+ /* Set device to main plane of flash */
+ DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP);
+ DoC_Command(docptr, NAND_CMD_READ0, CDSN_CTRL_WP);
+
+ if (eccbuf) {
+ /* Prime the ECC engine */
+ WriteDOC ( DOC_ECC_RESET, docptr, ECCConf);
+ WriteDOC ( DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
+ }
+
+ DoC_Command(docptr, NAND_CMD_SEQIN, 0);
+ DoC_Address(docptr, 3, to, 0, CDSN_CTRL_ECC_IO);
+
+ for (di=0; di < len ; di++) {
+ WriteDOC(buf[di], docptr, 2k_CDSN_IO);
+ }
+
+
+ if (eccbuf) {
+ WriteDOC( CDSN_CTRL_ECC_IO | CDSN_CTRL_CE , docptr, CDSNControl );
+
+#if 1
+ /* eduardp@m-sys.com says this shouldn't be necessary,
+ * but it doesn't actually work without it, so I've
+ * left it in for now. dwmw2.
+ */
+
+ WriteDOC( 0, docptr, 2k_CDSN_IO);
+ WriteDOC( 0, docptr, 2k_CDSN_IO);
+ WriteDOC( 0, docptr, 2k_CDSN_IO);
+#endif
+ /* Read the ECC data through the DiskOnChip ECC logic */
+ for (di=0; di<6; di++) {
+ eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
+ }
+#ifdef PSYCHO_DEBUG
+ printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+ (long) to, eccbuf[0], eccbuf[1], eccbuf[2],
+ eccbuf[3], eccbuf[4], eccbuf[5] );
+#endif
+ /* Reset the ECC engine */
+ WriteDOC(DOC_ECC_RESV, docptr , ECCConf);
+
+ }
+
+ DoC_Command(docptr, NAND_CMD_PAGEPROG, 0);
+
+ DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP);
+ /* There's an implicit DoC_WaitReady() in DoC_Command */
+
+ if (ReadDOC(docptr, 2k_CDSN_IO) & 1) {
+ printk("Error programming flash\n");
+ /* Error in programming */
+ *retlen = 0;
+ return -EIO;
+ }
+
+ /* Let the caller know we completed it */
+ *retlen = len;
+
+ return 0;
+}
+
+
+
+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, u_char *buf)
+{
+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ int i;
+ unsigned long docptr;
+ struct Nand *mychip;
+
+ docptr = this->virtadr;
+
+ mychip = &this->chips[ofs >> this->chipshift];
+
+ if (this->curfloor != mychip->floor) {
+ DoC_SelectFloor(docptr, mychip->floor);
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+ else if (this->curchip != mychip->chip) {
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+ this->curfloor = mychip->floor;
+ this->curchip = mychip->chip;
+
+
+
+ DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP);
+ DoC_Address(docptr, 3, ofs, CDSN_CTRL_WP, 0);
+
+ for (i=0; i<len; i++)
+ buf[i] = ReadDOC(docptr, 2k_CDSN_IO);
+
+ *retlen = len;
+ return 0;
+
+}
+
+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, const u_char *buf)
+{
+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ int i;
+ unsigned long docptr;
+ struct Nand *mychip;
+
+ // printk("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",(long)ofs, len,
+ // buf[0], buf[1], buf[2], buf[3], buf[8], buf[9], buf[14],buf[15]);
+
+ docptr = this->virtadr;
+
+ mychip = &this->chips[ofs >> this->chipshift];
+
+ if (this->curfloor != mychip->floor) {
+ DoC_SelectFloor(docptr, mychip->floor);
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+ else if (this->curchip != mychip->chip) {
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+ this->curfloor = mychip->floor;
+ this->curchip = mychip->chip;
+
+ DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP);
+ DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP);
+
+ DoC_Command(docptr, NAND_CMD_SEQIN, 0);
+ DoC_Address(docptr, 3, ofs, 0, 0);
+
+ for (i=0; i<len; i++)
+ WriteDOC(buf[i], docptr, 2k_CDSN_IO);
+
+ DoC_Command(docptr, NAND_CMD_PAGEPROG, 0);
+ DoC_Command(docptr, NAND_CMD_STATUS, 0);
+ /* DoC_WaitReady() is implicit in DoC_Command */
+
+ if (ReadDOC(docptr, 2k_CDSN_IO) & 1) {
+ printk("Error programming oob data\n");
+ /* There was an error */
+ *retlen = 0;
+ return -EIO;
+ }
+
+ *retlen = len;
+ return 0;
+
+}
+
+
+int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+ unsigned long ofs = instr->addr;
+ unsigned long len = instr->len;
+ unsigned long docptr;
+ struct Nand *mychip;
+
+ if(len != mtd->erasesize)
+ printk(KERN_WARNING "Erase not right size (%lx != %lx)n", len, mtd->erasesize);
+
+
+ docptr = this->virtadr;
+
+ mychip = &this->chips[ofs >> this->chipshift];
+
+ if (this->curfloor != mychip->floor) {
+ DoC_SelectFloor(docptr, mychip->floor);
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+ else if (this->curchip != mychip->chip) {
+ DoC_SelectChip(docptr, mychip->chip);
+ }
+ this->curfloor = mychip->floor;
+ this->curchip = mychip->chip;
+
+ instr->state = MTD_ERASE_PENDING;
+
+ DoC_Command(docptr, NAND_CMD_ERASE1, 0);
+ DoC_Address(docptr, 2, ofs, 0, 0);
+ DoC_Command(docptr, NAND_CMD_ERASE2, 0);
+
+ instr->state = MTD_ERASING;
+
+ DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP);
+
+ if (ReadDOC(docptr, 2k_CDSN_IO) & 1) {
+ printk("Error writing\n");
+ /* There was an error */
+ instr->state = MTD_ERASE_FAILED;
+ }
+ else
+ instr->state = MTD_ERASE_DONE;
+
+ if (instr->callback)
+ instr->callback(instr);
+
+ return 0;
+}
+
+
+
+#endif
+
+/****************************************************************************
+ *
+ * Module stuff
+ *
+ ****************************************************************************/
+
+#if LINUX_VERSION_CODE < 0x20300
+#ifdef MODULE
+#define cleanup_doc2001 cleanup_module
+#endif
+#define __exit
+#endif
+
+
+static void __exit cleanup_doc2001(void)
+{
+ struct mtd_info *mtd;
+ struct DiskOnChip *this;
+
+ while((mtd=docmillist)) {
+ this = (struct DiskOnChip *)mtd->priv;
+ docmillist = this->nextdoc;
+
+ del_mtd_device(mtd);
+
+ iounmap((void *)this->virtadr);
+ kfree(this->chips);
+ kfree(mtd);
+ }
+
+}
+
+#if LINUX_VERSION_CODE > 0x20300
+module_exit(cleanup_doc2001);
+#endif
+
diff --git a/drivers/mtd/docprobe.c b/drivers/mtd/docprobe.c
new file mode 100644
index 000000000..b2c4380d3
--- /dev/null
+++ b/drivers/mtd/docprobe.c
@@ -0,0 +1,269 @@
+
+/* Linux driver for Disk-On-Chip devices */
+/* Probe routines common to all DoC devices */
+/* (c) 1999 Machine Vision Holdings, Inc. */
+/* Author: David Woodhouse <dwmw2@mvhi.com> */
+/* $Id: docprobe.c,v 1.8 2000/06/26 20:40:53 dwmw2 Exp $ */
+
+
+
+/* DOC_PASSIVE_PROBE:
+ In order to ensure that the BIOS checksum is correct at boot time, and
+ hence that the onboard BIOS extension gets executed, the DiskOnChip
+ goes into reset mode when it is read sequentially: all registers
+ return 0xff until the chip is woken up again by writing to the
+ DOCControl register.
+
+ Unfortunately, this means that the probe for the DiskOnChip is unsafe,
+ because one of the first things it does is write to where it thinks
+ the DOCControl register should be - which may well be shared memory
+ for another device. I've had machines which lock up when this is
+ attempted. Hence the possibility to do a passive probe, which will fail
+ to detect a chip in reset mode, but is at least guaranteed not to lock
+ the machine.
+
+ If you have this problem, uncomment the following line:
+#define DOC_PASSIVE_PROBE
+*/
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/doc2000.h>
+
+/* Where to look for the devices? */
+
+#if defined (__alpha__) || defined(__i386__)
+static unsigned long __initdata doc_locations[] = {
+ 0xc8000, 0xca000, 0xcc000, 0xce000,
+ 0xd0000, 0xd2000, 0xd4000, 0xd6000,
+ 0xd8000, 0xda000, 0xdc000, 0xde000,
+ 0xe0000, 0xe2000, 0xe4000, 0xe6000,
+ 0xe8000, 0xea000, 0xec000, 0xee000, 0 };
+#elif defined(__ppc__)
+static unsigned long __initdata doc_locations[] = {
+ 0xe4000000, 0};
+#else
+#warning Unknown architecture for DiskOnChip. No default probe locations defined
+#endif
+
+#ifdef CONFIG_MTD_DOC2000
+extern void DoC2k_init(struct mtd_info *);
+#endif
+#ifdef CONFIG_MTD_DOC2001
+extern void DoCMil_init(struct mtd_info *);
+#endif
+
+/* doccheck: Probe a given memory window to see if there's a DiskOnChip present */
+
+static inline int __init doccheck(unsigned long potential, unsigned long physadr)
+{
+ unsigned long window=potential;
+ unsigned char tmp, ChipID;
+#ifndef DOC_PASSIVE_PROBE
+ unsigned char tmp2;
+#endif
+
+ /* Routine copied from the Linux DOC driver */
+
+ /* Check for 0x55 0xAA signature at beginning of window */
+ if (ReadDOC(window, Sig1) != 0x55 || ReadDOC(window, Sig2) != 0xaa)
+ return 0;
+
+#ifndef DOC_PASSIVE_PROBE
+ /* It's not possible to cleanly detect the DiskOnChip - the
+ * bootup procedure will put the device into reset mode, and
+ * it's not possible to talk to it without actually writing
+ * to the DOCControl register. So we store the current contents
+ * of the DOCControl register's location, in case we later decide
+ * that it's not a DiskOnChip, and want to put it back how we
+ * found it.
+ */
+ tmp2 = ReadDOC(window, DOCControl);
+
+ /* Reset the DiskOnChip ASIC */
+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
+ window, DOCControl);
+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
+ window, DOCControl);
+
+ /* Enable the DiskOnChip ASIC */
+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
+ window, DOCControl);
+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
+ window, DOCControl);
+#endif /* !DOC_PASSIVE_PROBE */
+
+ ChipID = ReadDOC(window, ChipID);
+
+ switch (ChipID) {
+ case DOC_ChipID_Doc2k:
+ /* Check the TOGGLE bit in the ECC register */
+ tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
+ if ((ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT) != tmp)
+ return ChipID;
+ break;
+
+ case DOC_ChipID_DocMil:
+ /* Check the TOGGLE bit in the ECC register */
+ tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
+ if ((ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT) != tmp)
+ return ChipID;
+ break;
+
+ default:
+ printk(KERN_WARNING "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
+ ChipID, physadr);
+
+#ifndef DOC_PASSIVE_PROBE
+ /* Put back the contents of the DOCControl register, in case it's not
+ * actually a DiskOnChip.
+ */
+ WriteDOC(tmp2, window, DOCControl);
+#endif
+ return 0;
+ }
+
+ printk(KERN_WARNING "DiskOnChip failed TOGGLE test, dropping.\n");
+
+#ifndef DOC_PASSIVE_PROBE
+ /* Put back the contents of the DOCControl register: it's not a DiskOnChip */
+ WriteDOC(tmp2, window, DOCControl);
+#endif
+ return 0;
+}
+
+
+static void DoC_Probe(unsigned long physadr)
+{
+ unsigned long docptr;
+ struct DiskOnChip *this;
+ struct mtd_info *mtd;
+ int ChipID;
+ char namebuf[15];
+ char *name = namebuf;
+ void (*initroutine)(struct mtd_info *) = NULL;
+ int initroutinedynamic = 0;
+
+ docptr = (unsigned long)ioremap(physadr, 0x2000);
+
+ if (!docptr)
+ return;
+
+ if ((ChipID = doccheck(docptr, physadr))) {
+
+ mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL);
+
+ if (!mtd) {
+ printk("Cannot allocate memory for data structures. Dropping.\n");
+ iounmap((void *)docptr);
+ return;
+ }
+
+ this = (struct DiskOnChip *)(&mtd[1]);
+
+ memset((char *)mtd,0, sizeof(struct mtd_info));
+ memset((char *)this, 0, sizeof(struct DiskOnChip));
+
+ mtd->priv = this;
+ this->virtadr = docptr;
+ this->physadr = physadr;
+ this->ChipID = ChipID;
+ sprintf(namebuf, "with ChipID %2.2X", ChipID);
+
+ switch(ChipID) {
+ case DOC_ChipID_Doc2k:
+ name="2000";
+#ifdef CONFIG_MTD_DOC2000
+ initroutine = &DoC2k_init;
+#elif CONFIG_MODULES
+ initroutinedynamic=1;
+ initroutine = (void *)get_module_symbol(NULL, "DoC2k_init");
+#ifdef CONFIG_KMOD
+ if (!initroutine) {
+ request_module("doc2000");
+ initroutine = (void *)get_module_symbol("doc2000", "DoC2k_init");
+ }
+#endif /* CONFIG_KMOD */
+#endif
+ break;
+
+ case DOC_ChipID_DocMil:
+ name="Millennium";
+#ifdef CONFIG_MTD_DOC2001
+ initroutine = &DocMil_init;
+#elif CONFIG_MODULES
+ initroutinedynamic=1;
+ initroutine = (void *)get_module_symbol(NULL, "DoCMil_init");
+#ifdef CONFIG_KMOD
+ if (!initroutine) {
+ request_module("doc2001");
+ initroutine = (void *)get_module_symbol("doc2001", "DoCMil_init");
+ }
+#endif /* CONFIG_KMOD */
+#endif
+ break;
+ }
+ if (initroutine) {
+ (*initroutine)(mtd);
+#if defined(CONFIG_MODULES) && LINUX_VERSION_CODE >= 0x20400
+ if (initroutinedynamic)
+ put_module_symbol(initroutine);
+#endif
+ return;
+ }
+ printk("Cannot find driver for DiskOnChip %s at 0x%X\n", name, physadr);
+ }
+ iounmap((void *)docptr);
+}
+
+
+/****************************************************************************
+ *
+ * Module stuff
+ *
+ ****************************************************************************/
+
+#if LINUX_VERSION_CODE < 0x20300
+#ifdef MODULE
+#define init_doc init_module
+#endif
+#define __exit
+#endif
+
+int __init init_doc(void)
+{
+ int i;
+
+ printk(KERN_NOTICE "M-Systems DiskOnChip driver. (C) 1999 Machine Vision Holdings, Inc.\n");
+#ifdef PRERELEASE
+ printk(KERN_INFO "$Id: docprobe.c,v 1.8 2000/06/26 20:40:53 dwmw2 Exp $\n");
+#endif
+
+ for (i=0; doc_locations[i]; i++) {
+ DoC_Probe(doc_locations[i]);
+ }
+
+ return 0;
+
+}
+
+
+#if LINUX_VERSION_CODE > 0x20300
+module_init(init_doc);
+#endif
+
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
new file mode 100644
index 000000000..1cf4a5f16
--- /dev/null
+++ b/drivers/mtd/ftl.c
@@ -0,0 +1,1458 @@
+/* This version ported to the Linux-MTD system by dwmw2@infradead.org
+ * $Id: ftl.c,v 1.20 2000/06/23 15:17:53 dwmw2 Exp $
+ * Based on:
+ */
+/*======================================================================
+
+ A Flash Translation Layer memory card driver
+
+ This driver implements a disk-like block device driver with an
+ apparent block size of 512 bytes for flash memory cards.
+
+ ftl_cs.c 1.62 2000/02/01 00:59:04
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ The initial developer of the original code is David A. Hinds
+ <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds
+ are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU Public License version 2 (the "GPL"), in which
+ case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+ LEGAL NOTE: The FTL format is patented by M-Systems. They have
+ granted a license for its use with PCMCIA devices:
+
+ "M-Systems grants a royalty-free, non-exclusive license under
+ any presently existing M-Systems intellectual property rights
+ necessary for the design and development of FTL-compatible
+ drivers, file systems and utilities using the data formats with
+ PCMCIA PC Cards as described in the PCMCIA Flash Translation
+ Layer (FTL) Specification."
+
+ Use of the FTL format for non-PCMCIA applications may be an
+ infringement of these patents. For additional information,
+ contact M-Systems (http://www.m-sys.com) directly.
+
+======================================================================*/
+#define FTL_DEBUG 5
+#ifdef FTL_DEBUG
+#define DEBUGLVL debug
+#endif
+
+#include <linux/module.h>
+#include <linux/mtd/compatmac.h>
+#include <linux/mtd/mtd.h>
+/*#define PSYCHO_DEBUG */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/hdreg.h>
+#include <stdarg.h>
+
+#if (LINUX_VERSION_CODE >= 0x20100)
+#include <linux/vmalloc.h>
+#endif
+#if (LINUX_VERSION_CODE >= 0x20303)
+#include <linux/blkpg.h>
+#endif
+
+#include <linux/mtd/ftl.h>
+/*====================================================================*/
+/* Stuff which really ought to be in compatmac.h */
+
+#if (LINUX_VERSION_CODE < 0x20328)
+#define register_disk(dev, drive, minors, ops, size) \
+ do { (dev)->part[(drive)*(minors)].nr_sects = size; \
+ if (size == 0) (dev)->part[(drive)*(minors)].start_sect = -1; \
+ resetup_one_dev(dev, drive); } while (0);
+#endif
+
+#if (LINUX_VERSION_CODE < 0x20320)
+#define BLK_DEFAULT_QUEUE(n) blk_dev[n].request_fn
+#define blk_init_queue(q, req) q = (req)
+#define blk_cleanup_queue(q) q = NULL
+#define request_arg_t void
+#else
+#define request_arg_t request_queue_t *q
+#endif
+
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Major device # for FTL device */
+static int shuffle_freq = 50;
+
+MODULE_PARM(shuffle_freq, "i");
+
+/*====================================================================*/
+
+#ifndef FTL_MAJOR
+#define FTL_MAJOR 44
+#endif
+
+
+/* Funky stuff for setting up a block device */
+#define MAJOR_NR FTL_MAJOR
+#define DEVICE_NAME "ftl"
+#define DEVICE_REQUEST do_ftl_request
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#define DEVICE_NR(minor) ((minor)>>5)
+#define REGION_NR(minor) (((minor)>>3)&3)
+#define PART_NR(minor) ((minor)&7)
+#define MINOR_NR(dev,reg,part) (((dev)<<5)+((reg)<<3)+(part))
+
+#include <linux/blk.h>
+
+#ifdef FTL_DEBUG
+static int debug = FTL_DEBUG;
+MODULE_PARM(debug, "i");
+#endif
+
+/*====================================================================*/
+
+#ifndef FTL_MAJOR
+#define FTL_MAJOR 44
+#endif
+
+/* Maximum number of separate memory devices we'll allow */
+#define MAX_DEV 4
+
+/* Maximum number of regions per device */
+#define MAX_REGION 4
+
+/* Maximum number of partitions in an FTL region */
+#define PART_BITS 3
+#define MAX_PART 8
+
+/* Maximum number of outstanding erase requests per socket */
+#define MAX_ERASE 8
+
+/* Sector size -- shouldn't need to change */
+#define SECTOR_SIZE 512
+
+
+/* Each memory region corresponds to a minor device */
+typedef struct partition_t {
+ struct mtd_info *mtd;
+ u_int32_t state;
+ u_int32_t *VirtualBlockMap;
+ u_int32_t *VirtualPageMap;
+ u_int32_t FreeTotal;
+ struct eun_info_t {
+ u_int32_t Offset;
+ u_int32_t EraseCount;
+ u_int32_t Free;
+ u_int32_t Deleted;
+ } *EUNInfo;
+ struct xfer_info_t {
+ u_int32_t Offset;
+ u_int32_t EraseCount;
+ u_int16_t state;
+ } *XferInfo;
+ u_int16_t bam_index;
+ u_int32_t *bam_cache;
+ u_int16_t DataUnits;
+ u_int32_t BlocksPerUnit;
+ erase_unit_header_t header;
+#if 0
+ region_info_t region;
+ memory_handle_t handle;
+#endif
+ atomic_t open;
+} partition_t;
+
+partition_t *myparts[MAX_MTD_DEVICES];
+
+static void ftl_notify_add(struct mtd_info *mtd);
+static void ftl_notify_remove(struct mtd_info *mtd);
+
+void ftl_freepart(partition_t *part);
+
+static struct mtd_notifier ftl_notifier={ftl_notify_add, ftl_notify_remove, NULL};
+
+/* Partition state flags */
+#define FTL_FORMATTED 0x01
+
+/* Transfer unit states */
+#define XFER_UNKNOWN 0x00
+#define XFER_ERASING 0x01
+#define XFER_ERASED 0x02
+#define XFER_PREPARED 0x03
+#define XFER_FAILED 0x04
+
+static struct hd_struct ftl_hd[MINOR_NR(MAX_DEV, 0, 0)];
+static int ftl_sizes[MINOR_NR(MAX_DEV, 0, 0)];
+static int ftl_blocksizes[MINOR_NR(MAX_DEV, 0, 0)];
+
+static struct gendisk ftl_gendisk = {
+ major: FTL_MAJOR,
+ major_name: "ftl",
+ minor_shift: PART_BITS,
+ max_p: MAX_PART,
+#if (LINUX_VERSION_CODE < 0x20328)
+ max_nr: MAX_DEV*MAX_PART,
+#endif
+ part: ftl_hd,
+ sizes: ftl_sizes,
+ nr_real: 0
+};
+
+/*====================================================================*/
+
+static int ftl_ioctl(struct inode *inode, struct file *file,
+ u_int cmd, u_long arg);
+static int ftl_open(struct inode *inode, struct file *file);
+static release_t ftl_close(struct inode *inode, struct file *file);
+static int ftl_reread_partitions(int minor);
+
+static void ftl_erase_callback(struct erase_info *done);
+
+#if LINUX_VERSION_CODE < 0x20326
+static struct file_operations ftl_blk_fops = {
+ open: ftl_open,
+ release: ftl_close,
+ ioctl: ftl_ioctl,
+ read: block_read,
+ write: block_write,
+ fsync: block_fsync
+};
+#else
+static struct block_device_operations ftl_blk_fops = {
+ open: ftl_open,
+ release: ftl_close,
+ ioctl: ftl_ioctl,
+};
+#endif
+
+/*======================================================================
+
+ Scan_header() checks to see if a memory region contains an FTL
+ partition. build_maps() reads all the erase unit headers, builds
+ the erase unit map, and then builds the virtual page map.
+
+======================================================================*/
+
+static int scan_header(partition_t *part)
+{
+ erase_unit_header_t header;
+ loff_t offset;
+ int ret;
+ part->header.FormattedSize = 0;
+ /* Search first megabyte for a valid FTL header */
+ for (offset = 0;
+ offset < 0x100000;
+ offset += part->mtd->erasesize?part->mtd->erasesize:0x2000) {
+
+ ret = part->mtd->read(part->mtd, offset, sizeof(header), &ret,
+ (unsigned char *)&header);
+
+ if (ret)
+ return ret;
+
+ if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
+ }
+
+ if (offset == 0x100000) {
+ printk(KERN_NOTICE "ftl_cs: FTL header not found.\n");
+ return -ENOENT;
+ }
+ if ((le16_to_cpu(header.NumEraseUnits) > 65536) || header.BlockSize != 9 ||
+ (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||
+ (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) {
+ printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
+ return -1;
+ }
+ if ((1 << header.EraseUnitSize) != part->mtd->erasesize) {
+ printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %lx\n",
+ 1 << header.EraseUnitSize,part->mtd->erasesize);
+ return -1;
+ }
+ part->header = header;
+ return 0;
+}
+
+static int build_maps(partition_t *part)
+{
+ erase_unit_header_t header;
+ u_int16_t xvalid, xtrans, i;
+ u_int blocks, j;
+ int hdr_ok, ret;
+ ssize_t retval;
+ loff_t offset;
+
+ /* Set up erase unit maps */
+ part->DataUnits = le16_to_cpu(part->header.NumEraseUnits) -
+ part->header.NumTransferUnits;
+ part->EUNInfo = kmalloc(part->DataUnits * sizeof(struct eun_info_t),
+ GFP_KERNEL);
+ if (!part->EUNInfo) return -1;
+ for (i = 0; i < part->DataUnits; i++)
+ part->EUNInfo[i].Offset = 0xffffffff;
+ part->XferInfo =
+ kmalloc(part->header.NumTransferUnits * sizeof(struct xfer_info_t),
+ GFP_KERNEL);
+ if (!part->XferInfo) return -1;
+
+ xvalid = xtrans = 0;
+ for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
+ offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
+ << part->header.EraseUnitSize);
+ ret = part->mtd->read(part->mtd, offset, sizeof(header), &retval,
+ (unsigned char *)&header);
+
+ if (ret)
+ return ret;
+
+ /* Is this a transfer partition? */
+ hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0);
+ if (hdr_ok && (le16_to_cpu(header.LogicalEUN) < part->DataUnits) &&
+ (part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset == 0xffffffff)) {
+ part->EUNInfo[le16_to_cpu(header.LogicalEUN)].Offset = offset;
+ part->EUNInfo[le16_to_cpu(header.LogicalEUN)].EraseCount =
+ le32_to_cpu(header.EraseCount);
+ xvalid++;
+ } else {
+ if (xtrans == part->header.NumTransferUnits) {
+ printk(KERN_NOTICE "ftl_cs: format error: too many "
+ "transfer units!\n");
+ return -1;
+ }
+ if (hdr_ok && (le16_to_cpu(header.LogicalEUN) == 0xffff)) {
+ part->XferInfo[xtrans].state = XFER_PREPARED;
+ part->XferInfo[xtrans].EraseCount = le32_to_cpu(header.EraseCount);
+ } else {
+ part->XferInfo[xtrans].state = XFER_UNKNOWN;
+ /* Pick anything reasonable for the erase count */
+ part->XferInfo[xtrans].EraseCount =
+ le32_to_cpu(part->header.EraseCount);
+ }
+ part->XferInfo[xtrans].Offset = offset;
+ xtrans++;
+ }
+ }
+ /* Check for format trouble */
+ header = part->header;
+ if ((xtrans != header.NumTransferUnits) ||
+ (xvalid+xtrans != le16_to_cpu(header.NumEraseUnits))) {
+ printk(KERN_NOTICE "ftl_cs: format error: erase units "
+ "don't add up!\n");
+ return -1;
+ }
+
+ /* Set up virtual page map */
+ blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
+ part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
+ memset(part->VirtualBlockMap, 0xff, blocks * sizeof(u_int32_t));
+ part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
+
+ part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(u_int32_t),
+ GFP_KERNEL);
+ if (!part->bam_cache) return -1;
+
+ part->bam_index = 0xffff;
+ part->FreeTotal = 0;
+
+ for (i = 0; i < part->DataUnits; i++) {
+ part->EUNInfo[i].Free = 0;
+ part->EUNInfo[i].Deleted = 0;
+ offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
+
+ ret = part->mtd->read(part->mtd, offset,
+ part->BlocksPerUnit * sizeof(u_int32_t), &retval,
+ (unsigned char *)part->bam_cache);
+
+ if (ret)
+ return ret;
+
+ for (j = 0; j < part->BlocksPerUnit; j++) {
+ if (BLOCK_FREE(le32_to_cpu(part->bam_cache[j]))) {
+ part->EUNInfo[i].Free++;
+ part->FreeTotal++;
+ } else if ((BLOCK_TYPE(le32_to_cpu(part->bam_cache[j])) == BLOCK_DATA) &&
+ (BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j])) < blocks))
+ part->VirtualBlockMap[BLOCK_NUMBER(le32_to_cpu(part->bam_cache[j]))] =
+ (i << header.EraseUnitSize) + (j << header.BlockSize);
+ else if (BLOCK_DELETED(le32_to_cpu(part->bam_cache[j])))
+ part->EUNInfo[i].Deleted++;
+ }
+ }
+
+ return 0;
+
+} /* build_maps */
+
+/*======================================================================
+
+ Erase_xfer() schedules an asynchronous erase operation for a
+ transfer unit.
+
+======================================================================*/
+
+static int erase_xfer(partition_t *part,
+ u_int16_t xfernum)
+{
+ int ret;
+ struct xfer_info_t *xfer;
+ struct erase_info *erase;
+
+ xfer = &part->XferInfo[xfernum];
+ DEBUG(1, "ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);
+ xfer->state = XFER_ERASING;
+
+ /* Is there a free erase slot? Always in MTD. */
+
+
+ erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
+ if (!erase)
+ return -ENOMEM;
+
+ erase->callback = ftl_erase_callback;
+ erase->addr = xfer->Offset;
+ erase->len = 1 << part->header.EraseUnitSize;
+ erase->priv = (u_long)part;
+
+ ret = part->mtd->erase(part->mtd, erase);
+
+ if (!ret)
+ xfer->EraseCount++;
+ else
+ kfree(erase);
+
+ return ret;
+} /* erase_xfer */
+
+/*======================================================================
+
+ Prepare_xfer() takes a freshly erased transfer unit and gives
+ it an appropriate header.
+
+======================================================================*/
+
+static void ftl_erase_callback(struct erase_info *erase)
+{
+ partition_t *part;
+ struct xfer_info_t *xfer;
+ int i;
+
+ /* Look up the transfer unit */
+ part = (partition_t *)(erase->priv);
+
+ for (i = 0; i < part->header.NumTransferUnits; i++)
+ if (part->XferInfo[i].Offset == erase->addr) break;
+
+ if (i == part->header.NumTransferUnits) {
+ printk(KERN_NOTICE "ftl_cs: internal error: "
+ "erase lookup failed!\n");
+ return;
+ }
+
+ xfer = &part->XferInfo[i];
+ if (erase->state == MTD_ERASE_DONE)
+ xfer->state = XFER_ERASED;
+ else {
+ xfer->state = XFER_FAILED;
+ printk(KERN_NOTICE "ftl_cs: erase failed: state = %d\n",
+ erase->state);
+ }
+
+ kfree(erase);
+
+} /* ftl_erase_callback */
+
+static int prepare_xfer(partition_t *part, int i)
+{
+ erase_unit_header_t header;
+ struct xfer_info_t *xfer;
+ int nbam, ret;
+ u_int32_t ctl;
+ ssize_t retlen;
+ loff_t offset;
+
+ xfer = &part->XferInfo[i];
+ xfer->state = XFER_FAILED;
+
+ DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
+
+ /* Write the transfer unit header */
+ header = part->header;
+ header.LogicalEUN = cpu_to_le16(0xffff);
+ header.EraseCount = cpu_to_le32(xfer->EraseCount);
+
+ ret = part->mtd->write(part->mtd, xfer->Offset, sizeof(header),
+ &retlen, (u_char *)&header);
+
+ if (ret) {
+ return ret;
+ }
+
+ /* Write the BAM stub */
+ nbam = (part->BlocksPerUnit * sizeof(u_int32_t) +
+ le32_to_cpu(part->header.BAMOffset) + SECTOR_SIZE - 1) / SECTOR_SIZE;
+
+ offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset);
+ ctl = cpu_to_le32(BLOCK_CONTROL);
+
+ for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
+
+ ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t),
+ &retlen, (u_char *)&ctl);
+
+ if (ret)
+ return ret;
+ }
+ xfer->state = XFER_PREPARED;
+ return 0;
+
+} /* prepare_xfer */
+
+/*======================================================================
+
+ Copy_erase_unit() takes a full erase block and a transfer unit,
+ copies everything to the transfer unit, then swaps the block
+ pointers.
+
+ All data blocks are copied to the corresponding blocks in the
+ target unit, so the virtual block map does not need to be
+ updated.
+
+======================================================================*/
+
+static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
+ u_int16_t xferunit)
+{
+ u_char buf[SECTOR_SIZE];
+ struct eun_info_t *eun;
+ struct xfer_info_t *xfer;
+ u_int32_t src, dest, free, i;
+ u_int16_t unit;
+ int ret;
+ ssize_t retlen;
+ loff_t offset;
+ u_int16_t srcunitswap = cpu_to_le16(srcunit);
+
+ eun = &part->EUNInfo[srcunit];
+ xfer = &part->XferInfo[xferunit];
+ DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
+ eun->Offset, xfer->Offset);
+
+
+ /* Read current BAM */
+ if (part->bam_index != srcunit) {
+
+ offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
+
+ ret = part->mtd->read(part->mtd, offset,
+ part->BlocksPerUnit * sizeof(u_int32_t),
+ &retlen, (u_char *) (part->bam_cache));
+
+ /* mark the cache bad, in case we get an error later */
+ part->bam_index = 0xffff;
+
+ if (ret) {
+ printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
+ return ret;
+ }
+ }
+
+ /* Write the LogicalEUN for the transfer unit */
+ xfer->state = XFER_UNKNOWN;
+ offset = xfer->Offset + 20; /* Bad! */
+ unit = cpu_to_le16(0x7fff);
+
+ ret = part->mtd->write(part->mtd, offset, sizeof(u_int16_t),
+ &retlen, (u_char *) &unit);
+
+ if (ret) {
+ printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
+ return ret;
+ }
+
+ /* Copy all data blocks from source unit to transfer unit */
+ src = eun->Offset; dest = xfer->Offset;
+
+ free = 0;
+ ret = 0;
+ for (i = 0; i < part->BlocksPerUnit; i++) {
+ switch (BLOCK_TYPE(le32_to_cpu(part->bam_cache[i]))) {
+ case BLOCK_CONTROL:
+ /* This gets updated later */
+ break;
+ case BLOCK_DATA:
+ case BLOCK_REPLACEMENT:
+ ret = part->mtd->read(part->mtd, src, SECTOR_SIZE,
+ &retlen, (u_char *) buf);
+ if (ret) {
+ printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
+ return ret;
+ }
+
+
+ ret = part->mtd->write(part->mtd, dest, SECTOR_SIZE,
+ &retlen, (u_char *) buf);
+ if (ret) {
+ printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n");
+ return ret;
+ }
+
+ break;
+ default:
+ /* All other blocks must be free */
+ part->bam_cache[i] = cpu_to_le32(0xffffffff);
+ free++;
+ break;
+ }
+ src += SECTOR_SIZE;
+ dest += SECTOR_SIZE;
+ }
+
+ /* Write the BAM to the transfer unit */
+ ret = part->mtd->write(part->mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
+ part->BlocksPerUnit * sizeof(int32_t), &retlen,
+ (u_char *)part->bam_cache);
+ if (ret) {
+ printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
+ return ret;
+ }
+
+
+ /* All clear? Then update the LogicalEUN again */
+ ret = part->mtd->write(part->mtd, xfer->Offset + 20, sizeof(u_int16_t),
+ &retlen, (u_char *)&srcunitswap);
+
+ if (ret) {
+ printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
+ return ret;
+ }
+
+
+ /* Update the maps and usage stats*/
+ i = xfer->EraseCount;
+ xfer->EraseCount = eun->EraseCount;
+ eun->EraseCount = i;
+ i = xfer->Offset;
+ xfer->Offset = eun->Offset;
+ eun->Offset = i;
+ part->FreeTotal -= eun->Free;
+ part->FreeTotal += free;
+ eun->Free = free;
+ eun->Deleted = 0;
+
+ /* Now, the cache should be valid for the new block */
+ part->bam_index = srcunit;
+
+ return 0;
+} /* copy_erase_unit */
+
+/*======================================================================
+
+ reclaim_block() picks a full erase unit and a transfer unit and
+ then calls copy_erase_unit() to copy one to the other. Then, it
+ schedules an erase on the expired block.
+
+ What's a good way to decide which transfer unit and which erase
+ unit to use? Beats me. My way is to always pick the transfer
+ unit with the fewest erases, and usually pick the data unit with
+ the most deleted blocks. But with a small probability, pick the
+ oldest data unit instead. This means that we generally postpone
+ the next reclaimation as long as possible, but shuffle static
+ stuff around a bit for wear leveling.
+
+======================================================================*/
+
+static int reclaim_block(partition_t *part)
+{
+ u_int16_t i, eun, xfer;
+ u_int32_t best;
+ int queued, ret;
+
+ DEBUG(0, "ftl_cs: reclaiming space...\n");
+ DEBUG(4, "NumTransferUnits == %x\n", part->header.NumTransferUnits);
+ /* Pick the least erased transfer unit */
+ best = 0xffffffff; xfer = 0xffff;
+ do {
+ queued = 0;
+ for (i = 0; i < part->header.NumTransferUnits; i++) {
+ int n=0;
+ if (part->XferInfo[i].state == XFER_UNKNOWN) {
+ DEBUG(4,"XferInfo[%d].state == XFER_UNKNOWN\n",i);
+ n=1;
+ erase_xfer(part, i);
+ }
+ if (part->XferInfo[i].state == XFER_ERASING) {
+ DEBUG(4,"XferInfo[%d].state == XFER_ERASING\n",i);
+ n=1;
+ queued = 1;
+ }
+ else if (part->XferInfo[i].state == XFER_ERASED) {
+ DEBUG(4,"XferInfo[%d].state == XFER_ERASED\n",i);
+ n=1;
+ prepare_xfer(part, i);
+ }
+ if (part->XferInfo[i].state == XFER_PREPARED) {
+ DEBUG(4,"XferInfo[%d].state == XFER_PREPARED\n",i);
+ n=1;
+ if (part->XferInfo[i].EraseCount <= best) {
+ best = part->XferInfo[i].EraseCount;
+ xfer = i;
+ }
+ }
+ if (!n)
+ DEBUG(4,"XferInfo[%d].state == %x\n",i, part->XferInfo[i].state);
+
+ }
+ if (xfer == 0xffff) {
+ if (queued) {
+ DEBUG(1, "ftl_cs: waiting for transfer "
+ "unit to be prepared...\n");
+ if (part->mtd->sync)
+ part->mtd->sync(part->mtd);
+ } else {
+ static int ne = 0;
+ if (++ne < 5)
+ printk(KERN_NOTICE "ftl_cs: reclaim failed: no "
+ "suitable transfer units!\n");
+ else
+ DEBUG(1, "ftl_cs: reclaim failed: no "
+ "suitable transfer units!\n");
+
+ return -EIO;
+ }
+ }
+ } while (xfer == 0xffff);
+
+ eun = 0;
+ if ((jiffies % shuffle_freq) == 0) {
+ DEBUG(1, "ftl_cs: recycling freshest block...\n");
+ best = 0xffffffff;
+ for (i = 0; i < part->DataUnits; i++)
+ if (part->EUNInfo[i].EraseCount <= best) {
+ best = part->EUNInfo[i].EraseCount;
+ eun = i;
+ }
+ } else {
+ best = 0;
+ for (i = 0; i < part->DataUnits; i++)
+ if (part->EUNInfo[i].Deleted >= best) {
+ best = part->EUNInfo[i].Deleted;
+ eun = i;
+ }
+ if (best == 0) {
+ static int ne = 0;
+ if (++ne < 5)
+ printk(KERN_NOTICE "ftl_cs: reclaim failed: "
+ "no free blocks!\n");
+ else
+ DEBUG(1,"ftl_cs: reclaim failed: "
+ "no free blocks!\n");
+
+ return -EIO;
+ }
+ }
+ ret = copy_erase_unit(part, eun, xfer);
+ if (!ret)
+ erase_xfer(part, xfer);
+ else
+ printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n");
+ return ret;
+} /* reclaim_block */
+
+/*======================================================================
+
+ Find_free() searches for a free block. If necessary, it updates
+ the BAM cache for the erase unit containing the free block. It
+ returns the block index -- the erase unit is just the currently
+ cached unit. If there are no free blocks, it returns 0 -- this
+ is never a valid data block because it contains the header.
+
+======================================================================*/
+
+#ifdef PSYCHO_DEBUG
+static void dump_lists(partition_t *part)
+{
+ int i;
+ printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal);
+ for (i = 0; i < part->DataUnits; i++)
+ printk(KERN_DEBUG "ftl_cs: unit %d: %d phys, %d free, "
+ "%d deleted\n", i,
+ part->EUNInfo[i].Offset >> part->header.EraseUnitSize,
+ part->EUNInfo[i].Free, part->EUNInfo[i].Deleted);
+}
+#endif
+
+static u_int32_t find_free(partition_t *part)
+{
+ u_int16_t stop, eun;
+ u_int32_t blk;
+ size_t retlen;
+ int ret;
+
+ /* Find an erase unit with some free space */
+ stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
+ eun = stop;
+ do {
+ if (part->EUNInfo[eun].Free != 0) break;
+ /* Wrap around at end of table */
+ if (++eun == part->DataUnits) eun = 0;
+ } while (eun != stop);
+
+ if (part->EUNInfo[eun].Free == 0)
+ return 0;
+
+ /* Is this unit's BAM cached? */
+ if (eun != part->bam_index) {
+ /* Invalidate cache */
+ part->bam_index = 0xffff;
+
+ ret = part->mtd->read(part->mtd,
+ part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
+ part->BlocksPerUnit * sizeof(u_int32_t),
+ &retlen, (u_char *) (part->bam_cache));
+
+ if (ret) {
+ printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
+ return 0;
+ }
+ part->bam_index = eun;
+ }
+
+ /* Find a free block */
+ for (blk = 0; blk < part->BlocksPerUnit; blk++)
+ if (BLOCK_FREE(le32_to_cpu(part->bam_cache[blk]))) break;
+ if (blk == part->BlocksPerUnit) {
+#ifdef PSYCHO_DEBUG
+ static int ne = 0;
+ if (++ne == 1)
+ dump_lists(part);
+#endif
+ printk(KERN_NOTICE "ftl_cs: bad free list!\n");
+ return 0;
+ }
+ DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
+ return blk;
+
+} /* find_free */
+
+/*======================================================================
+
+ This gets a memory handle for the region corresponding to the
+ minor device number.
+
+======================================================================*/
+
+static int ftl_open(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ partition_t *partition;
+
+ if (minor>>4 >= MAX_MTD_DEVICES)
+ return -ENODEV;
+
+ partition = myparts[minor>>4];
+
+ if (!partition)
+ return -ENODEV;
+
+ if (partition->state != FTL_FORMATTED)
+ return -ENXIO;
+
+ if (ftl_gendisk.part[minor].nr_sects == 0)
+ return -ENXIO;
+
+ MOD_INC_USE_COUNT;
+
+ if (!get_mtd_device(partition->mtd, -1)) {
+ MOD_DEC_USE_COUNT;
+ return /* -E'SBUGGEREDOFF */ -ENXIO;
+ }
+
+ if ((file->f_mode & 2) && !(partition->mtd->flags & MTD_CLEAR_BITS) ) {
+ put_mtd_device(partition->mtd);
+ MOD_DEC_USE_COUNT;
+ return -EROFS;
+ }
+
+ DEBUG(0, "ftl_cs: ftl_open(%d)\n", minor);
+
+ atomic_inc(&partition->open);
+
+ return 0;
+}
+
+/*====================================================================*/
+
+static release_t ftl_close(struct inode *inode, struct file *file)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+ struct super_block *sb = get_super(inode->i_rdev);
+#endif
+ int minor = MINOR(inode->i_rdev);
+ partition_t *part = myparts[minor >> 4];
+ int i;
+
+ DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor);
+
+ /* Flush all writes */
+ fsync_dev(inode->i_rdev);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+ if (sb) invalidate_inodes(sb);
+#endif
+ invalidate_buffers(inode->i_rdev);
+
+ /* Wait for any pending erase operations to complete */
+ if (part->mtd->sync)
+ part->mtd->sync(part->mtd);
+
+ for (i = 0; i < part->header.NumTransferUnits; i++) {
+ if (part->XferInfo[i].state == XFER_ERASED)
+ prepare_xfer(part, i);
+ }
+
+ atomic_dec(&part->open);
+
+ put_mtd_device(part->mtd);
+ MOD_DEC_USE_COUNT;
+ release_return(0);
+} /* ftl_close */
+
+
+/*======================================================================
+
+ Read a series of sectors from an FTL partition.
+
+======================================================================*/
+
+static int ftl_read(partition_t *part, caddr_t buffer,
+ u_long sector, u_long nblocks)
+{
+ u_int32_t log_addr, bsize;
+ u_long i;
+ int ret;
+ size_t offset, retlen;
+
+ DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
+ part, sector, nblocks);
+ if (!(part->state & FTL_FORMATTED)) {
+ printk(KERN_NOTICE "ftl_cs: bad partition\n");
+ return -EIO;
+ }
+ bsize = 1 << part->header.EraseUnitSize;
+
+ for (i = 0; i < nblocks; i++) {
+ if (((sector+i) * SECTOR_SIZE) >= le32_to_cpu(part->header.FormattedSize)) {
+ printk(KERN_NOTICE "ftl_cs: bad read offset\n");
+ return -EIO;
+ }
+ log_addr = part->VirtualBlockMap[sector+i];
+ if (log_addr == 0xffffffff)
+ memset(buffer, 0, SECTOR_SIZE);
+ else {
+ offset = (part->EUNInfo[log_addr / bsize].Offset
+ + (log_addr % bsize));
+ ret = part->mtd->read(part->mtd, offset, SECTOR_SIZE,
+ &retlen, (u_char *) buffer);
+
+ if (ret) {
+ printk(KERN_WARNING "Error reading MTD device in ftl_read()\n");
+ return ret;
+ }
+ }
+ buffer += SECTOR_SIZE;
+ }
+ return 0;
+} /* ftl_read */
+
+/*======================================================================
+
+ Write a series of sectors to an FTL partition
+
+======================================================================*/
+
+static int set_bam_entry(partition_t *part, u_int32_t log_addr,
+ u_int32_t virt_addr)
+{
+ u_int32_t bsize, blk;
+#ifdef PSYCHO_DEBUG
+ u_int32_t old_addr;
+#endif
+ u_int16_t eun;
+ int ret;
+ size_t retlen, offset;
+
+ DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
+ part, log_addr, virt_addr);
+ bsize = 1 << part->header.EraseUnitSize;
+ eun = log_addr / bsize;
+ blk = (log_addr % bsize) / SECTOR_SIZE;
+ offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +
+ le32_to_cpu(part->header.BAMOffset));
+
+#ifdef PSYCHO_DEBUG
+ ret = part->mtd->read(part->mtd, offset, sizeof(u_int32_t),
+ &retlen, (u_char *)&old_addr);
+ if (ret) {
+ printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
+ return ret;
+ }
+ old_addr = le32_to_cpu(old_addr);
+
+ if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||
+ ((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||
+ (!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {
+ static int ne = 0;
+ if (++ne < 5) {
+ printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n");
+ printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, old = 0x%x"
+ ", new = 0x%x\n", log_addr, old_addr, virt_addr);
+ }
+ return -EIO;
+ }
+#endif
+ if (part->bam_index == eun) {
+#ifdef PSYCHO_DEBUG
+ if (le32_to_cpu(part->bam_cache[blk]) != old_addr) {
+ static int ne = 0;
+ if (++ne < 5) {
+ printk(KERN_NOTICE "ftl_cs: set_bam_entry() "
+ "inconsistency!\n");
+ printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, cache"
+ " = 0x%x\n",
+ le32_to_cpu(part->bam_cache[blk]), old_addr);
+ }
+ return -EIO;
+ }
+#endif
+ part->bam_cache[blk] = cpu_to_le32(virt_addr);
+ }
+ ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t),
+ &retlen, (u_char *)&part->bam_cache[blk]);
+
+ if (ret) {
+ printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n");
+ printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, new = 0x%x\n",
+ log_addr, virt_addr);
+ }
+ return ret;
+} /* set_bam_entry */
+
+static int ftl_write(partition_t *part, caddr_t buffer,
+ u_long sector, u_long nblocks)
+{
+ u_int32_t bsize, log_addr, virt_addr, old_addr, blk;
+ u_long i;
+ int ret;
+ size_t retlen, offset;
+
+ DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
+ part, sector, nblocks);
+ if (!(part->state & FTL_FORMATTED)) {
+ printk(KERN_NOTICE "ftl_cs: bad partition\n");
+ return -EIO;
+ }
+ /* See if we need to reclaim space, before we start */
+ while (part->FreeTotal < nblocks) {
+ ret = reclaim_block(part);
+ if (ret)
+ return ret;
+ }
+
+ bsize = 1 << part->header.EraseUnitSize;
+
+ virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
+ for (i = 0; i < nblocks; i++) {
+ if (virt_addr >= le32_to_cpu(part->header.FormattedSize)) {
+ printk(KERN_NOTICE "ftl_cs: bad write offset\n");
+ return -EIO;
+ }
+
+ /* Grab a free block */
+ blk = find_free(part);
+ if (blk == 0) {
+ static int ne = 0;
+ if (++ne < 5)
+ printk(KERN_NOTICE "ftl_cs: internal error: "
+ "no free blocks!\n");
+ return -ENOSPC;
+ }
+
+ /* Tag the BAM entry, and write the new block */
+ log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
+ part->EUNInfo[part->bam_index].Free--;
+ part->FreeTotal--;
+ if (set_bam_entry(part, log_addr, 0xfffffffe))
+ return -EIO;
+ part->EUNInfo[part->bam_index].Deleted++;
+ offset = (part->EUNInfo[part->bam_index].Offset +
+ blk * SECTOR_SIZE);
+ ret = part->mtd->write(part->mtd, offset, SECTOR_SIZE, &retlen,
+ buffer);
+
+ if (ret) {
+ printk(KERN_NOTICE "ftl_cs: block write failed!\n");
+ printk(KERN_NOTICE "ftl_cs: log_addr = 0x%x, virt_addr"
+ " = 0x%x, Offset = 0x%x\n", log_addr, virt_addr,
+ offset);
+ return -EIO;
+ }
+
+ /* Only delete the old entry when the new entry is ready */
+ old_addr = part->VirtualBlockMap[sector+i];
+ if (old_addr != 0xffffffff) {
+ part->VirtualBlockMap[sector+i] = 0xffffffff;
+ part->EUNInfo[old_addr/bsize].Deleted++;
+ if (set_bam_entry(part, old_addr, 0))
+ return -EIO;
+ }
+
+ /* Finally, set up the new pointers */
+ if (set_bam_entry(part, log_addr, virt_addr))
+ return -EIO;
+ part->VirtualBlockMap[sector+i] = log_addr;
+ part->EUNInfo[part->bam_index].Deleted--;
+
+ buffer += SECTOR_SIZE;
+ virt_addr += SECTOR_SIZE;
+ }
+ return 0;
+} /* ftl_write */
+
+/*======================================================================
+
+ IOCTL calls for getting device parameters.
+
+======================================================================*/
+
+static int ftl_ioctl(struct inode *inode, struct file *file,
+ u_int cmd, u_long arg)
+{
+ struct hd_geometry *geo = (struct hd_geometry *)arg;
+ int ret = 0, minor = MINOR(inode->i_rdev);
+ partition_t *part= myparts[minor >> 4];
+ u_long sect;
+
+ if (!part)
+ return -ENODEV; /* How? */
+
+ switch (cmd) {
+ case HDIO_GETGEO:
+ ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(*geo));
+ if (ret) return ret;
+ /* Sort of arbitrary: round size down to 4K boundary */
+ sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
+ put_user(1, (char *)&geo->heads);
+ put_user(8, (char *)&geo->sectors);
+ put_user((sect>>3), (short *)&geo->cylinders);
+ put_user(ftl_hd[minor].start_sect, (u_long *)&geo->start);
+ break;
+ case BLKGETSIZE:
+ ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(long));
+ if (ret) return ret;
+ put_user(ftl_hd[minor].nr_sects,
+ (long *)arg);
+ break;
+ case BLKRRPART:
+ ret = ftl_reread_partitions(minor);
+ break;
+#if (LINUX_VERSION_CODE < 0x20303)
+ case BLKFLSBUF:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+ if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+#endif
+ fsync_dev(inode->i_rdev);
+ invalidate_buffers(inode->i_rdev);
+ break;
+ RO_IOCTLS(inode->i_rdev, arg);
+#else
+ case BLKROSET:
+ case BLKROGET:
+ case BLKFLSBUF:
+ ret = blk_ioctl(inode->i_rdev, cmd, arg);
+ break;
+#endif
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+} /* ftl_ioctl */
+
+/*======================================================================
+
+ Handler for block device requests
+
+======================================================================*/
+
+static int ftl_reread_partitions(int minor)
+{
+ partition_t *part = myparts[minor >> 4];
+ int i, whole;
+
+ DEBUG(0, "ftl_cs: ftl_reread_partition(%d)\n", minor);
+ if ((atomic_read(&part->open) > 1)) {
+ return -EBUSY;
+ }
+ whole = minor & ~(MAX_PART-1);
+
+ for (i = 0; i < MAX_PART; i++) {
+ if (ftl_hd[whole+i].nr_sects > 0) {
+ kdev_t rdev = MKDEV(FTL_MAJOR, whole+i);
+ sync_dev(rdev);
+ invalidate_buffers(rdev);
+ }
+ ftl_hd[whole+i].start_sect = 0;
+ ftl_hd[whole+i].nr_sects = 0;
+ }
+
+ scan_header(part);
+
+ register_disk(&ftl_gendisk, whole >> PART_BITS, MAX_PART,
+ &ftl_blk_fops, le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE);
+
+#ifdef PCMCIA_DEBUG
+ for (i = 0; i < MAX_PART; i++) {
+ if (ftl_hd[whole+i].nr_sects > 0)
+ printk(KERN_INFO " %d: start %ld size %ld\n", i,
+ ftl_hd[whole+i].start_sect,
+ ftl_hd[whole+i].nr_sects);
+ }
+#endif
+ return 0;
+}
+
+/*======================================================================
+
+ Handler for block device requests
+
+======================================================================*/
+
+static void do_ftl_request(request_arg_t)
+{
+ int ret, minor;
+ partition_t *part;
+
+ do {
+ // sti();
+ INIT_REQUEST;
+
+ minor = MINOR(CURRENT->rq_dev);
+
+ part = myparts[minor >> 4];
+ if (part) {
+ ret = 0;
+
+ switch (CURRENT->cmd) {
+ case READ:
+ ret = ftl_read(part, CURRENT->buffer,
+ CURRENT->sector+ftl_hd[minor].start_sect,
+ CURRENT->current_nr_sectors);
+ if (ret) printk("ftl_read returned %d\n", ret);
+ break;
+
+ case WRITE:
+ ret = ftl_write(part, CURRENT->buffer,
+ CURRENT->sector+ftl_hd[minor].start_sect,
+ CURRENT->current_nr_sectors);
+ if (ret) printk("ftl_write returned %d\n", ret);
+ break;
+
+ default:
+ panic("ftl_cs: unknown block command!\n");
+
+ }
+ } else {
+ ret = 1;
+ printk("NULL part in ftl_request\n");
+ }
+
+ if (!ret) {
+ CURRENT->sector += CURRENT->current_nr_sectors;
+ }
+
+ end_request((ret == 0) ? 1 : 0);
+ } while (1);
+} /* do_ftl_request */
+
+/*====================================================================*/
+
+void ftl_freepart(partition_t *part)
+{
+ if (part->VirtualBlockMap) {
+ vfree(part->VirtualBlockMap);
+ part->VirtualBlockMap = NULL;
+ }
+ if (part->VirtualPageMap) {
+ kfree(part->VirtualPageMap);
+ part->VirtualPageMap = NULL;
+ }
+ if (part->EUNInfo) {
+ kfree(part->EUNInfo);
+ part->EUNInfo = NULL;
+ }
+ if (part->XferInfo) {
+ kfree(part->XferInfo);
+ part->XferInfo = NULL;
+ }
+ if (part->bam_cache) {
+ kfree(part->bam_cache);
+ part->bam_cache = NULL;
+ }
+
+} /* ftl_freepart */
+
+static void ftl_notify_add(struct mtd_info *mtd)
+{
+ partition_t *partition;
+ int device;
+
+ for (device=0; device < MAX_MTD_DEVICES && myparts[device]; device++)
+ ;
+
+ if (device == MAX_MTD_DEVICES) {
+ printk(KERN_NOTICE "Maximum number of FTL partitions reached\n"
+ "Not scanning <%s>\n", mtd->name);
+ return;
+ }
+
+ partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
+
+ if (!partition) {
+ printk(KERN_WARNING "No memory to scan for FTL on %s\n",
+ mtd->name);
+ return;
+ }
+
+ memset(partition, 0, sizeof(partition_t));
+
+ partition->mtd = mtd;
+
+ if ((scan_header(partition) == 0) &&
+ (build_maps(partition) == 0)) {
+
+ partition->state = FTL_FORMATTED;
+ atomic_set(&partition->open, 0);
+ myparts[device] = partition;
+ ftl_reread_partitions(device << 4);
+#ifdef PCMCIA_DEBUG
+ printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n",
+ le32_to_cpu(partition->header.FormattedSize) >> 10);
+#endif
+ }
+}
+
+static void ftl_notify_remove(struct mtd_info *mtd)
+{
+ int i,j;
+
+ /* Q: What happens if you try to remove a device which has
+ * a currently-open FTL partition on it?
+ *
+ * A: You don't. The ftl_open routine is responsible for
+ * increasing the use count of the driver module which
+ * it uses.
+ */
+
+ /* That's the theory, anyway :) */
+
+ for (i=0; i< MAX_MTD_DEVICES; i++)
+ if (myparts[i] && myparts[i]->mtd == mtd) {
+
+ if (myparts[i]->state == FTL_FORMATTED)
+ ftl_freepart(myparts[i]);
+
+ myparts[i]->state = 0;
+ for (j=0; j<16; j++) {
+ ftl_gendisk.part[j].nr_sects=0;
+ ftl_gendisk.part[j].start_sect=0;
+ }
+ kfree(myparts[i]);
+ myparts[i] = NULL;
+ }
+}
+
+
+#if LINUX_VERSION_CODE < 0x20300
+#ifdef MODULE
+#define init_ftl init_module
+#define cleanup_ftl cleanup_module
+#endif
+#endif
+
+mod_init_t init_ftl(void)
+{
+ int i;
+
+ memset(myparts, 0, sizeof(myparts));
+
+ DEBUG(0, "$Id: ftl.c,v 1.20 2000/06/23 15:17:53 dwmw2 Exp $\n");
+
+ if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) {
+ printk(KERN_NOTICE "ftl_cs: unable to grab major "
+ "device number!\n");
+ return -EAGAIN;
+ }
+
+ for (i = 0; i < MINOR_NR(MAX_DEV, 0, 0); i++)
+ ftl_blocksizes[i] = 1024;
+ for (i = 0; i < MAX_DEV*MAX_PART; i++) {
+ ftl_hd[i].nr_sects = 0;
+ ftl_hd[i].start_sect = 0;
+ }
+ blksize_size[FTL_MAJOR] = ftl_blocksizes;
+ ftl_gendisk.major = FTL_MAJOR;
+ blk_init_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR), &do_ftl_request);
+ ftl_gendisk.next = gendisk_head;
+ gendisk_head = &ftl_gendisk;
+
+ register_mtd_user(&ftl_notifier);
+
+ return 0;
+}
+
+mod_exit_t cleanup_ftl(void)
+{
+ struct gendisk *gd, **gdp;
+
+ unregister_mtd_user(&ftl_notifier);
+
+ unregister_blkdev(FTL_MAJOR, "ftl");
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR));
+ blksize_size[FTL_MAJOR] = NULL;
+
+ for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
+ if (*gdp == &ftl_gendisk) {
+ gd = *gdp; *gdp = gd->next;
+ break;
+ }
+}
+
+#if LINUX_VERSION_CODE > 0x20300
+module_init(init_ftl);
+module_exit(cleanup_ftl);
+#endif
diff --git a/drivers/mtd/jedec.c b/drivers/mtd/jedec.c
new file mode 100644
index 000000000..74e9db84e
--- /dev/null
+++ b/drivers/mtd/jedec.c
@@ -0,0 +1,773 @@
+
+/* JEDEC Flash Interface.
+ * This is an older type of interface for self programming flash. It is
+ * commonly use in older AMD chips and is obsolete compared with CFI.
+ * It is called JEDEC because the JEDEC association distributes the ID codes
+ * for the chips.
+ *
+ * See the AMD flash databook for information on how to operate the interface.
+ *
+ * This code does not support anything wider than 8 bit flash chips, I am
+ * not going to guess how to send commands to them, plus I expect they will
+ * all speak CFI..
+ *
+ * $Id: jedec.c,v 1.1 2000/07/04 07:21:57 jgg Exp $
+ */
+
+#include <linux/mtd/jedec.h>
+
+struct mtd_info *jedec_probe(struct map_info *);
+int jedec_probe8(struct map_info *map,unsigned long base,
+ struct jedec_private *priv);
+int jedec_probe16(struct map_info *map,unsigned long base,
+ struct jedec_private *priv);
+int jedec_probe32(struct map_info *map,unsigned long base,
+ struct jedec_private *priv);
+static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
+ unsigned long len);
+static int flash_erase(struct mtd_info *mtd, struct erase_info *instr);
+static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
+ size_t *retlen, const u_char *buf);
+
+EXPORT_SYMBOL(jedec_probe);
+
+/* Listing of parts and sizes. We need this table to learn the sector
+ size of the chip and the total length */
+static const struct JEDECTable JEDEC_table[] =
+ {{0x01AD,"AMD Am29F016",2*1024*1024,64*1024,MTD_CAP_NORFLASH},
+ {0x01D5,"AMD Am29F080",1*1024*1024,64*1024,MTD_CAP_NORFLASH},
+ {0x01A4,"AMD Am29F040",512*1024,64*1024,MTD_CAP_NORFLASH},
+ {}};
+
+static void jedec_sync(struct mtd_info *mtd) {};
+static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf);
+static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf);
+
+/* Probe entry point */
+ struct jedec_private priv;
+ struct mtd_info __MTD;
+struct mtd_info *jedec_probe(struct map_info *map)
+{
+ struct mtd_info *MTD = &__MTD;
+ unsigned long Base;
+ unsigned long SectorSize;
+ unsigned count;
+ unsigned I,Uniq;
+ char Part[200];
+ memset(&priv,0,sizeof(priv));
+
+ if (map->bank_size == 0)
+ map->bank_size = map->size;
+
+ if (map->size/map->bank_size > MAX_JEDEC_CHIPS)
+ {
+ printk("mtd: Increase MAX_JEDEC_CHIPS, too many banks.\n");
+ return 0;
+ }
+
+ for (Base = 0; Base < map->size; Base += map->bank_size)
+ {
+ // Perhaps zero could designate all tests?
+ if (map->bus_width == 0)
+ map->bus_width = 8;
+
+ if (map->bus_width == 8)
+ jedec_probe8(map,Base,&priv);
+ if (map->bus_width == 16)
+ jedec_probe16(map,Base,&priv);
+ if (map->bus_width == 32)
+ jedec_probe32(map,Base,&priv);
+ }
+
+ // Get the biggest sector size
+ SectorSize = 0;
+ for (I = 0; priv.chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
+ {
+ if (priv.chips[I].sectorsize > SectorSize)
+ SectorSize = priv.chips[I].sectorsize;
+ }
+
+ // Quickly ensure that the other sector sizes are factors of the largest
+ for (I = 0; priv.chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
+ {
+ if ((SectorSize/priv.chips[I].sectorsize)*priv.chips[I].sectorsize != SectorSize)
+ {
+ printk("mtd: Failed. Device has incompatible mixed sector sizes\n");
+ return 0;
+ }
+ }
+
+ /* Generate a part name that includes the number of different chips and
+ other configuration information */
+ count = 1;
+ strncpy(Part,map->name,sizeof(Part)-10);
+ Part[sizeof(Part)-11] = 0;
+ strcat(Part," ");
+ Uniq = 0;
+ for (I = 0; priv.chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
+ {
+ const struct JEDECTable *JEDEC;
+
+ if (priv.chips[I+1].jedec == priv.chips[I].jedec)
+ {
+ count++;
+ continue;
+ }
+
+ // Locate the chip in the jedec table
+ JEDEC = jedec_idtoinf(priv.chips[I].jedec >> 8,priv.chips[I].jedec);
+ if (JEDEC == 0)
+ {
+ printk("mtd: Internal Error, JEDEC not set\n");
+ return 0;
+ }
+
+ if (Uniq != 0)
+ strcat(Part,",");
+ Uniq++;
+
+ if (count != 1)
+ sprintf(Part+strlen(Part),"%x*[%s]",count,JEDEC->name);
+ else
+ sprintf(Part+strlen(Part),"%s",JEDEC->name);
+ if (strlen(Part) > sizeof(Part)*2/3)
+ break;
+ count = 1;
+ }
+
+ /* Determine if the chips are organized in a linear fashion, or if there
+ are empty banks. Note, the last bank does not count here, only the
+ first banks are important. Holes on non-bank boundaries can not exist
+ due to the way the detection algorithm works. */
+ if (priv.size < map->bank_size)
+ map->bank_size = priv.size;
+ priv.is_banked = 0;
+ for (I = 0; I != priv.size/map->bank_size - 1; I++)
+ {
+ if (priv.bank_fill[I] != map->bank_size)
+ priv.is_banked = 1;
+
+ /* This even could be eliminated, but new de-optimized read/write
+ functions have to be written */
+ if (priv.bank_fill[I] != priv.bank_fill[0])
+ {
+ printk("mtd: Failed. Cannot handle unsymetric banking\n");
+ return 0;
+ }
+ }
+ if (priv.is_banked == 1)
+ strcat(Part,", banked");
+
+ xprintf("Part: '%s'\n",Part);
+
+ memset(MTD,0,sizeof(*MTD));
+ strncpy(MTD->name,Part,sizeof(MTD->name));
+ MTD->name[sizeof(MTD->name)-1] = 0;
+ MTD->type = MTD_NORFLASH;
+ MTD->flags = MTD_CAP_NORFLASH;
+ MTD->erasesize = SectorSize*(map->bus_width/8);
+ MTD->size = priv.size;
+ //MTD->module = THIS_MODULE; // ? Maybe this should be the low level module?
+ MTD->erase = flash_erase;
+ if (priv.is_banked == 1)
+ MTD->read = jedec_read_banked;
+ else
+ MTD->read = jedec_read;
+ MTD->write = flash_write;
+ MTD->sync = jedec_sync;
+ MTD->priv = map;
+ map->fldrv_priv = &priv;
+
+ return MTD;
+}
+
+/* Helper for the JEDEC function, JEDEC numbers all have odd parity */
+static int checkparity(u_char C)
+{
+ u_char parity = 0;
+ while (C != 0)
+ {
+ parity ^= C & 1;
+ C >>= 1;
+ }
+
+ return parity == 1;
+}
+
+
+/* Take an array of JEDEC numbers that represent interleved flash chips
+ and process them. Check to make sure they are good JEDEC numbers, look
+ them up and then add them to the chip list */
+int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count,
+ unsigned long base,struct jedec_private *priv)
+{
+ unsigned I,J;
+ unsigned long Size;
+ unsigned long SectorSize;
+ const struct JEDECTable *JEDEC;
+
+ // Test #2 JEDEC numbers exhibit odd parity
+ for (I = 0; I != Count; I++)
+ {
+ if (checkparity(Mfg[I]) == 0 || checkparity(Id[I]) == 0)
+ return 0;
+ }
+
+ // Finally, just make sure all the chip sizes are the same
+ JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
+
+ if (JEDEC == 0)
+ {
+ printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
+ return 0;
+ }
+
+ Size = JEDEC->size;
+ SectorSize = JEDEC->sectorsize;
+ for (I = 0; I != Count; I++)
+ {
+ JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
+ if (JEDEC == 0)
+ {
+ printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
+ return 0;
+ }
+
+ if (Size != JEDEC->size || SectorSize != JEDEC->sectorsize)
+ {
+ printk("mtd: Failed. Interleved flash does not have matching characteristics\n");
+ return 0;
+ }
+ }
+
+ // Load the Chips
+ for (I = 0; I != MAX_JEDEC_CHIPS; I++)
+ {
+ if (priv->chips[I].jedec == 0)
+ break;
+ }
+
+ if (I + Count > MAX_JEDEC_CHIPS)
+ {
+ printk("mtd: Device has too many chips. Increase MAX_JEDEC_CHIPS\n");
+ return 0;
+ }
+
+ // Add them to the table
+ for (J = 0; J != Count; J++)
+ {
+ unsigned long Bank;
+
+ JEDEC = jedec_idtoinf(Mfg[J],Id[J]);
+ priv->chips[I].jedec = (Mfg[J] << 8) | Id[J];
+ priv->chips[I].size = JEDEC->size;
+ priv->chips[I].sectorsize = JEDEC->sectorsize;
+ priv->chips[I].base = base + J;
+ priv->chips[I].datashift = J*8;
+ priv->chips[I].capabilities = JEDEC->capabilities;
+ priv->chips[I].offset = priv->size + J;
+
+ // log2 n :|
+ priv->chips[I].addrshift = 0;
+ for (Bank = Count; Bank != 1; Bank >>= 1, priv->chips[I].addrshift++);
+
+ // Determine how filled this bank is.
+ Bank = base & (~(map->bank_size-1));
+ if (priv->bank_fill[Bank/map->bank_size] < base +
+ (JEDEC->size << priv->chips[I].addrshift) - Bank)
+ priv->bank_fill[Bank/map->bank_size] = base + (JEDEC->size << priv->chips[I].addrshift) - Bank;
+ I++;
+ }
+
+ priv->size += priv->chips[I-1].size*Count;
+
+ return priv->chips[I-1].size;
+}
+
+/* Lookup the chip information from the JEDEC ID table. */
+const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id)
+{
+ __u16 Id = (mfr << 8) | id;
+ unsigned long I = 0;
+ for (I = 0; JEDEC_table[I].jedec != 0; I++)
+ if (JEDEC_table[I].jedec == Id)
+ return JEDEC_table + I;
+ return 0;
+}
+
+// Look for flash using an 8 bit bus interface
+int jedec_probe8(struct map_info *map,unsigned long base,
+ struct jedec_private *priv)
+{
+ return 0;
+}
+
+// Look for flash using a 16 bit bus interface (ie 2 8-bit chips)
+int jedec_probe16(struct map_info *map,unsigned long base,
+ struct jedec_private *priv)
+{
+ return 0;
+}
+
+// Look for flash using a 32 bit bus interface (ie 4 8-bit chips)
+int jedec_probe32(struct map_info *map,unsigned long base,
+ struct jedec_private *priv)
+{
+ #define flread(x) map->read32(map,base+((x)<<2))
+ #define flwrite(v,x) map->write32(map,v,base+((x)<<2))
+
+ const unsigned long AutoSel1 = 0xAAAAAAAA;
+ const unsigned long AutoSel2 = 0x55555555;
+ const unsigned long AutoSel3 = 0x90909090;
+ const unsigned long Reset = 0x90909090;
+ __u32 OldVal;
+ __u8 Mfg[4];
+ __u8 Id[4];
+ unsigned I;
+ unsigned long Size;
+
+ // Wait for any write/erase operation to settle
+ OldVal = flread(base);
+ for (I = 0; OldVal != flread(base) && I < 10000; I++)
+ OldVal = flread(base);
+
+ // Reset the chip
+ flwrite(Reset,0x555);
+
+ // Send the sequence
+ flwrite(AutoSel1,0x555);
+ flwrite(AutoSel2,0x2AA);
+ flwrite(AutoSel3,0x555);
+
+ // Test #1, JEDEC numbers are readable from 0x??00/0x??01
+ if (flread(0) != flread(0x100) ||
+ flread(1) != flread(0x101))
+ {
+ flwrite(Reset,0x555);
+ return 0;
+ }
+
+ // Split up the JEDEC numbers
+ OldVal = flread(0);
+ for (I = 0; I != 4; I++)
+ Mfg[I] = (OldVal >> (I*8));
+ OldVal = flread(1);
+ for (I = 0; I != 4; I++)
+ Id[I] = (OldVal >> (I*8));
+
+ Size = handle_jedecs(map,Mfg,Id,4,base,priv);
+ if (Size == 0)
+ {
+ flwrite(Reset,0x555);
+ return 0;
+ }
+
+ /* Check if there is address wrap around within a single bank, if this
+ returns JEDEC numbers then we assume that it is wrap around. Notice
+ we call this routine with the JEDEC return still enabled, if two or
+ more flashes have a truncated address space the probe test will still
+ work */
+ if (base + Size+0x555 < map->size &&
+ base + Size+0x555 < (base & (~(map->bank_size-1))) + map->bank_size)
+ {
+ if (flread(base+Size) != flread(base+Size + 0x100) ||
+ flread(base+Size + 1) != flread(base+Size + 0x101))
+ {
+ jedec_probe32(map,base+Size,priv);
+ }
+ }
+
+ // Reset.
+ flwrite(0xF0F0F0F0,0x555);
+
+ return 1;
+
+ #undef flread
+ #undef flwrite
+}
+
+/* Linear read. */
+static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct map_info *map = (struct map_info *)mtd->priv;
+
+ map->copy_from(map, buf, from, len);
+ *retlen = len;
+ return 0;
+}
+
+/* Banked read. Take special care to jump past the holes in the bank
+ mapping. This version assumes symetry in the holes.. */
+static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct map_info *map = (struct map_info *)mtd->priv;
+ struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv;
+
+ *retlen = 0;
+ while (len > 0)
+ {
+ // Determine what bank and offset into that bank the first byte is
+ unsigned long bank = from & (~(priv->bank_fill[0]-1));
+ unsigned long offset = from & (priv->bank_fill[0]-1);
+ unsigned long get = len;
+ if (priv->bank_fill[0] - offset < len)
+ get = priv->bank_fill[0] - offset;
+
+ bank /= priv->bank_fill[0];
+ map->copy_from(map,buf + *retlen,bank*map->bank_size + offset,get);
+
+ len -= get;
+ *retlen += get;
+ from += get;
+ }
+ return 0;
+}
+
+/* Pass the flags value that the flash return before it re-entered read
+ mode. */
+static void jedec_flash_failed(unsigned char code)
+{
+ /* Bit 5 being high indicates that there was an internal device
+ failure, erasure time limits exceeded or something */
+ if ((code & (1 << 5)) != 0)
+ {
+ printk("mtd: Internal Flash failure\n");
+ return;
+ }
+ printk("mtd: Programming didn't take\n");
+}
+
+/* This uses the erasure function described in the AMD Flash Handbook,
+ it will work for flashes with a fixed sector size only. Flashes with
+ a selection of sector sizes (ie the AMD Am29F800B) will need a different
+ routine. This routine tries to parallize erasing multiple chips/sectors
+ where possible */
+static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ // Does IO to the currently selected chip
+ #define flread(x) map->read8(map,chip->base+((x)<<chip->addrshift))
+ #define flwrite(v,x) map->write8(map,v,chip->base+((x)<<chip->addrshift))
+
+ unsigned long Time = 0;
+ unsigned long NoTime = 0;
+ unsigned long start = instr->addr, len = instr->len;
+ unsigned int I;
+ struct map_info *map = (struct map_info *)mtd->priv;
+ struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv;
+
+ // Verify the arguments..
+ if (start + len > mtd->size ||
+ (start % mtd->erasesize) != 0 ||
+ (len % mtd->erasesize) != 0 ||
+ (len/mtd->erasesize) == 0)
+ return -EINVAL;
+
+ jedec_flash_chip_scan(priv,start,len);
+
+ // Start the erase sequence on each chip
+ for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
+ {
+ unsigned long off;
+ struct jedec_flash_chip *chip = priv->chips + I;
+
+ if (chip->length == 0)
+ continue;
+
+ // Send the erase setup code
+ xprintf("Erase: ");
+ puth(chip->start); putc(' ');
+ puth(chip->base); putc(' ');
+ puth(chip->length); putc(' ');
+ puth(chip->sectorsize); putc('\n');
+
+ if (chip->start + chip->length > chip->size)
+ {
+ xprintf("DIE\n");
+ return -EIO;
+ }
+
+ flwrite(0xF0,chip->start + 0x555);
+ flwrite(0xAA,chip->start + 0x555);
+ flwrite(0x55,chip->start + 0x2AA);
+ flwrite(0x80,chip->start + 0x555);
+ flwrite(0xAA,chip->start + 0x555);
+ flwrite(0x55,chip->start + 0x2AA);
+
+ // Use chip erase if possible
+ if (chip->start == 0 && chip->length == chip->size)
+ {
+ flwrite(0x10,0x555);
+ continue;
+ }
+
+ /* Once we start selecting the erase sectors the delay between each
+ command must not exceed 50us or it will immediately start erasing
+ and ignore the other sectors */
+/* how do you portably turn off interrupts?
+ save_flags(flags);
+ cli();*/
+ for (off = 0; off < chip->length; off += chip->sectorsize)
+ {
+ // Check to make sure we didn't timeout
+ flwrite(0x30,chip->start + off);
+ if (off == 0)
+ continue;
+ if ((flread(chip->start + off) & (1 << 3)) != 0)
+ {
+ printk("mtd: Ack! We timed out the erase timer!\n");
+ return -EIO;
+ }
+ }
+// restore_flags(flags);
+ }
+
+ /* We could split this into a timer routine and return early, performing
+ background erasure.. Maybe later if the need warrents */
+
+ /* Poll the flash for erasure completion, specs say this can take as long
+ as 480 seconds to do all the sectors (for a 2 meg flash).
+ Erasure time is dependant on chip age, temp and wear.. */
+
+ /* This being a generic routine assumes a 32 bit bus. It does read32s
+ and bundles interleved chips into the same grouping. This will work
+ for all bus widths */
+ Time = 0;
+ NoTime = 0;
+ for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
+ {
+ struct jedec_flash_chip *chip = priv->chips + I;
+ unsigned long off = 0;
+ unsigned todo[4] = {0,0,0,0};
+ unsigned todo_left = 0;
+ unsigned J;
+
+ if (chip->length == 0)
+ continue;
+
+ /* Find all chips in this data line, realistically this is all
+ or nothing up to the interleve count */
+ for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
+ {
+ if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
+ (chip->base & (~((1<<chip->addrshift)-1))))
+ {
+ todo_left++;
+ todo[priv->chips[J].base & ((1<<chip->addrshift)-1)] = 1;
+ }
+ }
+
+ xprintf("todo: %x %x %x %x\n",(short)todo[0],(short)todo[1],
+ (short)todo[2],(short)todo[3]);
+
+ while (1)
+ {
+ __u32 Last[4];
+ unsigned long Count = 0;
+
+ /* During erase bit 7 is held low and bit 6 toggles, we watch this,
+ should it stop toggling or go high then the erase is completed,
+ or this is not really flash ;> */
+ Last[0] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
+ Last[1] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
+ Last[2] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
+ Count = 3;
+ while (todo_left != 0)
+ {
+ for (J = 0; J != 4; J++)
+ {
+ __u8 Byte1 = (Last[(Count-1)%4] >> (J*8)) & 0xFF;
+ __u8 Byte2 = (Last[(Count-2)%4] >> (J*8)) & 0xFF;
+ __u8 Byte3 = (Last[(Count-3)%4] >> (J*8)) & 0xFF;
+ if (todo[J] == 0)
+ continue;
+
+ if ((Byte1 & (1 << 7)) == 0 && Byte1 != Byte2)
+ {
+// printk("Check %x %x %x\n",(short)J,(short)Byte1,(short)Byte2);
+ continue;
+ }
+
+ if (Byte1 == Byte2)
+ {
+ jedec_flash_failed(Byte3);
+ return -EIO;
+ }
+
+ todo[J] = 0;
+ todo_left--;
+ }
+
+/* if (NoTime == 0)
+ Time += HZ/10 - schedule_timeout(HZ/10);*/
+ NoTime = 0;
+
+ Last[Count % 4] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
+ Count++;
+
+ putc('.');
+
+/* // Count time, max of 15s per sector (according to AMD)
+ if (Time > 15*len/mtd->erasesize*HZ)
+ {
+ printk("mtd: Flash Erase Timed out\n");
+ return -EIO;
+ } */
+ }
+
+ puts("out\n");
+
+ // Skip to the next chip if we used chip erase
+ if (chip->length == chip->size)
+ off = chip->size;
+ else
+ off += chip->sectorsize;
+
+ if (off >= chip->length)
+ break;
+ NoTime = 1;
+ }
+
+ for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
+ {
+ if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
+ (chip->base & (~((1<<chip->addrshift)-1))))
+ priv->chips[J].length = 0;
+ }
+ }
+
+ puts("done\n");
+ return 0;
+
+ #undef flread
+ #undef flwrite
+}
+
+/* This is the simple flash writing function. It writes to every byte, in
+ sequence. It takes care of how to properly address the flash if
+ the flash is interleved. It can only be used if all the chips in the
+ array are identical!*/
+static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ /* Does IO to the currently selected chip. It takes the bank addressing
+ base (which is divisable by the chip size) adds the necesary lower bits
+ of addrshift (interleve index) and then adds the control register index. */
+ #define flread(x) map->read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
+ #define flwrite(v,x) map->write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
+
+ struct map_info *map = (struct map_info *)mtd->priv;
+ struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv;
+ unsigned long base;
+ unsigned long off;
+
+ if (start + len > mtd->size)
+ return -EIO;
+
+ puts("Here");
+
+ while (len != 0)
+ {
+ struct jedec_flash_chip *chip = priv->chips;
+ unsigned long bank;
+ unsigned long boffset;
+
+ // Compute the base of the flash.
+ off = start % (chip->size << chip->addrshift);
+ base = start - off;
+
+ // Perform banked addressing translation.
+ bank = base & (~(priv->bank_fill[0]-1));
+ boffset = base & (priv->bank_fill[0]-1);
+ bank = (bank/priv->bank_fill[0])*map->bank_size;
+ base = bank + boffset;
+
+ xprintf("Flasing %X %X %X\n",base,chip->size,len);
+
+ // Loop over this page
+ for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++)
+ {
+ unsigned char oldbyte = map->read8(map,base+off);
+ unsigned char Last[4];
+ unsigned long Count = 0;
+
+// putc('.');
+
+ if (oldbyte == *buf)
+ continue;
+ if (((~oldbyte) & *buf) != 0)
+ printk("mtd: warn: Trying to set a 0 to a 1\n");
+
+ // Write
+ flwrite(0xAA,0x555);
+ flwrite(0x55,0x2AA);
+ flwrite(0xA0,0x555);
+ map->write8(map,*buf,base + off);
+ Last[0] = map->read8(map,base + off);
+ Last[1] = map->read8(map,base + off);
+ Last[2] = map->read8(map,base + off);
+
+ /* Wait for the flash to finish the operation. We store the last 4
+ status bytes that have been retrieved so we can determine why
+ it failed. The toggle bits keep toggling when there is a
+ failure */
+ for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] &&
+ Count < 10000; Count++)
+ Last[Count % 4] = map->read8(map,base + off);
+ if (Last[(Count - 1) % 4] != *buf)
+ {
+ jedec_flash_failed(Last[(Count - 3) % 4]);
+ return -EIO;
+ }
+ }
+ }
+ *retlen = len;
+ return 0;
+}
+
+/* This is used to enhance the speed of the erase routine,
+ when things are being done to multiple chips it is possible to
+ parallize the operations, particularly full memory erases of multi
+ chip memories benifit */
+static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
+ unsigned long len)
+{
+ unsigned int I;
+
+ // Zero the records
+ for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
+ priv->chips[I].start = priv->chips[I].length = 0;
+
+ // Intersect the region with each chip
+ for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
+ {
+ struct jedec_flash_chip *chip = priv->chips + I;
+ unsigned long ByteStart;
+ unsigned long ChipEndByte = chip->offset + (chip->size << chip->addrshift);
+
+ // End is before this chip or the start is after it
+ if (start+len < chip->offset ||
+ ChipEndByte - (1 << chip->addrshift) < start)
+ continue;
+
+ if (start < chip->offset)
+ {
+ ByteStart = chip->offset;
+ chip->start = 0;
+ }
+ else
+ {
+ chip->start = (start - chip->offset + (1 << chip->addrshift)-1) >> chip->addrshift;
+ ByteStart = start;
+ }
+
+ if (start + len >= ChipEndByte)
+ chip->length = (ChipEndByte - ByteStart) >> chip->addrshift;
+ else
+ chip->length = (start + len - ByteStart + (1 << chip->addrshift)-1) >> chip->addrshift;
+ }
+}
+ /*}}}*/
diff --git a/drivers/mtd/map_ram.c b/drivers/mtd/map_ram.c
new file mode 100644
index 000000000..706f7f5ff
--- /dev/null
+++ b/drivers/mtd/map_ram.c
@@ -0,0 +1,110 @@
+/*
+ * Common code to handle map devices which are simple RAM
+ * (C) 2000 Red Hat. GPL'd.
+ * $Id: map_ram.c,v 1.2 2000/07/03 10:01:38 dwmw2 Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+
+#include <linux/mtd/map.h>
+
+
+static int mapram_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int mapram_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+static int mapram_erase (struct mtd_info *, struct erase_info *);
+static void mapram_nop (struct mtd_info *);
+
+struct mtd_info *map_ram_probe(struct map_info *);
+EXPORT_SYMBOL(map_ram_probe);
+
+struct mtd_info *map_ram_probe(struct map_info *map)
+{
+ struct mtd_info *mtd;
+
+ /* Check the first byte is RAM */
+ map->write8(map, 0x55, 0);
+ if (map->read8(map, 0) != 0x55)
+ return NULL;
+
+ map->write8(map, 0xAA, 0);
+ if (map->read8(map, 0) != 0xAA)
+ return NULL;
+
+ /* Check the last byte is RAM */
+ map->write8(map, 0x55, map->size-1);
+ if (map->read8(map, map->size-1) != 0x55)
+ return NULL;
+
+ map->write8(map, 0xAA, map->size-1);
+ if (map->read8(map, map->size-1) != 0xAA)
+ return NULL;
+
+ /* OK. It seems to be RAM. */
+
+ mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+ if (!mtd)
+ return NULL;
+
+ memset(mtd, 0, sizeof(*mtd));
+
+ map->fldrv_destroy = mapram_nop;
+ mtd->priv = map;
+ mtd->name = map->name;
+ mtd->type = MTD_RAM;
+ mtd->erasesize = 0x10000;
+ mtd->size = map->size;
+ mtd->erase = mapram_erase;
+ mtd->read = mapram_read;
+ mtd->write = mapram_write;
+ mtd->sync = mapram_nop;
+ mtd->flags = MTD_CAP_RAM | MTD_VOLATILE;
+
+ MOD_INC_USE_COUNT;
+ return mtd;
+}
+
+
+static int mapram_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+ struct map_info *map = (struct map_info *)mtd->priv;
+
+ map->copy_from(map, buf, from, len);
+ *retlen = len;
+ return 0;
+}
+
+static int mapram_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
+{
+ struct map_info *map = (struct map_info *)mtd->priv;
+
+ map->copy_to(map, to, buf, len);
+ *retlen = len;
+ return 0;
+}
+
+static int mapram_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+ /* Yeah, it's inefficient. Who cares? It's faster than a _real_
+ flash erase. */
+ struct map_info *map = (struct map_info *)mtd->priv;
+ unsigned long i;
+
+ for (i=0; i<instr->len; i++)
+ map->write8(map, 0xFF, instr->addr + i);
+
+ if (instr->callback)
+ instr->callback(instr);
+
+ return 0;
+}
+
+static void mapram_nop(struct mtd_info *mtd)
+{
+ /* Nothing to see here */
+}
diff --git a/drivers/mtd/map_rom.c b/drivers/mtd/map_rom.c
new file mode 100644
index 000000000..d353938e9
--- /dev/null
+++ b/drivers/mtd/map_rom.c
@@ -0,0 +1,60 @@
+/*
+ * Common code to handle map devices which are simple ROM
+ * (C) 2000 Red Hat. GPL'd.
+ * $Id: map_rom.c,v 1.2 2000/07/03 10:01:38 dwmw2 Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+
+#include <linux/mtd/map.h>
+
+
+static int maprom_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static void maprom_nop (struct mtd_info *);
+
+struct mtd_info *map_rom_probe(struct map_info *);
+EXPORT_SYMBOL(map_rom_probe);
+
+struct mtd_info *map_rom_probe(struct map_info *map)
+{
+ struct mtd_info *mtd;
+
+ mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+ if (!mtd)
+ return NULL;
+
+ memset(mtd, 0, sizeof(*mtd));
+
+ map->fldrv_destroy = maprom_nop;
+ mtd->priv = map;
+ mtd->name = map->name;
+ mtd->type = MTD_ROM;
+ mtd->size = map->size;
+ mtd->read = maprom_read;
+ mtd->sync = maprom_nop;
+ mtd->flags = MTD_CAP_ROM;
+
+ MOD_INC_USE_COUNT;
+ return mtd;
+}
+
+
+static int maprom_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+ struct map_info *map = (struct map_info *)mtd->priv;
+
+ map->copy_from(map, buf, from, len);
+ *retlen = len;
+ return 0;
+}
+
+static void maprom_nop(struct mtd_info *mtd)
+{
+ /* Nothing to see here */
+}
diff --git a/drivers/mtd/mapped.c b/drivers/mtd/mapped.c
new file mode 100644
index 000000000..84a74036e
--- /dev/null
+++ b/drivers/mtd/mapped.c
@@ -0,0 +1,674 @@
+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: mapped.c,v 1.8 2000/03/31 14:40:42 dwmw2 Exp $
+/* ######################################################################
+
+ Flash MTD Routines
+
+ These routine support IDing and manipulating flash. Currently the
+ older JEDEC ID mechanism and a table is used for determining the
+ flash characterisitics, but it is trivial to add support for the
+ CFI specification:
+ http://www.pentium.com/design/flash/ in the technote section.
+
+ ##################################################################### */
+ /*}}}*/
+#include <linux/mtd/mapped.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+
+struct JEDECTable mtd_JEDEC_table[] =
+ {{0x01AD,"AMD Am29F016",2*1024*1024,64*1024,MTD_CAP_NORFLASH},
+ {0x01D5,"AMD Am29F080",1*1024*1024,64*1024,MTD_CAP_NORFLASH},
+ {}};
+
+// flash_setup - Setup the mapped_mtd_info structure for normal flash /*{{{*/
+// ---------------------------------------------------------------------
+/* There is a set of commands that flash manufactures follow for getting the
+ JEDEC id, erasing and writing. So long as your flash device supports
+ getting the JEDEC ID in this (standard?) way it will be supported as flash,
+ otherwise it is converted to ROM. Upon completion the structure is
+ registered with the MTD layer */
+int mtd_mapped_setup(struct mapped_mtd_info *map)
+{
+ DEBUG(1, "\n");
+ // Must define a page function to use the defaults!
+ if (map->page == 0)
+ return -1;
+
+ if (map->jedec_sense == 0)
+ map->jedec_sense = flash_jedec;
+
+ if (map->jedec_sense(map) != 0)
+ return -1;
+
+ if (map->mtd.erase == 0 && map->mtd.type == MTD_NORFLASH)
+ map->mtd.erase = flash_erase;
+ if (map->mtd.write == 0)
+ {
+ if (map->mtd.type == MTD_NORFLASH)
+ map->mtd.write = flash_write;
+ if (map->mtd.type == MTD_RAM)
+ map->mtd.write = ram_write;
+ }
+ if (map->mtd.read == 0)
+ map->mtd.read = rom_read;
+
+ return add_mtd_device(&map->mtd);
+}
+ /*}}}*/
+// flash_remove - Remove the flash device from the MTD layer /*{{{*/
+// ---------------------------------------------------------------------
+/* Free any memory allocated for the device here */
+int mtd_mapped_remove(struct mapped_mtd_info *map)
+{
+ return del_mtd_device(&map->mtd);
+}
+ /*}}}*/
+
+// checkparity - Checks a number for odd parity /*{{{*/
+// ---------------------------------------------------------------------
+/* Helper for the JEDEC function, JEDEC numbers all have odd parity */
+static int checkparity(u_char C)
+{
+ u_char parity = 0;
+ while (C != 0)
+ {
+ parity ^= C & 1;
+ C >>= 1;
+ }
+
+ return parity == 1;
+}
+ /*}}}*/
+// SetJedec - Set the jedec information for a chip /*{{{*/
+// ---------------------------------------------------------------------
+/* We track the configuration of each chip separately in the chip list,
+ each chip can have a different type and configuration to allow for
+ maximum flexability. */
+void set_jedec(struct mapped_mtd_info *map,unsigned chip,unsigned char mfr,
+ unsigned char id)
+{
+ unsigned long longID = (mfr << 8) + id;
+ unsigned int I;
+
+ map->mtd.type = MTD_NORFLASH;
+ map->mfr = mfr;
+ map->id = id;
+
+ // Locate the chip in the jedec table
+ for (I = 0; mtd_JEDEC_table[I].jedec != 0; I++)
+ {
+ if (mtd_JEDEC_table[I].jedec == longID)
+ break;
+ }
+
+ if (mtd_JEDEC_table[I].jedec != longID || longID == 0)
+ {
+ printk("Unknown JEDEC number %x-%x, treating as ROM\n",map->mfr,
+ map->id);
+ map->mtd.type = MTD_ROM;
+ return;
+ }
+
+ // Setup the MTD from the JEDEC information
+// map->mtd.size = mtd_JEDEC_table[I].size;
+// map->mtd.erasesize = mtd_JEDEC_table[I].sectorsize;
+// map->mtd.capabilities = mtd_JEDEC_table[I].capabilities;
+// strncpy(map->mtd.part,mtd_JEDEC_table[I].name,sizeof(map->mtd.part)-1);
+
+ map->chips[chip].jedec = longID;
+ map->chips[chip].size = mtd_JEDEC_table[I].size;
+ map->chips[chip].sectorsize = mtd_JEDEC_table[I].sectorsize;
+ map->chips[chip].capabilities = mtd_JEDEC_table[I].capabilities;
+ map->chips[chip].base = 0;
+}
+ /*}}}*/
+// isjedec - Check if reading from the memory location gives jedec #s /*{{{*/
+// ---------------------------------------------------------------------
+/* This is ment to be called on the flash window once it is in jedec mode */
+int isjedec(unsigned long base)
+{
+ // Test #1, JEDEC numbers are readable from 0x??00/0x??01
+ if (readb(base + 0) != readb(base + 0x100) ||
+ readb(base + 1) != readb(base + 0x101))
+ return 0;
+
+ // Test #2 JEDEC numbers exhibit odd parity
+ if (checkparity(readb(base + 0)) == 0 || checkparity(readb(base + 1)) == 0)
+ return 0;
+ return 1;
+}
+ /*}}}*/
+// flash_jedec - JEDEC ID sensor /*{{{*/
+// ---------------------------------------------------------------------
+/* The mysterious jedec flash probe sequence writes a specific pattern of
+ bytes to the flash. This should be general enough to work with any MTD
+ structure that may contain a flash chip, but note that it will corrupt
+ address 0x5555 on SRAM cards if the machine dies between the two
+ critical operations. */
+int flash_jedec(struct mapped_mtd_info *map)
+{
+ unsigned I;
+ u_char OldVal;
+ unsigned long base;
+ unsigned long baseaddr = 0;
+ unsigned chip = 0;
+ unsigned count;
+
+ // Who has a page size this small? :>
+ if (map->pagesize < 0x555)
+ return 1;
+
+ base = map->page(map,0);
+
+ // Wait for any write/erase operation to settle
+ OldVal = readb(base);
+ for (I = 0; OldVal != readb(base) && I < 10000; I++)
+ OldVal = readb(base);
+
+ /* Check for sram by writing to it, the write also happens to be part
+ of the flash reset sequence.. */
+ OldVal = readb(base + 0x555);
+ writeb(OldVal,base + 0x555);
+ writeb(0xF0,base + 0x555);
+ if (OldVal != readb(base + 0x555))
+ {
+ udelay(100);
+
+ // Set it back and make sure..
+ writeb(OldVal,base + 0x555);
+ if (OldVal == readb(base + 0x555))
+ {
+ map->mtd.type = MTD_RAM;
+ return 0;
+ }
+
+ writeb(0xF0,base + 0x555);
+ }
+
+ // Probe for chips
+ while (chip < sizeof(map->chips)/sizeof(map->chips[0]))
+ {
+ // Already in jedec mode, we might be doing some address wrap around
+ if (chip != 0 && isjedec(base) != 0)
+ {
+ /* Try to reset this page and check if that resets the first page
+ to confirm */
+ writeb(0xF0,base + 0x555);
+ if (isjedec(base) != 0)
+ break;
+ base = map->page(map,0);
+ if (isjedec(base) == 0)
+ break;
+ base = map->page(map,baseaddr/map->pagesize);
+ }
+
+ // Send the sequence
+ writeb(0xAA,base + 0x555);
+ writeb(0x55,base + 0x2AA);
+ writeb(0x90,base + 0x555);
+
+ // Check the jedec number
+ if (isjedec(base) == 0)
+ {
+ /* If this is the first chip it must be rom, otherwise it is the
+ end of the flash region */
+ if (chip == 0)
+ {
+ map->mtd.type = MTD_ROM;
+ return 0;
+ }
+ break;
+ }
+
+ // Store the jdec info
+ set_jedec(map,chip,readb(base + 0),readb(base + 1));
+ map->chips[chip].base = baseaddr;
+
+ // Jump to the next chip
+ baseaddr += map->chips[chip].size;
+ if (baseaddr/map->pagesize > map->maxsize)
+ break;
+ base = map->page(map,baseaddr/map->pagesize);
+ if (base == 0)
+ return -EIO;
+
+ chip++;
+ }
+
+ // Reset all of the chips
+ map->mtd.size = 0;
+ baseaddr = 0;
+ map->mtd.flags = 0xFFFF;
+ for (I = 0; map->chips[I].jedec != 0; I++)
+ {
+ // Fill in the various MTD structures
+ map->mtd.size += map->chips[I].size;
+ if (map->mtd.erasesize < map->chips[I].sectorsize)
+ map->mtd.erasesize = map->chips[I].sectorsize;
+ map->mtd.flags &= map->chips[I].capabilities;
+
+ base = map->page(map,baseaddr/map->pagesize);
+ baseaddr += map->chips[chip].size;
+ writeb(0xF0,base + 0); // Reset
+ }
+
+ /* Generate a part name that includes the number of different chips and
+ other configuration information */
+ count = 1;
+ map->part[0] = 0;
+ for (I = 0; map->chips[I].jedec != 0; I++)
+ {
+ unsigned J;
+ if (map->chips[I+1].jedec == map->chips[I].jedec)
+ {
+ count++;
+ continue;
+ }
+
+ // Locate the chip in the jedec table
+ for (J = 0; mtd_JEDEC_table[J].jedec != 0; J++)
+ {
+ if (mtd_JEDEC_table[J].jedec == map->chips[I].jedec)
+ break;
+ }
+
+ if (map->part[0] != 0)
+ strcat(map->part,",");
+
+ if (count != 1)
+ sprintf(map->part+strlen(map->part),"%u*[%s]",count,
+ mtd_JEDEC_table[J].name);
+ else
+ sprintf(map->part+strlen(map->part),"%s",
+ mtd_JEDEC_table[J].name);
+ count = 1;
+ }
+ return 0;
+}
+ /*}}}*/
+
+// flash_failed - Print a console message about why the failure /*{{{*/
+// ---------------------------------------------------------------------
+/* Pass the flags value that the flash return before it re-entered read
+ mode. */
+static void flash_failed(unsigned char code)
+{
+ /* Bit 5 being high indicates that there was an internal device
+ failure, erasure time limits exceeded or something */
+ if ((code & (1 << 5)) != 0)
+ {
+ printk("mtd: Internal Flash failure\n");
+ return;
+ }
+ printk("mtd: Programming didn't take\n");
+}
+ /*}}}*/
+// flash_erase - Generic erase function /*{{{*/
+// ---------------------------------------------------------------------
+/* This uses the erasure function described in the AMD Flash Handbook,
+ it will work for flashes with a fixed sector size only. Flashes with
+ a selection of sector sizes (ie the AMD Am29F800B) will need a different
+ routine. This routine tries to parallize erasing multiple chips/sectors
+ where possible */
+int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ unsigned long Time = 0;
+ unsigned long NoTime = 0;
+ unsigned long start = instr->addr, len = instr->len;
+ unsigned int I;
+ struct mapped_mtd_info *map = (struct mapped_mtd_info *)mtd;
+
+ // Verify the arguments..
+ if (start + len > map->mtd.size ||
+ (start % map->mtd.erasesize) != 0 ||
+ (len % map->mtd.erasesize) != 0 ||
+ (len/map->mtd.erasesize) == 0)
+ return -EINVAL;
+
+ flash_chip_scan(map,start,len);
+
+ // Start the erase sequence on each chip
+ for (I = 0; map->chips[I].jedec != 0; I++)
+ {
+ unsigned long off;
+ struct flash_chip *chip = map->chips + I;
+ unsigned long base;
+ unsigned long flags;
+
+ if (chip->length == 0)
+ continue;
+
+ if (page_jump(map,chip->base + chip->start,0x555,&base,0) != 0)
+ return -EIO;
+
+ // Send the erase setup code
+ writeb(0xF0,base + 0x555);
+ writeb(0xAA,base + 0x555);
+ writeb(0x55,base + 0x2AA);
+ writeb(0x80,base + 0x555);
+ writeb(0xAA,base + 0x555);
+ writeb(0x55,base + 0x2AA);
+
+ // Use chip erase if possible
+ if (chip->start == 0 && chip->length == chip->size)
+ {
+ writeb(0x10,base+0x555);
+ continue;
+ }
+
+ /* Once we start selecting the erase sectors the delay between each
+ command must not exceed 50us or it will immediately start erasing
+ and ignore the other sectors */
+ save_flags(flags);
+ cli();
+ for (off = 0; off < chip->length; off += chip->sectorsize)
+ {
+ if (page_jump(map,chip->base + chip->start + off,1,&base,0) != 0)
+ return -EIO;
+
+ // Check to make sure we didn't timeout
+ writeb(0x30,base);
+ if ((readb(base) & (1 << 3)) != 0)
+ {
+ printk("mtd: Ack! We timed out the erase timer!\n");
+ return -EIO;
+ }
+ }
+ restore_flags(flags);
+ }
+
+ /* We could split this into a timer routine and return early, performing
+ background erasure.. Maybe later if the need warrents */
+
+ /* Poll the flash for erasure completion, specs say this can take as long
+ as 480 seconds to do all the sectors (for a 2 meg flash).
+ Erasure time is dependant on chip age, temp and wear.. */
+ Time = 0;
+ NoTime = 0;
+ for (I = 0; map->chips[I].jedec != 0; I++)
+ {
+ struct flash_chip *chip = map->chips + I;
+ unsigned long base;
+ unsigned long off = 0;
+ if (chip->length == 0)
+ continue;
+
+ if (page_jump(map,chip->base + chip->start,1,&base,0) != 0)
+ return -EIO;
+
+ while (1)
+ {
+ unsigned char Last[4];
+ unsigned long Count = 0;
+
+ /* During erase bit 7 is held low and bit 6 toggles, we watch this,
+ should it stop toggling or go high then the erase is completed,
+ or this is not really flash ;> */
+ Last[0] = readb(base);
+ Last[1] = readb(base);
+ Last[2] = readb(base);
+ for (Count = 3; (Last[(Count - 1) % 4] & (1 << 7)) == 0 &&
+ Last[(Count - 1) % 4] != Last[(Count - 2) % 4]; Count++)
+ {
+ if (NoTime == 0)
+ Time += HZ/10 - schedule_timeout(HZ/10);
+ NoTime = 0;
+
+ Last[Count % 4] = readb(base);
+
+ // Count time, max of 15s per sector (according to AMD)
+ if (Time > 15*len/mtd->erasesize*HZ)
+ {
+ printk("mtd: Flash Erase Timed out\n");
+ return -EIO;
+ }
+ }
+
+ if (Last[(Count - 1) % 4] == Last[(Count - 2) % 4])
+ {
+ flash_failed(Last[(Count - 3) % 4]);
+ return -EIO;
+ }
+
+ // Skip to the next chip if we used chip erase
+ if (chip->length == chip->size)
+ off = chip->size;
+ else
+ off += chip->sectorsize;
+
+ if (off >= chip->length)
+ break;
+ if (page_jump(map,chip->base + chip->start + off,1,&base,0) != 0)
+ return -EIO;
+ NoTime = 1;
+ }
+ }
+
+ // Paranoid verify of erasure
+ {
+ unsigned long base;
+ unsigned long buflen;
+ while (len > 0)
+ {
+ unsigned long step;
+
+ if (page_jump(map,start,len,&base,&buflen) != 0)
+ return -EIO;
+ start += buflen;
+ len -= buflen;
+ step = buflen/128;
+ for (;buflen != 0; buflen -= step)
+ {
+ if (readb(base+buflen-1) != 0xFF)
+ {
+ printk("mtd: Flash Erase didn't take %lu %lu %lu\n",buflen,len,start);
+ return -EIO;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+#if 1
+ /*}}}*/
+// flash_write - Generic writing function /*{{{*/
+// ---------------------------------------------------------------------
+/* This could do parallel writes on multiple chips but doesnt, memory
+ constraints make that infeasable. This should work with any sort of
+ linear flash that is not interleved */
+extern int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct mapped_mtd_info *map = (struct mapped_mtd_info *)mtd;
+ unsigned long base;
+ unsigned long off;
+ DEBUG(1,"\n");
+ if (start + len > mtd->size)
+ return -EIO;
+
+ while (len != 0)
+ {
+ // Compute the page offset and reposition
+ base = map->page(map,(u_long)start/map->pagesize);
+ off = (u_long)start % map->pagesize;
+
+ // Loop over this page
+ for (; off != map->pagesize && len != 0; start++, len--, off++,buf++)
+ {
+ unsigned char oldbyte = readb(base+off);
+ unsigned char Last[4];
+ unsigned long Count = 0;
+
+ if (oldbyte == *buf)
+ continue;
+ if (((~oldbyte) & *buf) != 0)
+ printk("mtd: warn: Trying to set a 0 to a 1\n");
+
+ // Write
+ writeb(0xAA,base + 0x555);
+ writeb(0x55,base + 0x2AA);
+ writeb(0xA0,base + 0x555);
+ writeb(*buf,base + off);
+ Last[0] = readb(base + off);
+ Last[1] = readb(base + off);
+ Last[2] = readb(base + off);
+
+ /* Wait for the flash to finish the operation. We store the last 4
+ status bytes that have been retrieved so we can determine why
+ it failed. The toggle bits keep toggling when there is a
+ failure */
+ for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] &&
+ Count < 10000; Count++)
+ Last[Count % 4] = readb(base + off);
+ if (Last[(Count - 1) % 4] != *buf)
+ {
+ flash_failed(Last[(Count - 3) % 4]);
+ return -EIO;
+ }
+ }
+ }
+ *retlen = len;
+ return 0;
+}
+#endif
+
+// ram_write - Generic writing function for ram /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+extern int ram_write(struct mtd_info *mtd, loff_t start, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct mapped_mtd_info *map = (struct mapped_mtd_info *)mtd;
+ unsigned long base;
+ size_t origlen = len;
+ unsigned long buflen;
+ DEBUG(1,"\n");
+ if (start + len > mtd->size)
+ return -EIO;
+
+ while (len != 0)
+ {
+ // Reposition..
+ if (page_jump(map,start,len,&base,&buflen) != 0)
+ return -EIO;
+
+ // Copy
+ memcpy_toio(base,buf,buflen);
+ len -= buflen;
+ start += buflen;
+ }
+ *retlen = origlen;
+ return 0;
+}
+
+// rom_read - Read handler for any sort of device /*{{{*/
+// ---------------------------------------------------------------------
+/* This is a generic read function that should work with any device in the
+ mapped region. */
+extern int rom_read(struct mtd_info *mtd, loff_t start, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct mapped_mtd_info *map = (struct mapped_mtd_info *)mtd;
+ size_t origlen = len;
+ unsigned long base;
+ unsigned long buflen;
+
+ printk("Rom_Read\n");
+ if (start + len > mtd->size)
+ return -EIO;
+
+ while (len != 0)
+ {
+ // Reposition..
+ if (page_jump(map,start,len,&base,&buflen) != 0)
+ return -EIO;
+
+ // Copy
+ memcpy_fromio(buf,base,buflen);
+ len -= buflen;
+ start += buflen;
+ }
+ *retlen = origlen;
+ return 0;
+}
+
+// page_jump - Move the window and return the buffer /*{{{*/
+// ---------------------------------------------------------------------
+/* Unlike the page function this returns a buffer and length adjusted for
+ the page dimensions and the reading offset into the page, simplifies
+ many of the other routines */
+int page_jump(struct mapped_mtd_info *map,unsigned long start,
+ unsigned long len,unsigned long *base,
+ unsigned long *retlen)
+{
+ DEBUG(1,"Page Jump\n");
+ if (start > map->mtd.size || start + len > map->mtd.size)
+ return -EINVAL;
+
+ *base = map->page(map,start/map->pagesize);
+ if (*base == 0)
+ return -EIO;
+
+ *base += start % map->pagesize;
+
+ // If retlen is 0 that mean the caller requires len bytes, no quibbling.
+ if (retlen == 0)
+ {
+ if (len > map->pagesize - (start % map->pagesize))
+ return -EIO;
+ return 0;
+ }
+
+ // Compute the buffer paramaters and return
+ if (len > map->pagesize - (start % map->pagesize))
+ *retlen = map->pagesize - (start % map->pagesize);
+ else
+ *retlen = len;
+ return 0;
+}
+ /*}}}*/
+// flash_chip_scan - Intersect a region with the flash chip structure /*{{{*/
+// ---------------------------------------------------------------------
+/* This is used to enhance the speed of the erase routine,
+ when things are being done to multiple chips it is possible to
+ parallize the operations, particularly full memory erases of multi
+ chip memories benifit */
+
+void flash_chip_scan(struct mapped_mtd_info *map,unsigned long start,
+ unsigned long len)
+{
+ unsigned int I = 0;
+
+ DEBUG(1,"\n");
+ // Zero the records
+ for (I = 0; map->chips[I].jedec != 0; I++)
+ map->chips[I].start = map->chips[I].length = 0;
+
+ // Intesect our region with the chip structures
+ for (I = 0; map->chips[I].jedec != 0 && len != 0; I++)
+ {
+ // Havent found the start yet
+ if (start >= map->chips[I].base + map->chips[I].size)
+ continue;
+
+ // Store the portion of this chip that is being effected
+ map->chips[I].start = start - map->chips[I].base;
+ if (len <= map->chips[I].size - map->chips[I].start)
+ map->chips[I].length = len;
+ else
+ map->chips[I].length = map->chips[I].size - map->chips[I].start;
+ len -= map->chips[I].length;
+ start = map->chips[I].base + map->chips[I].size;
+ }
+}
+ /*}}}*/
+
diff --git a/drivers/mtd/mixmem.c b/drivers/mtd/mixmem.c
new file mode 100644
index 000000000..8326f864b
--- /dev/null
+++ b/drivers/mtd/mixmem.c
@@ -0,0 +1,151 @@
+/*
+ * mixmem - a block device driver for flash rom found on the
+ * piggyback board of the multi-purpose mixcom card
+ *
+ * Author: Gergely Madarasz <gorgo@itc.hu>
+ *
+ * Copyright (c) 1999 ITConsult-Pro Co. <info@itc.hu>
+ *
+ * This code is GPL
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <linux/init.h>
+#include <linux/mtd/mapped.h>
+
+#define MIXCOM_ID_OFFSET 0xc10
+#define MIXCOM_PAGE_OFFSET 0xc11
+#define MIXCOM_ID_1 0x11
+#define MIXCOM_ID_2 0x13
+#define MIXMEM_PAGESIZE 4096
+#define FIRST_BLOCK_OFFSET 0x1000
+
+#if LINUX_VERSION_CODE < 0x20300
+#define __exit
+#endif
+
+static unsigned int mixmem_addrs[] = { 0xc8000, 0xd8000, 0 };
+static unsigned int mixcom_ports[] = { 0x180, 0x280, 0x380, 0 };
+
+// We could store these in the mtd structure, but we only support 1 device..
+static unsigned long base_io = 0;
+static unsigned long base_addr = 0;
+static struct mapped_mtd_info *SSD;
+
+static unsigned long mixmem_page(struct mapped_mtd_info *map,
+ unsigned long page)
+{
+ outb((char)(page & 0xff), base_io+MIXCOM_PAGE_OFFSET);
+ outb((char)((page >> 8) & 0x7), base_io+MIXCOM_PAGE_OFFSET+1);
+ return base_addr;
+}
+
+static int flash_probe(int base)
+{
+ int prev,curr;
+ unsigned long flags;
+
+ writeb(0xf0, base);
+ save_flags(flags); cli();
+
+ prev=readw(base);
+
+ writeb(0xaa, base+0x555);
+ writeb(0x55, base+0x2AA);
+ writeb(0x90, base+0x555);
+
+ curr=readw(base);
+
+ restore_flags(flags);
+ writeb(0xf0, base);
+ return(prev==curr?0:curr);
+}
+
+static int mixmem_probe(void)
+{
+ int i;
+ int id;
+ int chip;
+
+ /* This should really check to see if the io ports are in use before
+ writing to them */
+ for(i=0;mixcom_ports[i]!=0;i++) {
+ id=inb(mixcom_ports[i]+MIXCOM_ID_OFFSET);
+ if(id==MIXCOM_ID_1 || id==MIXCOM_ID_2) {
+ printk("mixmem: mixcom board found at 0x%3x\n",mixcom_ports[i]);
+ break;
+ }
+ }
+
+ if(mixcom_ports[i]==0) {
+ printk("mixmem: no mixcom board found\n");
+ return -ENODEV;
+ }
+
+ if (check_region(mixcom_ports[i]+MIXCOM_PAGE_OFFSET, 2)) return -EAGAIN;
+
+
+
+ // What is the deal with first_block_offset?
+ for(i=0;mixmem_addrs[i]!=0;i++) {
+ chip=flash_probe(mixmem_addrs[i]+FIRST_BLOCK_OFFSET);
+ if(chip)break;
+ }
+
+ if(mixmem_addrs[i]==0) {
+ printk("mixmem: no flash available\n");
+ return -ENODEV;
+ }
+ base_io = mixcom_ports[i];
+ base_addr = mixmem_addrs[i];
+ request_region(mixcom_ports[i]+MIXCOM_PAGE_OFFSET, 2, "mixmem");
+ return 0;
+}
+
+
+static void __exit cleanup_mixmem()
+{
+ mtd_mapped_remove(SSD);
+ kfree(SSD);
+ SSD = 0;
+ release_region(base_io+MIXCOM_PAGE_OFFSET, 2);
+}
+
+//static int __init init_mixmem(void)
+int __init init_mixmem(void)
+{
+ if (mixmem_probe() != 0)
+ return -EAGAIN;
+
+ // Print out our little header..
+ printk("mixcom MTD IO:0x%lx MEM:0x%lx-0x%lx\n",base_io,base_addr,
+ base_addr+MIXMEM_PAGESIZE);
+
+ // Allocate some memory
+ SSD = (struct mapped_mtd_info *)kmalloc(sizeof(*SSD),GFP_KERNEL);
+ if (SSD == 0)
+ return 0;
+ memset(SSD,0,sizeof(*SSD));
+
+ // Setup the MTD structure
+ SSD->page = mixmem_page;
+ SSD->pagesize = MIXMEM_PAGESIZE;
+ SSD->maxsize = 0x7FF;
+ SSD->mtd.name = "mixcom piggyback";
+
+ // Setup the MTD, this will sense the flash parameters and so on..
+ if (mtd_mapped_setup(SSD) != 0)
+ {
+ printk("Failed to register new device\n");
+ cleanup_module();
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+module_init(init_mixmem);
+module_exit(cleanup_mixmem);
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
new file mode 100644
index 000000000..2d7b5d5fe
--- /dev/null
+++ b/drivers/mtd/mtdblock.c
@@ -0,0 +1,318 @@
+/*
+ * Direct MTD block device access
+ *
+ * $Id: mtdblock.c,v 1.16 2000/06/23 09:34:58 dwmw2 Exp $
+ */
+
+#ifdef MTDBLOCK_DEBUG
+#define DEBUGLVL debug
+#endif
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/config.h>
+
+#include <linux/mtd/mtd.h>
+
+#define MAJOR_NR MTD_BLOCK_MAJOR
+#define DEVICE_NAME "mtdblock"
+#define DEVICE_REQUEST mtdblock_request
+#define DEVICE_NR(device) (device)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+#define DEVICE_NO_RANDOM
+#include <linux/blk.h>
+
+#if LINUX_VERSION_CODE < 0x20300
+#define RQFUNC_ARG void
+#define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0)
+#else
+#define RQFUNC_ARG request_queue_t *q
+#endif
+
+#ifdef MTDBLOCK_DEBUG
+static int debug = MTDBLOCK_DEBUG;
+MODULE_PARM(debug, "i");
+#endif
+
+#if 1
+static void mtdblock_end_request(struct request *req, int res)
+{
+ if (end_that_request_first( req, res, "mtdblock" ))
+ return;
+ end_that_request_last( req );
+}
+#endif
+
+static int mtd_sizes[MAX_MTD_DEVICES];
+
+
+/* Keeping a separate list rather than just getting stuff directly out of
+ the MTD core's mtd_table is perhaps not very nice, but I happen
+ to dislike the idea of directly accessing mtd_table even more.
+ dwmw2 31/3/0
+*/
+
+static int mtdblock_open(struct inode *inode, struct file *file)
+{
+ struct mtd_info *mtd = NULL;
+
+ int dev;
+
+ DEBUG(1,"mtdblock_open\n");
+
+ if (inode == 0)
+ return -EINVAL;
+
+ dev = MINOR(inode->i_rdev);
+
+ MOD_INC_USE_COUNT;
+
+ mtd = get_mtd_device(NULL, dev);
+
+ if (!mtd) {
+ MOD_DEC_USE_COUNT;
+ return -ENODEV;
+ }
+
+ mtd_sizes[dev] = mtd->size>>9;
+
+ DEBUG(1, "ok\n");
+
+ return 0;
+}
+
+static release_t mtdblock_release(struct inode *inode, struct file *file)
+{
+ int dev;
+ struct mtd_info *mtd;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+ struct super_block * sb = get_super(inode->i_rdev);
+#endif
+ DEBUG(1, "mtdblock_release\n");
+
+ if (inode == NULL)
+ release_return(-ENODEV);
+
+ fsync_dev(inode->i_rdev);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+ if (sb) invalidate_inodes(sb);
+#endif
+ invalidate_buffers(inode->i_rdev);
+
+ dev = MINOR(inode->i_rdev);
+ mtd = __get_mtd_device(NULL, dev);
+
+ if (!mtd) {
+ printk(KERN_WARNING "MTD device is absent on mtd_release!\n");
+ MOD_DEC_USE_COUNT;
+ release_return(-ENODEV);
+
+ }
+
+ if (mtd->sync)
+ mtd->sync(mtd);
+
+ put_mtd_device(mtd);
+
+ DEBUG(1, "ok\n");
+
+ MOD_DEC_USE_COUNT;
+ release_return(0);
+}
+
+
+static void mtdblock_request(RQFUNC_ARG)
+{
+ struct request *current_request;
+ unsigned int res = 0;
+ struct mtd_info *mtd;
+
+ while (1)
+ {
+ /* Grab the Request and unlink it from the request list, INIT_REQUEST
+ will execute a return if we are done. */
+ INIT_REQUEST;
+ current_request = CURRENT;
+
+ if (MINOR(current_request->rq_dev) >= MAX_MTD_DEVICES)
+ {
+ printk("mtd: Unsupported device!\n");
+ end_request(0);
+ continue;
+ }
+
+ // Grab our MTD structure
+
+ mtd = __get_mtd_device(NULL, MINOR(current_request->rq_dev));
+ if (!mtd) {
+ printk("MTD device %d doesn't appear to exist any more\n", CURRENT_DEV);
+ end_request(0);
+ }
+
+ if (current_request->sector << 9 > mtd->size ||
+ (current_request->sector + current_request->nr_sectors) << 9 > mtd->size)
+ {
+ printk("mtd: Attempt to read past end of device!\n");
+ printk("size: %lx, sector: %lx, nr_sectors %lx\n", mtd->size, current_request->sector, current_request->nr_sectors);
+ end_request(0);
+ continue;
+ }
+
+ /* Remove the request we are handling from the request list so nobody messes
+ with it */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+ blkdev_dequeue_request(current_request);
+
+ /* Now drop the lock that the ll_rw_blk functions grabbed for us
+ and process the request. This is necessary due to the extreme time
+ we spend processing it. */
+ spin_unlock_irq(&io_request_lock);
+#endif
+
+ // Handle the request
+ switch (current_request->cmd)
+ {
+ size_t retlen;
+
+ case READ:
+ if (mtd->read(mtd,current_request->sector<<9,
+ current_request->nr_sectors << 9,
+ &retlen, current_request->buffer) == 0)
+ res = 1;
+ else
+ res = 0;
+ break;
+
+ case WRITE:
+//printk("mtdblock_request WRITE sector=%d(%d)\n",current_request->sector,
+// current_request->nr_sectors);
+
+ // Read only device
+ if ((mtd->flags & MTD_CAP_RAM) == 0)
+ {
+ res = 0;
+ break;
+ }
+
+ // Do the write
+ if (mtd->write(mtd,current_request->sector<<9,
+ current_request->nr_sectors << 9,
+ &retlen, current_request->buffer) == 0)
+ res = 1;
+ else
+ res = 0;
+ break;
+
+ // Shouldn't happen
+ default:
+ printk("mtd: unknown request\n");
+ break;
+ }
+
+ // Grab the lock and re-thread the item onto the linked list
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+ spin_lock_irq(&io_request_lock);
+ mtdblock_end_request(current_request, res);
+#else
+ end_request(res);
+#endif
+ }
+}
+
+
+
+static int mtdblock_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct mtd_info *mtd;
+
+ mtd = __get_mtd_device(NULL, MINOR(inode->i_rdev));
+
+ if (!mtd) return -EINVAL;
+
+ switch (cmd) {
+ case BLKGETSIZE: /* Return device size */
+ if (!arg) return -EFAULT;
+ return put_user((mtd->size >> 9),
+ (long *) arg);
+
+ case BLKFLSBUF:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+ if(!capable(CAP_SYS_ADMIN)) return -EACCES;
+#endif
+ fsync_dev(inode->i_rdev);
+ invalidate_buffers(inode->i_rdev);
+ if (mtd->sync)
+ mtd->sync(mtd);
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+ /*}}}*/
+#if LINUX_VERSION_CODE < 0x20326
+static struct file_operations mtd_fops =
+{
+ open: mtdblock_open,
+ ioctl: mtdblock_ioctl,
+ release: mtdblock_release,
+ read: block_read,
+ write: block_write
+};
+#else
+static struct block_device_operations mtd_fops =
+{
+ open: mtdblock_open,
+ release: mtdblock_release,
+ ioctl: mtdblock_ioctl
+};
+#endif
+
+#if LINUX_VERSION_CODE < 0x20300
+#ifdef MODULE
+#define init_mtdblock init_module
+#define cleanup_mtdblock cleanup_module
+#endif
+#define __exit
+#endif
+
+
+int __init init_mtdblock(void)
+{
+ int i;
+
+ if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) {
+ printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
+ MTD_BLOCK_MAJOR);
+ return EAGAIN;
+ }
+
+ /* We fill it in at open() time. */
+ for (i=0; i< MAX_MTD_DEVICES; i++) {
+ mtd_sizes[i] = 0;
+ }
+
+ /* Allow the block size to default to BLOCK_SIZE. */
+ blksize_size[MAJOR_NR] = NULL;
+ blk_size[MAJOR_NR] = mtd_sizes;
+
+#if LINUX_VERSION_CODE < 0x20320
+ blk_dev[MAJOR_NR].request_fn = mtdblock_request;
+#else
+ blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request);
+#endif
+ return 0;
+}
+
+static void __exit cleanup_mtdblock(void)
+{
+ unregister_blkdev(MAJOR_NR,DEVICE_NAME);
+}
+
+#if LINUX_VERSION_CODE > 0x20300
+module_init(init_mtdblock);
+module_exit(cleanup_mtdblock);
+#endif
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
new file mode 100644
index 000000000..d0e79a431
--- /dev/null
+++ b/drivers/mtd/mtdchar.c
@@ -0,0 +1,402 @@
+/*
+ * $Id: mtdchar.c,v 1.7 2000/06/30 15:54:19 dwmw2 Exp $
+ *
+ * Character-device access to raw MTD devices.
+ *
+ */
+
+
+#include <linux/mtd/compatmac.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/malloc.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
+#else
+static int mtd_lseek (struct inode *inode, struct file *file, off_t offset, int orig)
+#endif
+{
+ struct mtd_info *mtd=(struct mtd_info *)file->private_data;
+
+ switch (orig) {
+ case 0:
+ /* SEEK_SET */
+ file->f_pos = offset;
+ break;
+ case 1:
+ /* SEEK_CUR */
+ file->f_pos += offset;
+ break;
+ case 2:
+ /* SEEK_END */
+ file->f_pos =mtd->size + offset;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (file->f_pos < 0)
+ file->f_pos = 0;
+ else if (file->f_pos >= mtd->size)
+ file->f_pos = mtd->size - 1;
+
+ return file->f_pos;
+}
+
+
+
+static int mtd_open(struct inode *inode, struct file *file)
+{
+ int minor = MINOR(inode->i_rdev);
+ int devnum = minor >> 1;
+ struct mtd_info *mtd;
+
+ DEBUG(0, "MTD_open\n");
+
+ if (devnum >= MAX_MTD_DEVICES)
+ return -ENODEV;
+
+ /* You can't open the RO devices RW */
+ if ((file->f_mode & 2) && (minor & 1))
+ return -EACCES;
+
+ MOD_INC_USE_COUNT;
+
+ mtd = get_mtd_device(NULL, devnum);
+
+ if (!mtd) {
+ MOD_DEC_USE_COUNT;
+ return -ENODEV;
+ }
+
+ file->private_data = mtd;
+
+ /* You can't open it RW if it's not a writeable device */
+ if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) {
+ put_mtd_device(mtd);
+ MOD_DEC_USE_COUNT;
+ return -EACCES;
+ }
+
+ return 0;
+} /* mtd_open */
+
+/*====================================================================*/
+
+static release_t mtd_close(struct inode *inode,
+ struct file *file)
+{
+ struct mtd_info *mtd;
+
+ DEBUG(0, "MTD_close\n");
+
+ mtd = (struct mtd_info *)file->private_data;
+
+ if (mtd->sync)
+ mtd->sync(mtd);
+
+ put_mtd_device(mtd);
+
+ MOD_DEC_USE_COUNT;
+ release_return(0);
+} /* mtd_close */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+#define FILE_POS *ppos
+#else
+#define FILE_POS file->f_pos
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+static ssize_t mtd_read(struct file *file, char *buf, size_t count,loff_t *ppos)
+#else
+static int mtd_read(struct inode *inode,struct file *file, char *buf, int count)
+#endif
+{
+ struct mtd_info *mtd = (struct mtd_info *)file->private_data;
+ size_t retlen=0;
+ int ret=0;
+ char *kbuf;
+
+ DEBUG(0,"MTD_read\n");
+
+ if (FILE_POS + count > mtd->size)
+ count = mtd->size - FILE_POS;
+
+ if (!count)
+ return 0;
+
+ /* FIXME: Use kiovec in 2.3 or 2.2+rawio, or at
+ * least split the IO into smaller chunks.
+ */
+
+ kbuf = vmalloc(count);
+ if (!kbuf)
+ return -ENOMEM;
+
+ ret = MTD_READ(mtd, FILE_POS, count, &retlen, kbuf);
+ if (!ret) {
+ FILE_POS += retlen;
+ if (copy_to_user(buf, kbuf, retlen))
+ ret = -EFAULT;
+ else
+ ret = retlen;
+
+ }
+
+ vfree(kbuf);
+
+ return ret;
+} /* mtd_read */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+static ssize_t mtd_write(struct file *file, const char *buf, size_t count,loff_t *ppos)
+#else
+static read_write_t mtd_write(struct inode *inode,struct file *file, const char *buf, count_t count)
+#endif
+{
+ struct mtd_info *mtd = (struct mtd_info *)file->private_data;
+ char *kbuf;
+ size_t retlen;
+ int ret=0;
+
+ DEBUG(0,"MTD_write\n");
+
+ if (FILE_POS == mtd->size)
+ return -ENOSPC;
+
+ if (FILE_POS + count > mtd->size)
+ count = mtd->size - FILE_POS;
+
+ if (!count)
+ return 0;
+
+ kbuf=vmalloc(count);
+
+ if (!kbuf)
+ return -ENOMEM;
+
+ if (copy_from_user(kbuf, buf, count)) {
+ vfree(kbuf);
+ return -EFAULT;
+ }
+
+
+ ret = (*(mtd->write))(mtd, FILE_POS, count, &retlen, buf);
+
+ if (!ret) {
+ FILE_POS += retlen;
+ ret = retlen;
+ }
+
+ vfree(kbuf);
+
+ return ret;
+} /* mtd_write */
+
+/*======================================================================
+
+ IOCTL calls for getting device parameters.
+
+======================================================================*/
+static void mtd_erase_callback (struct erase_info *instr)
+{
+ wake_up((wait_queue_head_t *)instr->priv);
+}
+
+static int mtd_ioctl(struct inode *inode, struct file *file,
+ u_int cmd, u_long arg)
+{
+ struct mtd_info *mtd = (struct mtd_info *)file->private_data;
+ int ret = 0;
+ u_long size;
+
+ DEBUG(0, "MTD_ioctl\n");
+
+ size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
+ if (cmd & IOC_IN) {
+ ret = verify_area(VERIFY_READ, (char *)arg, size);
+ if (ret) return ret;
+ }
+ if (cmd & IOC_OUT) {
+ ret = verify_area(VERIFY_WRITE, (char *)arg, size);
+ if (ret) return ret;
+ }
+
+ switch (cmd) {
+ case MEMGETINFO:
+ copy_to_user((struct mtd_info *)arg, mtd,
+ sizeof(struct mtd_info_user));
+ break;
+
+ case MEMERASE:
+ {
+ struct erase_info *erase=kmalloc(sizeof(struct erase_info),GFP_KERNEL);
+ if (!erase)
+ ret = -ENOMEM;
+ else {
+ wait_queue_head_t waitq;
+ DECLARE_WAITQUEUE(wait, current);
+
+ init_waitqueue_head(&waitq);
+
+ memset (erase,0,sizeof(struct erase_info));
+ copy_from_user(&erase->addr, (u_long *)arg,
+ 2 * sizeof(u_long));
+ erase->mtd = mtd;
+ erase->callback = mtd_erase_callback;
+ erase->priv = (unsigned long)&waitq;
+
+ /* FIXME: Allow INTERRUPTIBLE. Which means
+ not having the wait_queue head on the stack
+
+ Does it? Why? Who wrote this? Was it my alter
+ ago - the intelligent one? Or was it the stupid
+ one, and now I'm being clever I don't know what
+ it was on about?
+
+ dwmw2.
+
+ It was the intelligent one. If the wq_head is
+ on the stack, and we leave because we got
+ interrupted, then the wq_head is no longer
+ there when the callback routine tries to
+ wake us up --> BOOM!.
+
+ */
+ current->state = TASK_UNINTERRUPTIBLE;
+ add_wait_queue(&waitq, &wait);
+ ret = mtd->erase(mtd, erase);
+ if (!ret)
+ schedule();
+ remove_wait_queue(&waitq, &wait);
+ current->state = TASK_RUNNING;
+ if (!ret)
+ ret = (erase->state == MTD_ERASE_FAILED);
+ kfree(erase);
+ }
+ break;
+ }
+
+ case MEMWRITEOOB:
+ {
+ struct mtd_oob_buf buf;
+ void *databuf;
+ ssize_t retlen;
+
+ copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf));
+
+ if (buf.length > 0x4096)
+ return -EINVAL;
+
+ if (!mtd->write_oob)
+ ret = -EOPNOTSUPP;
+ else
+ ret = verify_area(VERIFY_READ, (char *)buf.ptr, buf.length);
+
+ if (ret)
+ return ret;
+
+ databuf = kmalloc(buf.length, GFP_KERNEL);
+ if (!databuf)
+ return -ENOMEM;
+
+ copy_from_user(databuf, buf.ptr, buf.length);
+
+ ret = (mtd->write_oob)(mtd, buf.start, buf.length, &retlen, databuf);
+
+ copy_to_user((void *)arg + sizeof(loff_t), &retlen, sizeof(ssize_t));
+
+ kfree(databuf);
+ break;
+
+ }
+
+ case MEMREADOOB:
+ {
+ struct mtd_oob_buf buf;
+ void *databuf;
+ ssize_t retlen;
+
+ copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf));
+
+ if (buf.length > 0x4096)
+ return -EINVAL;
+
+ if (!mtd->read_oob)
+ ret = -EOPNOTSUPP;
+ else
+ ret = verify_area(VERIFY_WRITE, (char *)buf.ptr, buf.length);
+
+ if (ret)
+ return ret;
+
+ databuf = kmalloc(buf.length, GFP_KERNEL);
+ if (!databuf)
+ return -ENOMEM;
+
+ ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf);
+
+ copy_to_user((void *)arg + sizeof(loff_t), &retlen, sizeof(ssize_t));
+
+ if (retlen)
+ copy_to_user(buf.ptr, databuf, retlen);
+
+ kfree(databuf);
+ break;
+ }
+
+
+
+
+
+ default:
+ printk("Invalid ioctl %x (MEMGETINFO = %x)\n",cmd, MEMGETINFO);
+ ret = -EINVAL;
+ }
+
+ return ret;
+} /* memory_ioctl */
+
+static struct file_operations mtd_fops = {
+
+ llseek: mtd_lseek, /* lseek */
+ read: mtd_read, /* read */
+ write: mtd_write, /* write */
+ ioctl: mtd_ioctl, /* ioctl */
+ open: mtd_open, /* open */
+ release: mtd_close, /* release */
+};
+
+
+#if LINUX_VERSION_CODE < 0x20300
+#ifdef MODULE
+#define init_mtdchar init_module
+#define cleanup_mtdchar cleanup_module
+#endif
+#endif
+
+mod_init_t init_mtdchar(void)
+{
+
+ if (register_chrdev(MTD_CHAR_MAJOR,"mtd",&mtd_fops)) {
+ printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
+ MTD_CHAR_MAJOR);
+ return EAGAIN;
+ }
+
+ return 0;
+}
+
+mod_exit_t cleanup_mtdchar(void)
+{
+ unregister_chrdev(MTD_CHAR_MAJOR,"mtd");
+}
+
+#if LINUX_VERSION_CODE > 0x20300
+module_init(init_mtdchar);
+module_exit(cleanup_mtdchar);
+#endif
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
new file mode 100644
index 000000000..bbfc66eaa
--- /dev/null
+++ b/drivers/mtd/mtdcore.c
@@ -0,0 +1,398 @@
+/*
+ * $Id: mtdcore.c,v 1.8 2000/06/27 13:40:05 dwmw2 Exp $
+ *
+ * Core registration and callback routines for MTD
+ * drivers and users.
+ *
+ */
+
+#ifdef MTD_DEBUG
+#define DEBUGLVL debug
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <stdarg.h>
+#include <linux/mtd/compatmac.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
+
+#include <linux/mtd/mtd.h>
+
+#ifdef MTD_DEBUG
+static int debug = MTD_DEBUG;
+MODULE_PARM(debug, "i");
+#endif
+
+/* Init code required for 2.2 kernels */
+
+#if LINUX_VERSION_CODE < 0x20300
+
+#ifdef CONFIG_MTD_DOC1000
+extern int init_doc1000(void);
+#endif
+#ifdef CONFIG_MTD_DOCPROBE
+extern int init_doc(void);
+#endif
+#ifdef CONFIG_MTD_OCTAGON
+extern int init_octagon5066(void);
+#endif
+#ifdef CONFIG_MTD_VMAX
+extern int init_vmax301(void);
+#endif
+#ifdef CONFIG_MTD_MIXMEM
+extern int init_mixmem(void);
+#endif
+#ifdef CONFIG_MTD_PMC551
+extern int init_pmc551(void);
+#endif
+#ifdef CONFIG_MTD_NORA
+extern int init_nora(void);
+#endif
+#ifdef CONFIG_FTL
+extern int init_ftl(void);
+#endif
+#ifdef CONFIG_NFTL
+extern int init_nftl(void);
+#endif
+#ifdef CONFIG_MTD_BLOCK
+extern int init_mtdblock(void);
+#endif
+#ifdef CONFIG_MTD_CHAR
+extern int init_mtdchar(void);
+#endif
+
+#endif /* LINUX_VERSION_CODE < 0x20300 */
+
+
+static DECLARE_MUTEX(mtd_table_mutex);
+
+static struct mtd_info *mtd_table[MAX_MTD_DEVICES];
+
+static struct mtd_notifier *mtd_notifiers = NULL;
+
+
+int add_mtd_device(struct mtd_info *mtd)
+{
+ int i;
+
+ down(&mtd_table_mutex);
+
+ for (i=0; i< MAX_MTD_DEVICES; i++)
+ if (!mtd_table[i])
+ {
+ struct mtd_notifier *not=mtd_notifiers;
+
+ mtd_table[i] = mtd;
+ DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
+ while (not)
+ {
+ (*(not->add))(mtd);
+ not = not->next;
+ }
+ up(&mtd_table_mutex);
+ MOD_INC_USE_COUNT;
+ return 0;
+ }
+
+ up(&mtd_table_mutex);
+ return 1;
+}
+
+
+int del_mtd_device (struct mtd_info *mtd)
+{
+ struct mtd_notifier *not=mtd_notifiers;
+ int i;
+
+ down(&mtd_table_mutex);
+
+ for (i=0; i < MAX_MTD_DEVICES; i++)
+ {
+ if (mtd_table[i] == mtd)
+ {
+ while (not)
+ {
+ (*(not->remove))(mtd);
+ not = not->next;
+ }
+ mtd_table[i] = NULL;
+ up (&mtd_table_mutex);
+ MOD_DEC_USE_COUNT;
+ return 0;
+ }
+ }
+
+ up(&mtd_table_mutex);
+ return 1;
+}
+
+
+
+void register_mtd_user (struct mtd_notifier *new)
+{
+ int i;
+
+ down(&mtd_table_mutex);
+
+ new->next = mtd_notifiers;
+ mtd_notifiers = new;
+
+ MOD_INC_USE_COUNT;
+
+ for (i=0; i< MAX_MTD_DEVICES; i++)
+ if (mtd_table[i])
+ new->add(mtd_table[i]);
+
+ up(&mtd_table_mutex);
+}
+
+
+
+int unregister_mtd_user (struct mtd_notifier *old)
+{
+ struct mtd_notifier **prev = &mtd_notifiers;
+ struct mtd_notifier *cur;
+ int i;
+
+ down(&mtd_table_mutex);
+
+ while ((cur = *prev)) {
+ if (cur == old) {
+ *prev = cur->next;
+
+ MOD_DEC_USE_COUNT;
+
+ for (i=0; i< MAX_MTD_DEVICES; i++)
+ if (mtd_table[i])
+ old->remove(mtd_table[i]);
+
+ up(&mtd_table_mutex);
+ return 0;
+ }
+ prev = &cur->next;
+ }
+ up(&mtd_table_mutex);
+ return 1;
+}
+
+
+/* get_mtd_device():
+ * Prepare to use an MTD device referenced either by number or address.
+ *
+ * If <num> == -1, search the table for an MTD device located at <mtd>.
+ * If <mtd> == NULL, return the MTD device with number <num>.
+ * If both are set, return the MTD device with number <num> _only_ if it
+ * is located at <mtd>.
+ */
+
+struct mtd_info *__get_mtd_device(struct mtd_info *mtd, int num)
+{
+ struct mtd_info *ret = NULL;
+ int i;
+
+ down(&mtd_table_mutex);
+
+ if (num == -1) {
+ for (i=0; i< MAX_MTD_DEVICES; i++)
+ if (mtd_table[i] == mtd)
+ ret = mtd_table[i];
+ } else if (num < MAX_MTD_DEVICES) {
+ ret = mtd_table[num];
+ if (mtd && mtd != ret)
+ ret = NULL;
+ }
+
+ up(&mtd_table_mutex);
+ return ret;
+}
+
+EXPORT_SYMBOL(add_mtd_device);
+EXPORT_SYMBOL(del_mtd_device);
+EXPORT_SYMBOL(__get_mtd_device);
+EXPORT_SYMBOL(register_mtd_user);
+EXPORT_SYMBOL(unregister_mtd_user);
+
+/*====================================================================*/
+/* /proc/mtd support */
+
+#ifdef CONFIG_PROC_FS
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+struct proc_dir_entry *proc_mtd;
+#endif
+
+static inline int mtd_proc_info (char *buf, int i)
+{
+ struct mtd_info *this = mtd_table[i];
+
+ if (!this)
+ return 0;
+
+ return sprintf(buf, "mtd%d: %8.8lx \"%s\"\n", i, this->size,
+ this->name);
+}
+
+static int mtd_read_proc ( char *page, char **start, off_t off,int count
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+ ,int *eof, void *data_unused
+#else
+ ,int unused
+#endif
+ )
+{
+ int len = 0, l, i;
+ off_t begin = 0;
+
+ down(&mtd_table_mutex);
+
+ for (i=0; i< MAX_MTD_DEVICES; i++) {
+
+ l = mtd_proc_info(page + len, i);
+ len += l;
+ if (len+begin > off+count)
+ goto done;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+ *eof = 1;
+#endif
+
+done:
+ up(&mtd_table_mutex);
+ if (off >= len+begin)
+ return 0;
+ *start = page + (begin-off);
+ return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)
+struct proc_dir_entry mtd_proc_entry = {
+ 0, /* low_ino: the inode -- dynamic */
+ 3, "mtd", /* len of name and name */
+ S_IFREG | S_IRUGO, /* mode */
+ 1, 0, 0, /* nlinks, owner, group */
+ 0, NULL, /* size - unused; operations -- use default */
+ &mtd_read_proc, /* function used to read data */
+ /* nothing more */
+ };
+#endif
+
+#endif
+
+/*====================================================================*/
+
+
+#if LINUX_VERSION_CODE < 0x20300
+
+static inline void init_others(void)
+{
+ /* Shedloads of calls to init functions of all the
+ * other drivers and users of MTD, which we can
+ * ditch in 2.3 because of the sexy new way of
+ * finding init routines.
+ */
+#ifdef CONFIG_MTD_DOC1000
+ init_doc1000();
+#endif
+#ifdef CONFIG_MTD_DOCPROBE
+ init_doc(); /* This covers both the DiskOnChip 2000
+ * and the DiskOnChip Millennium.
+ * Theoretically all other DiskOnChip
+ * devices too. */
+#endif
+#ifdef CONFIG_MTD_OCTAGON
+ init_octagon5066();
+#endif
+#ifdef CONFIG_MTD_VMAX
+ init_vmax301();
+#endif
+#ifdef CONFIGF_MTD_MIXMEM
+ init_mixmem();
+#endif
+#ifdef CONFIG_MTD_PMC551
+ init_pmc551();
+#endif
+#ifdef CONFIG_MTD_NORA
+ init_nora();
+#endif
+#ifdef CONFIG_MTD_MTDRAM
+ init_mtdram();
+#endif
+#ifdef CONFIG_FTL
+ init_ftl();
+#endif
+#ifdef CONFIG_NFTL
+ init_nftl();
+#endif
+#ifdef CONFIG_MTD_BLOCK
+ init_mtdblock();
+#endif
+#ifdef CONFIG_MTD_CHAR
+ init_mtdchar();
+#endif
+}
+
+#ifdef MODULE
+#define init_mtd init_module
+#define cleanup_mtd cleanup_module
+#endif
+
+#endif /* LINUX_VERSION_CODE < 0x20300 */
+
+mod_init_t init_mtd(void)
+{
+ int i;
+ DEBUG(1, "INIT_MTD:\n");
+ for (i=0; i<MAX_MTD_DEVICES; i++)
+ mtd_table[i]=NULL;
+
+#ifdef CONFIG_PROC_FS
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+ if ((proc_mtd = create_proc_entry( "mtd", 0, 0 )))
+ proc_mtd->read_proc = mtd_read_proc;
+#else
+ proc_register_dynamic(&proc_root,&mtd_proc_entry);
+#endif
+
+#endif
+
+#if LINUX_VERSION_CODE < 0x20300
+ init_others();
+#endif
+
+ return 0;
+}
+
+mod_exit_t cleanup_mtd(void)
+{
+ unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
+#ifdef CONFIG_PROC_FS
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+ if (proc_mtd)
+ remove_proc_entry( "mtd", 0);
+#else
+ proc_unregister(&proc_root,mtd_proc_entry.low_ino);
+#endif
+#endif
+}
+
+#if LINUX_VERSION_CODE > 0x20300
+module_init(init_mtd);
+module_exit(cleanup_mtd);
+#endif
+
+
diff --git a/drivers/mtd/mtdram.c b/drivers/mtd/mtdram.c
new file mode 100644
index 000000000..674435272
--- /dev/null
+++ b/drivers/mtd/mtdram.c
@@ -0,0 +1,147 @@
+/*
+ * mtdram - a test mtd device
+ * $Id: mtdram.c,v 1.13 2000/07/03 10:01:38 dwmw2 Exp $
+ * Author: Alexander Larsson <alex@cendio.se>
+ *
+ * Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
+ *
+ * This code is GPL
+ *
+ */
+
+#include <linux/module.h>
+
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/mtd/compatmac.h>
+#include <linux/mtd/mtd.h>
+
+
+#define MTDRAM_TOTAL_SIZE 1024*1024*8
+#define MTDRAM_ERASE_SIZE 4*1024
+
+
+// We could store these in the mtd structure, but we only support 1 device..
+static struct mtd_info *mtd_info;
+
+
+static int
+ram_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ if (instr->addr + instr->len > mtd->size)
+ return -EINVAL;
+
+ memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
+
+ instr->state = MTD_ERASE_DONE;
+
+ if (instr->callback)
+ (*(instr->callback))(instr);
+ return 0;
+}
+
+static int ram_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
+{
+ if (from + len > mtd->size)
+ return -EINVAL;
+
+ *mtdbuf = mtd->priv + from;
+ *retlen = len;
+ return 0;
+}
+
+static void ram_unpoint (struct mtd_info *mtd, u_char *addr)
+{
+}
+
+static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ if (from + len > mtd->size)
+ return -EINVAL;
+
+ memcpy(buf, mtd->priv + from, len);
+
+ *retlen=len;
+ return 0;
+}
+
+static int ram_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ if (to + len > mtd->size)
+ return -EINVAL;
+
+ memcpy ((char *)mtd->priv + to, buf, len);
+
+ *retlen=len;
+ return 0;
+}
+
+#if LINUX_VERSION_CODE < 0x20300
+#ifdef MODULE
+#define init_mtdram init_module
+#define cleanup_mtdram cleanup_module
+#endif
+#endif
+
+//static void __exit cleanup_mtdram(void)
+mod_exit_t cleanup_mtdram(void)
+{
+ if (mtd_info) {
+ del_mtd_device(mtd_info);
+ if (mtd_info->priv)
+ vfree(mtd_info->priv);
+ kfree(mtd_info);
+ }
+}
+
+extern struct module __this_module;
+
+mod_init_t init_mtdram(void)
+{
+ // Allocate some memory
+ mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+ if (mtd_info == 0)
+ return 0;
+
+ memset(mtd_info, 0, sizeof(*mtd_info));
+
+ // Setup the MTD structure
+ mtd_info->name = "mtdram test device";
+ mtd_info->type = MTD_RAM;
+ mtd_info->flags = MTD_CAP_RAM;
+ mtd_info->size = MTDRAM_TOTAL_SIZE;
+ mtd_info->erasesize = MTDRAM_ERASE_SIZE;
+ mtd_info->priv = vmalloc(MTDRAM_TOTAL_SIZE);
+ memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+ mtd_info->module = THIS_MODULE;
+#endif
+
+ if (!mtd_info->priv) {
+ kfree(mtd_info);
+ mtd_info = NULL;
+ return -ENOMEM;
+ }
+ mtd_info->erase = ram_erase;
+ mtd_info->point = ram_point;
+ mtd_info->unpoint = ram_unpoint;
+ mtd_info->read = ram_read;
+ mtd_info->write = ram_write;
+
+ if (add_mtd_device(mtd_info)) {
+ vfree(mtd_info->priv);
+ kfree(mtd_info);
+ mtd_info = NULL;
+ return -EIO;
+ }
+
+ return 0;
+}
+
+#if LINUX_VERSION_CODE > 0x20300
+module_init(init_mtdram);
+module_exit(cleanup_mtdram);
+#endif
diff --git a/drivers/mtd/nftl.c b/drivers/mtd/nftl.c
new file mode 100644
index 000000000..083b1219e
--- /dev/null
+++ b/drivers/mtd/nftl.c
@@ -0,0 +1,1317 @@
+
+/* Linux driver for NAND Flash Translation Layer */
+/* (c) 1999 Machine Vision Holdings, Inc. */
+/* Author: David Woodhouse <dwmw2@infradead.org */
+/* $Id: nftl.c,v 1.34 2000/06/07 14:48:52 dwmw2 Exp $ */
+
+/*
+ LEGAL NOTE: The NFTL format is patented by M-Systems. They have
+ granted a licence for its use with their DiskOnChip products:
+
+ "M-Systems grants a royalty-free, non-exclusive license under
+ any presently existing M-Systems intellectual property rights
+ necessary for the design and development of NFTL-compatible
+ drivers, file systems and utilities to use the data formats with,
+ and solely to support, M-Systems' DiskOnChip products"
+
+ A signed copy of this agreement from M-Systems is kept on file by
+ Red Hat UK Limited. In the unlikely event that you need access to it,
+ please contact dwmw2@redhat.com for assistance.
+*/
+
+#define PRERELEASE
+
+#ifdef NFTL_DEBUG
+#define DEBUGLVL debug
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nftl.h>
+#include <linux/mtd/compatmac.h>
+
+#undef WE_KNOW_WTF_THIS_DOES_NOT_WORK
+
+/* NFTL block device stuff */
+#define MAJOR_NR NFTL_MAJOR
+#define DEVICE_REQUEST nftl_request
+#define DEVICE_OFF(device)
+#ifdef WE_KNOW_WTF_THIS_DOES_NOT_WORK
+#define LOCAL_END_REQUEST
+#endif
+#include <linux/blk.h>
+#include <linux/hdreg.h>
+
+
+#ifdef WE_KNOW_WTF_THIS_DOES_NOT_WORK
+
+static void nftl_end_request(struct request *req, int res)
+{
+ req->sector += req->current_nr_sectors;
+ req->nr_sectors -= req->current_nr_sectors;
+
+ if (end_that_request_first( req, res, "nftl" ))
+ return;
+ end_that_request_last( req );
+}
+#endif
+
+#ifdef NFTL_DEBUG
+static int debug = NFTL_DEBUG;
+MODULE_PARM(debug, "i");
+#endif
+
+
+
+/* Linux-specific block device functions */
+
+/* I _HATE_ the Linux block device setup more than anything else I've ever
+ * encountered, except ...
+ */
+
+static int nftl_sizes[256]={0,};
+static int nftl_blocksizes[256] = {0,};
+
+/* .. for the Linux partition table handling. */
+
+struct hd_struct part_table[256] = {{0,0},};
+
+#if LINUX_VERSION_CODE < 0x20328
+static void dummy_init (struct gendisk *crap)
+{}
+#endif
+
+static struct gendisk nftl_gendisk = {
+ NFTL_MAJOR, /* Major number */
+ "nftl", /* Major name */
+ 4, /* Bits to shift to get real from partition */
+ 15, /* Number of partitions per real */
+#if LINUX_VERSION_CODE < 0x20328
+ MAX_NFTLS, /* maximum number of real */
+ dummy_init, /* init function */
+#endif
+ part_table, /* hd struct */
+ nftl_sizes, /* block sizes */
+ 0, /* number */
+ NULL, /* internal use, not presently used */
+ NULL /* next */
+};
+
+
+struct NFTLrecord *NFTLs[MAX_NFTLS] = {NULL};
+
+static void NFTL_setup(struct mtd_info *mtd, unsigned long ofs,
+ struct NFTLMediaHeader *hdr)
+{
+ int i;
+ struct NFTLrecord *thisNFTL;
+ unsigned long temp;
+ int firstfree = -1;
+
+ DEBUG(1,"NFTL_setup\n");
+
+ for (i=0; i < MAX_NFTLS; i++) {
+ if (!NFTLs[i] && firstfree==-1)
+ firstfree = i;
+ else if (NFTLs[i] && NFTLs[i]->mtd == mtd &&
+ NFTLs[i]->MediaHdr.FirstPhysicalEUN == hdr->FirstPhysicalEUN) {
+ /* This is a Spare Media Header for an NFTL we've already found */
+ DEBUG(1, "Spare Media Header for NFTL %d found at %lx\n",i, ofs);
+ NFTLs[i]->SpareMediaUnit = ofs / mtd->erasesize;
+ return;
+ }
+ }
+
+
+ /* OK, it's a new one. Set up all the data structures. */
+#ifdef PSYCHO_DEBUG
+ printk("Found new NFTL nftl%c at offset %lx\n",firstfree + 'a', ofs);
+#endif
+ if (hdr->UnitSizeFactor != 0xff) {
+ printk("Sorry, we don't support UnitSizeFactor of != 1 yet\n");
+ return;
+ }
+
+ thisNFTL = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
+ if (!thisNFTL) {
+ printk(KERN_WARNING "Out of memory for NFTL data structures\n");
+ return;
+ }
+ init_MUTEX(&thisNFTL->mutex);
+ thisNFTL->EraseSize = mtd->erasesize;
+ memcpy(&thisNFTL->MediaHdr, hdr, sizeof(*hdr));
+ thisNFTL->mtd = mtd;
+ thisNFTL->MediaUnit = ofs / mtd->erasesize;
+ thisNFTL->SpareMediaUnit = 0xffff;
+ thisNFTL->numvunits = le32_to_cpu(thisNFTL->MediaHdr.FormattedSize) / 8192;
+ thisNFTL->nr_sects = thisNFTL->numvunits * (thisNFTL->EraseSize / 512);
+ thisNFTL->usecount = 0;
+
+ thisNFTL->cylinders = 1024;
+ thisNFTL->heads = 16;
+
+ temp = thisNFTL->cylinders * thisNFTL->heads;
+ thisNFTL->sectors = thisNFTL->nr_sects / temp;
+
+ if (thisNFTL->nr_sects % temp) {
+
+ thisNFTL->sectors++;
+ temp = thisNFTL->cylinders * thisNFTL->sectors;
+ thisNFTL->heads = thisNFTL->nr_sects / temp;
+
+ if (thisNFTL->nr_sects & temp) {
+ thisNFTL->heads++;
+ temp = thisNFTL->heads * thisNFTL->sectors;
+
+ thisNFTL->cylinders = thisNFTL->nr_sects / temp;
+ }
+ }
+ if (thisNFTL->nr_sects != thisNFTL->heads * thisNFTL->cylinders *
+ thisNFTL->sectors) {
+ printk(KERN_WARNING "Cannot calculate an NFTL geometry to match size of 0x%lx.\n", thisNFTL->nr_sects);
+ printk(KERN_WARNING "Using C:%d H:%d S:%d (== %lx sects)\n",
+ thisNFTL->cylinders, thisNFTL->heads ,
+ thisNFTL->sectors,
+ (long)thisNFTL->cylinders * (long)thisNFTL->heads *
+ (long)thisNFTL->sectors );
+
+ /* Oh no we don't
+ * thisNFTL->nr_sects = thisNFTL->heads * thisNFTL->cylinders * thisNFTL->sectors;
+ */
+ }
+
+
+ thisNFTL->EUNtable = kmalloc( 2 * thisNFTL->numvunits,
+ GFP_KERNEL);
+ if (!thisNFTL->EUNtable) {
+ printk("ENOMEM\n");
+ kfree(thisNFTL);
+ return;
+ }
+ memset(thisNFTL->EUNtable, 0xff, 2 * thisNFTL->numvunits);
+
+ thisNFTL->VirtualUnitTable = kmalloc( 2 * le16_to_cpu(thisNFTL->MediaHdr.NumEraseUnits) , GFP_KERNEL);
+ if (!thisNFTL->VirtualUnitTable) {
+ printk("ENOMEM\n");
+ kfree(thisNFTL->EUNtable);
+ kfree(thisNFTL);
+ return;
+ }
+ memset(thisNFTL->VirtualUnitTable, 0xff, 2 * le16_to_cpu(thisNFTL->MediaHdr.NumEraseUnits));
+
+ thisNFTL->ReplUnitTable = kmalloc( 2 * le16_to_cpu(thisNFTL->MediaHdr.NumEraseUnits) , GFP_KERNEL);
+ if (!thisNFTL->ReplUnitTable) {
+ printk("ENOMEM\n");
+ kfree(thisNFTL->VirtualUnitTable);
+ kfree(thisNFTL->EUNtable);
+ kfree(thisNFTL);
+ return;
+ }
+ memset(thisNFTL->ReplUnitTable, 0xff, 2 *le16_to_cpu(thisNFTL->MediaHdr.NumEraseUnits) );
+
+ /* Ought to check the media header for bad blocks */
+ thisNFTL->lastEUN = le16_to_cpu(thisNFTL->MediaHdr.NumEraseUnits) +
+ le16_to_cpu(thisNFTL->MediaHdr.FirstPhysicalEUN) - 1;
+ thisNFTL->numfreeEUNs = 0;
+
+ /* Scan each physical Erase Unit for validity and to find the
+ Virtual Erase Unit Chain to which it belongs */
+
+ for (i=le16_to_cpu(thisNFTL->MediaHdr.FirstPhysicalEUN);
+ i <= thisNFTL->lastEUN; i++) {
+
+ union nftl_uci uci;
+ unsigned long ofs;
+ size_t retlen;
+ ofs = i * thisNFTL->EraseSize;
+
+ MTD_READOOB(mtd, (i * thisNFTL->EraseSize) + 512 + 8, 8, &retlen, (char *)&uci);
+
+ if (uci.b.EraseMark != cpu_to_le16(0x3c69) ||
+ uci.b.EraseMark1 != cpu_to_le16(0x3c69)) {
+ printk("EUN %d: EraseMark not 0x3c69 (0x%4.4x 0x%4.4x instead)\n",
+ i, le16_to_cpu(uci.b.EraseMark), le16_to_cpu(uci.b.EraseMark1));
+ thisNFTL->VirtualUnitTable[i] = 0x7fff;
+ thisNFTL->ReplUnitTable[i] = 0xffff;
+ continue;
+ }
+
+ MTD_READOOB(mtd, (i * thisNFTL->EraseSize) + 8, 8, &retlen, (u_char *)&uci);
+
+ if (uci.a.VirtUnitNum != uci.a.SpareVirtUnitNum)
+ printk("EUN %d: VirtualUnitNumber (%x) != SpareVirtualUnitNumber (%x)\n",
+ i, le16_to_cpu(uci.a.VirtUnitNum),
+ le16_to_cpu(uci.a.SpareVirtUnitNum));
+
+ if (uci.a.ReplUnitNum != uci.a.SpareReplUnitNum)
+ printk("EUN %d: ReplacementUnitNumber (%x) != SpareReplacementUnitNumber (%x)\n",
+ i, le16_to_cpu(uci.a.ReplUnitNum),
+ le16_to_cpu(uci.a.SpareReplUnitNum));
+
+ /* We don't actually _do_ anything about the above, just whinge */
+
+ thisNFTL->VirtualUnitTable[i] = le16_to_cpu(uci.a.VirtUnitNum);
+ thisNFTL->ReplUnitTable[i] = le16_to_cpu(uci.a.ReplUnitNum);
+
+ /* if (!(VUN & 0x8000) && VUN < (arraybounds)).. optimises to: */
+ if (le16_to_cpu(uci.a.VirtUnitNum) < thisNFTL->numvunits)
+ thisNFTL->EUNtable[le16_to_cpu(uci.a.VirtUnitNum) & 0x7fff] = i;
+
+ if (uci.a.VirtUnitNum == 0xffff) {
+ /* Free block */
+ thisNFTL->LastFreeEUN = i;
+ thisNFTL->numfreeEUNs++;
+ }
+
+ }
+ NFTLs[firstfree] = thisNFTL;
+ thisNFTL->LastFreeEUN = le16_to_cpu(thisNFTL->MediaHdr.FirstPhysicalEUN);
+
+ //#define PSYCHO_DEBUG
+#ifdef PSYCHO_DEBUG
+ for (i=0; i < 10/* thisNFTL->numvunits*/; i++) {
+ u16 curEUN = thisNFTL->EUNtable[i];
+ int sillycount=100;
+
+ printk("Virtual Unit #%d: ",i);
+ if (!curEUN || curEUN == 0xffff) {
+ printk("Not present\n");
+ continue;
+ }
+ printk("%d", curEUN);
+
+ while ((curEUN = thisNFTL->ReplUnitTable[curEUN]) != 0xffff && --sillycount) {
+ printk(", %d", curEUN & 0xffff);
+
+ }
+ printk("\n");
+ }
+#endif
+
+ /* OK. Now we deal with the fact that we're in the real world. Sometimes
+ things don't actually happen the way they're supposed to. Find, fix,
+ and whinge about the most common deviations from spec that we have
+ been known to encounter.
+ */
+ /* Except that I haven't implemented that bit yet :) */
+
+ /* Finally, set up the block device sizes */
+ nftl_sizes[firstfree * 16]=thisNFTL->nr_sects;
+// nftl_blocksizes[firstfree*16] = 512;
+ part_table[firstfree * 16].nr_sects = thisNFTL->nr_sects;
+#if LINUX_VERSION_CODE < 0x20328
+ resetup_one_dev(&nftl_gendisk, firstfree);
+#else
+ grok_partitions(&nftl_gendisk, firstfree, 1<<4, thisNFTL->nr_sects);
+#endif
+
+}
+
+
+static void NFTL_unsetup(int i)
+{
+ struct NFTLrecord *thisNFTL = NFTLs[i];
+
+ DEBUG(1, "NFTL_unsetup %d\n", i);
+
+ NFTLs[i] = NULL;
+
+ if (thisNFTL->VirtualUnitTable)
+ kfree(thisNFTL->VirtualUnitTable);
+ if (thisNFTL->ReplUnitTable)
+ kfree(thisNFTL->ReplUnitTable);
+ if (thisNFTL->EUNtable)
+ kfree(thisNFTL->EUNtable);
+
+ kfree(thisNFTL);
+}
+
+
+
+
+/* Search the MTD device for NFTL partitions */
+static void NFTL_notify_add(struct mtd_info *mtd)
+{
+ int i;
+ unsigned long ofs;
+ struct NFTLMediaHeader hdr;
+
+ DEBUG(1, "NFTL_notify_add for %s\n", mtd->name);
+
+ if (mtd) {
+ if (!mtd->read_oob) /* If this MTD doesn't have out-of-band data,
+ then there's no point continuing */
+ {
+ DEBUG(1, "No OOB data, quitting\n");
+ return;
+ }
+ DEBUG(3, "mtd->read = %p,size = %d, erasesize = %d\n",
+ mtd->read, mtd->size, mtd->erasesize);
+ for (ofs = 0; ofs < mtd->size ; ofs += mtd->erasesize) {
+ size_t retlen = 0;
+ MTD_READ(mtd, ofs, sizeof(hdr), &retlen, (u_char *)&hdr);
+
+ if (retlen < sizeof(hdr))
+ {
+ continue;
+ }
+
+ if (!strncmp(hdr.DataOrgID, "ANAND", 6)) {
+ DEBUG(2, "Valid NFTL partition at ofs %ld\n", ofs);
+ NFTL_setup(mtd, ofs, &hdr);
+ }
+ else {
+ DEBUG(3,"No valid NFTL Partition at ofs %d\n", ofs);
+ for(i = 0; i < 6; i++) {
+ DEBUG(3,"%x, ", hdr.DataOrgID[i]);
+ }
+ DEBUG(3," = %s\n", hdr.DataOrgID);
+ DEBUG(3,"%d, %d, %d, %d\n", hdr.NumEraseUnits, hdr.FirstPhysicalEUN,
+ hdr.FormattedSize, hdr.UnitSizeFactor);
+
+ }
+ }
+ return;
+ }
+}
+
+static void NFTL_notify_remove(struct mtd_info *mtd)
+{
+ int i;
+
+ for (i=0; i< MAX_NFTLS; i++) {
+ if (NFTLs[i] && NFTLs[i]->mtd == mtd)
+ NFTL_unsetup(i);
+ }
+}
+
+
+#ifdef CONFIG_NFTL_RW
+
+/* Actual NFTL access routines */
+
+
+static u16 NFTL_findfreeblock( struct NFTLrecord *thisNFTL, int desperate )
+{
+ /* For a given Virtual Unit Chain: find or create a free block and
+ add it to the chain */
+ /* We're passed the number of the last EUN in the chain, to save us from
+ having to look it up again */
+
+ u16 pot = thisNFTL->LastFreeEUN;
+ int silly = -1;
+
+ /* Normally, we force a fold to happen before we run out of free blocks completely */
+
+ if (!desperate && thisNFTL->numfreeEUNs < 2) {
+ // printk("NFTL_findfreeblock: there are too few free EUNs\n");
+ return 0xffff;
+ }
+
+ /* Scan for a free block */
+
+ do {
+ if (thisNFTL->VirtualUnitTable[pot] == 0xffff) {
+ thisNFTL->LastFreeEUN = pot;
+ thisNFTL->numfreeEUNs--;
+ return pot;
+ }
+
+ if (++pot > thisNFTL->lastEUN)
+ pot = le16_to_cpu(thisNFTL->MediaHdr.FirstPhysicalEUN);
+
+ if (!silly--) {
+ printk("Tell Dave he fucked up. LastFreeEUN = %d, FirstEUN = %d\n",
+ thisNFTL->LastFreeEUN, le16_to_cpu(thisNFTL->MediaHdr.FirstPhysicalEUN));
+ return 0xffff;
+ }
+
+ } while (pot != thisNFTL->LastFreeEUN);
+
+ return 0xffff;
+}
+
+
+
+
+
+static u16 NFTL_foldchain (struct NFTLrecord *thisNFTL, u16 thisVUC, unsigned pendingblock )
+{
+ u16 BlockMap[thisNFTL->EraseSize / 512];
+ unsigned char BlockLastState[thisNFTL->EraseSize / 512];
+ unsigned char BlockFreeFound[thisNFTL->EraseSize / 512];
+ u16 thisEUN;
+ int block;
+ int silly = -1;
+ u16 targetEUN = 0xffff;
+ struct nftl_oob oob;
+ int inplace = 1;
+
+ memset(BlockMap, 0xff, sizeof(BlockMap));
+ memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
+
+ thisEUN = thisNFTL->EUNtable[thisVUC];
+
+ if (thisEUN == 0xffff) {
+ printk(KERN_WARNING "Trying to fold non-existent Virtual Unit Chain %d!\n", thisVUC);
+ return 0xffff;
+ }
+
+ /* Scan to find the Erase Unit which holds the actual data for each
+ 512-byte block within the Chain.
+ */
+
+ while( thisEUN <= thisNFTL->lastEUN ) {
+ size_t retlen;
+
+ targetEUN = thisEUN;
+
+ for (block = 0 ; block < thisNFTL->EraseSize / 512; block ++) {
+
+ MTD_READOOB(thisNFTL->mtd, (thisEUN * thisNFTL->EraseSize) + (block * 512),16 , &retlen, (char *)&oob);
+
+ if (block == 2) {
+ if (oob.u.c.WriteInh != 0xffffffff) {
+ printk("Write Inhibited on EUN %d\n", thisEUN);
+ inplace = 0;
+ } else {
+ /* There's no other reason not to do inplace,
+ except ones that come later. So we don't need
+ to preserve inplace */
+ inplace = 1;
+ }
+ }
+
+ BlockLastState[block] = (unsigned char) oob.b.Status & 0xff;
+
+ switch(oob.b.Status) {
+ case __constant_cpu_to_le16(BLOCK_FREE):
+ BlockFreeFound[block]=1;
+ break;
+
+ case __constant_cpu_to_le16(BLOCK_USED):
+ if (!BlockFreeFound[block])
+ BlockMap[block] = thisEUN;
+ else
+ printk(KERN_WARNING "BLOCK_USED found after BLOCK_FREE in Virtual Unit Chain %d for block %d\n", thisVUC, block);
+ break;
+ case __constant_cpu_to_le16(BLOCK_IGNORE):
+ case __constant_cpu_to_le16(BLOCK_DELETED):
+ break;
+ default:
+ printk("Unknown status for block %d in EUN %d: %x\n",block,thisEUN, oob.b.Status);
+ }
+ }
+
+ if (!silly--) {
+ printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n", thisVUC);
+ return 0xffff;
+ }
+
+ thisEUN = thisNFTL->ReplUnitTable[thisEUN] & 0x7fff;
+ }
+
+ if (inplace) {
+ /* We're being asked to be a fold-in-place. Check
+ that all blocks are either present or BLOCK_FREE
+ in the target block. If not, we're going to have
+ to fold out-of-place anyway.
+ */
+
+ for (block = 0; block < thisNFTL->EraseSize / 512 ; block++) {
+
+ if (BlockLastState[block] != (unsigned char) (cpu_to_le16(BLOCK_FREE) & 0xff) &&
+ BlockMap[block] != targetEUN) {
+ DEBUG(1, "Setting inplace to 0. VUC %d, block %d was %x lastEUN, and is in EUN %d (%s) %d\n",
+ thisVUC, block, BlockLastState[block], BlockMap[block] , BlockMap[block]==targetEUN?"==":"!=", targetEUN);
+
+ inplace = 0;
+ break;
+ }
+ }
+
+ if ( pendingblock >= (thisVUC * (thisNFTL->EraseSize / 512)) &&
+ pendingblock < ((thisVUC + 1)* (thisNFTL->EraseSize / 512)) &&
+ BlockLastState[ pendingblock - (thisVUC * (thisNFTL->EraseSize / 512))] !=
+ (unsigned char) (cpu_to_le16(BLOCK_FREE) & 0xff)) {
+ DEBUG(1, "Pending write not free in EUN %d. Folding out of place.\n", targetEUN);
+ inplace = 0;
+ }
+
+ }
+
+ if (!inplace) {
+ DEBUG(1, "Cannot fold Virtual Unit Chain %d in place. Trying out-of-place\n", thisVUC);
+ /* We need to find a targetEUN to fold into. */
+ targetEUN = NFTL_findfreeblock(thisNFTL, 1);
+ if (targetEUN == 0xffff) {
+ /* Ouch. Now we're screwed. We need to do a
+ fold-in-place of another chain to make room
+ for this one. We need a better way of selecting
+ which chain to fold, because makefreeblock will
+ only ask us to fold the same one again.
+ */
+ printk(KERN_WARNING"NFTL_findfreeblock(desperate) returns 0xffff.\n");
+ return 0xffff;
+ }
+
+ }
+
+
+ /* OK. We now know the location of every block in the Virtual Unit Chain,
+ and the Erase Unit into which we are supposed to be copying.
+ Go for it.
+ */
+
+ DEBUG(1,"Folding chain %d into unit %d\n", thisVUC, targetEUN);
+
+ for (block = 0; block < thisNFTL->EraseSize / 512 ; block++) {
+ unsigned char movebuf[512];
+ struct nftl_oob oob;
+ size_t retlen;
+
+ memset(&oob, 0xff, sizeof(oob));
+
+ /* If it's in the target EUN already, or if it's pending write, do nothing */
+ if (BlockMap[block] == targetEUN ||(pendingblock == (thisVUC * (thisNFTL->EraseSize / 512) + block))) {
+ /* Except if it's the first block, in which case we have to
+ set the UnitNumbers */
+ if (block == 0) {
+
+ thisNFTL->mtd->read_oob(thisNFTL->mtd, (thisNFTL->EraseSize * targetEUN) ,
+ 16, &retlen, (char *)&oob);
+
+ // printk("Setting VirtUnitNum on EUN %d to %x, was %x\n", targetEUN, thisVUC,
+ // le16_to_cpu(oob.u.a.VirtUnitNum));
+
+ oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC & 0x7fff);
+
+ thisNFTL->mtd->write_oob(thisNFTL->mtd, (thisNFTL->EraseSize * targetEUN) ,
+ 16, &retlen, (char *)&oob);
+ }
+ continue;
+ }
+
+ oob.b.Status = BLOCK_USED;
+
+ switch(block) {
+ case 0:
+ oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC & 0x7fff);
+ // printk("Setting VirtUnitNum on EUN %d to %x\n", targetEUN, thisVUC);
+
+ oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
+ break;
+
+ case 1:
+ oob.u.b.WearInfo = cpu_to_le32(3); // We don't use this, but M-Systems' drivers do
+ oob.u.b.EraseMark = oob.u.b.EraseMark1 = cpu_to_le16(0x3c69);
+ break;
+
+ case 2:
+ default:
+ oob.u.c.WriteInh = 0xffffffff;
+ oob.u.c.unused = 0xffffffff;
+ }
+ if (thisNFTL->mtd->read_ecc(thisNFTL->mtd, (thisNFTL->EraseSize * BlockMap[block]) + (block * 512),
+ 512, &retlen, movebuf, (char *)&oob) == -EIO) {
+ if (thisNFTL->mtd->read_ecc(thisNFTL->mtd, (thisNFTL->EraseSize * BlockMap[block]) + (block * 512),
+ 512, &retlen, movebuf, (char *)&oob) != -EIO)
+ printk("Error went away on retry.\n");
+ }
+
+ thisNFTL->mtd->write_ecc(thisNFTL->mtd, (thisNFTL->EraseSize * targetEUN) + (block * 512),
+ 512, &retlen, movebuf, (char *)&oob);
+
+
+ /* FIXME: Add some error checking.... */
+ thisNFTL->mtd->write_oob(thisNFTL->mtd, (thisNFTL->EraseSize * targetEUN) + (block * 512),
+ 16, &retlen, (char *)&oob);
+
+ }
+
+ /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
+
+ /* At this point, we have two different chains for this Virtual Unit, and no way to tell
+ them apart. If we crash now, we get confused. However, both contain the same data, so we
+ shouldn't actually lose data in this case. It's just that when we load up on a medium which
+ has duplicate chains, we need to free one of the chains because it's not necessary any more.
+ */
+
+
+ thisEUN = thisNFTL->EUNtable[thisVUC];
+
+ DEBUG(1,"Want to erase\n");
+ /* For each block in the old chain (except the targetEUN of course),
+ free it and make it available for future use */
+
+ while( thisEUN <= thisNFTL->lastEUN && thisEUN != targetEUN) {
+ size_t retlen;
+ struct erase_info *instr;
+ u16 EUNtmp;
+
+ instr = kmalloc(sizeof(struct erase_info), GFP_KERNEL);
+ if (!instr) {
+ printk(KERN_WARNING "Out of memory for struct erase_info\n");
+
+ EUNtmp = thisEUN;
+
+ thisEUN = thisNFTL->ReplUnitTable[EUNtmp] & 0x7fff;
+ thisNFTL->VirtualUnitTable[EUNtmp] = 0x7fff;
+ thisNFTL->ReplUnitTable[EUNtmp] = 0xffff;
+ } else {
+ memset(instr, 0, sizeof(struct erase_info));
+ instr->addr = thisEUN * thisNFTL->EraseSize;
+ instr->len = thisNFTL->EraseSize;
+
+ MTD_ERASE(thisNFTL->mtd, instr);
+ /* This is an async interface. Or will be. At which point
+ this code will break. */
+
+#if 0
+ MTD_READOOB(thisNFTL->mtd, (thisEUN * thisNFTL->EraseSize) + 512, 16, &retlen, (char *)&oob);
+
+ printk("After erasing, EUN %d contains: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+ thisEUN, oob.b.ECCSig[0],
+ oob.b.ECCSig[1],
+ oob.b.ECCSig[2],
+ oob.b.ECCSig[3],
+ oob.b.ECCSig[4],
+ oob.b.ECCSig[5]);
+#endif
+ memset(&oob, 0xff, sizeof(oob));
+ oob.u.b.WearInfo = cpu_to_le32(3);
+ oob.u.b.EraseMark = oob.u.b.EraseMark1 = cpu_to_le16(0x3c69);
+
+ MTD_WRITEOOB(thisNFTL->mtd, (thisEUN * thisNFTL->EraseSize) + 512, 16, &retlen, (char *)&oob);
+
+ EUNtmp = thisEUN;
+
+ thisEUN = thisNFTL->ReplUnitTable[EUNtmp] & 0x7fff;
+ thisNFTL->VirtualUnitTable[EUNtmp] = 0xffff;
+ thisNFTL->ReplUnitTable[EUNtmp] = 0xffff;
+
+ thisNFTL->numfreeEUNs++;
+
+ }
+
+ // shifted upwards: thisEUN = thisNFTL->ReplUnitTable[thisEUN] & 0x7fff;
+
+ }
+
+ /* Make this the new start of chain for thisVUC */
+ thisNFTL->VirtualUnitTable[targetEUN] = thisVUC;
+ thisNFTL->ReplUnitTable[targetEUN] = 0xffff;
+
+ thisNFTL->EUNtable[thisVUC] = targetEUN;
+ return targetEUN;
+
+}
+
+u16 NFTL_makefreeblock( struct NFTLrecord *thisNFTL , unsigned pendingblock)
+{
+ /* This is the part that needs some cleverness applied.
+ For now, I'm doing the minimum applicable to actually
+ get the thing to work.
+ Wear-levelling and other clever stuff needs to be implemented
+ and we also need to do some assessment of the results when
+ the system loses power half-way through the routine.
+ */
+
+ u16 LongestChain = 0;
+ u16 ChainLength = 0, thislen;
+ u16 chain, EUN;
+
+
+ for (chain=0; chain < thisNFTL->MediaHdr.FormattedSize / thisNFTL->EraseSize; chain++) {
+ EUN = thisNFTL->EUNtable[chain];
+
+ thislen = 0;
+
+ while (EUN <= thisNFTL->lastEUN) {
+ thislen++;
+ // printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN);
+ EUN = thisNFTL->ReplUnitTable[EUN] & 0x7fff;
+ if (thislen > 0xff00) {
+ printk("Endless loop in Virtual Chain %d: Unit %x\n", chain, EUN);
+ }
+ if (thislen > 0xff10) {
+ /* Actually, don't return failure. Just ignore this chain and
+ get on with it. */
+ thislen = 0;
+ break;
+ }
+
+ }
+
+
+ if (thislen > ChainLength) {
+ // printk("New longest chain is %d with length %d\n", chain, thislen);
+ ChainLength = thislen;
+ LongestChain = chain;
+ }
+ }
+
+ if (ChainLength < 2) {
+ printk(KERN_WARNING "No Virtual Unit Chains available for folding. Failing request\n");
+ return 0xffff;
+ }
+
+ return NFTL_foldchain (thisNFTL, LongestChain, pendingblock);
+}
+
+/* NFTL_findwriteunit: Return the unit number into which we can write
+ for this block. Make it available if it isn't already
+*/
+
+static inline u16 NFTL_findwriteunit(struct NFTLrecord *thisNFTL, unsigned block)
+{
+ u16 lastEUN;
+ u16 thisVUC = block / (thisNFTL->EraseSize / 512);
+ u16 writeEUN;
+ unsigned long blockofs = (block * 512) & (thisNFTL->EraseSize -1);
+ size_t retlen;
+ int silly = 0x10000, silly2 = 3;
+ struct nftl_oob oob;
+ int debug=0;
+
+ do {
+
+ /* Scan the media to find a unit in the VUC which has
+ a free space for the block in question.
+ */
+
+ /* This condition catches the 0x[7f]fff cases, as well as
+ being a sanity check for past-end-of-media access
+ */
+ lastEUN = 0xffff;
+ writeEUN = thisNFTL->EUNtable[thisVUC];
+
+ while(writeEUN <= thisNFTL->lastEUN) {
+ struct nftl_bci bci;
+ size_t retlen;
+
+ lastEUN = writeEUN;
+
+ MTD_READOOB(thisNFTL->mtd, (writeEUN * thisNFTL->EraseSize)
+ + blockofs,8, &retlen, (char *)&bci);
+
+ if (debug)
+ printk("Status of block %d in EUN %d is %x\n", block , writeEUN, le16_to_cpu(bci.Status));
+
+ switch(bci.Status) {
+ case __constant_cpu_to_le16(BLOCK_FREE):
+ return writeEUN;
+
+ case __constant_cpu_to_le16(BLOCK_DELETED):
+ case __constant_cpu_to_le16(BLOCK_USED):
+ case __constant_cpu_to_le16(BLOCK_IGNORE):
+ break;
+ default:
+ // Invalid block. Don't use it any more. Must implement.
+ break;
+ }
+
+ if (!silly--) {
+ printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n", thisVUC);
+ return 0xffff;
+ }
+
+ /* Skip to next block in chain */
+
+ writeEUN = thisNFTL->ReplUnitTable[writeEUN] & 0x7fff;
+ }
+
+ /* OK. We didn't find one in the existing chain, or there
+ is no existing chain. */
+
+ /* Try to find an already-free block */
+
+ writeEUN = NFTL_findfreeblock(thisNFTL, 0);
+
+ if (writeEUN == 0xffff) {
+ /* That didn't work - there were no free blocks just
+ waiting to be picked up. We're going to have to fold
+ a chain to make room.
+ */
+
+ /* First remember the start of this chain */
+ // u16 startEUN = thisNFTL->EUNtable[thisVUC];
+
+ //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
+ writeEUN = NFTL_makefreeblock(thisNFTL, block);
+
+ if (writeEUN == 0xffff) {
+ /* Ouch. This should never happen - we should
+ always be able to make some room somehow.
+ If we get here, we've allocated more storage
+ space than actual media, or our makefreeblock
+ routine is missing something.
+ */
+ printk(KERN_WARNING "Cannot make free space.\n");
+ return 0xffff;
+ }
+ // printk("Restarting scan\n");
+ lastEUN = 0xffff;
+ // debug = 1;
+ continue;
+#if 0
+ if (startEUN != thisNFTL->EUNtable[thisVUC]) {
+ /* The fold operation has moved the chain
+ that we're looking at. Start the scan again.
+ */
+ continue;
+ }
+#endif
+ }
+
+ /* We've found a free block. Insert it into the chain. */
+
+ if (lastEUN != 0xffff) {
+ /* Addition to an existing chain. Make the previous
+ last block in the chain point to this one.
+ */
+
+ //printk("Linking EUN %d to EUN %d in VUC %d\n",
+ // lastEUN, writeEUN, thisVUC);
+ /* Both in our cache... */
+ thisNFTL->ReplUnitTable[lastEUN] = writeEUN;
+
+
+ /* ... and on the flash itself */
+ MTD_READOOB(thisNFTL->mtd, (lastEUN * thisNFTL->EraseSize), 16, &retlen,
+ (char *)&oob);
+
+ oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = cpu_to_le16(writeEUN);
+
+ MTD_WRITEOOB(thisNFTL->mtd, (lastEUN * thisNFTL->EraseSize), 16, &retlen,
+ (char *)&oob);
+
+ thisVUC |= 0x8000; /* It's a replacement block */
+ } else {
+ /* The first block in a new chain */
+ thisNFTL->EUNtable[thisVUC] = writeEUN;
+ }
+
+ /* Now set up the actual EUN we're writing into */
+
+ /* Both in our cache... */
+ thisNFTL->VirtualUnitTable[writeEUN] = thisVUC;
+ thisNFTL->ReplUnitTable[writeEUN] = 0xffff;
+
+ /* ... and on the flash itself */
+ MTD_READOOB(thisNFTL->mtd, writeEUN * thisNFTL->EraseSize, 16,
+ &retlen, (char *)&oob);
+
+ oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
+
+ MTD_WRITEOOB(thisNFTL->mtd, writeEUN * thisNFTL->EraseSize, 16,
+ &retlen, (char *)&oob);
+
+ return writeEUN;
+
+ } while (silly2--);
+
+ printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n", thisVUC);
+ return 0xffff;
+}
+
+static int NFTL_writeblock(struct NFTLrecord *thisNFTL, unsigned block,
+ char *buffer)
+{
+ u16 writeEUN;
+ unsigned long blockofs = (block * 512) & (thisNFTL->EraseSize -1);
+ size_t retlen;
+ u16 eccbuf[8];
+
+ // if (thisEUN == 0xffff) thisEUN = 0;
+
+ writeEUN = NFTL_findwriteunit(thisNFTL, block);
+
+// printk("writeblock(%d): Write to Unit %d\n", block, writeEUN);
+
+ if (writeEUN == 0xffff) {
+ printk(KERN_WARNING "NFTL_writeblock(): Cannot find block to write to\n");
+ /* If we _still_ haven't got a block to use, we're screwed */
+ return 1;
+ }
+// printk("Writing block %lx to EUN %x\n",block, writeEUN);
+
+
+ thisNFTL->mtd->write_ecc(thisNFTL->mtd,
+ (writeEUN * thisNFTL->EraseSize) + blockofs,
+ 512, &retlen, (char *)buffer, (char *)eccbuf);
+ eccbuf[3] = BLOCK_USED;
+ eccbuf[4] = eccbuf[5] = eccbuf[6] = eccbuf[7] = 0xffff;
+
+ thisNFTL->mtd->write_oob(thisNFTL->mtd,
+ (writeEUN * thisNFTL->EraseSize) + blockofs,
+ 16, &retlen, (char *)eccbuf);
+
+ return 0;
+}
+
+#endif /* CONFIG_NFTL_RW */
+
+static int NFTL_readblock(struct NFTLrecord *thisNFTL,
+ unsigned block, char *buffer)
+{
+ u16 lastgoodEUN = 0xffff;
+ u16 thisEUN = thisNFTL->EUNtable[block / (thisNFTL->EraseSize / 512)];
+ unsigned long blockofs = (block * 512) & (thisNFTL->EraseSize -1);
+
+ int silly = -1;
+
+ if (thisEUN == 0xffff) thisEUN = 0;
+
+ while(thisEUN && (thisEUN & 0x7fff) != 0x7fff) {
+ struct nftl_bci bci;
+ size_t retlen;
+
+ MTD_READOOB(thisNFTL->mtd, (thisEUN * thisNFTL->EraseSize) + blockofs,8, &retlen, (char *)&bci);
+
+ switch(bci.Status) {
+ case __constant_cpu_to_le16(BLOCK_FREE):
+ thisEUN = 0;
+ break;
+ case __constant_cpu_to_le16(BLOCK_USED):
+ lastgoodEUN = thisEUN;
+ break;
+ case __constant_cpu_to_le16(BLOCK_IGNORE):
+ case __constant_cpu_to_le16(BLOCK_DELETED):
+ break;
+ default:
+ printk("Unknown status for block %d in EUN %d: %x\n",block,thisEUN, bci.Status);
+ }
+
+ if (!silly--) {
+ printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",block / (thisNFTL->EraseSize / 512));
+ return 1;
+ }
+ if (thisEUN)
+ thisEUN = thisNFTL->ReplUnitTable[thisEUN] & 0x7fff;
+ }
+ if (lastgoodEUN == 0xffff) {
+ memset(buffer, 0, 512);
+ } else {
+ loff_t ptr = (lastgoodEUN * thisNFTL->EraseSize) + blockofs;
+ size_t retlen;
+ u_char eccbuf[6];
+ thisNFTL->mtd->read_ecc(thisNFTL->mtd, ptr, 512, &retlen, buffer, eccbuf);
+ }
+ return 0;
+}
+
+
+static int nftl_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct NFTLrecord *thisNFTL;
+
+ thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16];
+
+ if (!thisNFTL) return -EINVAL;
+
+
+ switch (cmd) {
+ case HDIO_GETGEO: {
+ struct hd_geometry g;
+
+ g.heads = thisNFTL->heads;
+ g.sectors = thisNFTL->sectors;
+ g.cylinders = thisNFTL->cylinders;
+ g.start = part_table[MINOR(inode->i_rdev)].start_sect;
+ return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0;
+ }
+ case BLKGETSIZE: /* Return device size */
+ if (!arg) return -EINVAL;
+ return put_user(part_table[MINOR(inode->i_rdev)].nr_sects,
+ (long *) arg);
+
+ case BLKFLSBUF:
+ if(!capable(CAP_SYS_ADMIN)) return -EACCES;
+ fsync_dev(inode->i_rdev);
+ invalidate_buffers(inode->i_rdev);
+ if (thisNFTL->mtd->sync)
+ thisNFTL->mtd->sync(thisNFTL->mtd);
+ return 0;
+
+ case BLKRRPART:
+ if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+ if (thisNFTL->usecount > 1) {
+ // printk("Use count %d\n", thisNFTL->usecount);
+ return -EBUSY;
+ }
+#if LINUX_VERSION_CODE < 0x20328
+ resetup_one_dev(&nftl_gendisk, MINOR(inode->i_dev) / 16);
+#else
+ grok_partitions(&nftl_gendisk, MINOR(inode->i_dev) / 16, 1<<4, thisNFTL->nr_sects);
+#endif
+ return 0;
+
+ // RO_IOCTLS(inode->i_rdev, arg); /* ref. linux/blk.h */
+ default:
+ return -EINVAL;
+ }
+}
+
+
+void nftl_request(RQFUNC_ARG)
+{
+ unsigned int dev, block, nsect;
+ struct NFTLrecord *thisNFTL;
+ char *buffer;
+ struct request *req;
+ int res;
+
+ while (1) {
+ INIT_REQUEST; /* blk.h */
+
+ req = CURRENT;
+#ifdef WE_KNOW_WTF_THIS_DOES_NOT_WORK
+ blkdev_dequeue_request(req);
+ spin_unlock_irq(&io_request_lock);
+#else
+ req = CURRENT;
+#endif
+
+ DEBUG(2,"NFTL_request\n");
+ DEBUG(3,"NFTL %d request, %lx, %lx", req->cmd,
+ req->sector, req->current_nr_sectors);
+ dev = MINOR(req->rq_dev);
+ block = req->sector;
+ nsect = req->current_nr_sectors;
+ buffer = req->buffer;
+ res = 1; /* succeed */
+
+ if (dev >= MAX_NFTLS * 16) {
+ printk("fl: bad minor number: device=%s\n",
+ kdevname(req->rq_dev));
+ res = 0; /* fail */
+ goto repeat;
+ }
+
+ thisNFTL = NFTLs[dev / 16];
+ DEBUG(3,"Waiting for mutex\n");
+ down(&thisNFTL->mutex);
+ DEBUG(3,"Got mutex\n");
+
+ if (block + nsect >= part_table[dev].nr_sects) {
+ printk("nftl%c%d: bad access: block=%d, count=%d\n",
+ (MINOR(req->rq_dev)>>6)+'a', dev & 0xf, block, nsect);
+ up(&thisNFTL->mutex);
+ res = 0; /* fail */
+ goto repeat;
+ }
+
+ block += part_table[dev].start_sect;
+
+ if (req->cmd == READ) {
+ DEBUG(2,"NFTL read\n");
+ for ( ; nsect > 0; nsect-- , block++, buffer+= 512) {
+ /* Read a single sector to req->buffer + (512 * i) */
+
+ if (NFTL_readblock(thisNFTL, block, buffer)) {
+ DEBUG(2,"NFTL read request failed\n");
+ up(&thisNFTL->mutex);
+ res = 0;
+ goto repeat;
+ }
+ }
+ DEBUG(2,"NFTL read request completed OK\n");
+ up(&thisNFTL->mutex);
+ goto repeat;
+ }
+ else if (req->cmd == WRITE) {
+ DEBUG(2,"NFTL write request of 0x%x sectors @ %x (req->nr_sectors == %lx\n",nsect, block, req->nr_sectors);
+#ifdef CONFIG_NFTL_RW
+ for ( ; nsect > 0; nsect-- , block++, buffer+= 512) {
+ /* Read a single sector to req->buffer + (512 * i) */
+
+ if (NFTL_writeblock(thisNFTL, block, buffer)) {
+ DEBUG(1,"NFTL write request failed\n");
+
+ up(&thisNFTL->mutex);
+ res = 0;
+ goto repeat;
+ }
+ }
+ DEBUG(2,"NFTL write request completed OK\n");
+#else
+ res=0; /* Writes always fail */
+#endif /* CONFIG_NFTL_RW */
+ up(&thisNFTL->mutex);
+ goto repeat;
+ }
+ else {
+ DEBUG(0,"NFTL ??? request\n");
+ up(&thisNFTL->mutex);
+ res = 0;
+ goto repeat;
+ }
+ repeat:
+ DEBUG(3,"end_request(%d)\n", res);
+#ifdef WE_KNOW_WTF_THIS_DOES_NOT_WORK
+ spin_lock_irq(&io_request_lock);
+ nftl_end_request(req, res);
+#else
+ end_request(res);
+#endif
+ }
+}
+
+static int nftl_open(struct inode *ip, struct file *fp)
+{
+ struct NFTLrecord *thisNFTL;
+ thisNFTL = NFTLs[MINOR(ip->i_rdev) / 16];
+
+ DEBUG(2,"NFTL_open\n");
+
+ if (!thisNFTL) {
+ DEBUG(2,"ENODEV: thisNFTL = %d, minor = %d, ip = %p, fp = %p\n",
+ MINOR(ip->i_rdev) / 16,ip->i_rdev,ip, fp);
+ return -ENODEV;
+ }
+#ifndef CONFIG_NFTL_RW
+ if (fp->f_mode & FMODE_WRITE)
+ return -EROFS;
+#endif /* !CONFIG_NFTL_RW */
+ thisNFTL->usecount++;
+ MOD_INC_USE_COUNT;
+ if (!get_mtd_device(thisNFTL->mtd, -1)) {
+ MOD_DEC_USE_COUNT;
+ return /* -E'SBUGGEREDOFF */ -ENXIO;
+ }
+
+ return 0;
+}
+
+static int nftl_release(struct inode *inode, struct file *fp)
+{
+ struct super_block *sb = get_super(inode->i_rdev);
+ struct NFTLrecord *thisNFTL;
+
+ thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16];
+
+ DEBUG(2, "NFTL_release\n");
+
+ fsync_dev(inode->i_rdev);
+ if (sb)
+ invalidate_inodes(sb);
+ invalidate_buffers(inode->i_rdev);
+
+ if (thisNFTL->mtd->sync)
+ thisNFTL->mtd->sync(thisNFTL->mtd);
+ thisNFTL->usecount--;
+ MOD_DEC_USE_COUNT;
+
+ put_mtd_device(thisNFTL->mtd);
+
+ return 0;
+}
+#if LINUX_VERSION_CODE < 0x20326
+static struct file_operations nftl_fops = {
+ NULL, /* lseek - default */
+ block_read, /* read - block dev read */
+ block_write, /* write - block dev write */
+ NULL, /* readdir - not here! */
+ NULL, /* select */
+ nftl_ioctl, /* ioctl */
+ NULL, /* mmap */
+ nftl_open, /* open */
+ NULL, /* flush */
+ nftl_release, /* no special release code... */
+ block_fsync /* fsync */
+};
+#else
+static struct block_device_operations nftl_fops =
+{
+ open: nftl_open,
+ release: nftl_release,
+ ioctl: nftl_ioctl
+};
+#endif
+
+
+
+/****************************************************************************
+ *
+ * Module stuff
+ *
+ ****************************************************************************/
+
+#if LINUX_VERSION_CODE < 0x20300
+#ifdef MODULE
+#define init_nftl init_module
+#define cleanup_nftl cleanup_module
+#endif
+#define __exit
+#endif
+
+static struct mtd_notifier nftl_notifier = {NFTL_notify_add, NFTL_notify_remove, NULL};
+
+
+/* static int __init init_nftl(void) */
+int __init init_nftl(void)
+{
+ int i;
+
+ printk(KERN_NOTICE "M-Systems NAND Flash Translation Layer driver. (C) 1999 MVHI\n");
+#ifdef PRERELEASE
+ printk(KERN_INFO"$Id: nftl.c,v 1.34 2000/06/07 14:48:52 dwmw2 Exp $\n");
+#endif
+
+ if (register_blkdev(NFTL_MAJOR, "nftl", &nftl_fops)){
+ printk("unable to register NFTL block device\n");
+ } else {
+#if LINUX_VERSION_CODE < 0x20320
+ blk_dev[MAJOR_NR].request_fn = nftl_request;
+#else
+ blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &nftl_request);
+#endif
+ for (i=0; i < 256 ; i++) {
+ nftl_blocksizes[i] = 1024;
+ }
+ blksize_size[NFTL_MAJOR] = nftl_blocksizes;
+ nftl_gendisk.next = gendisk_head;
+ gendisk_head = &nftl_gendisk;
+ }
+
+ register_mtd_user(&nftl_notifier);
+
+ return 0;
+}
+
+static void __exit cleanup_nftl(void)
+{
+ struct gendisk *gd, **gdp;
+
+ unregister_mtd_user(&nftl_notifier);
+
+ unregister_blkdev(NFTL_MAJOR, "nftl");
+#if LINUX_VERSION_CODE < 0x20320
+ blk_dev[MAJOR_NR].request_fn = 0;
+#else
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+#endif
+ for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
+ if (*gdp == &nftl_gendisk) {
+ gd = *gdp; *gdp = gd->next;
+ break;
+ }
+
+}
+
+#if LINUX_VERSION_CODE > 0x20300
+module_init(init_nftl);
+module_exit(cleanup_nftl);
+#endif
diff --git a/drivers/mtd/nora.c b/drivers/mtd/nora.c
new file mode 100644
index 000000000..a92e47734
--- /dev/null
+++ b/drivers/mtd/nora.c
@@ -0,0 +1,208 @@
+/*
+ * $Id: nora.c,v 1.11 2000/07/04 16:42:50 dwmw2 Exp $
+ *
+ * This is so simple I love it.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+
+
+#define WINDOW_ADDR 0xd0000000
+#define WINDOW_SIZE 0x04000000
+
+static struct mtd_info *mymtd;
+
+__u8 nora_read8(struct map_info *map, unsigned long ofs)
+{
+ return *(__u8 *)(WINDOW_ADDR + ofs);
+}
+
+__u16 nora_read16(struct map_info *map, unsigned long ofs)
+{
+ return *(__u16 *)(WINDOW_ADDR + ofs);
+}
+
+__u32 nora_read32(struct map_info *map, unsigned long ofs)
+{
+ return *(__u32 *)(WINDOW_ADDR + ofs);
+}
+
+void nora_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ memcpy(to, (void *)(WINDOW_ADDR + from), len);
+}
+
+void nora_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ *(__u8 *)(WINDOW_ADDR + adr) = d;
+}
+
+void nora_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ *(__u16 *)(WINDOW_ADDR + adr) = d;
+}
+
+void nora_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ *(__u32 *)(WINDOW_ADDR + adr) = d;
+}
+
+void nora_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ memcpy((void *)(WINDOW_ADDR + to), from, len);
+}
+
+struct map_info nora_map = {
+ "NORA",
+ WINDOW_SIZE,
+ 2,
+ nora_read8,
+ nora_read16,
+ nora_read32,
+ nora_copy_from,
+ nora_write8,
+ nora_write16,
+ nora_write32,
+ nora_copy_to,
+ 0,
+ 0
+};
+
+
+static int nora_mtd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+ return mymtd->read(mymtd, from + (unsigned long)mtd->priv, len, retlen, buf);
+}
+
+static int nora_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
+{
+ return mymtd->write(mymtd, to + (unsigned long)mtd->priv, len, retlen, buf);
+}
+
+static int nora_mtd_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+ instr->addr += (unsigned long)mtd->priv;
+ return mymtd->erase(mymtd, instr);
+}
+
+static void nora_mtd_sync (struct mtd_info *mtd)
+{
+ mymtd->sync(mymtd);
+}
+
+static int nora_mtd_suspend (struct mtd_info *mtd)
+{
+ return mymtd->suspend(mymtd);
+}
+
+static void nora_mtd_resume (struct mtd_info *mtd)
+{
+ mymtd->resume(mymtd);
+}
+
+
+static struct mtd_info nora_mtds[4] = { /* boot, kernel, ramdisk, fs */
+ {
+ type: MTD_NORFLASH,
+ flags: MTD_CAP_NORFLASH,
+ size: 0x60000,
+ erasesize: 0x20000,
+ name: "NORA boot firmware",
+ module: THIS_MODULE,
+ erase: nora_mtd_erase,
+ read: nora_mtd_read,
+ write: nora_mtd_write,
+ suspend: nora_mtd_suspend,
+ resume: nora_mtd_resume,
+ sync: nora_mtd_sync,
+ priv: (void *)0
+ },
+ {
+ type: MTD_NORFLASH,
+ flags: MTD_CAP_NORFLASH,
+ size: 0x1a0000,
+ erasesize: 0x20000,
+ name: "NORA kernel",
+ module: THIS_MODULE,
+ erase: nora_mtd_erase,
+ read: nora_mtd_read,
+ write: nora_mtd_write,
+ suspend: nora_mtd_suspend,
+ resume: nora_mtd_resume,
+ sync: nora_mtd_sync,
+ priv: (void *)0x60000
+ },
+ {
+ type: MTD_NORFLASH,
+ flags: MTD_CAP_NORFLASH,
+ size: 0xe00000,
+ erasesize: 0x20000,
+ name: "NORA ramdisk",
+ module: THIS_MODULE,
+ erase: nora_mtd_erase,
+ read: nora_mtd_read,
+ write: nora_mtd_write,
+ suspend: nora_mtd_suspend,
+ resume: nora_mtd_resume,
+ sync: nora_mtd_sync,
+ priv: (void *)0x200000
+ },
+ {
+ type: MTD_NORFLASH,
+ flags: MTD_CAP_NORFLASH,
+ size: 0x1000000,
+ erasesize: 0x20000,
+ name: "NORA filesystem",
+ module: THIS_MODULE,
+ erase: nora_mtd_erase,
+ read: nora_mtd_read,
+ write: nora_mtd_write,
+ suspend: nora_mtd_suspend,
+ resume: nora_mtd_resume,
+ sync: nora_mtd_sync,
+ priv: (void *)0x1000000
+ }
+};
+
+#if LINUX_VERSION_CODE < 0x20300
+#ifdef MODULE
+#define init_nora init_module
+#define cleanup_nora cleanup_module
+#endif
+#endif
+
+int __init init_nora(void)
+{
+ printk(KERN_NOTICE "nora flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
+
+ mymtd = do_cfi_probe(&nora_map);
+ if (mymtd) {
+#ifdef MODULE
+ mymtd->module = &__this_module;
+#endif
+
+ add_mtd_device(&nora_mtds[3]);
+ add_mtd_device(&nora_mtds[0]);
+ add_mtd_device(&nora_mtds[1]);
+ add_mtd_device(&nora_mtds[2]);
+ return 0;
+ }
+
+ return -ENXIO;
+}
+
+static void __exit cleanup_nora(void)
+{
+ if (mymtd) {
+ del_mtd_device(&nora_mtds[2]);
+ del_mtd_device(&nora_mtds[1]);
+ del_mtd_device(&nora_mtds[0]);
+ del_mtd_device(&nora_mtds[3]);
+ map_destroy(mymtd);
+ }
+}
diff --git a/drivers/mtd/octagon-5066.c b/drivers/mtd/octagon-5066.c
new file mode 100644
index 000000000..167e0da13
--- /dev/null
+++ b/drivers/mtd/octagon-5066.c
@@ -0,0 +1,290 @@
+// $Id: octagon-5066.c,v 1.9 2000/07/03 10:01:38 dwmw2 Exp $
+/* ######################################################################
+
+ Octagon 5066 MTD Driver.
+
+ The Octagon 5066 is a SBC based on AMD's 586-WB running at 133 MHZ. It
+ comes with a builtin AMD 29F016 flash chip and a socketed EEPROM that
+ is replacable by flash. Both units are mapped through a multiplexer
+ into a 32k memory window at 0xe8000. The control register for the
+ multiplexing unit is located at IO 0x208 with a bit map of
+ 0-5 Page Selection in 32k increments
+ 6-7 Device selection:
+ 00 SSD off
+ 01 SSD 0 (Socket)
+ 10 SSD 1 (Flash chip)
+ 11 undefined
+
+ On each SSD, the first 128k is reserved for use by the bios
+ (actually it IS the bios..) This only matters if you are booting off the
+ flash, you must not put a file system starting there.
+
+ The driver tries to do a detection algorithm to guess what sort of devices
+ are plugged into the sockets.
+
+ ##################################################################### */
+
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <asm/io.h>
+
+#include <linux/mtd/map.h>
+
+#define WINDOW_START 0xe8000
+#define WINDOW_LENGTH 0x8000
+#define WINDOW_SHIFT 27
+#define WINDOW_MASK 0x7FFF
+#define PAGE_IO 0x208
+
+static volatile char page_n_dev = 0;
+static unsigned long iomapadr;
+static spinlock_t oct5066_spin = SPIN_LOCK_UNLOCKED;
+
+/*
+ * We use map_priv_1 to identify which device we are.
+ */
+
+static void __oct5066_page(struct map_info *map, __u8 byte)
+{
+ outb(byte,PAGE_IO);
+ page_n_dev = byte;
+}
+
+static inline void oct5066_page(struct map_info *map, unsigned long ofs)
+{
+ __u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT);
+
+ if (page_n_dev != byte);
+ __oct5066_page(map, byte);
+}
+
+
+static __u8 oct5066_read8(struct map_info *map, unsigned long ofs)
+{
+ __u8 ret;
+ spin_lock(&oct5066_spin);
+ oct5066_page(map, ofs);
+ ret = readb(iomapadr + (ofs & WINDOW_MASK));
+ spin_unlock(&oct5066_spin);
+ return ret;
+}
+
+static __u16 oct5066_read16(struct map_info *map, unsigned long ofs)
+{
+ __u16 ret;
+ spin_lock(&oct5066_spin);
+ oct5066_page(map, ofs);
+ ret = readw(iomapadr + (ofs & WINDOW_MASK));
+ spin_unlock(&oct5066_spin);
+ return ret;
+}
+
+static __u32 oct5066_read32(struct map_info *map, unsigned long ofs)
+{
+ __u32 ret;
+ spin_lock(&oct5066_spin);
+ oct5066_page(map, ofs);
+ ret = readl(iomapadr + (ofs & WINDOW_MASK));
+ spin_unlock(&oct5066_spin);
+ return ret;
+}
+
+static void oct5066_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ while(len) {
+ unsigned long thislen = len;
+ if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
+ thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
+
+ spin_lock(&oct5066_spin);
+ oct5066_page(map, from);
+ memcpy_fromio(to, iomapadr + from, thislen);
+ spin_unlock(&oct5066_spin);
+ to += thislen;
+ from += thislen;
+ len -= thislen;
+ }
+}
+
+static void oct5066_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ spin_lock(&oct5066_spin);
+ oct5066_page(map, adr);
+ writeb(d, iomapadr + (adr & WINDOW_MASK));
+ spin_unlock(&oct5066_spin);
+}
+
+static void oct5066_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ spin_lock(&oct5066_spin);
+ oct5066_page(map, adr);
+ writew(d, iomapadr + (adr & WINDOW_MASK));
+ spin_unlock(&oct5066_spin);
+}
+
+static void oct5066_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ spin_lock(&oct5066_spin);
+ oct5066_page(map, adr);
+ writel(d, iomapadr + (adr & WINDOW_MASK));
+ spin_unlock(&oct5066_spin);
+}
+
+static void oct5066_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ while(len) {
+ unsigned long thislen = len;
+ if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
+ thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
+
+ spin_lock(&oct5066_spin);
+ oct5066_page(map, to);
+ memcpy_toio(iomapadr + to, from, thislen);
+ spin_unlock(&oct5066_spin);
+ to += thislen;
+ from += thislen;
+ len -= thislen;
+ }
+}
+
+static struct map_info oct5066_map[2] = {
+ {
+ "Octagon 5066 Socket",
+ 512 * 1024,
+ 1,
+ oct5066_read8,
+ oct5066_read16,
+ oct5066_read32,
+ oct5066_copy_from,
+ oct5066_write8,
+ oct5066_write16,
+ oct5066_write32,
+ oct5066_copy_to,
+ 1<<6
+ },
+ {
+ "Octagon 5066 Internal Flash",
+ 2 * 1024 * 1024,
+ 1,
+ oct5066_read8,
+ oct5066_read16,
+ oct5066_read32,
+ oct5066_copy_from,
+ oct5066_write8,
+ oct5066_write16,
+ oct5066_write32,
+ oct5066_copy_to,
+ 2<<6
+ }
+};
+
+static struct mtd_info *oct5066_mtd[2] = {NULL, NULL};
+
+// OctProbe - Sense if this is an octagon card
+// ---------------------------------------------------------------------
+/* Perform a simple validity test, we map the window select SSD0 and
+ change pages while monitoring the window. A change in the window,
+ controlled by the PAGE_IO port is a functioning 5066 board. This will
+ fail if the thing in the socket is set to a uniform value. */
+static int __init OctProbe()
+{
+ unsigned int Base = (1 << 6);
+ unsigned long I;
+ unsigned long Values[10];
+ for (I = 0; I != 20; I++)
+ {
+ outb(Base + (I%10),PAGE_IO);
+ if (I < 10)
+ {
+ // Record the value and check for uniqueness
+ Values[I%10] = readl(iomapadr);
+ if (I > 0 && Values[I%10] == Values[0])
+ return -EAGAIN;
+ }
+ else
+ {
+ // Make sure we get the same values on the second pass
+ if (Values[I%10] != readl(iomapadr))
+ return -EAGAIN;
+ }
+ }
+ return 0;
+}
+
+#if LINUX_VERSION_CODE < 0x20300
+#ifdef MODULE
+#define init_oct5066 init_module
+#define cleanup_oct5066 cleanup_module
+#endif
+#define __exit
+#endif
+
+void cleanup_oct5066(void)
+{
+ int i;
+ for (i=0; i<2; i++) {
+ if (oct5066_mtd[i]) {
+ del_mtd_device(oct5066_mtd[i]);
+ map_destroy(oct5066_mtd[i]);
+ }
+ }
+ iounmap((void *)iomapadr);
+ release_region(PAGE_IO,1);
+}
+
+int __init init_oct5066(void)
+{
+ int i;
+
+ // Do an autoprobe sequence
+ if (check_region(PAGE_IO,1) != 0)
+ {
+ printk("5066: Page Register in Use\n");
+ return -EAGAIN;
+ }
+ iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
+ if (!iomapadr) {
+ printk("Failed to ioremap memory region\n");
+ return -EIO;
+ }
+ if (OctProbe() != 0)
+ {
+ printk("5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
+ iounmap((void *)iomapadr);
+ return -EAGAIN;
+ }
+
+ request_region(PAGE_IO,1,"Octagon SSD");
+
+ // Print out our little header..
+ printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START,
+ WINDOW_START+WINDOW_LENGTH);
+
+ for (i=0; i<2; i++) {
+ oct5066_mtd[i] = do_cfi_probe(&oct5066_map[i]);
+ if (!oct5066_mtd[i])
+ oct5066_mtd[i] = do_jedec_probe(&oct5066_map[i]);
+ if (!oct5066_mtd[i])
+ oct5066_mtd[i] = do_ram_probe(&oct5066_map[i]);
+ if (!oct5066_mtd[i])
+ oct5066_mtd[i] = do_rom_probe(&oct5066_map[i]);
+ if (oct5066_mtd[i]) {
+ oct5066_mtd[i]->module = THIS_MODULE;
+ add_mtd_device(oct5066_mtd[i]);
+ }
+ }
+
+ if (!oct5066_mtd[1] && !oct5066_mtd[2]) {
+ cleanup_oct5066();
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+#if LINUX_VERSION_CODE > 0x20300
+module_init(init_oct5066);
+module_exit(cleanup_oct5066);
+#endif
diff --git a/drivers/mtd/physmap.c b/drivers/mtd/physmap.c
new file mode 100644
index 000000000..e470a6c97
--- /dev/null
+++ b/drivers/mtd/physmap.c
@@ -0,0 +1,114 @@
+/*
+ * $Id: physmap.c,v 1.1 2000/07/04 08:58:10 dwmw2 Exp $
+ *
+ * Normal mappings of chips in physical memory
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+
+
+#define WINDOW_ADDR 0x8000000
+#define WINDOW_SIZE 0x4000000
+
+static struct mtd_info *mymtd;
+
+__u8 physmap_read8(struct map_info *map, unsigned long ofs)
+{
+ return readb(map->map_priv_1 + ofs);
+}
+
+__u16 physmap_read16(struct map_info *map, unsigned long ofs)
+{
+ return readw(map->map_priv_1 + ofs);
+}
+
+__u32 physmap_read32(struct map_info *map, unsigned long ofs)
+{
+ return readl(map->map_priv_1 + ofs);
+}
+
+void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void physmap_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ writeb(d, map->map_priv_1 + adr);
+}
+
+void physmap_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ writew(d, map->map_priv_1 + adr);
+}
+
+void physmap_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ writel(d, map->map_priv_1 + adr);
+}
+
+void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+struct map_info physmap_map = {
+ "Physically mapped flash",
+ WINDOW_SIZE,
+ 2,
+ physmap_read8,
+ physmap_read16,
+ physmap_read32,
+ physmap_copy_from,
+ physmap_write8,
+ physmap_write16,
+ physmap_write32,
+ physmap_copy_to,
+ 0,
+ 0
+};
+
+#if LINUX_VERSION_CODE < 0x20300
+#ifdef MODULE
+#define init_physmap init_module
+#define cleanup_physmap cleanup_module
+#endif
+#endif
+
+int __init init_physmap(void)
+{
+ printk(KERN_NOTICE "physmap flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
+ physmap_map.map_priv_1 = (unsigned long)ioremap(WINDOW_SIZE, WINDOW_ADDR);
+
+ if (!physmap_map.map_priv_1) {
+ printk("Failed to ioremap\n");
+ return -EIO;
+ }
+ mymtd = do_cfi_probe(&physmap_map);
+ if (mymtd) {
+#ifdef MODULE
+ mymtd->module = &__this_module;
+#endif
+ add_mtd_device(mymtd);
+ return 0;
+ }
+
+ return -ENXIO;
+}
+
+static void __exit cleanup_physmap(void)
+{
+ if (mymtd) {
+ del_mtd_device(mymtd);
+ map_destroy(mymtd);
+ }
+ if (physmap_map.map_priv_1) {
+ iounmap((void *)physmap_map.map_priv_1);
+ physmap_map.map_priv_1 = 0;
+ }
+}
diff --git a/drivers/mtd/pmc551.c b/drivers/mtd/pmc551.c
new file mode 100644
index 000000000..98d5c3069
--- /dev/null
+++ b/drivers/mtd/pmc551.c
@@ -0,0 +1,689 @@
+/*
+ * $Id: pmc551.c,v 1.7 2000/07/03 10:01:38 dwmw2 Exp $
+ *
+ * PMC551 PCI Mezzanine Ram Device
+ *
+ * Author:
+ * Mark Ferrell
+ * Copyright 1999,2000 Nortel Networks
+ *
+ * License:
+ * As part of this driver was derrived from the slram.c driver it falls
+ * under the same license, which is GNU General Public License v2
+ *
+ * Description:
+ * This driver is intended to support the PMC551 PCI Ram device from
+ * Ramix Inc. The PMC551 is a PMC Mezzanine module for cPCI embeded
+ * systems. The device contains a single SROM that initally programs the
+ * V370PDC chipset onboard the device, and various banks of DRAM/SDRAM
+ * onboard. This driver implements this PCI Ram device as an MTD (Memory
+ * Technologies Device) so that it can be used to hold a filesystem, or
+ * for added swap space in embeded systems. Since the memory on this
+ * board isn't as fast as main memory we do not try to hook it into main
+ * memeory as that would simply reduce performance on the system. Using
+ * it as a block device allows us to use it as high speed swap or for a
+ * high speed disk device of some sort. Which becomes very usefull on
+ * diskless systems in the embeded market I might add.
+ *
+ * Credits:
+ * Saeed Karamooz <saeed@ramix.com> of Ramix INC. for the initial
+ * example code of how to initialize this device and for help with
+ * questions I had concerning operation of the device.
+ *
+ * Most of the MTD code for this driver was originally written for the
+ * slram.o module in the MTD drivers package written by David Hinds
+ * <dhinds@allegro.stanford.edu> which allows the mapping of system
+ * memory into an mtd device. Since the PMC551 memory module is
+ * accessed in the same fashion as system memory, the slram.c code
+ * became a very nice fit to the needs of this driver. All we added was
+ * PCI detection/initialization to the driver and automaticly figure out
+ * the size via the PCI detection.o, later changes by Corey Minyard
+ * settup the card to utilize a 1M sliding apature.
+ *
+ * Corey Minyard <minyard@nortelnetworks.com>
+ * * Modified driver to utilize a sliding apature instead of mapping all
+ * memory into kernel space which turned out to be very wastefull.
+ * * Located a bug in the SROM's initialization sequence that made the
+ * memory unussable, added a fix to code to touch up the DRAM some.
+ *
+ * Bugs/FIXME's:
+ * * MUST fix the init function to not spin on a register
+ * waiting for it to set .. this does not safely handle busted devices
+ * that never reset the register correctly which will cause the system to
+ * hang w/ a reboot beeing the only chance at recover.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <stdarg.h>
+#include <linux/pci.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/pmc551.h>
+#include <linux/mtd/compatmac.h>
+
+#if LINUX_VERSION_CODE > 0x20300
+#define PCI_BASE_ADDRESS(dev) (dev->resource[0].start)
+#else
+#define PCI_BASE_ADDRESS(dev) (dev->base_address[0])
+#endif
+
+static struct mtd_info *pmc551list = NULL;
+
+static int pmc551_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+ struct mypriv *priv = mtd->priv;
+ u32 start_addr_highbits;
+ u32 end_addr_highbits;
+ u32 start_addr_lowbits;
+ u32 end_addr_lowbits;
+ unsigned long end;
+
+ end = instr->addr + instr->len;
+
+ /* Is it too much memory? The second check find if we wrap around
+ past the end of a u32. */
+ if ((end > mtd->size) || (end < instr->addr)) {
+ return -EINVAL;
+ }
+
+ start_addr_highbits = instr->addr & PMC551_ADDR_HIGH_MASK;
+ end_addr_highbits = end & PMC551_ADDR_HIGH_MASK;
+ start_addr_lowbits = instr->addr & PMC551_ADDR_LOW_MASK;
+ end_addr_lowbits = end & PMC551_ADDR_LOW_MASK;
+
+ pci_write_config_dword ( priv->dev,
+ PMC551_PCI_MEM_MAP0,
+ (priv->mem_map0_base_val
+ | start_addr_highbits));
+ if (start_addr_highbits == end_addr_highbits) {
+ /* The whole thing fits within one access, so just one shot
+ will do it. */
+ memset(priv->start + start_addr_lowbits,
+ 0xff,
+ instr->len);
+ } else {
+ /* We have to do multiple writes to get all the data
+ written. */
+ memset(priv->start + start_addr_lowbits,
+ 0xff,
+ priv->aperture_size - start_addr_lowbits);
+ start_addr_highbits += priv->aperture_size;
+ while (start_addr_highbits != end_addr_highbits) {
+ pci_write_config_dword ( priv->dev,
+ PMC551_PCI_MEM_MAP0,
+ (priv->mem_map0_base_val
+ | start_addr_highbits));
+ memset(priv->start,
+ 0xff,
+ priv->aperture_size);
+ start_addr_highbits += priv->aperture_size;
+ }
+ priv->curr_mem_map0_val = (priv->mem_map0_base_val
+ | start_addr_highbits);
+ pci_write_config_dword ( priv->dev,
+ PMC551_PCI_MEM_MAP0,
+ priv->curr_mem_map0_val);
+ memset(priv->start,
+ 0xff,
+ end_addr_lowbits);
+ }
+
+ instr->state = MTD_ERASE_DONE;
+
+ if (instr->callback) {
+ (*(instr->callback))(instr);
+ }
+
+ return 0;
+}
+
+
+static void pmc551_unpoint (struct mtd_info *mtd, u_char *addr)
+{}
+
+
+static int pmc551_read (struct mtd_info *mtd,
+ loff_t from,
+ size_t len,
+ size_t *retlen,
+ u_char *buf)
+{
+ struct mypriv *priv = (struct mypriv *)mtd->priv;
+ u32 start_addr_highbits;
+ u32 end_addr_highbits;
+ u32 start_addr_lowbits;
+ u32 end_addr_lowbits;
+ unsigned long end;
+ u_char *copyto = buf;
+
+
+ /* Is it past the end? */
+ if (from > mtd->size) {
+ return -EINVAL;
+ }
+
+ end = from + len;
+ start_addr_highbits = from & PMC551_ADDR_HIGH_MASK;
+ end_addr_highbits = end & PMC551_ADDR_HIGH_MASK;
+ start_addr_lowbits = from & PMC551_ADDR_LOW_MASK;
+ end_addr_lowbits = end & PMC551_ADDR_LOW_MASK;
+
+
+ /* Only rewrite the first value if it doesn't match our current
+ values. Most operations are on the same page as the previous
+ value, so this is a pretty good optimization. */
+ if (priv->curr_mem_map0_val !=
+ (priv->mem_map0_base_val | start_addr_highbits)) {
+ priv->curr_mem_map0_val = (priv->mem_map0_base_val
+ | start_addr_highbits);
+ pci_write_config_dword ( priv->dev,
+ PMC551_PCI_MEM_MAP0,
+ priv->curr_mem_map0_val);
+ }
+
+ if (start_addr_highbits == end_addr_highbits) {
+ /* The whole thing fits within one access, so just one shot
+ will do it. */
+ memcpy(copyto,
+ priv->start + start_addr_lowbits,
+ len);
+ copyto += len;
+ } else {
+ /* We have to do multiple writes to get all the data
+ written. */
+ memcpy(copyto,
+ priv->start + start_addr_lowbits,
+ priv->aperture_size - start_addr_lowbits);
+ copyto += priv->aperture_size - start_addr_lowbits;
+ start_addr_highbits += priv->aperture_size;
+ while (start_addr_highbits != end_addr_highbits) {
+ pci_write_config_dword ( priv->dev,
+ PMC551_PCI_MEM_MAP0,
+ (priv->mem_map0_base_val
+ | start_addr_highbits));
+ memcpy(copyto,
+ priv->start,
+ priv->aperture_size);
+ copyto += priv->aperture_size;
+ start_addr_highbits += priv->aperture_size;
+ if (start_addr_highbits >= mtd->size) {
+ /* Make sure we have the right value here. */
+ priv->curr_mem_map0_val
+ = (priv->mem_map0_base_val
+ | start_addr_highbits);
+ goto out;
+ }
+ }
+ priv->curr_mem_map0_val = (priv->mem_map0_base_val
+ | start_addr_highbits);
+ pci_write_config_dword ( priv->dev,
+ PMC551_PCI_MEM_MAP0,
+ priv->curr_mem_map0_val);
+ memcpy(copyto,
+ priv->start,
+ end_addr_lowbits);
+ copyto += end_addr_lowbits;
+ }
+
+out:
+ *retlen = copyto - buf;
+ return 0;
+}
+
+static int pmc551_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
+{
+ struct mypriv *priv = (struct mypriv *)mtd->priv;
+ u32 start_addr_highbits;
+ u32 end_addr_highbits;
+ u32 start_addr_lowbits;
+ u32 end_addr_lowbits;
+ unsigned long end;
+ const u_char *copyfrom = buf;
+
+
+ /* Is it past the end? */
+ if (to > mtd->size) {
+ return -EINVAL;
+ }
+
+ end = to + len;
+ start_addr_highbits = to & PMC551_ADDR_HIGH_MASK;
+ end_addr_highbits = end & PMC551_ADDR_HIGH_MASK;
+ start_addr_lowbits = to & PMC551_ADDR_LOW_MASK;
+ end_addr_lowbits = end & PMC551_ADDR_LOW_MASK;
+
+
+ /* Only rewrite the first value if it doesn't match our current
+ values. Most operations are on the same page as the previous
+ value, so this is a pretty good optimization. */
+ if (priv->curr_mem_map0_val !=
+ (priv->mem_map0_base_val | start_addr_highbits)) {
+ priv->curr_mem_map0_val = (priv->mem_map0_base_val
+ | start_addr_highbits);
+ pci_write_config_dword ( priv->dev,
+ PMC551_PCI_MEM_MAP0,
+ priv->curr_mem_map0_val);
+ }
+
+ if (start_addr_highbits == end_addr_highbits) {
+ /* The whole thing fits within one access, so just one shot
+ will do it. */
+ memcpy(priv->start + start_addr_lowbits,
+ copyfrom,
+ len);
+ copyfrom += len;
+ } else {
+ /* We have to do multiple writes to get all the data
+ written. */
+ memcpy(priv->start + start_addr_lowbits,
+ copyfrom,
+ priv->aperture_size - start_addr_lowbits);
+ copyfrom += priv->aperture_size - start_addr_lowbits;
+ start_addr_highbits += priv->aperture_size;
+ while (start_addr_highbits != end_addr_highbits) {
+ pci_write_config_dword ( priv->dev,
+ PMC551_PCI_MEM_MAP0,
+ (priv->mem_map0_base_val
+ | start_addr_highbits));
+ memcpy(priv->start,
+ copyfrom,
+ priv->aperture_size);
+ copyfrom += priv->aperture_size;
+ start_addr_highbits += priv->aperture_size;
+ if (start_addr_highbits >= mtd->size) {
+ /* Make sure we have the right value here. */
+ priv->curr_mem_map0_val
+ = (priv->mem_map0_base_val
+ | start_addr_highbits);
+ goto out;
+ }
+ }
+ priv->curr_mem_map0_val = (priv->mem_map0_base_val
+ | start_addr_highbits);
+ pci_write_config_dword ( priv->dev,
+ PMC551_PCI_MEM_MAP0,
+ priv->curr_mem_map0_val);
+ memcpy(priv->start,
+ copyfrom,
+ end_addr_lowbits);
+ copyfrom += end_addr_lowbits;
+ }
+
+out:
+ *retlen = copyfrom - buf;
+ return 0;
+}
+
+/*
+ * Fixup routines for the V370PDC
+ * PCI device ID 0x020011b0
+ *
+ * This function basicly kick starts the DRAM oboard the card and gets it
+ * ready to be used. Before this is done the device reads VERY erratic, so
+ * much that it can crash the Linux 2.2.x series kernels when a user cat's
+ * /proc/pci .. though that is mainly a kernel bug in handling the PCI DEVSEL
+ * register. FIXME: stop spinning on registers .. must implement a timeout
+ * mechanism
+ * returns the size of the memory region found.
+ */
+static u32 fixup_pmc551 (struct pci_dev *dev)
+{
+#ifdef PMC551_DRAM_BUG
+ u32 dram_data;
+#endif
+ u32 size, dcmd;
+ u16 cmd, i;
+
+ /* Sanity Check */
+ if(!dev) {
+ return -ENODEV;
+ }
+
+ /*
+ * Get the size of the memory by reading all the DRAM size values
+ * and adding them up.
+ *
+ * KLUDGE ALERT: the boards we are using have invalid column and
+ * row mux values. We fix them here, but this will break other
+ * memory configurations.
+ */
+#ifdef PMC551_DRAM_BUG
+ pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dram_data);
+ size = PMC551_DRAM_BLK_GET_SIZE(dram_data);
+ dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
+ dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
+ pci_write_config_dword(dev, PMC551_DRAM_BLK0, dram_data);
+
+ pci_read_config_dword(dev, PMC551_DRAM_BLK1, &dram_data);
+ size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
+ dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
+ dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
+ pci_write_config_dword(dev, PMC551_DRAM_BLK1, dram_data);
+
+ pci_read_config_dword(dev, PMC551_DRAM_BLK2, &dram_data);
+ size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
+ dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
+ dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
+ pci_write_config_dword(dev, PMC551_DRAM_BLK2, dram_data);
+
+ pci_read_config_dword(dev, PMC551_DRAM_BLK3, &dram_data);
+ size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
+ dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
+ dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
+ pci_write_config_dword(dev, PMC551_DRAM_BLK3, dram_data);
+#endif /* PMC551_DRAM_BUG */
+
+ /*
+ * Oops .. something went wrong
+ */
+ if( (size &= PCI_BASE_ADDRESS_MEM_MASK) == 0) {
+ return -ENODEV;
+ }
+
+ /*
+ * Set to be prefetchable
+ */
+ pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &dcmd );
+ dcmd |= 0x8;
+
+ /*
+ * Put it back the way it was
+ */
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dcmd );
+ pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &dcmd );
+
+ /*
+ * Some screen fun
+ */
+ printk(KERN_NOTICE "pmc551: %dM (0x%x) of %sprefetchable memory at 0x%lx\n",
+ size/1024/1024, size, ((dcmd&0x8) == 0)?"non-":"",
+ PCI_BASE_ADDRESS(dev)&PCI_BASE_ADDRESS_MEM_MASK );
+
+ /*
+ * Turn on PCI memory and I/O bus access just for kicks
+ */
+ pci_write_config_word( dev, PCI_COMMAND,
+ PCI_COMMAND_MEMORY | PCI_COMMAND_IO );
+
+ /*
+ * Config DRAM
+ */
+ pci_write_config_word( dev, PMC551_SDRAM_MA, 0x0400 );
+ pci_write_config_word( dev, PMC551_SDRAM_CMD, 0x00bf );
+
+ /*
+ * Wait untill command has gone through
+ * FIXME: register spinning issue
+ */
+ do { pci_read_config_word( dev, PMC551_SDRAM_CMD, &cmd );
+ } while ( (PCI_COMMAND_IO) & cmd );
+
+ /*
+ * Must be held high for some duration of time to take effect??
+ */
+ for ( i = 1; i<=8 ; i++) {
+ pci_write_config_word (dev, PMC551_SDRAM_CMD, 0x0df);
+
+ /*
+ * Make certain command has gone through
+ * FIXME: register spinning issue
+ */
+ do { pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
+ } while ( (PCI_COMMAND_IO) & cmd );
+ }
+
+ pci_write_config_word ( dev, PMC551_SDRAM_MA, 0x0020);
+ pci_write_config_word ( dev, PMC551_SDRAM_CMD, 0x0ff);
+
+ /*
+ * Wait until command completes
+ * FIXME: register spinning issue
+ */
+ do { pci_read_config_word ( dev, PMC551_SDRAM_CMD, &cmd);
+ } while ( (PCI_COMMAND_IO) & cmd );
+
+ pci_read_config_dword ( dev, PMC551_DRAM_CFG, &dcmd);
+ dcmd |= 0x02000000;
+ pci_write_config_dword ( dev, PMC551_DRAM_CFG, dcmd);
+
+ /*
+ * Check to make certain fast back-to-back, if not
+ * then set it so
+ */
+ pci_read_config_word( dev, PCI_STATUS, &cmd);
+ if((cmd&PCI_COMMAND_FAST_BACK) == 0) {
+ cmd |= PCI_COMMAND_FAST_BACK;
+ pci_write_config_word( dev, PCI_STATUS, cmd);
+ }
+
+ /*
+ * Check to make certain the DEVSEL is set correctly, this device
+ * has a tendancy to assert DEVSEL and TRDY when a write is performed
+ * to the memory when memory is read-only
+ */
+ if((cmd&PCI_STATUS_DEVSEL_MASK) != 0x0) {
+ cmd &= ~PCI_STATUS_DEVSEL_MASK;
+ pci_write_config_word( dev, PCI_STATUS, cmd );
+ }
+
+ /*
+ * Check to see the state of the memory
+ * FIXME: perhaps hide some of this around an #ifdef DEBUG as
+ * it doesn't effect or enhance cards functionality
+ */
+ pci_read_config_dword( dev, 0x74, &dcmd );
+ printk(KERN_NOTICE "pmc551: DRAM_BLK3 Flags: %s,%s\n",
+ ((0x2&dcmd) == 0)?"RW":"RO",
+ ((0x1&dcmd) == 0)?"Off":"On" );
+
+ pci_read_config_dword( dev, 0x70, &dcmd );
+ printk(KERN_NOTICE "pmc551: DRAM_BLK2 Flags: %s,%s\n",
+ ((0x2&dcmd) == 0)?"RW":"RO",
+ ((0x1&dcmd) == 0)?"Off":"On" );
+
+ pci_read_config_dword( dev, 0x6C, &dcmd );
+ printk(KERN_NOTICE "pmc551: DRAM_BLK1 Flags: %s,%s\n",
+ ((0x2&dcmd) == 0)?"RW":"RO",
+ ((0x1&dcmd) == 0)?"Off":"On" );
+
+ pci_read_config_dword( dev, 0x68, &dcmd );
+ printk(KERN_NOTICE "pmc551: DRAM_BLK0 Flags: %s,%s\n",
+ ((0x2&dcmd) == 0)?"RW":"RO",
+ ((0x1&dcmd) == 0)?"Off":"On" );
+
+ pci_read_config_word( dev, 0x4, &cmd );
+ printk( KERN_NOTICE "pmc551: Memory Access %s\n",
+ ((0x2&cmd) == 0)?"off":"on" );
+ printk( KERN_NOTICE "pmc551: I/O Access %s\n",
+ ((0x1&cmd) == 0)?"off":"on" );
+
+ pci_read_config_word( dev, 0x6, &cmd );
+ printk( KERN_NOTICE "pmc551: Devsel %s\n",
+ ((PCI_STATUS_DEVSEL_MASK&cmd)==0x000)?"Fast":
+ ((PCI_STATUS_DEVSEL_MASK&cmd)==0x200)?"Medium":
+ ((PCI_STATUS_DEVSEL_MASK&cmd)==0x400)?"Slow":"Invalid" );
+
+ printk( KERN_NOTICE "pmc551: %sFast Back-to-Back\n",
+ ((PCI_COMMAND_FAST_BACK&cmd) == 0)?"Not ":"" );
+
+ return size;
+}
+
+/*
+ * Kernel version specific module stuffages
+ */
+#if LINUX_VERSION_CODE < 0x20300
+#ifdef MODULE
+#define init_pmc551 init_module
+#define cleanup_pmc551 cleanup_module
+#endif
+#define __exit
+#endif
+
+
+/*
+ * PMC551 Card Initialization
+ */
+//static int __init init_pmc551(void)
+int __init init_pmc551(void)
+{
+ struct pci_dev *PCI_Device = NULL;
+ struct mypriv *priv;
+ int count, found=0;
+ struct mtd_info *mtd;
+ u32 length = 0;
+
+
+ printk(KERN_NOTICE "Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n");
+ printk(KERN_INFO "$Id: pmc551.c,v 1.7 2000/07/03 10:01:38 dwmw2 Exp $\n");
+
+ if(!pci_present()) {
+ printk(KERN_NOTICE "pmc551: PCI not enabled.\n");
+ return -ENODEV;
+ }
+
+ /*
+ * PCU-bus chipset probe.
+ */
+ for( count = 0; count < MAX_MTD_DEVICES; count++ ) {
+
+ if ( (PCI_Device = pci_find_device( PCI_VENDOR_ID_V3_SEMI,
+ PCI_DEVICE_ID_V3_SEMI_V370PDC, PCI_Device ) ) == NULL) {
+ break;
+ }
+
+ printk(KERN_NOTICE "pmc551: Found PCI V370PDC IRQ:%d\n",
+ PCI_Device->irq);
+
+ /*
+ * The PMC551 device acts VERY wierd if you don't init it
+ * first. i.e. it will not correctly report devsel. If for
+ * some reason the sdram is in a wrote-protected state the
+ * device will DEVSEL when it is written to causing problems
+ * with the oldproc.c driver in
+ * some kernels (2.2.*)
+ */
+ if((length = fixup_pmc551(PCI_Device)) <= 0) {
+ printk(KERN_NOTICE "pmc551: Cannot init SDRAM\n");
+ break;
+ }
+
+ mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+ if (!mtd) {
+ printk(KERN_NOTICE "pmc551: Cannot allocate new MTD device.\n");
+ break;
+ }
+
+ memset(mtd, 0, sizeof(struct mtd_info));
+
+ priv = kmalloc (sizeof(struct mypriv), GFP_KERNEL);
+ if (!priv) {
+ printk(KERN_NOTICE "pmc551: Cannot allocate new MTD device.\n");
+ kfree(mtd);
+ break;
+ }
+ memset(priv, 0, sizeof(*priv));
+ mtd->priv = priv;
+
+ priv->dev = PCI_Device;
+ priv->aperture_size = PMC551_APERTURE_SIZE;
+ priv->start = ioremap((PCI_BASE_ADDRESS(PCI_Device)
+ & PCI_BASE_ADDRESS_MEM_MASK),
+ priv->aperture_size);
+ priv->mem_map0_base_val = (PMC551_APERTURE_VAL
+ | PMC551_PCI_MEM_MAP_REG_EN
+ | PMC551_PCI_MEM_MAP_ENABLE);
+ priv->curr_mem_map0_val = priv->mem_map0_base_val;
+
+ pci_write_config_dword ( priv->dev,
+ PMC551_PCI_MEM_MAP0,
+ priv->curr_mem_map0_val);
+
+ mtd->size = length;
+ mtd->flags = (MTD_CLEAR_BITS
+ | MTD_SET_BITS
+ | MTD_WRITEB_WRITEABLE
+ | MTD_VOLATILE);
+ mtd->erase = pmc551_erase;
+ mtd->point = NULL;
+ mtd->unpoint = pmc551_unpoint;
+ mtd->read = pmc551_read;
+ mtd->write = pmc551_write;
+ mtd->module = THIS_MODULE;
+ mtd->type = MTD_RAM;
+ mtd->name = "PMC551 RAM board";
+ mtd->erasesize = 0x10000;
+
+ if (add_mtd_device(mtd)) {
+ printk(KERN_NOTICE "pmc551: Failed to register new device\n");
+ kfree(mtd->priv);
+ kfree(mtd);
+ break;
+ }
+ printk(KERN_NOTICE "Registered pmc551 memory device.\n");
+ printk(KERN_NOTICE "Mapped %dM of memory from 0x%p to 0x%p\n",
+ priv->aperture_size/1024/1024,
+ priv->start,
+ priv->start + priv->aperture_size);
+ printk(KERN_NOTICE "Total memory is %dM\n", length/1024/1024);
+ priv->nextpmc551 = pmc551list;
+ pmc551list = mtd;
+ found++;
+ }
+
+ if( !pmc551list ) {
+ printk(KERN_NOTICE "pmc551: not detected,\n");
+ return -ENODEV;
+ } else {
+ return 0;
+ printk(KERN_NOTICE "pmc551: %d pmc551 devices loaded\n", found);
+ }
+}
+
+/*
+ * PMC551 Card Cleanup
+ */
+static void __exit cleanup_pmc551(void)
+{
+ int found=0;
+ struct mtd_info *mtd;
+ struct mypriv *priv;
+
+ while((mtd=pmc551list)) {
+ priv = (struct mypriv *)mtd->priv;
+ pmc551list = priv->nextpmc551;
+
+ if(priv->start)
+ iounmap(((struct mypriv *)mtd->priv)->start);
+
+ kfree (mtd->priv);
+ del_mtd_device(mtd);
+ kfree(mtd);
+ found++;
+ }
+
+ printk(KERN_NOTICE "pmc551: %d pmc551 devices unloaded\n", found);
+}
+
+#if LINUX_VERSION_CODE > 0x20300
+module_init(init_pmc551);
+module_exit(cleanup_pmc551);
+#endif
+
+
+
diff --git a/drivers/mtd/rpxlite.c b/drivers/mtd/rpxlite.c
new file mode 100644
index 000000000..783c863ac
--- /dev/null
+++ b/drivers/mtd/rpxlite.c
@@ -0,0 +1,160 @@
+/*
+ * $Id: rpxlite.c,v 1.2 2000/07/04 12:16:26 dwmw2 Exp $
+ *
+ * Handle the strange 16-in-32-bit mapping on the RPXLite board
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+
+
+#define WINDOW_ADDR 0x8000000
+#define WINDOW_SIZE 0x2000000
+
+#define MAP_TO_ADR(x) ( ( ( x & ~1 ) << 1 ) | (x&1) )
+
+static struct mtd_info *mymtd;
+
+__u8 rpxlite_read8(struct map_info *map, unsigned long ofs)
+{
+ return readb(map->map_priv_1 + MAP_TO_ADR(ofs));
+}
+
+__u16 rpxlite_read16(struct map_info *map, unsigned long ofs)
+{
+ return readw(map->map_priv_1 + MAP_TO_ADR(ofs));
+}
+
+__u32 rpxlite_read32(struct map_info *map, unsigned long ofs)
+{
+ return readl(map->map_priv_1 + MAP_TO_ADR(ofs));
+}
+
+void rpxlite_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ if (from & 1) {
+ *(__u8 *)to = readb(map->map_priv_1 + MAP_TO_ADR(from));
+ from++;
+ len--;
+ }
+ /* Can't do this if it's not aligned */
+ if (!((unsigned long)to & 1)) {
+ unsigned long fromadr = MAP_TO_ADR(from);
+
+ while (len > 1) {
+ *(__u16 *)to = readw(map->map_priv_1 + fromadr);
+ to += 2;
+ fromadr += 4;
+ from += 2;
+ len -= 2;
+ }
+ }
+ while(len) {
+ *(__u8 *)to = readb(map->map_priv_1 + MAP_TO_ADR(from));
+ to++;
+ from++;
+ len--;
+ }
+}
+
+void rpxlite_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ writeb(d, map->map_priv_1 + MAP_TO_ADR(adr));
+}
+
+void rpxlite_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ writew(d, map->map_priv_1 + MAP_TO_ADR(adr));
+}
+
+void rpxlite_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ writel(d, map->map_priv_1 + MAP_TO_ADR(adr));
+}
+
+void rpxlite_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ if (to & 1) {
+ writeb(*(__u8 *)from, map->map_priv_1 + MAP_TO_ADR(to));
+ from++;
+ len--;
+ }
+ /* Can't do this if it's not aligned */
+ if (!((unsigned long)from & 1)) {
+ unsigned long toadr = map->map_priv_1 + MAP_TO_ADR(to);
+
+ while (len > 1) {
+ writew(*(__u16 *)from, toadr);
+ from += 2;
+ toadr += 4;
+ to += 2;
+ len -= 2;
+ }
+ }
+ while(len) {
+ writeb(*(__u8 *)from, map->map_priv_1 + MAP_TO_ADR(to));
+ to++;
+ from++;
+ len--;
+ }
+}
+
+struct map_info rpxlite_map = {
+ "RPXLITE",
+ WINDOW_SIZE,
+ 2,
+ rpxlite_read8,
+ rpxlite_read16,
+ rpxlite_read32,
+ rpxlite_copy_from,
+ rpxlite_write8,
+ rpxlite_write16,
+ rpxlite_write32,
+ rpxlite_copy_to,
+ 0,
+ 0
+};
+
+#if LINUX_VERSION_CODE < 0x20300
+#ifdef MODULE
+#define init_rpxlite init_module
+#define cleanup_rpxlite cleanup_module
+#endif
+#endif
+
+int __init init_rpxlite(void)
+{
+ printk(KERN_NOTICE "rpxlite flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
+ rpxlite_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 2);
+
+ if (!rpxlite_map.map_priv_1) {
+ printk("Failed to ioremap\n");
+ return -EIO;
+ }
+ mymtd = do_cfi_probe(&rpxlite_map);
+ if (mymtd) {
+#ifdef MODULE
+ mymtd->module = &__this_module;
+#endif
+ add_mtd_device(mymtd);
+ return 0;
+ }
+
+ return -ENXIO;
+}
+
+static void __exit cleanup_rpxlite(void)
+{
+ if (mymtd) {
+ del_mtd_device(mymtd);
+ map_destroy(mymtd);
+ }
+ if (rpxlite_map.map_priv_1) {
+ iounmap((void *)rpxlite_map.map_priv_1);
+ rpxlite_map.map_priv_1 = 0;
+ }
+}
diff --git a/drivers/mtd/slram.c b/drivers/mtd/slram.c
new file mode 100644
index 000000000..48067c814
--- /dev/null
+++ b/drivers/mtd/slram.c
@@ -0,0 +1,226 @@
+/*======================================================================
+
+ $Id: slram.c,v 1.10 2000/07/03 10:01:38 dwmw2 Exp $
+
+======================================================================*/
+
+
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <stdarg.h>
+
+#include <linux/mtd/mtd.h>
+
+struct mypriv {
+ u_char *start;
+ u_char *end;
+};
+
+int physmem_erase (struct mtd_info *mtd, struct erase_info *instr);
+int physmem_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
+void physmem_unpoint (struct mtd_info *mtd, u_char *addr);
+int physmem_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+int physmem_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
+
+
+int physmem_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+ struct mypriv *priv = mtd->priv;
+
+ if (instr->addr + instr->len > mtd->size)
+ return -EINVAL;
+
+ memset(priv->start + instr->addr, 0xff, instr->len);
+
+ /* This'll catch a few races. Free the thing before returning :)
+ * I don't feel at all ashamed. This kind of thing is possible anyway
+ * with flash, but unlikely.
+ */
+
+ instr->state = MTD_ERASE_DONE;
+
+ if (instr->callback)
+ (*(instr->callback))(instr);
+ else
+ kfree(instr);
+
+ return 0;
+}
+
+
+int physmem_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
+{
+ struct mypriv *priv = (struct mypriv *)mtd->priv;
+
+ *mtdbuf = priv->start + from;
+ *retlen = len;
+ return 0;
+}
+
+void physmem_unpoint (struct mtd_info *mtd, u_char *addr)
+{
+}
+
+int physmem_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+ struct mypriv *priv = (struct mypriv *)mtd->priv;
+
+ memcpy (buf, priv->start + from, len);
+
+ *retlen=len;
+ return 0;
+}
+
+int physmem_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
+{
+ struct mypriv *priv = (struct mypriv *)mtd->priv;
+
+ memcpy (priv->start + to, buf, len);
+
+ *retlen=len;
+ return 0;
+}
+
+
+
+
+/*====================================================================*/
+
+/* Place your defaults here */
+
+static u_long start = 100663296;
+static u_long length = 33554432;
+static u_long end = 0;
+
+#if LINUX_VERSION_CODE < 0x20300
+#ifdef MODULE
+#define init_slram init_module
+#define cleanup_slram cleanup_module
+#endif
+#define __exit
+#endif
+
+#ifdef MODULE
+MODULE_PARM(start,"l");
+MODULE_PARM(length,"l");
+MODULE_PARM(end,"l");
+#endif
+
+struct mtd_info *mymtd;
+
+void __init mtd_slram_setup(char *str, int *ints)
+{
+ if (ints[0] > 0)
+ start=ints[1];
+ if (ints[0] > 1)
+ length=ints[2];
+}
+
+int init_slram(void)
+{
+ if (!start)
+ {
+ printk(KERN_NOTICE "physmem: No start address for memory device.\n");
+ return -EINVAL;
+ }
+
+ if (!length && !end)
+ {
+ printk(KERN_NOTICE "physmem: No length or endpointer given.\n");
+ return -EINVAL;
+ }
+
+ if (!end)
+ end = start + length;
+
+ if (!length)
+ length = end - start;
+
+ if (start + length != end)
+ {
+ printk(KERN_NOTICE "physmem: start(%lx) + length(%lx) != end(%lx) !\n",
+ start, length, end);
+ return -EINVAL;
+ }
+
+ mymtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+
+ memset(mymtd, 0, sizeof(*mymtd));
+
+ if (mymtd)
+ {
+ memset((char *)mymtd, 0, sizeof(struct mtd_info));
+ mymtd->priv = (void *) kmalloc (sizeof(struct mypriv), GFP_KERNEL);
+ if (!mymtd->priv)
+ {
+ kfree(mymtd);
+ mymtd = NULL;
+ }
+ memset(mymtd->priv, 0, sizeof(struct mypriv));
+ }
+
+ if (!mymtd)
+ {
+ printk(KERN_NOTICE "physmem: Cannot allocate new MTD device.\n");
+ return -ENOMEM;
+ }
+
+
+ ((struct mypriv *)mymtd->priv)->start = ioremap(start, length);
+ ((struct mypriv *)mymtd->priv)->end = ((struct mypriv *)mymtd->priv)->start + length;
+
+
+ mymtd->name = "Raw memory";
+
+ mymtd->size = length;
+ mymtd->flags = MTD_CLEAR_BITS | MTD_SET_BITS | MTD_WRITEB_WRITEABLE | MTD_VOLATILE;
+ mymtd->erase = physmem_erase;
+ mymtd->point = physmem_point;
+ mymtd->unpoint = physmem_unpoint;
+ mymtd->read = physmem_read;
+ mymtd->write = physmem_write;
+ mymtd->module = THIS_MODULE;
+ mymtd->type = MTD_RAM;
+ mymtd->erasesize = 0x10000;
+
+ if (add_mtd_device(mymtd))
+ {
+ printk("Failed to register new device\n");
+ kfree(mymtd->priv);
+ kfree(mymtd);
+ return -EAGAIN;
+ }
+ printk("Registered physmem device from %dKb to %dKb\n",
+ (int)(start / 1024), (int)(end / 1024));
+ printk("Mapped from 0x%p to 0x%p\n",((struct mypriv *)mymtd->priv)->start,
+((struct mypriv *)mymtd->priv)->end);
+
+ return 0;
+}
+
+static void __exit cleanup_slram(void)
+{
+ iounmap(((struct mypriv *)mymtd->priv)->start);
+ kfree (mymtd->priv);
+ del_mtd_device(mymtd);
+ kfree(mymtd);
+}
+
+#if LINUX_VERSION_CODE > 0x20300
+module_init(init_slram);
+module_exit(cleanup_slram);
+#endif
diff --git a/drivers/mtd/vmax301.c b/drivers/mtd/vmax301.c
new file mode 100644
index 000000000..553beaad6
--- /dev/null
+++ b/drivers/mtd/vmax301.c
@@ -0,0 +1,243 @@
+// $Id: vmax301.c,v 1.13 2000/07/03 10:01:38 dwmw2 Exp $
+/* ######################################################################
+
+ Tempustech VMAX SBC301 MTD Driver.
+
+ The VMAx 301 is a SBC based on . It
+ comes with three builtin AMD 29F016B flash chips and a socket for SRAM or
+ more flash. Each unit has it's own 8k mapping into a settable region
+ (0xD8000). There are two 8k mappings for each MTD, the first is always set
+ to the lower 8k of the device the second is paged. Writing a 16 bit page
+ value to anywhere in the first 8k will cause the second 8k to page around.
+
+ To boot the device a bios extension must be installed into the first 8k
+ of flash that is smart enough to copy itself down, page in the rest of
+ itself and begin executing.
+
+ ##################################################################### */
+
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <asm/spinlock.h>
+#include <asm/io.h>
+
+#include <linux/mtd/map.h>
+
+
+#define WINDOW_START 0xd8000
+#define WINDOW_LENGTH 0x2000
+#define WINDOW_SHIFT 25
+#define WINDOW_MASK 0x1FFF
+
+/* Actually we could use two spinlocks, but we'd have to have
+ more private space in the struct map_info. We lose a little
+ performance like this, but we'd probably lose more by having
+ the extra indirection from having one of the map->map_priv
+ fields pointing to yet another private struct.
+*/
+static spinlock_t vmax301_spin = SPIN_LOCK_UNLOCKED;
+
+static void __vmax301_page(struct map_info *map, unsigned long page)
+{
+ writew(page, map->map_priv_2 - WINDOW_LENGTH);
+ map->map_priv_1 = page;
+}
+
+static inline void vmax301_page(struct map_info *map,
+ unsigned long ofs)
+{
+ unsigned long page = (ofs >> WINDOW_SHIFT);
+ if (map->map_priv_1 != page)
+ __vmax301_page(map, page);
+}
+
+static __u8 vmax301_read8(struct map_info *map, unsigned long ofs)
+{
+ __u8 ret;
+ spin_lock(&vmax301_spin);
+ vmax301_page(map, ofs);
+ ret = readb(map->map_priv_2 + (ofs & WINDOW_MASK));
+ spin_unlock(&vmax301_spin);
+ return ret;
+}
+
+static __u16 vmax301_read16(struct map_info *map, unsigned long ofs)
+{
+ __u16 ret;
+ spin_lock(&vmax301_spin);
+ vmax301_page(map, ofs);
+ ret = readw(map->map_priv_2 + (ofs & WINDOW_MASK));
+ spin_unlock(&vmax301_spin);
+ return ret;
+}
+
+static __u32 vmax301_read32(struct map_info *map, unsigned long ofs)
+{
+ __u32 ret;
+ spin_lock(&vmax301_spin);
+ vmax301_page(map, ofs);
+ ret = readl(map->map_priv_2 + (ofs & WINDOW_MASK));
+ spin_unlock(&vmax301_spin);
+ return ret;
+}
+
+static void vmax301_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ while(len) {
+ unsigned long thislen = len;
+ if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
+ thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
+ spin_lock(&vmax301_spin);
+ vmax301_page(map, from);
+ memcpy_fromio(to, map->map_priv_2 + from, thislen);
+ spin_unlock(&vmax301_spin);
+ to += thislen;
+ from += thislen;
+ len -= thislen;
+ }
+}
+
+static void vmax301_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ spin_lock(&vmax301_spin);
+ vmax301_page(map, adr);
+ writeb(d, map->map_priv_2 + (adr & WINDOW_MASK));
+ spin_unlock(&vmax301_spin);
+}
+
+static void vmax301_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ spin_lock(&vmax301_spin);
+ vmax301_page(map, adr);
+ writew(d, map->map_priv_2 + (adr & WINDOW_MASK));
+ spin_unlock(&vmax301_spin);
+}
+
+static void vmax301_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ spin_lock(&vmax301_spin);
+ vmax301_page(map, adr);
+ writel(d, map->map_priv_2 + (adr & WINDOW_MASK));
+ spin_unlock(&vmax301_spin);
+}
+
+static void vmax301_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ while(len) {
+ unsigned long thislen = len;
+ if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
+ thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
+
+ spin_lock(&vmax301_spin);
+ vmax301_page(map, to);
+ memcpy_toio(map->map_priv_2 + to, from, thislen);
+ spin_unlock(&vmax301_spin);
+ to += thislen;
+ from += thislen;
+ len -= thislen;
+ }
+}
+
+static struct map_info vmax_map[2] = {
+ {
+ "VMAX301 Internal Flash",
+ 3*2*1024*1024,
+ 1,
+ vmax301_read8,
+ vmax301_read16,
+ vmax301_read32,
+ vmax301_copy_from,
+ vmax301_write8,
+ vmax301_write16,
+ vmax301_write32,
+ vmax301_copy_to,
+ WINDOW_START + WINDOW_LENGTH,
+ 0xFFFFFFFF
+ },
+ {
+ "VMAX301 Socket",
+ 0,
+ 1,
+ vmax301_read8,
+ vmax301_read16,
+ vmax301_read32,
+ vmax301_copy_from,
+ vmax301_write8,
+ vmax301_write16,
+ vmax301_write32,
+ vmax301_copy_to,
+ WINDOW_START + (3*WINDOW_LENGTH),
+ 0xFFFFFFFF
+ }
+};
+
+static struct mtd_info *vmax_mtd[2] = {NULL, NULL};
+
+#if LINUX_VERSION_CODE < 0x20300
+#ifdef MODULE
+#define init_vmax301 init_module
+#define cleanup_vmax301 cleanup_module
+#endif
+#define __exit
+#endif
+
+static void __exit cleanup_vmax301(void)
+{
+ int i;
+
+ for (i=0; i<2; i++) {
+ if (vmax_mtd[i]) {
+ del_mtd_device(vmax_mtd[i]);
+ map_destroy(vmax_mtd[i]);
+ }
+ }
+ iounmap((void *)vmax_map[0].map_priv_1 - WINDOW_START);
+}
+
+int __init init_vmax301(void)
+{
+ int i;
+ unsigned long iomapadr;
+ // Print out our little header..
+ printk("Tempustech VMAX 301 MEM:0x%x-0x%x\n",WINDOW_START,
+ WINDOW_START+4*WINDOW_LENGTH);
+
+ iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH*4);
+ if (!iomapadr) {
+ printk("Failed to ioremap memory region\n");
+ return -EIO;
+ }
+ /* Put the address in the map's private data area.
+ We store the actual MTD IO address rather than the
+ address of the first half, because it's used more
+ often.
+ */
+ vmax_map[0].map_priv_1 = iomapadr + WINDOW_START;
+ vmax_map[1].map_priv_1 = iomapadr + (3*WINDOW_START);
+
+ for (i=0; i<2; i++) {
+ vmax_mtd[i] = do_cfi_probe(&vmax_map[i]);
+ if (!vmax_mtd[i])
+ vmax_mtd[i] = do_jedec_probe(&vmax_map[i]);
+ if (!vmax_mtd[i])
+ vmax_mtd[i] = do_ram_probe(&vmax_map[i]);
+ if (!vmax_mtd[i])
+ vmax_mtd[i] = do_rom_probe(&vmax_map[i]);
+ if (vmax_mtd[i]) {
+ vmax_mtd[i]->module = THIS_MODULE;
+ add_mtd_device(vmax_mtd[i]);
+ }
+ }
+
+ if (!vmax_mtd[1] && !vmax_mtd[2])
+ return -ENXIO;
+
+ return 0;
+}
+
+#if LINUX_VERSION_CODE > 0x20300
+module_init(init_vmax301);
+module_exit(cleanup_vmax301);
+#endif
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 315f99e5b..25257b052 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -111,7 +111,6 @@ extern int de600_probe(struct net_device *);
extern int de620_probe(struct net_device *);
/* FDDI adapters */
-extern int dfx_probe(void);
extern int apfddi_init(struct net_device *dev);
extern int skfp_probe(struct net_device *dev);
@@ -177,9 +176,6 @@ struct devprobe eisa_probes[] __initdata = {
#ifdef CONFIG_NE3210
{ne3210_probe, 0},
#endif
-#ifdef CONFIG_DEFXX
- {dfx_probe, 0},
-#endif
{NULL, 0},
};
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index e5a60310c..681379708 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -1239,6 +1239,7 @@ int __init ltpc_probe(struct net_device *dev)
return 0;
}
+#ifndef MODULE
/* handles "ltpc=io,irq,dma" kernel command lines */
static int __init ltpc_setup(char *str)
{
@@ -1270,6 +1271,12 @@ static int __init ltpc_setup(char *str)
}
__setup("ltpc=", ltpc_setup);
+#endif /* MODULE */
+
+MODULE_PARM(debug, "i");
+MODULE_PARM(io, "i");
+MODULE_PARM(irq, "i");
+MODULE_PARM(dma, "i");
#ifdef MODULE
@@ -1279,12 +1286,7 @@ static struct net_device dev_ltpc = {
0x0, 0,
0, 0, 0, NULL, ltpc_probe };
-MODULE_PARM(debug, "i");
-MODULE_PARM(io, "i");
-MODULE_PARM(irq, "i");
-MODULE_PARM(dma, "i");
-
-int init_module(void)
+int __init init_module(void)
{
int err, result;
@@ -1306,8 +1308,9 @@ int init_module(void)
return 0;
}
}
+#endif
-void cleanup_module(void)
+static void __exit ltpc_cleanup(void)
{
long timeout;
@@ -1360,5 +1363,5 @@ void cleanup_module(void)
if(debug&DEBUG_VERBOSE) printk("returning from cleanup_module\n");
}
-#endif /* MODULE */
+module_exit(ltpc_cleanup);
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 39939746d..096dd03c5 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -125,7 +125,7 @@ static unsigned int net_debug = NET_DEBUG;
#include <linux/timer.h>
static void atp_timed_checker(unsigned long ignored);
static struct net_device *atp_timed_dev;
-static struct timer_list atp_timer = {NULL, NULL, 0, 0, atp_timed_checker};
+static struct timer_list atp_timer = { function: atp_timed_checker };
#endif
/* Index to functions, as function prototypes. */
diff --git a/drivers/net/bonding.c b/drivers/net/bonding.c
index 67f076d46..c806f028d 100644
--- a/drivers/net/bonding.c
+++ b/drivers/net/bonding.c
@@ -126,8 +126,6 @@ static void bond_set_multicast_list(struct net_device *master)
slave->dev->flags = master->flags;
slave->dev->set_multicast_list(slave->dev);
}
-
- return 0;
}
static int bond_enslave(struct net_device *master, struct net_device *dev)
@@ -182,7 +180,7 @@ static int bond_release(struct net_device *master, struct net_device *dev)
}
}
- return 0;
+ return;
}
/* It is pretty silly, SIOCSIFHWADDR exists to make this. */
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 841b314ee..d6f22eb04 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -1558,7 +1558,10 @@ init_module(void)
#if DEBUGGING
net_debug = debug;
+#else
+ debug = 0;
#endif
+
dev_cs89x0.irq = irq;
dev_cs89x0.base_addr = io;
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 1a8fedb5d..64f49180f 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -195,16 +195,12 @@
* device open. Updated transmit path to post a
* single fragment which includes PRH->end of data.
* Mar 2000 AC Did various cleanups for 2.3.x
+ * Jun 2000 jgarzik PCI and resource alloc cleanups
*/
-/* Version information string - should be updated prior to each new release!!! */
-
-static const char *version = "defxx.c:v1.05 2000/03/26 Lawrence V. Stefani (stefani@lkg.dec.com) and others\n";
-
/* Include files */
#include <linux/module.h>
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -226,6 +222,10 @@ static const char *version = "defxx.c:v1.05 2000/03/26 Lawrence V. Stefani (ste
#include "defxx.h"
+/* Version information string - should be updated prior to each new release!!! */
+static char version[] __initdata =
+ "defxx.c:v1.05a 2000/06/11 Lawrence V. Stefani (stefani@lkg.dec.com) and others\n";
+
#define DYNAMIC_BUFFERS 1
#define SKBUFF_RX_COPYBREAK 200
@@ -235,10 +235,6 @@ static const char *version = "defxx.c:v1.05 2000/03/26 Lawrence V. Stefani (ste
*/
#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128)
-/* Define global routines */
-
-int dfx_probe(void);
-
/* Define module-wide (static) routines */
static struct net_device *dfx_alloc_device(u16 iobase);
@@ -428,22 +424,92 @@ static inline void dfx_port_read_long(
*/
static struct net_device *bp_root;
+static int version_disp;
+static int have_pci_driver;
+
+static struct pci_device_id dfx_pci_tbl[] __initdata = {
+ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, PCI_ANY_ID, PCI_ANY_ID, },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, dfx_pci_tbl);
-int __init dfx_probe(void)
+static int __init dfx_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *dev;
+ DFX_board_t *bp; /* board pointer */
+ int port;
+
+ if (!version_disp) { /* display version info if adapter is found */
+ version_disp = 1; /* set display flag to TRUE so that */
+ printk (version); /* we only display this string ONCE */
+ }
+
+ if (pci_enable_device (pdev))
+ goto err_out;
+ pci_set_master (pdev);
+
+ /* Get I/O base address from PCI Configuration Space */
+ port = pci_resource_start (pdev, 1);
+
+ if (!request_region (port, PFI_K_CSR_IO_LEN, "defxx")) {
+ printk (KERN_ERR
+ "defxx: I/O range allocated to adapter (0x%X-0x%X) is already being used!\n",
+ port, (port + PFI_K_CSR_IO_LEN - 1));
+ goto err_out;
+ }
+
+ /* Allocate a new device structure for this adapter */
+ dev = dfx_alloc_device (port);
+ if (dev == NULL) {
+ printk (KERN_ERR "defxx: alloc device failed\n");
+ goto err_out_region;
+ }
+
+ /* Initialize board structure with bus-specific info */
+ bp = (DFX_board_t *) dev->priv;
+ bp->dev = dev;
+ bp->next = bp_root;
+ bp_root = dev;
+ bp->bus_type = DFX_BUS_TYPE_PCI;
+ bp->pci_dev = pdev;
+
+ /*
+ * FIXME FIXME FIXME
+ * Suck! The original driver didn't clean up after
+ * itself at this stage, so we won't either. Someone
+ * needs to go back and see what (if anything) we need
+ * to free here... -jgarzik
+ */
+ if (dfx_driver_init (dev) != DFX_K_SUCCESS) {
+ dev->base_addr = 0; /* clear port address field in device structure on failure */
+ goto err_out_region;
+ }
+
+ return 0;
+
+err_out_region:
+ release_region (port, PFI_K_CSR_IO_LEN);
+err_out:
+ return -ENODEV;
+};
+
+static struct pci_driver dfx_driver = {
+ name: "defxx",
+ id_table: dfx_pci_tbl,
+ probe: dfx_init_one,
+};
+
+static int __init dfx_probe(void)
{
int i; /* used in for loops */
- int version_disp; /* was version info string already displayed? */
- int port_len; /* length of port address range (in bytes) */
u16 port; /* temporary I/O (port) address */
- struct pci_dev * pdev = NULL; /* PCI device record */
- u16 command; /* PCI Configuration space Command register val */
u32 slot_id; /* EISA hardware (slot) ID read from adapter */
DFX_board_t *bp; /* board pointer */
struct net_device *dev;
DBG_printk("In dfx_probe...\n");
- version_disp = 0; /* default to version string not displayed */
already_probed = 1; /* set global flag */
/* Scan for FDDI EISA controllers */
@@ -463,9 +529,7 @@ int __init dfx_probe(void)
port = (i << 12); /* recalc base addr */
/* Verify port address range is not already being used */
-
- port_len = PI_ESIC_K_CSR_IO_LEN;
- if (check_region(port, port_len) == 0)
+ if (request_region(port, PI_ESIC_K_CSR_IO_LEN, "defxx"))
{
/* Allocate a new device structure for this adapter */
@@ -485,70 +549,17 @@ int __init dfx_probe(void)
}
}
else
- printk("I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1));
+ printk("I/O range allocated to adapter (0x%X-0x%X) is already being used!\n",
+ port, (port + PI_ESIC_K_CSR_IO_LEN-1));
}
}
/* Scan for FDDI PCI controllers */
-
- if (pci_present()) /* is PCI even present? */
- while ((pdev = pci_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, pdev)))
- {
- if (!version_disp) /* display version info if adapter is found */
- {
- version_disp = 1; /* set display flag to TRUE so that */
- printk(version); /* we only display this string ONCE */
- }
-
- if (pci_enable_device(pdev))
- continue;
-
- /* Verify that I/O enable bit is set (PCI slot is enabled) */
-
- pci_read_config_word(pdev, PCI_COMMAND, &command);
- if ((command & PCI_COMMAND_IO) == 0)
- printk(KERN_ERR "defxx: I/O enable bit not set! Verify that slot is enabled\n");
- else
- {
- /* Turn off memory mapped space and enable mastering */
-
- command |= PCI_COMMAND_MASTER;
- command &= ~PCI_COMMAND_MEMORY;
- pci_write_config_word(pdev, PCI_COMMAND, command);
-
- /* Get I/O base address from PCI Configuration Space */
-
- port = pci_resource_start (pdev, 1);
-
- /* Verify port address range is not already being used */
-
- port_len = PFI_K_CSR_IO_LEN;
-
- if (check_region(port, port_len) == 0)
- {
- /* Allocate a new device structure for this adapter */
-
- dev = dfx_alloc_device(port);
- if (dev != NULL)
- {
- /* Initialize board structure with bus-specific info */
-
- bp = (DFX_board_t *) dev->priv;
- bp->dev = dev;
- bp->next = bp_root;
- bp_root = dev;
- bp->bus_type = DFX_BUS_TYPE_PCI;
- bp->pci_dev = pdev;
- if (dfx_driver_init(dev) == DFX_K_SUCCESS)
- num_boards++; /* only increment global board count on success */
- else
- dev->base_addr = 0; /* clear port address field in device structure on failure */
- }
- }
- else
- printk(KERN_ERR "defxx: I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1));
- }
- }
+ i = pci_register_driver (&dfx_driver);
+ if (i > 0) {
+ num_boards += i;
+ have_pci_driver = 1;
+ }
/*
* If we're at this point we're going through dfx_probe() for the first
@@ -556,10 +567,7 @@ int __init dfx_probe(void)
* Otherwise, return failure (-ENODEV).
*/
- if (num_boards > 0)
- return(0);
- else
- return(-ENODEV);
+ return (num_boards > 0) ? 0 : -ENODEV;
}
@@ -3464,28 +3472,34 @@ void dfx_xmt_flush(
}
-#ifdef MODULE
-
-int init_module(void)
-{
- if(dfx_probe()<0)
- return -ENODEV;
- return 0;
-}
-void cleanup_module(void)
+static void __exit dfx_cleanup(void)
{
while(bp_root!=NULL)
{
struct net_device *tmp=bp_root;
DFX_board_t *priv=tmp->priv;
bp_root=priv->next;
+
+ /* FIXME: need to unregister FDDI device here?
+ * The original driver didn't do it, but I think so..
+ * -jgarzik
+ */
+
+ if (priv->bus_type == DFX_BUS_TYPE_EISA)
+ release_region(tmp->base_addr, PI_ESIC_K_CSR_IO_LEN);
+ else
+ release_region(tmp->base_addr, PFI_K_CSR_IO_LEN);
+
kfree(tmp->priv);
kfree(tmp);
}
+ if (have_pci_driver)
+ pci_unregister_driver(&dfx_driver);
}
-#endif
+module_init(dfx_probe);
+module_exit(dfx_cleanup);
/*
diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c
index 20865a48d..8ff607a01 100644
--- a/drivers/net/hamradio/baycom_par.c
+++ b/drivers/net/hamradio/baycom_par.c
@@ -63,6 +63,7 @@
* 0.7 10.08.1999 Check if parport can do SPP and is safe to access during interrupt contexts
* 0.8 12.02.2000 adapted to softnet driver interface
* removed direct parport access, uses parport driver methods
+ * 0.9 03.07.2000 fix interface name handling
*/
/*****************************************************************************/
@@ -101,7 +102,7 @@
static const char bc_drvname[] = "baycom_par";
static const char bc_drvinfo[] = KERN_INFO "baycom_par: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_par: version 0.8 compiled " __TIME__ " " __DATE__ "\n";
+KERN_INFO "baycom_par: version 0.9 compiled " __TIME__ " " __DATE__ "\n";
/* --------------------------------------------------------------------- */
@@ -512,14 +513,15 @@ static int __init init_baycompar(void)
*/
for (i = 0; i < NR_PORTS; i++) {
struct net_device *dev = baycom_device+i;
- sprintf(dev->name, "bcp%d", i);
+ char ifname[IFNAMSIZ];
+ sprintf(ifname, "bcp%d", i);
if (!mode[i])
set_hw = 0;
if (!set_hw)
iobase[i] = 0;
j = hdlcdrv_register_hdlcdrv(dev, &par96_ops, sizeof(struct baycom_state),
- dev->name, iobase[i], 0, 0);
+ ifname, iobase[i], 0, 0);
if (!j) {
bc = (struct baycom_state *)dev->priv;
if (set_hw && baycom_setmode(bc, mode[i]))
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
index 6a6603ba3..cb43d038e 100644
--- a/drivers/net/hamradio/baycom_ser_fdx.c
+++ b/drivers/net/hamradio/baycom_ser_fdx.c
@@ -66,6 +66,7 @@
* 0.7 03.08.1999 adapt to Linus' new __setup/__initcall
* 0.8 10.08.1999 use module_init/module_exit
* 0.9 12.02.2000 adapted to softnet driver interface
+ * 0.10 03.07.2000 fix interface name handling
*/
/*****************************************************************************/
@@ -88,7 +89,7 @@
static const char bc_drvname[] = "baycom_ser_fdx";
static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_ser_fdx: version 0.9 compiled " __TIME__ " " __DATE__ "\n";
+KERN_INFO "baycom_ser_fdx: version 0.10 compiled " __TIME__ " " __DATE__ "\n";
/* --------------------------------------------------------------------- */
@@ -628,14 +629,15 @@ static int __init init_baycomserfdx(void)
*/
for (i = 0; i < NR_PORTS; i++) {
struct net_device *dev = baycom_device+i;
- sprintf(dev->name, "bcsf%d", i);
+ char ifname[IFNAMSIZ];
+ sprintf(ifname, "bcsf%d", i);
if (!mode[i])
set_hw = 0;
if (!set_hw)
iobase[i] = irq[i] = 0;
j = hdlcdrv_register_hdlcdrv(dev, &ser12_ops, sizeof(struct baycom_state),
- dev->name, iobase[i], irq[i], 0);
+ ifname, iobase[i], irq[i], 0);
if (!j) {
bc = (struct baycom_state *)dev->priv;
if (set_hw && baycom_setmode(bc, mode[i]))
diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c
index 80483a171..dfe2312f0 100644
--- a/drivers/net/hamradio/baycom_ser_hdx.c
+++ b/drivers/net/hamradio/baycom_ser_hdx.c
@@ -56,6 +56,7 @@
* 0.7 03.08.1999 adapt to Linus' new __setup/__initcall
* 0.8 10.08.1999 use module_init/module_exit
* 0.9 12.02.2000 adapted to softnet driver interface
+ * 0.10 03.07.2000 fix interface name handling
*/
/*****************************************************************************/
@@ -78,7 +79,7 @@
static const char bc_drvname[] = "baycom_ser_hdx";
static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "baycom_ser_hdx: version 0.9 compiled " __TIME__ " " __DATE__ "\n";
+KERN_INFO "baycom_ser_hdx: version 0.10 compiled " __TIME__ " " __DATE__ "\n";
/* --------------------------------------------------------------------- */
@@ -668,14 +669,15 @@ static int __init init_baycomserhdx(void)
*/
for (i = 0; i < NR_PORTS; i++) {
struct net_device *dev = baycom_device+i;
- sprintf(dev->name, "bcsh%d", i);
+ char ifname[IFNAMSIZ];
+ sprintf(ifname, "bcsh%d", i);
if (!mode[i])
set_hw = 0;
if (!set_hw)
iobase[i] = irq[i] = 0;
j = hdlcdrv_register_hdlcdrv(dev, &ser12_ops, sizeof(struct baycom_state),
- dev->name, iobase[i], irq[i], 0);
+ ifname, iobase[i], irq[i], 0);
if (!j) {
bc = (struct baycom_state *)dev->priv;
if (set_hw && baycom_setmode(bc, mode[i]))
diff --git a/drivers/net/hamradio/soundmodem/sm.c b/drivers/net/hamradio/soundmodem/sm.c
index c9bf6b119..c5a52b8ab 100644
--- a/drivers/net/hamradio/soundmodem/sm.c
+++ b/drivers/net/hamradio/soundmodem/sm.c
@@ -46,6 +46,7 @@
* removed some pre-2.2 kernel compatibility cruft
* 0.10 10.08.1999 Check if parport can do SPP and is safe to access during interrupt contexts
* 0.11 12.02.2000 adapted to softnet driver interface
+ * 0.12 03.07.2000 fix interface name handling
*/
/*****************************************************************************/
@@ -65,7 +66,7 @@
/*static*/ const char sm_drvname[] = "soundmodem";
static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "soundmodem: version 0.11 compiled " __TIME__ " " __DATE__ "\n";
+KERN_INFO "soundmodem: version 0.12 compiled " __TIME__ " " __DATE__ "\n";
/* --------------------------------------------------------------------- */
@@ -648,8 +649,9 @@ static int __init init_soundmodem(void)
*/
for (i = 0; i < NR_PORTS; i++) {
struct net_device *dev = sm_device+i;
- sprintf(dev->name, "sm%d", i);
+ char ifname[IFNAMSIZ];
+ sprintf(ifname, "sm%d", i);
if (!mode[i])
set_hw = 0;
else {
@@ -671,7 +673,7 @@ static int __init init_soundmodem(void)
}
if (!set_hw)
iobase[i] = irq[i] = 0;
- j = hdlcdrv_register_hdlcdrv(dev, &sm_ops, sizeof(struct sm_state), dev->name, iobase[i], irq[i], dma[i]);
+ j = hdlcdrv_register_hdlcdrv(dev, &sm_ops, sizeof(struct sm_state), ifname, iobase[i], irq[i], dma[i]);
if (!j) {
sm = (struct sm_state *)dev->priv;
sm->hdrv.ptt_out.dma2 = dma2[i];
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index df9c63621..57d57d339 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -1989,7 +1989,6 @@ static void nsc_ircc_suspend(struct nsc_ircc_cb *self)
static void nsc_ircc_wakeup(struct nsc_ircc_cb *self)
{
- struct net_device *dev = self->netdev;
int iobase;
if (!self->io.suspended)
diff --git a/drivers/net/irda/smc-ircc.c b/drivers/net/irda/smc-ircc.c
index 06ebc072c..470d6dd4d 100644
--- a/drivers/net/irda/smc-ircc.c
+++ b/drivers/net/irda/smc-ircc.c
@@ -83,7 +83,9 @@ static int ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev);
static void ircc_dma_xmit(struct ircc_cb *self, int iobase, int bofs);
static void ircc_change_speed(void *priv, __u32 speed);
static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+#if 0 /* unused */
static int ircc_is_receiving(struct ircc_cb *self);
+#endif /* unused */
static int ircc_net_open(struct net_device *dev);
static int ircc_net_close(struct net_device *dev);
@@ -789,7 +791,6 @@ static int ircc_dma_receive(struct ircc_cb *self, int iobase)
*/
static void ircc_dma_receive_complete(struct ircc_cb *self, int iobase)
{
- unsigned long flags;
struct sk_buff *skb;
int len, msgcnt;
@@ -893,6 +894,7 @@ static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_unlock(&self->lock);
}
+#if 0 /* unused */
/*
* Function ircc_is_receiving (self)
*
@@ -915,6 +917,7 @@ static int ircc_is_receiving(struct ircc_cb *self)
return status;
}
+#endif /* unused */
/*
* Function ircc_net_open (dev)
@@ -990,8 +993,6 @@ static int ircc_net_close(struct net_device *dev)
static void ircc_suspend(struct ircc_cb *self)
{
- int i = 10;
-
MESSAGE("%s, Suspending\n", driver_name);
if (self->io.suspended)
@@ -1004,7 +1005,6 @@ static void ircc_suspend(struct ircc_cb *self)
static void ircc_wakeup(struct ircc_cb *self)
{
- struct net_device *dev = self->netdev;
unsigned long flags;
if (!self->io.suspended)
diff --git a/drivers/net/ncr885e.c b/drivers/net/ncr885e.c
index 9a5c65cb4..2500cb282 100644
--- a/drivers/net/ncr885e.c
+++ b/drivers/net/ncr885e.c
@@ -1144,18 +1144,11 @@ static int __init ncr885e_probe1(unsigned long ioaddr, unsigned char irq )
unsigned char *p;
int i;
- dev = init_etherdev(NULL, 0 );
-
- /* construct private data for the 885 ethernet */
- dev->priv = kmalloc( sizeof( struct ncr885e_private ), GFP_KERNEL );
-
- if ( dev->priv == NULL ) {
- release_region( ioaddr, NCR885E_TOTAL_SIZE );
+ dev = init_etherdev( NULL, sizeof( struct ncr885e_private ) );
+ if (!dev)
return -ENOMEM;
- }
- sp = (struct ncr885e_private *) dev->priv;
- memset( sp, 0, sizeof( struct ncr885e_private ));
+ sp = dev->priv;
/* snag the station address and display it */
for( i = 0; i < 3; i++ ) {
@@ -1210,7 +1203,8 @@ static int __init ncr885e_probe(void)
unsigned short cmd;
unsigned char irq, latency;
- while(( pdev = pci_find_device( PCI_VENDOR_ID_NCR,
+ /* use 'if' not 'while' where because driver only supports one device */
+ if (( pdev = pci_find_device( PCI_VENDOR_ID_NCR,
PCI_DEVICE_ID_NCR_53C885_ETHERNET,
pdev )) != NULL ) {
@@ -1219,47 +1213,27 @@ static int __init ncr885e_probe(void)
printk( KERN_INFO "%s", version );
}
+ if (pci_enable_device(pdev))
+ continue;
+
/* Use I/O space */
- pci_read_config_dword( pdev, PCI_BASE_ADDRESS_0, &ioaddr );
- pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq );
+ ioaddr = pci_resource_start (pdev, 0);
+ irq = pdev->irq;
- ioaddr &= ~3;
/* Adjust around the Grackle... */
#ifdef CONFIG_GEMINI
ioaddr |= 0xfe000000;
#endif
- if ( check_region( ioaddr, NCR885E_TOTAL_SIZE ))
+ if ( !request_region( ioaddr, NCR885E_TOTAL_SIZE, "ncr885e" ))
continue;
/* finish off the probe */
if ( !(ncr885e_probe1(ioaddr, irq ))) {
-
chips++;
-
- /* Access is via I/O space, bus master enabled... */
- pci_read_config_word( pdev, PCI_COMMAND, &cmd );
-
- if ( !(cmd & PCI_COMMAND_MASTER) ) {
- printk( KERN_INFO " PCI master bit not set! Now setting.\n");
- cmd |= PCI_COMMAND_MASTER;
- pci_write_config_word( pdev, PCI_COMMAND, cmd );
- }
-
- if ( !(cmd & PCI_COMMAND_IO) ) {
- printk( KERN_INFO " Enabling I/O space.\n" );
- cmd |= PCI_COMMAND_IO;
- pci_write_config_word( pdev, PCI_COMMAND, cmd );
- }
-
- pci_read_config_byte( pdev, PCI_LATENCY_TIMER, &latency );
-
- if ( latency < 10 ) {
- printk( KERN_INFO " PCI latency timer (CFLT) is unreasonably"
- " low at %d. Setting to 255.\n", latency );
- pci_write_config_byte( pdev, PCI_LATENCY_TIMER, 255 );
- }
- }
+ pci_set_master (pdev);
+ } else
+ release_region( ioaddr, NCR885E_TOTAL_SIZE );
}
if ( !chips )
@@ -1401,14 +1375,10 @@ init_module(void)
static void __exit cleanup_module(void)
{
- struct ncr885e_private *np;
-
if ( root_dev ) {
-
unregister_netdev( root_dev );
- np = (struct ncr885e_private *) root_dev->priv;
release_region( root_dev->base_addr, NCR885E_TOTAL_SIZE );
- kfree( root_dev->priv );
+ kfree( root_dev );
root_dev = NULL;
}
}
diff --git a/drivers/net/pcmcia/aironet4500_cs.c b/drivers/net/pcmcia/aironet4500_cs.c
index 1ff446fc2..d623828b9 100644
--- a/drivers/net/pcmcia/aironet4500_cs.c
+++ b/drivers/net/pcmcia/aironet4500_cs.c
@@ -602,7 +602,7 @@ static int awc_event(event_t event, int priority,
-static int aironet_cs_init(void)
+static int __init aironet_cs_init(void)
{
servinfo_t serv;
@@ -619,7 +619,7 @@ static int aironet_cs_init(void)
return 0;
}
-static void aironet_cs_exit(void)
+static void __exit aironet_cs_exit(void)
{
DEBUG(0, "awc_cs: unloading %c ",'\n');
unregister_pcmcia_driver(&dev_info);
@@ -635,5 +635,5 @@ static void aironet_cs_exit(void)
}
module_init(aironet_cs_init);
-module_exit(aironet_cs_init);
+module_exit(aironet_cs_exit);
diff --git a/drivers/net/sk98lin/skvpd.c b/drivers/net/sk98lin/skvpd.c
index 51751cbdc..de25856bc 100644
--- a/drivers/net/sk98lin/skvpd.c
+++ b/drivers/net/sk98lin/skvpd.c
@@ -233,6 +233,7 @@ int addr) /* VPD address */
2: error, data verify error
*/
+#if 0 /* unused */
static int VpdWriteDWord(
SK_AC *pAC, /* pAC pointer */
SK_IOC IoC, /* IO Context */
@@ -264,6 +265,7 @@ SK_U32 data) /* VPD data to write */
}
return(0) ;
}
+#endif /* unused */
/*
* Read one Stream of 'len' bytes of VPD data, starting at 'addr' from
diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c
index 0f0d15518..1a6da6e79 100644
--- a/drivers/net/sk_g16.c
+++ b/drivers/net/sk_g16.c
@@ -615,7 +615,6 @@ int __init SK_init(struct net_device *dev)
} /* End of SK_init */
-static int io = 0; /* 0 == probe */
MODULE_AUTHOR("Patrick J.D. Weichmann");
MODULE_DESCRIPTION("Schneider & Koch G16 Ethernet Device Driver");
MODULE_PARM(io, "i");
@@ -623,6 +622,8 @@ MODULE_PARM_DESC(io, "0 to probe common ports (unsafe), or the I/O base of the b
#ifdef MODULE
+static int io = 0; /* 0 == probe */
+
static int __init SK_init_module (void)
{
int rc;
diff --git a/drivers/net/skfp/ecm.c b/drivers/net/skfp/ecm.c
index 411169286..9dcca7f55 100644
--- a/drivers/net/skfp/ecm.c
+++ b/drivers/net/skfp/ecm.c
@@ -432,8 +432,8 @@ int cmd ;
static void prop_actions(smc)
struct s_smc *smc ;
{
- int port_in ;
- int port_out ;
+ int port_in = 0 ;
+ int port_out = 0 ;
RS_SET(smc,RS_EVENT) ;
switch (smc->s.sas) {
diff --git a/drivers/net/skfp/ess.c b/drivers/net/skfp/ess.c
index 868237b30..a4c6409b4 100644
--- a/drivers/net/skfp/ess.c
+++ b/drivers/net/skfp/ess.c
@@ -64,8 +64,8 @@ static const u_short plist_raf_alc_res[] = { SMT_P0012, SMT_P320B, SMT_P320F,
static const u_short plist_raf_chg_req[] = { SMT_P320B, SMT_P320F, SMT_P3210,
SMT_P001A, 0 } ;
-static const struct fddi_addr smt_sba_da = {0x80,0x01,0x43,0x00,0x80,0x0C} ;
-static const struct fddi_addr null_addr = {0,0,0,0,0,0} ;
+static const struct fddi_addr smt_sba_da = {{0x80,0x01,0x43,0x00,0x80,0x0C}} ;
+static const struct fddi_addr null_addr = {{0,0,0,0,0,0}} ;
/*
-------------------------------------------------------------
diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c
index f5bda2464..4d816c584 100644
--- a/drivers/net/skfp/fplustm.c
+++ b/drivers/net/skfp/fplustm.c
@@ -69,9 +69,9 @@ static char cam_warning [] = "E_SMT_004: CAM still busy\n";
} \
}
-const struct fddi_addr fddi_broadcast = {0xff,0xff,0xff,0xff,0xff,0xff};
-static const struct fddi_addr null_addr = {0,0,0,0,0,0} ;
-static const struct fddi_addr dbeacon_multi = {0x01,0x80,0xc2,0x00,0x01,0x00};
+const struct fddi_addr fddi_broadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
+static const struct fddi_addr null_addr = {{0,0,0,0,0,0}};
+static const struct fddi_addr dbeacon_multi = {{0x01,0x80,0xc2,0x00,0x01,0x00}};
static const u_short my_said = 0xffff ; /* short address (n.u.) */
static const u_short my_sagp = 0xffff ; /* short group address (n.u.) */
diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c
index ed8538958..b02ab9a2d 100644
--- a/drivers/net/skfp/smt.c
+++ b/drivers/net/skfp/smt.c
@@ -51,7 +51,7 @@ static const char *const smt_class_name[] = {
#define LAST_CLASS (SMT_PMF_SET)
static const struct fddi_addr SMT_Unknown = {
- 0,0,0x1f,0,0,0
+ { 0,0,0x1f,0,0,0 }
} ;
/*
diff --git a/drivers/net/skfp/srf.c b/drivers/net/skfp/srf.c
index 79bbfedc6..d5f091c54 100644
--- a/drivers/net/skfp/srf.c
+++ b/drivers/net/skfp/srf.c
@@ -391,7 +391,7 @@ struct s_smc *smc ;
int i ;
static const struct fddi_addr SMT_SRF_DA = {
- 0x80, 0x01, 0x43, 0x00, 0x80, 0x08
+ { 0x80, 0x01, 0x43, 0x00, 0x80, 0x08 }
} ;
/*
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index 86c04c5c7..084fd4120 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -1591,9 +1591,8 @@ static void smc_set_multicast_list(struct net_device *dev)
#ifdef MODULE
-static char devicename[9] = { 0, };
static struct net_device devSMC9194 = {
- devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+ "", /* device name is inserted by linux/drivers/net/net_init.c */
0, 0, 0, 0,
0, 0, /* I/O address, IRQ */
0, 0, 0, NULL, smc_init };
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index ae14cf96d..5db78eb16 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1287,7 +1287,6 @@ static void lance_set_multicast(struct net_device *dev)
static void lance_set_multicast_retry(unsigned long _opaque)
{
struct net_device *dev = (struct net_device *) _opaque;
- struct lance_private *lp = (struct lance_private *) dev->priv;
lance_set_multicast(dev);
}
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 971bea2cf..b59414255 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -295,7 +295,9 @@ static int __init ibmtr_probe1(struct net_device *dev, int PIOaddr)
struct tok_info *ti=0;
__u32 cd_chanid;
unsigned char *tchanid, ctemp;
+#ifndef PCMCIA
unsigned long timeout;
+#endif
#ifndef MODULE
#ifndef PCMCIA
diff --git a/drivers/net/wan/comx-proto-lapb.c b/drivers/net/wan/comx-proto-lapb.c
index abf8977ff..0e2737ac3 100644
--- a/drivers/net/wan/comx-proto-lapb.c
+++ b/drivers/net/wan/comx-proto-lapb.c
@@ -518,11 +518,7 @@ static struct comx_protocol comx25_protocol = {
NULL
};
-#ifdef MODULE
-#define comx_proto_lapb_init init_module
-#endif
-
-__initfunc(int comx_proto_lapb_init(void))
+int __init comx_proto_lapb_init(void)
{
int ret;
@@ -532,11 +528,13 @@ __initfunc(int comx_proto_lapb_init(void))
return comx_register_protocol(&comx25_protocol);
}
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit comx_proto_lapb_exit(void)
{
comx_unregister_protocol(comxlapb_protocol.name);
comx_unregister_protocol(comx25_protocol.name);
}
-#endif /* MODULE */
+#ifdef MODULE
+module_init(comx_proto_lapb_init);
+#endif
+module_exit(comx_proto_lapb_exit);
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index c27d89ca9..dc0b212f5 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -395,7 +395,7 @@ static int __init cosa_init(void)
cosa_cards[i].num = -1;
for (i=0; io[i] != 0 && i < MAX_CARDS; i++)
cosa_probe(io[i], irq[i], dma[i]);
- devfs_handle = devfs_mk_dir (NULL, "cosa", 4, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "cosa", NULL);
devfs_register_series (devfs_handle, "%u", nr_cards, DEVFS_FL_DEFAULT,
cosa_major, 0,
S_IFCHR | S_IRUSR | S_IWUSR,
diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c
index a4d038f05..b28fdafc1 100644
--- a/drivers/net/wan/hostess_sv11.c
+++ b/drivers/net/wan/hostess_sv11.c
@@ -222,19 +222,17 @@ static struct sv11_device *sv11_init(int iobase, int irq)
{
struct z8530_dev *dev;
struct sv11_device *sv;
- int i;
unsigned long flags;
/*
* Get the needed I/O space
*/
- if(check_region(iobase, 8))
+ if(!request_region(iobase, 8, "Comtrol SV11"))
{
printk(KERN_WARNING "hostess: I/O 0x%X already in use.\n", iobase);
return NULL;
}
- request_region(iobase, 8, "Comtrol SV11");
sv=(struct sv11_device *)kmalloc(sizeof(struct sv11_device), GFP_KERNEL);
if(!sv)
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index 274e5f286..c0b17f79f 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -1043,7 +1043,6 @@ int lmc_probe (struct net_device *dev) /*fold00*/
{
int pci_index = 0;
unsigned long pci_ioaddr;
- unsigned short pci_command;
unsigned int pci_irq_line;
u16 vendor, subvendor, device, subdevice;
u32 foundaddr = 0;
diff --git a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog
index 1dd9a4ae2..f22c69b2a 100644
--- a/drivers/parport/ChangeLog
+++ b/drivers/parport/ChangeLog
@@ -1,3 +1,30 @@
+2000-06-30 Petr Vandrovec <vandrove@vc.cvut.cz>
+
+ * procfs.c (do_hardware_modes): Generated string can be up to 34
+ chars long.
+
+2000-06-20 Gunther Mayer <gunther.mayer@braunschweig.okersurf.de>
+
+ * parport_pc.c (parport_pc_compat_write_block_pio): Warn about
+ change_mode failures.
+ (parport_pc_ecp_write_block_pio): Likewise.
+ (parport_pc_ecp_read_block_pio): Likewise.
+
+2000-06-20 Gunther Mayer <gunther.mayer@braunschweig.okersurf.de>
+
+ * parport_pc.c (parport_SPP_supported): Warn more about possibly
+ incorrect parameters.
+
+2000-06-15 Tim Waugh <twaugh@redhat.com>
+
+ * parport_pc.c (parport_ECP_supported): Set PARPORT_MODE_COMPAT
+ for ECP ports, since they can all do hardware accelerated
+ compatibility mode (I assume).
+
+2000-06-13 Tim Waugh <twaugh@redhat.com>
+
+ * parport_pc.c (cleanup_module): Remark about possible bugs.
+
2000-06-13 Tim Waugh <twaugh@redhat.com>
* procfs.c: Break 'hardware' out into separate files.
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 13a4faea4..12b56f585 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -714,7 +714,9 @@ size_t parport_pc_compat_write_block_pio (struct parport *port,
/* Set up parallel port FIFO mode.*/
parport_pc_data_forward (port); /* Must be in PS2 mode */
parport_pc_frob_control (port, PARPORT_CONTROL_STROBE, 0);
- change_mode (port, ECR_PPF); /* Parallel port FIFO */
+ r = change_mode (port, ECR_PPF); /* Parallel port FIFO */
+ if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_PPF failed\n", port->name);
+
port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
/* Write the data to the FIFO. */
@@ -793,7 +795,8 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port,
PARPORT_CONTROL_STROBE |
PARPORT_CONTROL_AUTOFD,
0);
- change_mode (port, ECR_ECP); /* ECP FIFO */
+ r = change_mode (port, ECR_ECP); /* ECP FIFO */
+ if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", port->name);
port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
/* Write the data to the FIFO. */
@@ -917,7 +920,8 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port,
PARPORT_CONTROL_STROBE |
PARPORT_CONTROL_AUTOFD,
0);
- change_mode (port, ECR_ECP); /* ECP FIFO */
+ r = change_mode (port, ECR_ECP); /* ECP FIFO */
+ if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", port->name);
port->ieee1284.phase = IEEE1284_PH_REV_DATA;
/* Do the transfer. */
@@ -1412,6 +1416,12 @@ static int __devinit get_superio_irq (struct parport *p)
/*
* Checks for port existence, all ports support SPP MODE
+ * Returns:
+ * 0 : No parallel port at this adress
+ * PARPORT_MODE_PCSPP : SPP port detected
+ * (if the user specified an ioport himself,
+ * this shall always be the case!)
+ *
*/
static int __devinit parport_SPP_supported(struct parport *pb)
{
@@ -1447,8 +1457,8 @@ static int __devinit parport_SPP_supported(struct parport *pb)
if (user_specified)
/* That didn't work, but the user thinks there's a
* port here. */
- printk (KERN_DEBUG "0x%lx: CTR: wrote 0x%02x, read 0x%02x\n",
- pb->base, w, r);
+ printk (KERN_DEBUG "parport 0x%lx (WARNING): CTR: "
+ "wrote 0x%02x, read 0x%02x\n", pb->base, w, r);
/* Try the data register. The data lines aren't tri-stated at
* this stage, so we expect back what we wrote. */
@@ -1463,11 +1473,15 @@ static int __devinit parport_SPP_supported(struct parport *pb)
return PARPORT_MODE_PCSPP;
}
- if (user_specified)
+ if (user_specified) {
/* Didn't work, but the user is convinced this is the
* place. */
- printk (KERN_DEBUG "0x%lx: DATA: wrote 0x%02x, read 0x%02x\n",
- pb->base, w, r);
+ printk (KERN_DEBUG "parport 0x%lx (WARNING): DATA: "
+ "wrote 0x%02x, read 0x%02x\n", pb->base, w, r);
+ printk (KERN_DEBUG "parport 0x%lx: You gave this address, "
+ "but there is probably no parallel port there!\n",
+ pb->base);
+ }
/* It's possible that we can't read the control register or
* the data register. In that case just believe the user. */
@@ -1692,7 +1706,7 @@ static int __devinit parport_ECP_supported(struct parport *pb)
/* Go back to mode 000 */
frob_econtrol (pb, 0xe0, ECR_SPP << 5);
- pb->modes |= PARPORT_MODE_ECP;
+ pb->modes |= PARPORT_MODE_ECP | PARPORT_MODE_COMPAT;
return 1;
}
@@ -2598,6 +2612,7 @@ int init_module(void)
void cleanup_module(void)
{
+ /* We ought to keep track of which ports are actually ours. */
struct parport *p = parport_enumerate(), *tmp;
if (!user_specified)
diff --git a/drivers/parport/procfs.c b/drivers/parport/procfs.c
index 15efdd657..b82b4e2f2 100644
--- a/drivers/parport/procfs.c
+++ b/drivers/parport/procfs.c
@@ -198,7 +198,7 @@ static int do_hardware_modes (ctl_table *table, int write,
size_t *lenp)
{
struct parport *port = (struct parport *)table->extra1;
- char buffer[20];
+ char buffer[40];
int len = 0;
if (filp->f_pos) {
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 0c42771ee..f278c9e41 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -309,50 +309,63 @@ static void reset_socket(u_long i);
static void unreset_socket(u_long i);
static void parse_events(void *info, u_int events);
-int register_ss_entry(int nsock, struct pccard_operations * ss_entry)
+socket_info_t *pcmcia_register_socket (int slot,
+ struct pccard_operations * ss_entry,
+ int use_bus_pm)
{
- int i, ns;
socket_info_t *s;
+ int i;
- DEBUG(0, "cs: register_ss_entry(%d, 0x%p)\n", nsock, ss_entry);
+ DEBUG(0, "cs: pcmcia_register_socket(0x%p)\n", ss_entry);
+
+ s = kmalloc(sizeof(struct socket_info_t), GFP_KERNEL);
+ memset(s, 0, sizeof(socket_info_t));
+
+ s->ss_entry = ss_entry;
+ s->sock = slot;
+ s->setup.data = sockets;
+ s->setup.function = &setup_socket;
+ s->shutdown.data = sockets;
+ s->shutdown.function = &shutdown_socket;
+ /* base address = 0, map = 0 */
+ s->cis_mem.flags = 0;
+ s->cis_mem.speed = cis_speed;
+ s->use_bus_pm = use_bus_pm;
+ s->erase_busy.next = s->erase_busy.prev = &s->erase_busy;
+ spin_lock_init(&s->lock);
+
+ for (i = 0; i < sockets; i++)
+ if (socket_table[i] == NULL) break;
+ socket_table[i] = s;
+ if (i == sockets) sockets++;
- for (ns = 0; ns < nsock; ns++) {
- s = kmalloc(sizeof(struct socket_info_t), GFP_KERNEL);
- memset(s, 0, sizeof(socket_info_t));
-
- s->ss_entry = ss_entry;
- s->sock = ns;
- s->setup.data = sockets;
- s->setup.function = &setup_socket;
- s->shutdown.data = sockets;
- s->shutdown.function = &shutdown_socket;
- /* base address = 0, map = 0 */
- s->cis_mem.flags = 0;
- s->cis_mem.speed = cis_speed;
- s->erase_busy.next = s->erase_busy.prev = &s->erase_busy;
- spin_lock_init(&s->lock);
-
- for (i = 0; i < sockets; i++)
- if (socket_table[i] == NULL) break;
- socket_table[i] = s;
- if (i == sockets) sockets++;
-
- init_socket(s);
- ss_entry->inquire_socket(ns, &s->cap);
+ init_socket(s);
+ ss_entry->inquire_socket(slot, &s->cap);
#ifdef CONFIG_PROC_FS
- if (proc_pccard) {
- char name[3];
- sprintf(name, "%02d", i);
- s->proc = proc_mkdir(name, proc_pccard);
- if (s->proc)
- ss_entry->proc_setup(ns, s->proc);
+ if (proc_pccard) {
+ char name[3];
+ sprintf(name, "%02d", i);
+ s->proc = proc_mkdir(name, proc_pccard);
+ if (s->proc)
+ ss_entry->proc_setup(slot, s->proc);
#ifdef PCMCIA_DEBUG
- if (s->proc)
- create_proc_read_entry("clients", 0, s->proc,
- proc_read_clients, s);
+ if (s->proc)
+ create_proc_read_entry("clients", 0, s->proc,
+ proc_read_clients, s);
#endif
- }
+ }
#endif
+ return s;
+} /* pcmcia_register_socket */
+
+int register_ss_entry(int nsock, struct pccard_operations * ss_entry)
+{
+ int ns;
+
+ DEBUG(0, "cs: register_ss_entry(%d, 0x%p)\n", nsock, ss_entry);
+
+ for (ns = 0; ns < nsock; ns++) {
+ pcmcia_register_socket (ns, ss_entry, 0);
}
return 0;
@@ -360,49 +373,57 @@ int register_ss_entry(int nsock, struct pccard_operations * ss_entry)
/*====================================================================*/
-void unregister_ss_entry(struct pccard_operations * ss_entry)
+void pcmcia_unregister_socket(socket_info_t *s)
{
- int i, j;
- socket_info_t *s = NULL;
+ int j, socket = -1;
client_t *client;
+ for (j = 0; j < MAX_SOCK; j++)
+ if (socket_table [j] == s) {
+ socket = j;
+ break;
+ }
+ if (socket < 0)
+ return;
+
#ifdef CONFIG_PROC_FS
- for (i = 0; i < sockets; i++) {
- s = socket_table[i];
- if (s->ss_entry != ss_entry) continue;
- if (proc_pccard) {
- char name[3];
- sprintf(name, "%02d", i);
+ if (proc_pccard) {
+ char name[3];
+ sprintf(name, "%02d", socket);
#ifdef PCMCIA_DEBUG
- remove_proc_entry("clients", s->proc);
+ remove_proc_entry("clients", s->proc);
#endif
- remove_proc_entry(name, proc_pccard);
- }
+ remove_proc_entry(name, proc_pccard);
}
#endif
- for (;;) {
- for (i = 0; i < sockets; i++) {
- s = socket_table[i];
- if (s->ss_entry == ss_entry) break;
- }
- if (i == sockets)
- break;
- shutdown_socket(i);
- release_cis_mem(s);
- while (s->clients) {
- client = s->clients;
- s->clients = s->clients->next;
- kfree(client);
- }
- s->ss_entry = NULL;
- kfree(s);
- socket_table[i] = NULL;
- for (j = i; j < sockets-1; j++)
- socket_table[j] = socket_table[j+1];
- sockets--;
+ shutdown_socket(socket);
+ release_cis_mem(s);
+ while (s->clients) {
+ client = s->clients;
+ s->clients = s->clients->next;
+ kfree(client);
+ }
+ s->ss_entry = NULL;
+ kfree(s);
+
+ socket_table[socket] = NULL;
+ for (j = socket; j < sockets-1; j++)
+ socket_table[j] = socket_table[j+1];
+ sockets--;
+} /* pcmcia_unregister_socket */
+
+void unregister_ss_entry(struct pccard_operations * ss_entry)
+{
+ int i;
+
+ for (i = 0; i < sockets; i++) {
+ socket_info_t *socket = socket_table[i];
+ if (socket->ss_entry == ss_entry)
+ pcmcia_unregister_socket (socket);
+ else
+ i++;
}
-
} /* unregister_ss_entry */
/*======================================================================
@@ -675,35 +696,51 @@ static void parse_events(void *info, u_int events)
======================================================================*/
+void pcmcia_suspend_socket (socket_info_t *s)
+{
+ if ((s->state & SOCKET_PRESENT) && !(s->state & SOCKET_SUSPEND)) {
+ send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
+ suspend_socket(s);
+ s->state |= SOCKET_SUSPEND;
+ }
+}
+
+void pcmcia_resume_socket (socket_info_t *s)
+{
+ int stat;
+
+ /* Do this just to reinitialize the socket */
+ init_socket(s);
+ get_socket_status(s, &stat);
+
+ /* If there was or is a card here, we need to do something
+ about it... but parse_events will sort it all out. */
+ if ((s->state & SOCKET_PRESENT) || (stat & SS_DETECT))
+ parse_events(s, SS_DETECT);
+}
+
static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data)
{
- int i, stat;
+ int i;
socket_info_t *s;
-
+
+ /* only for busses that don't suspend/resume slots directly */
+
switch (rqst) {
case PM_SUSPEND:
DEBUG(1, "cs: received suspend notification\n");
for (i = 0; i < sockets; i++) {
- s = socket_table[i];
- if ((s->state & SOCKET_PRESENT) &&
- !(s->state & SOCKET_SUSPEND)){
- send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
- suspend_socket(s);
- s->state |= SOCKET_SUSPEND;
- }
+ s = socket_table [i];
+ if (!s->use_bus_pm)
+ pcmcia_suspend_socket (socket_table [i]);
}
break;
case PM_RESUME:
DEBUG(1, "cs: received resume notification\n");
for (i = 0; i < sockets; i++) {
- s = socket_table[i];
- /* Do this just to reinitialize the socket */
- init_socket(s);
- get_socket_status(s, &stat);
- /* If there was or is a card here, we need to do something
- about it... but parse_events will sort it all out. */
- if ((s->state & SOCKET_PRESENT) || (stat & SS_DETECT))
- parse_events(s, SS_DETECT);
+ s = socket_table [i];
+ if (!s->use_bus_pm)
+ pcmcia_resume_socket (socket_table [i]);
}
break;
}
@@ -2331,6 +2368,11 @@ EXPORT_SYMBOL(MTDHelperEntry);
EXPORT_SYMBOL(proc_pccard);
#endif
+EXPORT_SYMBOL(pcmcia_register_socket);
+EXPORT_SYMBOL(pcmcia_unregister_socket);
+EXPORT_SYMBOL(pcmcia_suspend_socket);
+EXPORT_SYMBOL(pcmcia_resume_socket);
+
static int __init init_pcmcia_cs(void)
{
printk(KERN_INFO "%s\n", release);
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index f355c337b..abd518a7f 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -160,6 +160,7 @@ typedef struct socket_info_t {
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc;
#endif
+ int use_bus_pm;
} socket_info_t;
/* Flags in config state */
diff --git a/drivers/pcmcia/pci_socket.c b/drivers/pcmcia/pci_socket.c
index 3f4463e75..9cc901603 100644
--- a/drivers/pcmcia/pci_socket.c
+++ b/drivers/pcmcia/pci_socket.c
@@ -28,6 +28,14 @@
#include "pci_socket.h"
+
+extern struct socket_info_t *pcmcia_register_socket (int slot,
+ struct pccard_operations *vtable, int use_bus_pm);
+extern void pcmcia_unregister_socket (struct socket_info_t *socket);
+extern void pcmcia_suspend_socket (struct socket_info_t *socket);
+extern void pcmcia_resume_socket (struct socket_info_t *socket);
+
+
/*
* Arbitrary define. This is the array of active cardbus
* entries.
@@ -161,45 +169,87 @@ static struct pccard_operations pci_socket_operations = {
pci_proc_setup
};
-static int __init add_pci_socket(int nr, struct pci_dev *dev, struct pci_socket_ops *ops)
+static int __devinit add_pci_socket(int nr, struct pci_dev *dev, struct pci_socket_ops *ops)
{
pci_socket_t *socket = nr + pci_socket_array;
memset(socket, 0, sizeof(*socket));
socket->dev = dev;
socket->op = ops;
+ dev->driver_data = socket;
init_waitqueue_head(&socket->wait);
return socket->op->open(socket);
}
-static int __init pci_socket_init(void)
+static int __devinit
+cardbus_probe (struct pci_dev *dev, const struct pci_device_id *id)
{
- struct pci_dev *dev = NULL;
- int nr = 0;
-
- while ((dev = pci_find_class(PCI_CLASS_BRIDGE_CARDBUS << 8, dev)) != NULL) {
- printk("Adding cardbus controller %d: %s\n", nr, dev->name);
- add_pci_socket(nr, dev, &yenta_operations);
- nr++;
+ int s;
+
+ for (s = 0; s < MAX_SOCKETS; s++) {
+ if (pci_socket_array [s].dev == 0) {
+ add_pci_socket (s, dev, &yenta_operations);
+ pci_socket_array [s].pcmcia_socket =
+ pcmcia_register_socket (s,
+ &pci_socket_operations,
+ 1);
+ return 0;
+ }
}
+ return -1;
+}
- if (nr <= 0)
- return -1;
- register_ss_entry(nr, &pci_socket_operations);
- return 0;
+static void __devexit cardbus_remove (struct pci_dev *dev)
+{
+ pci_socket_t *socket = (pci_socket_t *) dev->driver_data;
+
+ pcmcia_unregister_socket (socket->pcmcia_socket);
+ if (socket->op && socket->op->close)
+ socket->op->close(socket);
+ dev->driver_data = 0;
+}
+
+static void cardbus_suspend (struct pci_dev *dev)
+{
+ pci_socket_t *socket = (pci_socket_t *) dev->driver_data;
+ pcmcia_suspend_socket (socket->pcmcia_socket);
}
-static void __exit pci_socket_exit(void)
+static void cardbus_resume (struct pci_dev *dev)
{
- int i;
+ pci_socket_t *socket = (pci_socket_t *) dev->driver_data;
+ pcmcia_resume_socket (socket->pcmcia_socket);
+}
- unregister_ss_entry(&pci_socket_operations);
- for (i = 0; i < MAX_SOCKETS; i++) {
- pci_socket_t *socket = pci_socket_array + i;
- if (socket->op && socket->op->close)
- socket->op->close(socket);
- }
+static struct pci_device_id cardbus_table [] = { {
+ class: PCI_CLASS_BRIDGE_CARDBUS << 8,
+ class_mask: ~0,
+
+ vendor: PCI_ANY_ID,
+ device: PCI_ANY_ID,
+ subvendor: PCI_ANY_ID,
+ subdevice: PCI_ANY_ID,
+}, { /* all zeroes */ }
+};
+
+static struct pci_driver pci_cardbus_driver = {
+ name: "cardbus",
+ id_table: cardbus_table,
+ probe: cardbus_probe,
+ remove: cardbus_remove,
+ suspend: cardbus_suspend,
+ resume: cardbus_resume,
+};
+
+static int __devinit pci_socket_init(void)
+{
+ return pci_module_init (&pci_cardbus_driver);
+}
+
+static void __devexit pci_socket_exit (void)
+{
+ pci_unregister_driver (&pci_cardbus_driver);
}
module_init(pci_socket_init);
diff --git a/drivers/pcmcia/pci_socket.h b/drivers/pcmcia/pci_socket.h
index 8db7c68b5..6893fb1c2 100644
--- a/drivers/pcmcia/pci_socket.h
+++ b/drivers/pcmcia/pci_socket.h
@@ -8,6 +8,7 @@
#define __PCI_SOCKET_H
struct pci_socket_ops;
+struct socket_info_t;
typedef struct pci_socket {
struct pci_dev *dev;
@@ -19,6 +20,7 @@ typedef struct pci_socket {
socket_cap_t cap;
wait_queue_head_t wait;
unsigned int events;
+ struct socket_info_t *pcmcia_socket;
/* A few words of private data for the low-level driver.. */
unsigned int private[8];
diff --git a/drivers/sbus/audio/audio.c b/drivers/sbus/audio/audio.c
index 586945b10..a4db8b9c4 100644
--- a/drivers/sbus/audio/audio.c
+++ b/drivers/sbus/audio/audio.c
@@ -2175,7 +2175,7 @@ int unregister_sparcaudio_driver(struct sparcaudio_driver *drv, int duplex)
/* Unregister ourselves with devfs */
for (i=0; i < sizeof (dev_list) / sizeof (*dev_list); i++) {
sparcaudio_mkname (name_buf, dev_list[i].name, drv->index);
- de = devfs_find_handle (devfs_handle, name_buf, 0, 0, 0,
+ de = devfs_find_handle (devfs_handle, name_buf, 0, 0,
DEVFS_SPECIAL_CHR, 0);
devfs_unregister (de);
}
@@ -2219,7 +2219,7 @@ int __init sparcaudio_init(void)
if (devfs_register_chrdev(SOUND_MAJOR, "sparcaudio", &sparcaudio_fops))
return -EIO;
- devfs_handle = devfs_mk_dir (NULL, "sound", 0, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "sound", NULL);
#ifdef CONFIG_SPARCAUDIO_AMD7930
amd7930_init();
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
index 6dfc4c132..ebe9928c2 100644
--- a/drivers/sbus/char/bpp.c
+++ b/drivers/sbus/char/bpp.c
@@ -1029,7 +1029,7 @@ int __init bpp_init(void)
instances[idx].opened = 0;
probeLptPort(idx);
}
- devfs_handle = devfs_mk_dir (NULL, "bpp", 3, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "bpp", NULL);
devfs_register_series (devfs_handle, "%u", BPP_NO, DEVFS_FL_DEFAULT,
BPP_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR,
&bpp_fops, NULL);
diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
index 458fe20af..e197661f7 100644
--- a/drivers/sbus/char/jsflash.c
+++ b/drivers/sbus/char/jsflash.c
@@ -701,5 +701,6 @@ void cleanup_module(void) {
misc_deregister(&jsf_dev);
if (unregister_blkdev(JSFD_MAJOR, "jsfd") != 0)
printk("jsfd: cleanup_module failed\n");
+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
}
#endif
diff --git a/drivers/sbus/char/sab82532.c b/drivers/sbus/char/sab82532.c
index 51fa5a68c..378148159 100644
--- a/drivers/sbus/char/sab82532.c
+++ b/drivers/sbus/char/sab82532.c
@@ -2391,9 +2391,6 @@ void cleanup_module(void)
/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
save_flags(flags);
cli();
- timer_active &= ~(1 << RS_TIMER);
- timer_table[RS_TIMER].fn = NULL;
- timer_table[RS_TIMER].expires = 0;
remove_bh(SERIAL_BH);
if ((e1 = tty_unregister_driver(&serial_driver)))
printk("SERIAL: failed to unregister serial driver (%d)\n",
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index 589b787d0..eed298c6e 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -672,7 +672,7 @@ static int vfc_probe(void)
kfree(vfc_dev_lst);
return -EIO;
}
- devfs_handle = devfs_mk_dir (NULL, "vfc", 3, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "vfc", NULL);
instance = 0;
for_all_sbusdev(sdev, sbus) {
diff --git a/drivers/sbus/char/zs.c b/drivers/sbus/char/zs.c
index fb687102c..f9512e12c 100644
--- a/drivers/sbus/char/zs.c
+++ b/drivers/sbus/char/zs.c
@@ -913,14 +913,6 @@ static int startup(struct sun_serial * info)
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
/*
- * Set up serial timers...
- */
-#if 0 /* Works well and stops the machine. */
- timer_table[RS_TIMER].expires = jiffies + 2;
- timer_active |= 1 << RS_TIMER;
-#endif
-
- /*
* and set the speed of the serial port
*/
change_speed(info);
@@ -2404,8 +2396,6 @@ int __init zs_init(void)
/* Setup base handler, and timer table. */
init_bh(SERIAL_BH, do_serial_bh);
- timer_table[RS_TIMER].fn = zs_timer;
- timer_table[RS_TIMER].expires = 0;
show_serial_version();
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index 24861d034..13d7dc398 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -1057,7 +1057,6 @@ static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout)
oldto = scp->timeout_per_command;
scp->timeout_per_command = timeout;
-#if LINUX_VERSION_CODE >= 0x02014B
if (timeout == 0) {
del_timer(&scp->eh_timeout);
scp->eh_timeout.data = (unsigned long) NULL;
@@ -1069,17 +1068,5 @@ static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout)
scp->eh_timeout.expires = jiffies + timeout;
add_timer(&scp->eh_timeout);
}
-#else
- if (timeout > 0) {
- if (timer_table[SCSI_TIMER].expires == 0) {
- timer_table[SCSI_TIMER].expires = jiffies + timeout;
- timer_active |= 1 << SCSI_TIMER;
- } else {
- if (jiffies + timeout < timer_table[SCSI_TIMER].expires)
- timer_table[SCSI_TIMER].expires = jiffies + timeout;
- }
- }
-#endif
-
return oldto;
}
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index b7d3b9cc1..51a4eabc6 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -1529,7 +1529,7 @@ int __init scsi_dev_init(void)
/* Yes we're here... */
- scsi_devfs_handle = devfs_mk_dir (NULL, "scsi", 4, NULL);
+ scsi_devfs_handle = devfs_mk_dir (NULL, "scsi", NULL);
/*
* This makes /proc/scsi and /proc/scsi/scsi visible.
*/
@@ -2646,7 +2646,7 @@ int init_module(void)
scsi_loadable_module_flag = 1;
- scsi_devfs_handle = devfs_mk_dir (NULL, "scsi", 4, NULL);
+ scsi_devfs_handle = devfs_mk_dir (NULL, "scsi", NULL);
scsi_host_no_init (scsihosts);
/*
* This is where the processing takes place for most everything
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 042493e3e..362173b56 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -87,6 +87,7 @@ int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int at_head)
SCpnt->request.cmd = SPECIAL;
SCpnt->request.special = (void *) SCpnt;
SCpnt->request.q = NULL;
+ SCpnt->request.free_list = NULL;
SCpnt->request.nr_segments = 0;
/*
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 152f8afc3..056b2f1b5 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -278,7 +278,6 @@ void scan_scsis(struct Scsi_Host *shpnt,
* is pointless work.
*/
scsi_initialize_queue(SDpnt, shpnt);
- blk_queue_headactive(&SDpnt->request_queue, 0);
SDpnt->request_queue.queuedata = (void *) SDpnt;
/* Make sure we have something that is valid for DMA purposes */
scsi_result = ((!shpnt->unchecked_isa_dma)
@@ -425,8 +424,10 @@ void scan_scsis(struct Scsi_Host *shpnt,
}
/* Last device block does not exist. Free memory. */
- if (SDpnt != NULL)
+ if (SDpnt != NULL) {
+ blk_cleanup_queue(&SDpnt->request_queue);
kfree((char *) SDpnt);
+ }
/* If we allocated a buffer so we could do DMA, free it now */
if (scsi_result != &scsi_result0[0] && scsi_result != NULL) {
@@ -594,7 +595,7 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
sprintf (devname, "host%d/bus%d/target%d/lun%d",
SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun);
if (SDpnt->de) printk ("DEBUG: dir: \"%s\" already exists\n", devname);
- else SDpnt->de = devfs_mk_dir (scsi_devfs_handle, devname, 0, NULL);
+ else SDpnt->de = devfs_mk_dir (scsi_devfs_handle, devname, NULL);
for (sdtpnt = scsi_devicelist; sdtpnt;
sdtpnt = sdtpnt->next)
@@ -691,8 +692,6 @@ static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
* is pointless work.
*/
scsi_initialize_queue(SDpnt, shpnt);
- blk_queue_headactive(&SDpnt->request_queue, 0);
- SDpnt->request_queue.queuedata = (void *) SDpnt;
SDpnt->host = shpnt;
initialize_merge_fn(SDpnt);
diff --git a/drivers/sgi/char/sgiserial.c b/drivers/sgi/char/sgiserial.c
index 8b3126340..b0ccff4f8 100644
--- a/drivers/sgi/char/sgiserial.c
+++ b/drivers/sgi/char/sgiserial.c
@@ -665,19 +665,6 @@ static void do_serial_hangup(void *private_)
}
-/*
- * This subroutine is called when the RS_TIMER goes off. It is used
- * by the serial driver to handle ports that do not have an interrupt
- * (irq=0). This doesn't work at all for 16450's, as a sun has a Z8530.
- */
-
-static void rs_timer(void)
-{
- printk("rs_timer called\n");
- prom_halt();
- return;
-}
-
static int startup(struct sgi_serial * info)
{
volatile unsigned char junk;
@@ -751,14 +738,6 @@ static int startup(struct sgi_serial * info)
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
/*
- * Set up serial timers...
- */
-#if 0 /* Works well and stops the machine. */
- timer_table[RS_TIMER].expires = jiffies + 2;
- timer_active |= 1 << RS_TIMER;
-#endif
-
- /*
* and set the speed of the serial port
*/
change_speed(info);
@@ -1842,8 +1821,6 @@ int rs_init(void)
/* Setup base handler, and timer table. */
init_bh(SERIAL_BH, do_serial_bh);
- timer_table[RS_TIMER].fn = rs_timer;
- timer_table[RS_TIMER].expires = 0;
show_serial_version();
diff --git a/drivers/sound/cmpci.c b/drivers/sound/cmpci.c
index 527d570cf..3b5639054 100644
--- a/drivers/sound/cmpci.c
+++ b/drivers/sound/cmpci.c
@@ -312,7 +312,6 @@ struct cm_state {
/* --------------------------------------------------------------------- */
static struct cm_state *devs = NULL;
-static struct cm_state *devaudio = NULL;
static unsigned long wavetable_mem = 0;
/* --------------------------------------------------------------------- */
@@ -2462,10 +2461,8 @@ int __init init_cmpci(void)
err_irq:
if(s->iosynth)
release_region(s->iosynth, CM_EXTENT_SYNTH);
- err_region1:
if(s->iomidi)
release_region(s->iomidi, CM_EXTENT_MIDI);
- err_region4:
release_region(s->iobase, CM_EXTENT_CODEC);
err_region5:
kfree_s(s, sizeof(struct cm_state));
diff --git a/drivers/sound/esssolo1.c b/drivers/sound/esssolo1.c
index 930e58f46..cfc89d3ee 100644
--- a/drivers/sound/esssolo1.c
+++ b/drivers/sound/esssolo1.c
@@ -273,6 +273,7 @@ static void write_ctrl(struct solo1_state *s, unsigned char reg, unsigned char d
write_seq(s, data);
}
+#if 0 /* unused */
static unsigned char read_ctrl(struct solo1_state *s, unsigned char reg)
{
unsigned char r;
@@ -282,6 +283,7 @@ static unsigned char read_ctrl(struct solo1_state *s, unsigned char reg)
read_seq(s, &r);
return r;
}
+#endif /* unused */
static void write_mixer(struct solo1_state *s, unsigned char reg, unsigned char data)
{
diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c
index ce5cd829e..58d5ef474 100644
--- a/drivers/sound/sb_common.c
+++ b/drivers/sound/sb_common.c
@@ -28,7 +28,6 @@
#include "sound_config.h"
#include "sound_firmware.h"
-#include "soundmodule.h"
#include "mpu401.h"
diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c
index 0d50924d8..c9c66a73f 100644
--- a/drivers/sound/sonicvibes.c
+++ b/drivers/sound/sonicvibes.c
@@ -535,7 +535,7 @@ static void frobindir(struct sv_state *s, unsigned char idx, unsigned char mask,
static unsigned setpll(struct sv_state *s, unsigned char reg, unsigned rate)
{
unsigned long flags;
- unsigned char r, m, n;
+ unsigned char r, m=0, n=0;
unsigned xm, xn, xr, xd, metric = ~0U;
/* the warnings about m and n used uninitialized are bogus and may safely be ignored */
diff --git a/drivers/sound/sound_core.c b/drivers/sound/sound_core.c
index 9ec821b91..938b77968 100644
--- a/drivers/sound/sound_core.c
+++ b/drivers/sound/sound_core.c
@@ -63,7 +63,7 @@ extern int msnd_classic_init(void);
extern int msnd_pinnacle_init(void);
#endif
#ifdef CONFIG_SOUND_CMPCI
-extern init_cmpci(void);
+extern int init_cmpci(void);
#endif
/*
@@ -559,7 +559,7 @@ int soundcore_init(void)
printk(KERN_ERR "soundcore: sound device already in use.\n");
return -EBUSY;
}
- devfs_handle = devfs_mk_dir (NULL, "sound", 0, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "sound", NULL);
/*
* Now init non OSS drivers
*/
diff --git a/drivers/sound/sound_syms.c b/drivers/sound/sound_syms.c
index b6f2855be..a3601dcf6 100644
--- a/drivers/sound/sound_syms.c
+++ b/drivers/sound/sound_syms.c
@@ -53,7 +53,8 @@ extern int softoss_dev;
EXPORT_SYMBOL(softoss_dev);
/* Locking */
-#include "soundmodule.h"
+extern struct notifier_block *sound_locker;
+extern void sound_notifier_chain_register(struct notifier_block *);
EXPORT_SYMBOL(sound_locker);
EXPORT_SYMBOL(sound_notifier_chain_register);
diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c
index aa7b82280..0351fe7ce 100644
--- a/drivers/sound/soundcard.c
+++ b/drivers/sound/soundcard.c
@@ -43,7 +43,7 @@
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/smp_lock.h>
-#include "soundmodule.h"
+#include <linux/notifier.h>
struct notifier_block *sound_locker=(struct notifier_block *)0;
@@ -572,7 +572,7 @@ static void soundcard_register_devfs (int do_register)
else {
devfs_handle_t de;
- de = devfs_find_handle (NULL, name_buf, 0, 0, 0,
+ de = devfs_find_handle (NULL, name_buf, 0, 0,
DEVFS_SPECIAL_CHR, 0);
devfs_unregister (de);
}
diff --git a/drivers/sound/sscape.c b/drivers/sound/sscape.c
index 89470da82..b9ac2879e 100644
--- a/drivers/sound/sscape.c
+++ b/drivers/sound/sscape.c
@@ -272,12 +272,14 @@ static int host_read(struct sscape_info *devc)
return data;
}
+#if 0 /* unused */
static int host_command1(struct sscape_info *devc, int cmd)
{
unsigned char buf[10];
buf[0] = (unsigned char) (cmd & 0xff);
return host_write(devc, buf, 1);
}
+#endif /* unused */
static int host_command2(struct sscape_info *devc, int cmd, int parm1)
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c
index 8f4fd8e6d..7fa446c00 100644
--- a/drivers/tc/zs.c
+++ b/drivers/tc/zs.c
@@ -559,10 +559,6 @@ static void do_softint(void *private_)
}
}
-static void rs_timer(void)
-{
-}
-
static int startup(struct dec_serial * info)
{
unsigned long flags;
@@ -1664,8 +1660,6 @@ int __init zs_init(void)
/* Setup base handler, and timer table. */
init_bh(SERIAL_BH, do_serial_bh);
- timer_table[RS_TIMER].fn = rs_timer;
- timer_table[RS_TIMER].expires = 0;
/* Find out how many Z8530 SCCs we have */
if (zs_chain == 0)
diff --git a/drivers/usb/devio.c b/drivers/usb/devio.c
index d6cedee9b..5609ae1c2 100644
--- a/drivers/usb/devio.c
+++ b/drivers/usb/devio.c
@@ -514,6 +514,7 @@ static int findintfif(struct usb_device *dev, unsigned int ifn)
extern struct list_head usb_driver_list;
+#if 0
static int finddriver(struct usb_driver **driver, char *name)
{
struct list_head *tmp;
@@ -533,6 +534,7 @@ static int finddriver(struct usb_driver **driver, char *name)
return -EINVAL;
}
+#endif
/*
* file operations
@@ -715,6 +717,27 @@ static int proc_resetep(struct dev_state *ps, void *arg)
return 0;
}
+static int proc_clearhalt(struct dev_state *ps, void *arg)
+{
+ unsigned int ep;
+ int pipe;
+ int ret;
+
+ get_user_ret(ep, (unsigned int *)arg, -EFAULT);
+ if ((ret = findintfep(ps->dev, ep)) < 0)
+ return ret;
+ if ((ret = checkintf(ps, ret)))
+ return ret;
+ if (ep & USB_DIR_IN)
+ pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);
+ else
+ pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f);
+
+ usb_clear_halt(ps->dev, pipe);
+ return 0;
+}
+
+
static int proc_getdriver(struct dev_state *ps, void *arg)
{
struct usbdevfs_getdriver gd;
@@ -1120,6 +1143,12 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
case USBDEVFS_RESET:
ret = proc_resetdevice(ps);
break;
+
+ case USBDEVFS_CLEAR_HALT:
+ ret = proc_clearhalt(ps, (void *)arg);
+ if (ret >= 0)
+ inode->i_mtime = CURRENT_TIME;
+ break;
case USBDEVFS_GETDRIVER:
ret = proc_getdriver(ps, (void *)arg);
diff --git a/drivers/usb/ibmcam.c b/drivers/usb/ibmcam.c
index f643dee47..1001362e6 100644
--- a/drivers/usb/ibmcam.c
+++ b/drivers/usb/ibmcam.c
@@ -2933,11 +2933,11 @@ static int ibmcam_find_struct(void)
* 1/22/00 Moved camera init code to ibmcam_open()
* 1/27/00 Changed to use static structures, added locking.
* 5/24/00 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
+ * 7/3/00 Fixed endianness bug.
*/
static void *usb_ibmcam_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_ibmcam *ibmcam = NULL;
- const unsigned char *p_rev;
const struct usb_interface_descriptor *interface;
const struct usb_endpoint_descriptor *endpoint;
int devnum, model=0;
@@ -2955,20 +2955,24 @@ static void *usb_ibmcam_probe(struct usb_device *dev, unsigned int ifnum)
return NULL;
/* Check the version/revision */
- p_rev = (const unsigned char *) &dev->descriptor.bcdDevice;
- if (p_rev[1] == 0x00 && p_rev[0] == 0x02) {
+ switch (dev->descriptor.bcdDevice) {
+ case 0x0002:
if (ifnum != 2)
return NULL;
- printk(KERN_INFO "IBM USB camera found (model 1).\n");
+ printk(KERN_INFO "IBM USB camera found (model 1, rev. 0x%04x).\n",
+ dev->descriptor.bcdDevice);
model = IBMCAM_MODEL_1;
- } else if (p_rev[1] == 0x03 && p_rev[0] == 0x0A) {
+ break;
+ case 0x030A:
if (ifnum != 0)
return NULL;
- printk(KERN_INFO "IBM USB camera found (model 2).\n");
+ printk(KERN_INFO "IBM USB camera found (model 2, rev. 0x%04x).\n",
+ dev->descriptor.bcdDevice);
model = IBMCAM_MODEL_2;
- } else {
- printk(KERN_ERR "IBM camera revision=%02x.%02x not supported\n",
- p_rev[1], p_rev[0]);
+ break;
+ default:
+ printk(KERN_ERR "IBM camera with revision 0x%04x is not supported.\n",
+ dev->descriptor.bcdDevice);
return NULL;
}
diff --git a/drivers/usb/input.c b/drivers/usb/input.c
index 4fb2985af..a21df12dc 100644
--- a/drivers/usb/input.c
+++ b/drivers/usb/input.c
@@ -401,7 +401,7 @@ static int __init input_init(void)
printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
return -EBUSY;
}
- input_devfs_handle = devfs_mk_dir(NULL, "input", 5, NULL);
+ input_devfs_handle = devfs_mk_dir(NULL, "input", NULL);
return 0;
}
diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
index 261d5ac00..12a2c5796 100644
--- a/drivers/usb/serial/usbserial.c
+++ b/drivers/usb/serial/usbserial.c
@@ -14,6 +14,9 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (07/03/2000) gkh
+ * Added more debugging to serial_ioctl call
+ *
* (06/25/2000) gkh
* Changed generic_write_bulk_callback to not call wake_up_interruptible
* directly, but to have port_softint do it at a safer time.
@@ -644,7 +647,7 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in
return -ENODEV;
}
- dbg(__FUNCTION__ " - port %d", port->number);
+ dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd);
if (!port->active) {
dbg (__FUNCTION__ " - port not open");
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index fa7f475c6..a455e8dc8 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -11,6 +11,10 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (07/03/2000) gkh
+ * Added visor_set_ioctl and visor_set_termios functions (they don't do much
+ * of anything, but are good for debugging.)
+ *
* (06/25/2000) gkh
* Fixed bug in visor_unthrottle that should help with the disconnect in PPP
* bug that people have been reporting.
@@ -59,6 +63,8 @@ static void visor_close (struct usb_serial_port *port, struct file *filp);
static void visor_throttle (struct usb_serial_port *port);
static void visor_unthrottle (struct usb_serial_port *port);
static int visor_startup (struct usb_serial *serial);
+static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios);
/* All of the device info needed for the Handspring Visor */
static __u16 handspring_vendor_id = HANDSPRING_VENDOR_ID;
@@ -79,6 +85,8 @@ struct usb_serial_device_type handspring_device = {
throttle: visor_throttle,
unthrottle: visor_unthrottle,
startup: visor_startup,
+ ioctl: visor_ioctl,
+ set_termios: visor_set_termios,
};
@@ -211,3 +219,78 @@ static int visor_startup (struct usb_serial *serial)
return (0);
}
+
+static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd);
+
+ return -ENOIOCTLCMD;
+}
+
+
+/* This function is all nice and good, but we don't change anything based on it :) */
+static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{
+ unsigned int cflag = port->tty->termios->c_cflag;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ /* check that they really want us to change something */
+ if (old_termios) {
+ if ((cflag == old_termios->c_cflag) &&
+ (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+ dbg(__FUNCTION__ " - nothing to change...");
+ return;
+ }
+ }
+
+ if ((!port->tty) || (!port->tty->termios)) {
+ dbg(__FUNCTION__" - no tty structures");
+ return;
+ }
+
+ /* get the byte size */
+ switch (cflag & CSIZE) {
+ case CS5: dbg(__FUNCTION__ " - data bits = 5"); break;
+ case CS6: dbg(__FUNCTION__ " - data bits = 6"); break;
+ case CS7: dbg(__FUNCTION__ " - data bits = 7"); break;
+ default:
+ case CS8: dbg(__FUNCTION__ " - data bits = 8"); break;
+ }
+
+ /* determine the parity */
+ if (cflag & PARENB)
+ if (cflag & PARODD)
+ dbg(__FUNCTION__ " - parity = odd");
+ else
+ dbg(__FUNCTION__ " - parity = even");
+ else
+ dbg(__FUNCTION__ " - parity = none");
+
+ /* figure out the stop bits requested */
+ if (cflag & CSTOPB)
+ dbg(__FUNCTION__ " - stop bits = 2");
+ else
+ dbg(__FUNCTION__ " - stop bits = 1");
+
+
+ /* figure out the flow control settings */
+ if (cflag & CRTSCTS)
+ dbg(__FUNCTION__ " - RTS/CTS is enabled");
+ else
+ dbg(__FUNCTION__ " - RTS/CTS is disabled");
+
+ /* determine software flow control */
+ if (I_IXOFF(port->tty))
+ dbg(__FUNCTION__ " - XON/XOFF is enabled, XON = %2x, XOFF = %2x", START_CHAR(port->tty), STOP_CHAR(port->tty));
+ else
+ dbg(__FUNCTION__ " - XON/XOFF is disabled");
+
+ /* get the baud rate wanted */
+ dbg(__FUNCTION__ " - baud rate = %d", tty_get_baud_rate(port->tty));
+
+ return;
+}
+
+
+
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index c168efa02..91afddd56 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -11,6 +11,11 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (07/04/2000) gkh
+ * Added support for port settings. Baud rate can now be changed. Line signals
+ * are not transferred to and from the tty layer yet, but things seem to be
+ * working well now.
+ *
* (05/04/2000) gkh
* First cut at open and close commands. Data can flow through the ports at
* default speeds now.
@@ -55,6 +60,7 @@
/* function prototypes for the Connect Tech WhiteHEAT serial converter */
static int whiteheat_open (struct usb_serial_port *port, struct file *filp);
static void whiteheat_close (struct usb_serial_port *port, struct file *filp);
+static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
static void whiteheat_set_termios (struct usb_serial_port *port, struct termios * old);
static void whiteheat_throttle (struct usb_serial_port *port);
static void whiteheat_unthrottle (struct usb_serial_port *port);
@@ -93,6 +99,7 @@ struct usb_serial_device_type whiteheat_device = {
close: whiteheat_close,
throttle: whiteheat_throttle,
unthrottle: whiteheat_unthrottle,
+ ioctl: whiteheat_ioctl,
set_termios: whiteheat_set_termios,
shutdown: whiteheat_shutdown,
};
@@ -103,6 +110,13 @@ struct whiteheat_private {
};
+/* local function prototypes */
+static inline void set_rts (struct usb_serial_port *port, unsigned char rts);
+static inline void set_dtr (struct usb_serial_port *port, unsigned char dtr);
+static inline void set_break (struct usb_serial_port *port, unsigned char brk);
+
+
+
#define COMMAND_PORT 4
#define COMMAND_TIMEOUT (2*HZ) /* 2 second timeout for a command */
@@ -116,7 +130,7 @@ static void command_port_write_callback (struct urb *urb)
int i;
#endif
- dbg ("command_port_write_callback");
+ dbg (__FUNCTION__);
if (urb->status) {
dbg ("nonzero urb status: %d", urb->status);
@@ -125,7 +139,7 @@ static void command_port_write_callback (struct urb *urb)
#ifdef DEBUG
if (urb->actual_length) {
- printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+ printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", urb->actual_length);
for (i = 0; i < urb->actual_length; ++i) {
printk ("%.2x ", data[i]);
}
@@ -145,16 +159,16 @@ static void command_port_read_callback (struct urb *urb)
int i;
#endif
- dbg ("command_port_write_callback");
+ dbg (__FUNCTION__);
if (urb->status) {
- dbg ("nonzero urb status: %d", urb->status);
+ dbg (__FUNCTION__ " - nonzero urb status: %d", urb->status);
return;
}
#ifdef DEBUG
if (urb->actual_length) {
- printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+ printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", urb->actual_length);
for (i = 0; i < urb->actual_length; ++i) {
printk ("%.2x ", data[i]);
}
@@ -179,7 +193,7 @@ static int whiteheat_send_cmd (struct usb_serial *serial, __u8 command, __u8 *da
int timeout;
__u8 *transfer_buffer;
- dbg("whiteheat_send_cmd: %d", command);
+ dbg(__FUNCTION__" - command %d", command);
port = &serial->port[COMMAND_PORT];
info = (struct whiteheat_private *)port->private;
@@ -189,8 +203,10 @@ static int whiteheat_send_cmd (struct usb_serial *serial, __u8 command, __u8 *da
transfer_buffer[0] = command;
memcpy (&transfer_buffer[1], data, datasize);
port->write_urb->transfer_buffer_length = datasize + 1;
- if (usb_submit_urb (port->write_urb))
- dbg ("submit urb failed");
+ if (usb_submit_urb (port->write_urb)) {
+ dbg (__FUNCTION__" - submit urb failed");
+ return -1;
+ }
/* wait for the command to complete */
timeout = COMMAND_TIMEOUT;
@@ -199,6 +215,7 @@ static int whiteheat_send_cmd (struct usb_serial *serial, __u8 command, __u8 *da
}
if (info->command_finished == FALSE) {
+ dbg (__FUNCTION__ " - command timed out.");
return -1;
}
@@ -212,10 +229,10 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
struct usb_serial_port *command_port;
struct whiteheat_private *info;
- dbg("whiteheat_open port %d", port->number);
+ dbg(__FUNCTION__" - port %d", port->number);
if (port->active) {
- dbg ("device already open");
+ dbg (__FUNCTION__ " - device already open");
return -EINVAL;
}
port->active = 1;
@@ -225,7 +242,7 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
if (command_port->private == NULL) {
info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL);
if (info == NULL) {
- err("out of memory");
+ err(__FUNCTION__ " - out of memory");
return -ENOMEM;
}
@@ -238,7 +255,7 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
/* Start reading from the device */
if (usb_submit_urb(port->read_urb))
- dbg("usb_submit_urb(read bulk) failed");
+ dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
/* send an open port command */
open_command.port = port->number - port->minor;
@@ -247,9 +264,9 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
/* Need to do device specific setup here (control lines, baud rate, etc.) */
/* FIXME!!! */
- dbg("whiteheat_open exit");
+ dbg(__FUNCTION__ " - exit");
- return (0);
+ return 0;
}
@@ -257,7 +274,7 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
{
struct whiteheat_min_set close_command;
- dbg("whiteheat_close port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
/* send a close command to the port */
close_command.port = port->number - port->minor;
@@ -273,30 +290,102 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
}
+static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd);
+
+ return -ENOIOCTLCMD;
+}
+
+
static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios)
{
unsigned int cflag = port->tty->termios->c_cflag;
+ struct whiteheat_port_settings port_settings;
- dbg("whiteheat_set_termios port %d", port->number);
+ dbg(__FUNCTION__ " -port %d", port->number);
/* check that they really want us to change something */
if (old_termios) {
if ((cflag == old_termios->c_cflag) &&
(RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
- dbg("nothing to change...");
+ dbg(__FUNCTION__ " - nothing to change...");
return;
}
}
- /* do the parsing of the cflag to see what to set the line to */
- /* FIXME!! */
+ if ((!port->tty) || (!port->tty->termios)) {
+ dbg(__FUNCTION__" - no tty structures");
+ return;
+ }
+
+ /* get the byte size */
+ switch (cflag & CSIZE) {
+ case CS5: port_settings.bits = 5; break;
+ case CS6: port_settings.bits = 6; break;
+ case CS7: port_settings.bits = 7; break;
+ default:
+ case CS8: port_settings.bits = 8; break;
+ }
+ dbg(__FUNCTION__ " - data bits = %d", port_settings.bits);
+
+ /* determine the parity */
+ if (cflag & PARENB)
+ if (cflag & PARODD)
+ port_settings.parity = 'o';
+ else
+ port_settings.parity = 'e';
+ else
+ port_settings.parity = 'n';
+ dbg(__FUNCTION__ " - parity = %c", port_settings.parity);
+
+ /* figure out the stop bits requested */
+ if (cflag & CSTOPB)
+ port_settings.stop = 2;
+ else
+ port_settings.stop = 1;
+ dbg(__FUNCTION__ " - stop bits = %d", port_settings.stop);
+
+
+ /* figure out the flow control settings */
+ if (cflag & CRTSCTS)
+ port_settings.hflow = (WHITEHEAT_CTS_FLOW | WHITEHEAT_RTS_FLOW);
+ else
+ port_settings.hflow = 0;
+ dbg(__FUNCTION__ " - hardware flow control = %s %s %s %s",
+ (port_settings.hflow | WHITEHEAT_CTS_FLOW) ? "CTS" : "",
+ (port_settings.hflow | WHITEHEAT_RTS_FLOW) ? "RTS" : "",
+ (port_settings.hflow | WHITEHEAT_DSR_FLOW) ? "DSR" : "",
+ (port_settings.hflow | WHITEHEAT_DTR_FLOW) ? "DTR" : "");
+
+ /* determine software flow control */
+ if (I_IXOFF(port->tty))
+ port_settings.sflow = 'b';
+ else
+ port_settings.sflow = 'n';
+ dbg(__FUNCTION__ " - software flow control = %c", port_settings.sflow);
+
+ port_settings.xon = START_CHAR(port->tty);
+ port_settings.xoff = STOP_CHAR(port->tty);
+ dbg(__FUNCTION__ " - XON = %2x, XOFF = %2x", port_settings.xon, port_settings.xoff);
+
+ /* get the baud rate wanted */
+ port_settings.baud = tty_get_baud_rate(port->tty);
+ dbg(__FUNCTION__ " - baud rate = %d", port_settings.baud);
+ /* handle any settings that aren't specified in the tty structure */
+ port_settings.lloop = 0;
+
+ /* now send the message to the device */
+ whiteheat_send_cmd (port->serial, WHITEHEAT_SETUP_PORT, (__u8 *)&port_settings, sizeof(port_settings));
+
return;
}
+
static void whiteheat_throttle (struct usb_serial_port *port)
{
- dbg("whiteheat_throttle port %d", port->number);
+ dbg(__FUNCTION__" - port %d", port->number);
/* Change the control signals */
/* FIXME!!! */
@@ -307,7 +396,7 @@ static void whiteheat_throttle (struct usb_serial_port *port)
static void whiteheat_unthrottle (struct usb_serial_port *port)
{
- dbg("whiteheat_unthrottle port %d", port->number);
+ dbg(__FUNCTION__" - port %d", port->number);
/* Change the control signals */
/* FIXME!!! */
@@ -334,7 +423,7 @@ static int whiteheat_startup (struct usb_serial *serial)
int response;
const struct whiteheat_hex_record *record;
- dbg("whiteheat_startup");
+ dbg(__FUNCTION__);
response = ezusb_set_reset (serial, 1);
@@ -343,7 +432,7 @@ static int whiteheat_startup (struct usb_serial *serial)
response = ezusb_writememory (serial, record->address,
(unsigned char *)record->data, record->data_size, 0xa0);
if (response < 0) {
- err("ezusb_writememory failed for loader (%d %04X %p %d)",
+ err(__FUNCTION__ " - ezusb_writememory failed for loader (%d %04X %p %d)",
response, record->address, record->data, record->data_size);
break;
}
@@ -360,7 +449,7 @@ static int whiteheat_startup (struct usb_serial *serial)
response = ezusb_writememory (serial, record->address,
(unsigned char *)record->data, record->data_size, 0xa3);
if (response < 0) {
- err("ezusb_writememory failed for first firmware step (%d %04X %p %d)",
+ err(__FUNCTION__ " - ezusb_writememory failed for first firmware step (%d %04X %p %d)",
response, record->address, record->data, record->data_size);
break;
}
@@ -374,7 +463,7 @@ static int whiteheat_startup (struct usb_serial *serial)
response = ezusb_writememory (serial, record->address,
(unsigned char *)record->data, record->data_size, 0xa0);
if (response < 0) {
- err("ezusb_writememory failed for second firmware step (%d %04X %p %d)",
+ err(__FUNCTION__" - ezusb_writememory failed for second firmware step (%d %04X %p %d)",
response, record->address, record->data, record->data_size);
break;
}
@@ -392,9 +481,9 @@ static void whiteheat_shutdown (struct usb_serial *serial)
{
struct usb_serial_port *command_port;
- dbg("whiteheat_shutdown");
+ dbg(__FUNCTION__);
- /* set up some stuff for our command port */
+ /* free up our private data for our command port */
command_port = &serial->port[COMMAND_PORT];
if (command_port->private != NULL) {
kfree (command_port->private);
@@ -404,3 +493,35 @@ static void whiteheat_shutdown (struct usb_serial *serial)
return;
}
+
+
+
+static void set_command (struct usb_serial_port *port, unsigned char state, unsigned char command)
+{
+ struct whiteheat_rdb_set rdb_command;
+
+ /* send a set rts command to the port */
+ rdb_command.port = port->number - port->minor;
+ rdb_command.state = state;
+
+ whiteheat_send_cmd (port->serial, command, (__u8 *)&rdb_command, sizeof(rdb_command));
+}
+
+
+static inline void set_rts (struct usb_serial_port *port, unsigned char rts)
+{
+ set_command (port, rts, WHITEHEAT_SET_RTS);
+}
+
+
+static inline void set_dtr (struct usb_serial_port *port, unsigned char dtr)
+{
+ set_command (port, dtr, WHITEHEAT_SET_DTR);
+}
+
+
+static inline void set_break (struct usb_serial_port *port, unsigned char brk)
+{
+ set_command (port, brk, WHITEHEAT_SET_BREAK);
+}
+
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
index b1d2d2a01..d1155e0ee 100644
--- a/drivers/usb/usb-ohci.c
+++ b/drivers/usb/usb-ohci.c
@@ -307,7 +307,7 @@ static void ohci_dump_roothub (ohci_t *controller, int verbose)
static void ohci_dump (ohci_t *controller, int verbose)
{
- dbg ("OHCI controller %p state", controller->regs);
+ dbg ("OHCI controller %s state", controller->ohci_dev->slot_name);
// dumps some of the state we know about
ohci_dump_status (controller);
@@ -831,8 +831,8 @@ static int ep_unlink (ohci_t * ohci, ed_t * ed)
}
break;
- case INT:
- int_branch = ed->int_branch;
+ case INT:
+ int_branch = ed->int_branch;
interval = ed->int_interval;
for (i = 0; i < ep_rev (6, interval); i += inter) {
@@ -1392,6 +1392,14 @@ static int rh_send_irq (ohci_t * ohci, void * rh_data, int rh_len)
__u8 data[8];
num_ports = readl (&ohci->regs->roothub.a) & RH_A_NDP;
+ if (num_ports > MAX_ROOT_PORTS) {
+ err ("bogus NDP=%d for OHCI %s", num_ports,
+ ohci->ohci_dev->slot_name);
+ err ("rereads as NDP=%d",
+ readl (&ohci->regs->roothub.a) & RH_A_NDP);
+ /* retry later; "should not happen" */
+ return 0;
+ }
*(__u8 *) data = (readl (&ohci->regs->roothub.status) & (RH_HS_LPSC | RH_HS_OCIC))
? 1: 0;
ret = *(__u8 *) data;
@@ -1424,8 +1432,12 @@ static void rh_int_timer_do (unsigned long ptr)
ohci_t * ohci = urb->dev->bus->hcpriv;
if (ohci->disabled)
- return;
-
+ return;
+
+ /* ignore timers firing during PM suspend, etc */
+ if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER)
+ return;
+
if(ohci->rh.send) {
len = rh_send_irq (ohci, urb->transfer_buffer, urb->transfer_buffer_length);
if (len > 0) {
@@ -1702,7 +1714,9 @@ static int hc_reset (ohci_t * ohci)
/* Disable HC interrupts */
writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
- dbg("USB HC reset_hc: %x ;", readl (&ohci->regs->control));
+ dbg("USB HC reset_hc %s: ctrl = %x ;",
+ ohci->ohci_dev->slot_name,
+ readl (&ohci->regs->control));
/* Reset USB (needed by some controllers) */
writel (0, &ohci->regs->control);
@@ -1793,17 +1807,24 @@ static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
if ((ohci->hcca.done_head != 0) && !(le32_to_cpup (&ohci->hcca.done_head) & 0x01)) {
ints = OHCI_INTR_WDH;
- } else {
- if ((ints = (readl (&regs->intrstatus) & readl (&regs->intrenable))) == 0)
- return;
+ } else if ((ints = (readl (&regs->intrstatus) & readl (&regs->intrenable))) == 0) {
+ return;
}
// dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no));
if (ints & OHCI_INTR_UE) {
ohci->disabled++;
- err ("OHCI Unrecoverable Error, controller disabled");
+ err ("OHCI Unrecoverable Error, controller %s disabled",
+ ohci->ohci_dev->slot_name);
// e.g. due to PCI Master/Target Abort
+
+#ifndef DEBUG
+ // FIXME: be optimistic, hope that bug won't repeat often.
+ // Make some non-interrupt context restart the controller.
+ // Count and limit the retries though; either hardware or
+ // software errors can go forever...
+#endif
}
if (ints & OHCI_INTR_WDH) {
@@ -1823,7 +1844,8 @@ static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
if (ohci->ed_rm_list[!frame] != NULL) {
dl_del_list (ohci, !frame);
}
- if (ohci->ed_rm_list[frame] != NULL) writel (OHCI_INTR_SF, &regs->intrenable);
+ if (ohci->ed_rm_list[frame] != NULL)
+ writel (OHCI_INTR_SF, &regs->intrenable);
}
writel (ints, &regs->intrstatus);
writel (OHCI_INTR_MIE, &regs->intrenable);
@@ -1885,20 +1907,20 @@ static ohci_t * hc_alloc_ohci (void * mem_base)
static void hc_release_ohci (ohci_t * ohci)
{
- dbg("USB HC release ohci");
+ dbg ("USB HC release ohci %s", ohci->ohci_dev->slot_name);
/* disconnect all devices */
if (ohci->bus->root_hub)
usb_disconnect (&ohci->bus->root_hub);
- hc_reset (ohci);
- writel (OHCI_USB_RESET, &ohci->regs->control);
- wait_ms (10);
+ if (!ohci->disabled)
+ hc_reset (ohci);
if (ohci->irq >= 0) {
free_irq (ohci->irq, ohci);
ohci->irq = -1;
}
+ ohci->ohci_dev->driver_data = 0;
usb_deregister_bus (ohci->bus);
usb_free_bus (ohci->bus);
@@ -1926,13 +1948,15 @@ static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
#endif
printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n",
(unsigned long) mem_base, bufp);
- printk(KERN_INFO __FILE__ ": %s\n", dev->name);
+ printk(KERN_INFO __FILE__ ": pci slot %s, %s\n", dev->slot_name, dev->name);
ohci = hc_alloc_ohci (mem_base);
if (!ohci) {
return -ENOMEM;
}
+ ohci->ohci_dev = dev;
+ dev->driver_data = ohci;
INIT_LIST_HEAD (&ohci->ohci_hcd_list);
list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
@@ -1960,7 +1984,6 @@ static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
#ifdef DEBUG
ohci_dump (ohci, 1);
#endif
-
return 0;
}
err("request interrupt %d failed", irq);
@@ -2037,7 +2060,7 @@ static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data)
switch (rqst) {
case PM_SUSPEND:
/* act as if usb suspend can always be used */
- dbg("USB suspend: %p", ohci->regs);
+ dbg("USB suspend: %s", ohci->ohci_dev->slot_name);
ohci->hc_control = OHCI_USB_SUSPEND;
writel (ohci->hc_control, &ohci->regs->control);
wait_ms (10);
@@ -2050,7 +2073,7 @@ static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data)
switch (temp) {
case OHCI_USB_RESET: // lost power
- dbg("USB reset: %p", ohci->regs);
+ dbg("USB reset: %s", ohci->ohci_dev->slot_name);
ohci->disabled = 1;
if (ohci->bus->root_hub)
usb_disconnect (&ohci->bus->root_hub);
@@ -2058,14 +2081,16 @@ static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data)
if ((temp = hc_reset (ohci)) < 0
|| (temp = hc_start (ohci)) < 0) {
ohci->disabled = 1;
- err ("can't restart, %d", temp);
+ err ("can't restart %s, %d",
+ ohci->ohci_dev->slot_name,
+ temp);
}
dbg ("reset done");
break;
case OHCI_USB_SUSPEND: // host wakeup
case OHCI_USB_RESUME: // remote wakeup
- dbg("USB resume: %p", ohci->regs);
+ dbg("USB resume: %s", ohci->ohci_dev->slot_name);
ohci->hc_control = OHCI_USB_RESUME;
writel (ohci->hc_control, &ohci->regs->control);
wait_ms (20);
diff --git a/drivers/usb/usb-ohci.h b/drivers/usb/usb-ohci.h
index 3ac5dafb2..e326f5ee6 100644
--- a/drivers/usb/usb-ohci.h
+++ b/drivers/usb/usb-ohci.h
@@ -8,13 +8,9 @@
*/
-#define MODSTR "ohci: "
-
-
static int cc_to_error[16] = {
/* mapping of the OHCI CC status to error codes */
-#ifdef USB_ST_CRC /* status codes */
/* No Error */ USB_ST_NOERROR,
/* CRC Error */ USB_ST_CRC,
/* Bit Stuff */ USB_ST_BITSTUFF,
@@ -33,28 +29,6 @@ static int cc_to_error[16] = {
/* Not Access */ USB_ST_NORESPONSE
};
-#else /* error codes */
- /* No Error */ 0,
- /* CRC Error */ -EILSEQ,
- /* Bit Stuff */ -EPROTO,
- /* Data Togg */ -EILSEQ,
- /* Stall */ -EPIPE,
- /* DevNotResp */ -ETIMEDOUT,
- /* PIDCheck */ -EPROTO,
- /* UnExpPID */ -EPROTO,
- /* DataOver */ -EOVERFLOW,
- /* DataUnder */ -EREMOTEIO,
- /* reservd */ -ETIMEDOUT,
- /* reservd */ -ETIMEDOUT,
- /* BufferOver */ -ECOMM,
- /* BuffUnder */ -ECOMM,
- /* Not Access */ -ETIMEDOUT,
- /* Not Access */ -ETIMEDOUT
-};
-#define USB_ST_URB_PENDING -EINPROGRESS
-#endif
-
-
struct ed;
struct td;
@@ -410,6 +384,7 @@ typedef struct ohci {
struct usb_bus * bus;
struct usb_device * dev[128];
struct virt_root_hub rh;
+ struct pci_dev *ohci_dev;
} ohci_t;
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
index ba9b44ac3..626bfc93c 100644
--- a/drivers/usb/usb-uhci.c
+++ b/drivers/usb/usb-uhci.c
@@ -1393,8 +1393,10 @@ _static int uhci_submit_iso_urb (urb_t *urb)
{
uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
urb_priv_t *urb_priv = urb->hcpriv;
+#ifdef ISO_SANITY_CHECK
int pipe=urb->pipe;
int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
+#endif
int n, ret, last=0;
uhci_desc_t *td, **tdm;
int status, destination;
@@ -1422,18 +1424,18 @@ _static int uhci_submit_iso_urb (urb_t *urb)
tdm[n] = 0;
continue;
}
-
- if(urb->iso_frame_desc[n].length > maxsze) {
+
#ifdef ISO_SANITY_CHECK
+ if(urb->iso_frame_desc[n].length > maxsze) {
err("submit_iso: urb->iso_frame_desc[%d].length(%d)>%d",n , urb->iso_frame_desc[n].length, maxsze);
tdm[n] = 0;
ret=-EINVAL;
goto inval;
-#endif
}
-
+ else
+#endif
ret = alloc_td (&td, UHCI_PTR_DEPTH);
- inval:
+
if (ret) {
int i; // Cleanup allocated TDs
diff --git a/drivers/video/Config.in b/drivers/video/Config.in
index 6529b53c5..0b30ebb38 100644
--- a/drivers/video/Config.in
+++ b/drivers/video/Config.in
@@ -119,7 +119,7 @@ if [ "$CONFIG_FB" = "y" ]; then
fi
tristate ' ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY
tristate ' ATI Rage 128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128
- bool ' 3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
+ tristate ' 3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
tristate ' SIS 630/540 display support (EXPERIMENTAL)' CONFIG_FB_SIS
fi
fi
@@ -240,7 +240,7 @@ if [ "$CONFIG_FB" = "y" ]; then
"$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
"$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
"$CONFIG_FB_P9100" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
- "$CONFIG_FB_RIVA" = "m" -o \
+ "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_3DFX" = "m" -o \
"$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \
"$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then
define_tristate CONFIG_FBCON_CFB8 m
@@ -263,7 +263,7 @@ if [ "$CONFIG_FB" = "y" ]; then
if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
"$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
"$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \
- "$CONFIG_FB_Q40" = "m" -o \
+ "$CONFIG_FB_Q40" = "m" -o "$CONFIG_FB_3DFX" = "m" -o \
"$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
"$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
"$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
@@ -306,6 +306,7 @@ if [ "$CONFIG_FB" = "y" ]; then
"$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
"$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
"$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
+ "$CONFIG_FB_3DFX" = "m" -o \
"$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then
define_tristate CONFIG_FBCON_CFB32 m
fi
diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c
index 08fcf8141..d32a621b7 100644
--- a/drivers/video/atyfb.c
+++ b/drivers/video/atyfb.c
@@ -612,6 +612,7 @@ static inline void aty_st_8(unsigned int regindex, u8 val,
writeb (val, info->ati_regbase + regindex);
}
+#if defined(CONFIG_PPC) || defined(CONFIG_PMAC_PBOOK)
static void aty_st_lcd(int index, u32 val, const struct fb_info_aty *info)
{
unsigned long temp;
@@ -633,6 +634,7 @@ static u32 aty_ld_lcd(int index, const struct fb_info_aty *info)
/* read the register value */
return aty_ld_le32(LCD_DATA, info);
}
+#endif
/*
* Generic Mach64 routines
diff --git a/drivers/video/clgenfb.c b/drivers/video/clgenfb.c
index bb8d302fc..bdabd1e45 100644
--- a/drivers/video/clgenfb.c
+++ b/drivers/video/clgenfb.c
@@ -2557,7 +2557,6 @@ static int __init clgen_pci_setup (struct clgenfb_info *info,
#endif /* CONFIG_FB_OF */
struct pci_dev *pdev;
unsigned long board_addr, board_size;
- u16 tmp16;
DPRINTK ("ENTER\n");
@@ -2618,14 +2617,12 @@ static int __init clgen_pci_setup (struct clgenfb_info *info,
}
if (!request_mem_region(board_addr, board_size, "clgenfb")) {
- pci_write_config_word (pdev, PCI_COMMAND, tmp16);
printk(KERN_ERR "clgen: cannot reserve region 0x%lx, abort\n",
board_addr);
return -1;
}
#if 0 /* if the system didn't claim this region, we would... */
if (!request_mem_region(0xA0000, 65535, "clgenfb")) {
- pci_write_config_word (pdev, PCI_COMMAND, tmp16);
printk(KERN_ERR "clgen: cannot reserve region 0x%lx, abort\n",
0xA0000L);
release_mem_region(board_addr, board_size);
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 3707b611a..2ab527f02 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -709,7 +709,7 @@ fbmem_init(void)
create_proc_read_entry("fb", 0, 0, fbmem_read_proc, NULL);
- devfs_handle = devfs_mk_dir (NULL, "fb", 0, NULL);
+ devfs_handle = devfs_mk_dir (NULL, "fb", NULL);
if (devfs_register_chrdev(FB_MAJOR,"fb",&fb_fops))
printk("unable to get major %d for fb devs\n", FB_MAJOR);
diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c
index db84a3000..e8a3738f8 100644
--- a/drivers/video/matrox/matroxfb_DAC1064.c
+++ b/drivers/video/matrox/matroxfb_DAC1064.c
@@ -169,9 +169,9 @@ static void matroxfb_DAC1064_cursor(struct display* p, int mode, int x, int y) {
if (mode == CM_ERASE) {
if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
+ del_timer_sync(&ACCESS_FBINFO(cursor.timer));
matroxfb_DAC_lock_irqsave(flags);
ACCESS_FBINFO(cursor.state) = CM_ERASE;
- del_timer(&ACCESS_FBINFO(cursor.timer));
outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_DIS);
matroxfb_DAC_unlock_irqrestore(flags);
}
@@ -184,6 +184,7 @@ static void matroxfb_DAC1064_cursor(struct display* p, int mode, int x, int y) {
y -= p->var.yoffset;
if (p->var.vmode & FB_VMODE_DOUBLE)
y *= 2;
+ del_timer_sync(&ACCESS_FBINFO(cursor.timer));
matroxfb_DAC_lock_irqsave(flags);
if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y)) || ACCESS_FBINFO(cursor.redraw)) {
ACCESS_FBINFO(cursor.redraw) = 0;
@@ -339,16 +340,18 @@ void DAC1064_global_init(CPMINFO struct matrox_hw_state* hw) {
#if defined(CONFIG_FB_MATROX_MAVEN) || defined(CONFIG_FB_MATROX_MAVEN_MODULE)
if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT;
- hw->DACreg[POS1064_XMISCCTRL] |= G400_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12;
- } else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY)
- hw->DACreg[POS1064_XMISCCTRL] |= G400_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12;
+ hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12;
+ } else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
+ hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12;
+ } else
+#endif
+ if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
+ hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12;
else
- hw->DACreg[POS1064_XMISCCTRL] |= G400_XMISCCTRL_MFC_DIS;
+ hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;
+
if ((ACCESS_FBINFO(output.ph) | ACCESS_FBINFO(output.sh)) & MATROXFB_OUTPUT_CONN_PRIMARY)
hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
-#else
- hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_MFC_DIS | M1064_XMISCCTRL_DAC_EN;
-#endif
}
void DAC1064_global_restore(CPMINFO const struct matrox_hw_state* hw) {
diff --git a/drivers/video/matrox/matroxfb_DAC1064.h b/drivers/video/matrox/matroxfb_DAC1064.h
index 4a8fdb801..256a11d2c 100644
--- a/drivers/video/matrox/matroxfb_DAC1064.h
+++ b/drivers/video/matrox/matroxfb_DAC1064.h
@@ -84,10 +84,10 @@ void DAC1064_global_restore(CPMINFO const struct matrox_hw_state*);
#define M1064_XMISCCTRL_MFC_VGA 0x00
#define M1064_XMISCCTRL_MFC_MAFC 0x02
#define M1064_XMISCCTRL_MFC_DIS 0x06
-#define G400_XMISCCTRL_MFC_MAFC 0x02
-#define G400_XMISCCTRL_MFC_PANELLINK 0x04
-#define G400_XMISCCTRL_MFC_DIS 0x06
-#define G400_XMISCCTRL_MFC_MASK 0x06
+#define GX00_XMISCCTRL_MFC_MAFC 0x02
+#define GX00_XMISCCTRL_MFC_PANELLINK 0x04
+#define GX00_XMISCCTRL_MFC_DIS 0x06
+#define GX00_XMISCCTRL_MFC_MASK 0x06
#define M1064_XMISCCTRL_DAC_6BIT 0x00
#define M1064_XMISCCTRL_DAC_8BIT 0x08
#define M1064_XMISCCTRL_DAC_WIDTHMASK 0x08
diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c
index 6bc3cea64..67dc556b0 100644
--- a/drivers/video/matrox/matroxfb_Ti3026.c
+++ b/drivers/video/matrox/matroxfb_Ti3026.c
@@ -352,9 +352,9 @@ static void matroxfb_ti3026_cursor(struct display* p, int mode, int x, int y) {
if (mode == CM_ERASE) {
if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
+ del_timer_sync(&ACCESS_FBINFO(cursor.timer));
matroxfb_DAC_lock_irqsave(flags);
ACCESS_FBINFO(cursor.state) = CM_ERASE;
- del_timer(&ACCESS_FBINFO(cursor.timer));
outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(currenthw->DACreg[POS3026_XCURCTRL]));
matroxfb_DAC_unlock_irqrestore(flags);
}
@@ -367,6 +367,7 @@ static void matroxfb_ti3026_cursor(struct display* p, int mode, int x, int y) {
y -= p->var.yoffset;
if (p->var.vmode & FB_VMODE_DOUBLE)
y *= 2;
+ del_timer_sync(&ACCESS_FBINFO(cursor.timer));
matroxfb_DAC_lock_irqsave(flags);
if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y)) || ACCESS_FBINFO(cursor.redraw)) {
ACCESS_FBINFO(cursor.redraw) = 0;
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index 040c79c2d..ef94171bc 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -97,7 +97,6 @@
#if defined(CONFIG_FB_OF)
unsigned char nvram_read_byte(int);
-int matrox_of_init(struct device_node *dp);
static int default_vmode = VMODE_NVRAM;
static int default_cmode = CMODE_NVRAM;
#endif
@@ -192,7 +191,7 @@ static void matroxfb_remove(WPMINFO int dummy) {
}
matroxfb_unregister_device(MINFO);
unregister_framebuffer(&ACCESS_FBINFO(fbcon));
- del_timer(&ACCESS_FBINFO(cursor.timer));
+ del_timer_sync(&ACCESS_FBINFO(cursor.timer));
#ifdef CONFIG_MTRR
if (ACCESS_FBINFO(mtrr.vram_valid))
mtrr_del(ACCESS_FBINFO(mtrr.vram), ACCESS_FBINFO(video.base), ACCESS_FBINFO(video.len));
@@ -827,7 +826,7 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
/* copy last setting... */
memcpy(hw, ohw, sizeof(*hw));
- del_timer(&ACCESS_FBINFO(cursor.timer));
+ del_timer_sync(&ACCESS_FBINFO(cursor.timer));
ACCESS_FBINFO(cursor.state) = CM_ERASE;
ACCESS_FBINFO(hw_switch->init(PMINFO hw, &mt, display));
@@ -845,7 +844,7 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
hw->CRTCEXT[8] = pos >> 21;
- if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_PRIMARY) {
+ if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) {
if (ACCESS_FBINFO(primout))
ACCESS_FBINFO(primout)->compute(MINFO, &mt, hw);
}
@@ -856,7 +855,7 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
up_read(&ACCESS_FBINFO(altout.lock));
}
ACCESS_FBINFO(hw_switch->restore(PMINFO hw, ohw, display));
- if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_PRIMARY) {
+ if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) {
if (ACCESS_FBINFO(primout))
ACCESS_FBINFO(primout)->program(MINFO, hw);
}
@@ -869,7 +868,7 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
ACCESS_FBINFO(cursor.redraw) = 1;
ACCESS_FBINFO(currenthw) = hw;
ACCESS_FBINFO(newhw) = ohw;
- if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_PRIMARY) {
+ if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) {
if (ACCESS_FBINFO(primout))
ACCESS_FBINFO(primout)->start(MINFO);
}
@@ -881,7 +880,7 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
}
matrox_cfbX_init(PMINFO display);
do_install_cmap(PMINFO display);
-#if defined(CONFIG_FB_OF) && defined(CONFIG_FB_COMPAT_XPMAC)
+#if defined(CONFIG_FB_COMPAT_XPMAC)
if (console_fb_info == &ACCESS_FBINFO(fbcon)) {
int vmode, cmode;
@@ -899,7 +898,7 @@ static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
display_info.cmap_data_address = 0;
display_info.disp_reg_address = ACCESS_FBINFO(mmio.base);
}
-#endif /* CONFIG_FB_OF && CONFIG_FB_COMPAT_XPMAC */
+#endif /* CONFIG_FB_COMPAT_XPMAC */
}
}
return 0;
@@ -1065,6 +1064,13 @@ static int matroxfb_ioctl(struct inode *inode, struct file *file,
up_read(&ACCESS_FBINFO(crtc2.lock));
}
return 0;
+ case MATROXFB_OUTPUT_DFP:
+ if (!(ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_DFP))
+ return -ENXIO;
+ if (mom.mode!= MATROXFB_OUTPUT_MODE_MONITOR)
+ return -EINVAL;
+ /* mode did not change... */
+ return 0;
default:
return -EINVAL;
}
@@ -1091,6 +1097,11 @@ static int matroxfb_ioctl(struct inode *inode, struct file *file,
if (val)
return val;
break;
+ case MATROXFB_OUTPUT_DFP:
+ if (!(ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_DFP))
+ return -ENXIO;
+ mom.mode = MATROXFB_OUTPUT_MODE_MONITOR;
+ break;
default:
return -EINVAL;
}
@@ -1106,6 +1117,12 @@ static int matroxfb_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
if (tmp & ACCESS_FBINFO(output.sh))
return -EINVAL;
+ if (tmp & MATROXFB_OUTPUT_CONN_DFP) {
+ if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY)
+ return -EINVAL;
+ if (ACCESS_FBINFO(output.sh))
+ return -EINVAL;
+ }
if (tmp == ACCESS_FBINFO(output.ph))
return 0;
ACCESS_FBINFO(output.ph) = tmp;
@@ -1122,6 +1139,10 @@ static int matroxfb_ioctl(struct inode *inode, struct file *file,
u_int32_t tmp;
tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.sh);
+ if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
+ tmp &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
+ if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY)
+ tmp &= ~MATROXFB_OUTPUT_CONN_DFP;
put_user_ret(tmp, (u_int32_t*)arg, -EFAULT);
return 0;
}
@@ -1290,6 +1311,7 @@ static int sync = -1; /* "matrox:sync:xxxxx" */
static unsigned int fv = 0; /* "matrox:fv:xxxxx" */
static unsigned int fh = 0; /* "matrox:fh:xxxxxk" */
static unsigned int maxclk = 0; /* "matrox:maxclk:xxxxM" */
+static int dfp = 0; /* "matrox:dfp */
static char fontname[64]; /* "matrox:font:xxxxx" */
#ifndef MODULE
@@ -1386,11 +1408,13 @@ static struct video_board vbG400 = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG4
#define DEVF_TEXT16B 0x0400
#define DEVF_CRTC2 0x0800
#define DEVF_MAVEN_CAPABLE 0x1000
+#define DEVF_PANELLINK_CAPABLE 0x2000
#define DEVF_GCORE (DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2)
+#define DEVF_G2CORE (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE)
#define DEVF_G100 (DEVF_GCORE) /* no doc, no vxres... */
-#define DEVF_G200 (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE)
-#define DEVF_G400 (DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2)
+#define DEVF_G200 (DEVF_G2CORE)
+#define DEVF_G400 (DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2)
static struct board {
unsigned short vendor, device, rev, svid, sid;
@@ -1586,6 +1610,12 @@ static int initMatrox2(WPMINFO struct display* d, struct board* b){
ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES);
ACCESS_FBINFO(devflags.crtc2) = b->flags & DEVF_CRTC2;
ACCESS_FBINFO(devflags.maven_capable) = b->flags & DEVF_MAVEN_CAPABLE;
+ if (b->flags & DEVF_PANELLINK_CAPABLE) {
+ ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_DFP;
+ if (dfp)
+ ACCESS_FBINFO(output.ph) |= MATROXFB_OUTPUT_CONN_DFP;
+ }
+
ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode);
ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode);
@@ -1791,7 +1821,7 @@ static int initMatrox2(WPMINFO struct display* d, struct board* b){
}
/* FIXME: Where to move this?! */
-#if defined(CONFIG_FB_OF)
+#if defined(CONFIG_PPC)
#if defined(CONFIG_FB_COMPAT_XPMAC)
strcpy(ACCESS_FBINFO(matrox_name), "MTRX,"); /* OpenFirmware naming convension */
strncat(ACCESS_FBINFO(matrox_name), b->name, 26);
@@ -1817,7 +1847,7 @@ static int initMatrox2(WPMINFO struct display* d, struct board* b){
vesafb_defined = var; /* Note: mac_vmode_to_var() doesnot set all parameters */
}
}
-#endif
+#endif /* CONFIG_PPC */
vesafb_defined.xres_virtual = vesafb_defined.xres;
if (nopan) {
vesafb_defined.yres_virtual = vesafb_defined.yres;
@@ -2383,6 +2413,8 @@ int __init matroxfb_setup(char *options) {
blink = value;
else if (!strcmp(this_opt, "grayscale"))
grayscale = value;
+ else if (!strcmp(this_opt, "dfp"))
+ dfp = value;
else {
strncpy(videomode, this_opt, sizeof(videomode)-1);
}
@@ -2407,21 +2439,6 @@ int __init matroxfb_init(void)
return 0;
}
-#if defined(CONFIG_FB_OF)
-int __init matrox_of_init(struct device_node *dp){
- DBG("matrox_of_init");
-
- if (disabled)
- return -ENXIO;
- if (!initialized) {
- initialized = 1;
- matrox_init();
- }
- /* failure? */
- return 0;
-}
-#endif /* CONFIG_FB_OF */
-
#else
/* *************************** init module code **************************** */
@@ -2500,6 +2517,8 @@ MODULE_PARM(grayscale, "i");
MODULE_PARM_DESC(grayscale, "Sets display into grayscale. Works perfectly with paletized videomode (4, 8bpp), some limitations apply to 16, 24 and 32bpp videomodes (default=nograyscale)");
MODULE_PARM(cross4MB, "i");
MODULE_PARM_DESC(cross4MB, "Specifies that 4MB boundary can be in middle of line. (default=autodetected)");
+MODULE_PARM(dfp, "i");
+MODULE_PARM_DESC(dfp, "Specifies whether to use digital flat panel interface of G200/G400 (0 or 1) (default=0)");
#ifdef CONFIG_FB_OF
MODULE_PARM(vmode, "i");
MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)");
diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h
index 0cb21b0f9..c8a47fe9e 100644
--- a/drivers/video/matrox/matroxfb_base.h
+++ b/drivers/video/matrox/matroxfb_base.h
@@ -56,10 +56,10 @@
#include <video/fbcon-cfb24.h>
#include <video/fbcon-cfb32.h>
-#if defined(CONFIG_FB_OF)
#if defined(CONFIG_FB_COMPAT_XPMAC)
#include <asm/vc_ioctl.h>
#endif
+#if defined(CONFIG_PPC)
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <video/macmodes.h>
@@ -544,7 +544,7 @@ struct matrox_fb_info {
struct timer_list timer;
} cursor;
struct { unsigned red, green, blue, transp; } palette[256];
-#if defined(CONFIG_FB_OF) && defined(CONFIG_FB_COMPAT_XPMAC)
+#if defined(CONFIG_FB_COMPAT_XPMAC)
char matrox_name[32];
#endif
/* These ifdefs must be last! They differ for module & non-module compiles */
diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c
index 1219c0f2f..f4824762b 100644
--- a/drivers/video/matrox/matroxfb_crtc2.c
+++ b/drivers/video/matrox/matroxfb_crtc2.c
@@ -527,6 +527,10 @@ static int matroxfb_dh_ioctl(struct inode* inode,
return -EINVAL;
if (tmp & ACCESS_FBINFO(output.ph))
return -EINVAL;
+ if (tmp & MATROXFB_OUTPUT_CONN_DFP)
+ return -EINVAL;
+ if ((ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP) && tmp)
+ return -EINVAL;
if (tmp == ACCESS_FBINFO(output.sh))
return 0;
ACCESS_FBINFO(output.sh) = tmp;
@@ -542,7 +546,11 @@ static int matroxfb_dh_ioctl(struct inode* inode,
{
u_int32_t tmp;
- tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.ph);
+ /* we do not support DFP from CRTC2 */
+ tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.ph) & ~MATROXFB_OUTPUT_CONN_DFP;
+ /* CRTC1 in DFP mode disables CRTC2 at all (I know, I'm lazy) */
+ if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
+ tmp = 0;
put_user_ret(tmp, (u_int32_t*)arg, -EFAULT);
return 0;
}
@@ -675,6 +683,10 @@ static int matroxfb_dh_regit(CPMINFO struct matroxfb_dh_fb_info* m2info) {
if (ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_SECONDARY) {
ACCESS_FBINFO(output.sh) |= MATROXFB_OUTPUT_CONN_SECONDARY;
ACCESS_FBINFO(output.ph) &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
+ if (ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_DFP) {
+ ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_DFP;
+ ACCESS_FBINFO(output.ph) &= ~MATROXFB_OUTPUT_CONN_DFP;
+ }
}
matroxfb_dh_set_var(&matroxfb_dh_defined, -2, &m2info->fbcon);
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index eebefb776..d98ab4e0e 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -275,9 +275,6 @@ extern void imsttfb_of_init(struct device_node *dp);
#ifdef CONFIG_FB_CT65550
extern void chips_of_init(struct device_node *dp);
#endif /* CONFIG_FB_CT65550 */
-#ifdef CONFIG_FB_MATROX
-extern int matrox_of_init(struct device_node *dp);
-#endif /* CONFIG_FB_MATROX */
#ifdef CONFIG_FB_CONTROL
extern void control_of_init(struct device_node *dp);
#endif /* CONFIG_FB_CONTROL */
@@ -411,12 +408,6 @@ static int __init offb_init_driver(struct device_node *dp)
return 1;
}
#endif /* CONFIG_FB_CT65550 */
-#ifdef CONFIG_FB_MATROX
- if (!strncmp(dp->name, "MTRX", 4)) {
- matrox_of_init(dp);
- return 1;
- }
-#endif /* CONFIG_FB_MATROX */
#ifdef CONFIG_FB_CONTROL
if(!strcmp(dp->name, "control")) {
control_of_init(dp);
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 4c2a13791..4b388f60b 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -402,7 +402,7 @@ static int __devinit riva_init_disp (struct rivafb_info *rinfo)
disp->var = rivafb_default_var;
info->disp = disp;
-#warning FIXME: assure that disp->cmap is completely filled out
+ /* FIXME: assure that disp->cmap is completely filled out */
disp->screen_base = rinfo->fb_base;
disp->visual = FB_VISUAL_PSEUDOCOLOR;
@@ -727,7 +727,7 @@ static int rivafb_get_fix (struct fb_fix_screeninfo *fix, int con,
fix->line_length = p->line_length;
-#warning FIXME: set up MMIO region, export via FB_ACCEL_xxx
+ /* FIXME: set up MMIO region, export via FB_ACCEL_xxx */
fix->mmio_start = 0;
fix->mmio_len = 0;
fix->accel = FB_ACCEL_NONE;
@@ -960,7 +960,7 @@ static int rivafb_set_var (struct fb_var_screeninfo *var, int con,
dsp->type = FB_TYPE_PACKED_PIXELS;
-#warning FIXME: verify that the above code sets dsp->* fields correctly
+ /* FIXME: verify that the above code sets dsp->* fields correctly */
memcpy (&dsp->var, &v, sizeof (v));
diff --git a/drivers/video/riva/riva_hw.c b/drivers/video/riva/riva_hw.c
index 1bd904c8e..532f8c017 100644
--- a/drivers/video/riva/riva_hw.c
+++ b/drivers/video/riva/riva_hw.c
@@ -592,7 +592,7 @@ static void nv4CalcArbitration
)
{
int data, pagemiss, cas,width, video_enable, color_key_enable, bpp, align;
- int nvclks, mclks, pclks, vpagemiss, crtpagemiss, vbs;
+ int nvclks, mclks, pclks, vpagemiss, crtpagemiss, vbs=0;
int found, mclk_extra, mclk_loop, cbs, m1, p1;
int mclk_freq, pclk_freq, nvclk_freq, mp_enable;
int us_m, us_n, us_p, video_drain_rate, crtc_drain_rate;
diff --git a/drivers/video/riva/riva_tbl.h b/drivers/video/riva/riva_tbl.h
index 8188c0fd8..23e7cb75b 100644
--- a/drivers/video/riva/riva_tbl.h
+++ b/drivers/video/riva/riva_tbl.h
@@ -60,6 +60,8 @@ static unsigned RivaTablePTIMER[][2] =
{0x00000050, 0x00000000},
{0x00000040, 0xFFFFFFFF}
};
+
+#if 0
static unsigned RivaTableFIFO[][2] =
{
{0x00000000, 0x80000000},
@@ -70,6 +72,8 @@ static unsigned RivaTableFIFO[][2] =
{0x00002800, 0x80000012},
{0x00003800, 0x80000013}
};
+#endif
+
static unsigned nv3TablePFIFO[][2] =
{
{0x00000140, 0x00000000},
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
index 499d8fef7..bbd547454 100644
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -86,23 +86,7 @@
#include <video/fbcon-cfb24.h>
#include <video/fbcon-cfb32.h>
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
-#ifndef KERNEL_VERSION
-#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
-#define PCI_DEVICE_ID_3DFX_VOODOO3 0x0005
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
-/* nothing? */
-#else
#include <linux/spinlock.h>
-#endif
/* membase0 register offsets */
#define STATUS 0x00
@@ -332,10 +316,10 @@ struct fb_info_tdfx {
u32 max_pixclock;
unsigned long regbase_phys;
- unsigned long regbase_virt;
+ void *regbase_virt;
unsigned long regbase_size;
unsigned long bufbase_phys;
- unsigned long bufbase_virt;
+ void *bufbase_virt;
unsigned long bufbase_size;
unsigned long iobase;
@@ -368,6 +352,9 @@ struct fb_info_tdfx {
} cursor;
spinlock_t DAClock;
+#ifdef CONFIG_MTRR
+ int mtrr_idx;
+#endif
};
/*
@@ -468,11 +455,7 @@ static unsigned long do_lfb_size(void);
/*
* Interface used by the world
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
-void tdfxfb_init(void);
-#else
int tdfxfb_init(void);
-#endif
void tdfxfb_setup(char *options,
int *ints);
@@ -505,71 +488,8 @@ struct mode default_mode[] = {
0, FB_VMODE_NONINTERLACED
}
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
- ,
- { "800x600-8@56", /* @ 56 Hz */
- {
- 800, 600, 800, 600, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
- 27778, 128, 24, 22, 1, 72, 2,
- 0, FB_VMODE_NONINTERLACED
- }
- },
- { "1024x768-8@60", /* @ 60 Hz */
- {
- 1024, 768, 1024, 768, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
- 15385, 168, 8, 29, 3, 144, 6,
- 0, FB_VMODE_NONINTERLACED
- }
- },
- { "1280x1024-8@61", /* @ 61 Hz */
- {
- 1280, 1024, 1280, 1024, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
- 9091, 200, 48, 26, 1, 184, 3,
- 0, FB_VMODE_NONINTERLACED
- }
- },
- { "1024x768-16@60", /* @ 60 Hz */ /* basically for testing */
- {
- 1024, 768, 1024, 768, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
- 15385, 168, 8, 29, 3, 144, 6,
- 0, FB_VMODE_NONINTERLACED
- }
- },
- { "1024x768-24@60", /* @ 60 Hz */
- {
- 1024, 768, 1024, 768, 0, 0, 24, 0,
- {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
- 15385, 168, 8, 29, 3, 144, 6,
- 0, FB_VMODE_NONINTERLACED
- }
- },
- { "1024x768-32@60", /* @ 60 Hz */
- {
- 1024, 768, 1024, 768, 0, 0, 32, 0,
- {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
- 15385, 168, 8, 29, 3, 144, 6,
- 0, FB_VMODE_NONINTERLACED
- }
- }
-
-#endif
};
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
-static int modes = sizeof(default_mode)/sizeof(struct mode);
-static int default_mode_index = 0;
-#endif
-
static struct fb_info_tdfx fb_info;
static int noaccel = 0;
@@ -1674,17 +1594,10 @@ static int tdfxfb_encode_fix(struct fb_fix_screeninfo* fix,
info->dev == PCI_DEVICE_ID_3DFX_BANSHEE
? "3Dfx Banshee"
: "3Dfx Voodoo3");
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
- fix->smem_start = (char*)info->bufbase_phys;
- fix->smem_len = info->bufbase_size;
- fix->mmio_start = (char*)info->regbase_phys;
- fix->mmio_len = info->regbase_size;
-#else
fix->smem_start = info->bufbase_phys;
fix->smem_len = info->bufbase_size;
fix->mmio_start = info->regbase_phys;
fix->mmio_len = info->regbase_size;
-#endif
fix->accel = FB_ACCEL_3DFX_BANSHEE;
fix->type = FB_TYPE_PACKED_PIXELS;
fix->type_aux = 0;
@@ -1815,7 +1728,7 @@ static int tdfxfb_set_var(struct fb_var_screeninfo *var,
struct fb_fix_screeninfo fix;
tdfxfb_encode_fix(&fix, &par, info);
- display->screen_base = (char *)info->bufbase_virt;
+ display->screen_base = info->bufbase_virt;
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
@@ -1940,20 +1853,10 @@ static int tdfxfb_ioctl(struct inode *inode,
return -EINVAL;
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
-__initfunc(void tdfxfb_init(void)) {
-#else
int __init tdfxfb_init(void) {
-#endif
struct pci_dev *pdev = NULL;
struct fb_var_screeninfo var;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
- if(!pcibios_present()) return;
-#else
- if(!pcibios_present()) return -ENXIO;
-#endif
-
while ((pdev = pci_find_device(PCI_VENDOR_ID_3DFX, PCI_ANY_ID, pdev))) {
if(((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
((pdev->device == PCI_DEVICE_ID_3DFX_BANSHEE) ||
@@ -1968,67 +1871,38 @@ int __init tdfxfb_init(void) {
? BANSHEE_MAX_PIXCLOCK
: VOODOO3_MAX_PIXCLOCK;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
- fb_info.regbase_phys = pdev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
- fb_info.regbase_size = 1 << 24;
- fb_info.regbase_virt =
- (unsigned long)ioremap_nocache(fb_info.regbase_phys, 1 << 24);
- if(!fb_info.regbase_virt) {
- printk("fb: Can't remap %s register area.\n", name);
- return;
- }
-
- fb_info.bufbase_phys = pdev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK;
- if(!(fb_info.bufbase_size = do_lfb_size())) {
- printk("fb: Can't count %s memory.\n", name);
- iounmap((void*)fb_info.regbase_virt);
- return;
- }
- fb_info.bufbase_virt =
- (unsigned long)ioremap_nocache(fb_info.bufbase_phys, fb_info.bufbase_size);
- if(!fb_info.regbase_virt) {
- printk("fb: Can't remap %s framebuffer.\n", name);
- iounmap((void*)fb_info.regbase_virt);
- return;
- }
-
- fb_info.iobase = pdev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK;
-#else
fb_info.regbase_phys = pci_resource_start(pdev, 0);
fb_info.regbase_size = 1 << 24;
- fb_info.regbase_virt =
- (unsigned long)ioremap_nocache(fb_info.regbase_phys, 1 << 24);
+ fb_info.regbase_virt = ioremap_nocache(fb_info.regbase_phys, 1 << 24);
if(!fb_info.regbase_virt) {
printk("fb: Can't remap %s register area.\n", name);
return -ENXIO;
}
- fb_info.bufbase_phys = pdev->resource[1].start;
+ fb_info.bufbase_phys = pci_resource_start (pdev, 1);
if(!(fb_info.bufbase_size = do_lfb_size())) {
- iounmap((void*)fb_info.regbase_virt);
+ iounmap(fb_info.regbase_virt);
printk("fb: Can't count %s memory.\n", name);
return -ENXIO;
}
- fb_info.bufbase_virt =
- (unsigned long)ioremap_nocache(fb_info.bufbase_phys, fb_info.bufbase_size);
+ fb_info.bufbase_virt = ioremap_nocache(fb_info.bufbase_phys, fb_info.bufbase_size);
if(!fb_info.regbase_virt) {
printk("fb: Can't remap %s framebuffer.\n", name);
- iounmap((void*)fb_info.regbase_virt);
+ iounmap(fb_info.regbase_virt);
return -ENXIO;
}
- fb_info.iobase = pdev->resource[2].start;
-#endif
+ fb_info.iobase = pci_resource_start (pdev, 2);
printk("fb: %s memory = %ldK\n", name, fb_info.bufbase_size >> 10);
#ifdef CONFIG_MTRR
if (!nomtrr) {
- if (mtrr_add(fb_info.bufbase_phys, fb_info.bufbase_size,
- MTRR_TYPE_WRCOMB, 1)>=0)
+ fb_info.mtrr_idx = mtrr_add(fb_info.bufbase_phys, fb_info.bufbase_size,
+ MTRR_TYPE_WRCOMB, 1);
printk("fb: MTRR's turned on\n");
}
-#endif
+#endif
/* clear framebuffer memory */
memset_io(fb_info.bufbase_virt, 0, fb_info.bufbase_size);
@@ -2053,16 +1927,10 @@ int __init tdfxfb_init(void) {
fb_info.fb_info.blank = &tdfxfb_blank;
fb_info.fb_info.flags = FBINFO_FLAG_DEFAULT;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
- var = default_mode[default_mode_index < modes
- ? default_mode_index
- : 0].var;
-#else
memset(&var, 0, sizeof(var));
if(!mode_option ||
!fb_find_mode(&var, &fb_info.fb_info, mode_option, NULL, 0, NULL, 8))
var = default_mode[0].var;
-#endif
if(noaccel) var.accel_flags &= ~FB_ACCELF_TEXT;
else var.accel_flags |= FB_ACCELF_TEXT;
@@ -2081,57 +1949,73 @@ int __init tdfxfb_init(void) {
if(tdfxfb_decode_var(&var, &fb_info.default_par, &fb_info)) {
/* this is getting really bad!... */
printk("tdfxfb: can't decode default video mode\n");
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
- return;
-#else
return -ENXIO;
-#endif
}
}
- fb_info.disp.screen_base = (void*)fb_info.bufbase_virt;
+ fb_info.disp.screen_base = fb_info.bufbase_virt;
fb_info.disp.var = var;
if(tdfxfb_set_var(&var, -1, &fb_info.fb_info)) {
printk("tdfxfb: can't set default video mode\n");
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
- return;
-#else
return -ENXIO;
-#endif
}
if(register_framebuffer(&fb_info.fb_info) < 0) {
printk("tdfxfb: can't register framebuffer\n");
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
- return;
-#else
return -ENXIO;
-#endif
}
printk("fb%d: %s frame buffer device\n",
GET_FB_IDX(fb_info.fb_info.node),
fb_info.fb_info.modename);
+ /* FIXME: module cannot be unloaded */
+ /* verify tdfxfb_exit before removing this */
MOD_INC_USE_COUNT;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
- return;
-#else
return 0;
-#endif
}
}
/* hmm, no frame suitable buffer found ... */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
- return;
-#else
return -ENXIO;
+}
+
+/**
+ * tdfxfb_exit - Driver cleanup
+ *
+ * Releases all resources allocated during the
+ * course of the driver's lifetime.
+ *
+ * FIXME - do results of fb_alloc_cmap need disposal?
+ */
+static void __exit tdfxfb_exit (void)
+{
+ unregister_framebuffer(&fb_info.fb_info);
+ del_timer_sync(&fb_info.cursor.timer);
+
+#ifdef CONFIG_MTRR
+ if (!nomtrr) {
+ mtrr_del(fb_info.mtrr_idx, fb_info.bufbase_phys, fb_info.bufbase_size);
+ printk("fb: MTRR's turned off\n");
+ }
#endif
+
+ iounmap(fb_info.regbase_virt);
+ iounmap(fb_info.bufbase_virt);
}
+MODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>");
+MODULE_DESCRIPTION("3Dfx framebuffer device driver");
+
+#ifdef MODULE
+module_init(tdfxfb_init);
+#endif
+module_exit(tdfxfb_exit);
+
+
+#ifndef MODULE
void tdfxfb_setup(char *options,
int *ints) {
char* this_opt;
@@ -2160,19 +2044,11 @@ void tdfxfb_setup(char *options,
} else if (!strncmp(this_opt, "font:", 5)) {
strncpy(fontname, this_opt + 5, 40);
} else {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
- int i;
- for(i = 0; i < modes; i++) {
- if(!strcmp(this_opt, default_mode[i].name)) {
- default_mode_index = i;
- }
- }
-#else
mode_option = this_opt;
-#endif
}
}
}
+#endif
static int tdfxfb_switch_con(int con,
struct fb_info *fb) {
@@ -2438,7 +2314,7 @@ static void tdfxfb_hwcursor_init(void)
start = (fb_info.bufbase_size-1024) & PAGE_MASK;
fb_info.bufbase_size=start;
fb_info.cursor.cursorimage=fb_info.bufbase_size;
- printk("tdfxfb: reserving 1024 bytes for the hwcursor at 0x%08lx\n",
+ printk("tdfxfb: reserving 1024 bytes for the hwcursor at %p\n",
fb_info.regbase_virt+fb_info.cursor.cursorimage);
}