diff -Nru a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile --- a/Documentation/DocBook/Makefile Mon Nov 4 14:31:01 2002 +++ b/Documentation/DocBook/Makefile Mon Nov 4 14:31:01 2002 @@ -160,8 +160,6 @@ $(patsubst %.fig,%.png, $(IMG-parportbook)) \ $(C-procfs-example) -ifneq ($(wildcard $(BOOKS)),) -clean-rule := rm -rf $(wildcard $(BOOKS)) +ifneq ($(wildcard $(patsubst %.html,%,$(HTML))),) +clean-rule := rm -rf $(wildcard $(patsubst %.html,%,$(HTML))) endif - -include $(TOPDIR)/Rules.make diff -Nru a/Documentation/filesystems/driverfs.txt b/Documentation/filesystems/driverfs.txt --- a/Documentation/filesystems/driverfs.txt Mon Nov 4 14:31:02 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,336 +0,0 @@ - -driverfs - The Device Driver Filesystem - -Patrick Mochel - -2 August 2002 - - -What it is: -~~~~~~~~~~~ -driverfs is a ram-based filesystem. It was created by copying -ramfs/inode.c to driverfs/inode.c and doing a little search-and-replace. - -driverfs is a means to export kernel data structures, their -attributes, and the linkages between them to userspace. - -driverfs provides a unified interface for exporting attributes to -userspace. Currently, this interface is available only to device and -bus drivers. - - -Using driverfs -~~~~~~~~~~~~~~ -driverfs is always compiled in. You can access it by doing something like: - - mount -t driverfs driverfs /devices - - -Top Level Directory Layout -~~~~~~~~~~~~~~~~~~~~~~~~~~ -The driverfs directory arrangement exposes the relationship of kernel -data structures. - -The top level driverfs diretory looks like: - -bus/ -root/ - -root/ contains a filesystem representation of the device tree. It maps -directly to the internal kernel device tree, which is a hierarchy of -struct device. - -bus/ contains flat directory layout of the various bus types in the -kernel. Each bus's directory contains two subdirectories: - - devices/ - drivers/ - -devices/ contains symlinks for each device discovered in the system -that point to the device's directory under root/. - -drivers/ contains a directory for each device driver that is loaded -for devices on that particular bus (this assmumes that drivers do not -span multiple bus types). - - -More information can device-model specific features can be found in -Documentation/device-model/. - - -Directory Contents -~~~~~~~~~~~~~~~~~~ -Each object that is represented in driverfs gets a directory, rather -than a file, to make it simple to export attributes of that object. -Attributes are exported via ASCII text files. The programming -interface is discussed below. - -Instead of having monolithic files that are difficult to parse, all -files are intended to export one attribute. The name of the attribute -is the name of the file. The value of the attribute are the contents -of the file. - -There should be few, if any, exceptions to this rule. You should not -violate it, for fear of public humilation. - - -The Two-Tier Model -~~~~~~~~~~~~~~~~~~ - -driverfs is a very simple, low-level interface. In order for kernel -objects to use it, there must be an intermediate layer in place for -each object type. - -All calls in driverfs are intended to be as type-safe as possible. -In order to extend driverfs to support multiple data types, a layer of -abstraction was required. This intermediate layer converts between the -generic calls and data structures of the driverfs core to the -subsystem-specific objects and calls. - - -The Subsystem Interface -~~~~~~~~~~~~~~~~~~~~~~~ - -The subsystems bear the responsibility of implementing driverfs -extensions for the objects they control. Fortunately, it's intended to -be really easy to do so. - -It's divided into three sections: directories, files, and operations. - - -Directories -~~~~~~~~~~~ - -struct driver_dir_entry { - char * name; - struct dentry * dentry; - mode_t mode; - struct driverfs_ops * ops; -}; - - -int -driverfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *); - -void -driverfs_remove_dir(struct driver_dir_entry * entry); - -The directory structure should be statically allocated, and reside in -a subsystem-specific data structure: - -struct device { - ... - struct driver_dir_entry dir; -}; - -The subsystem is responsible for initializing the name, mode, and ops -fields of the directory entry. (More on struct driverfs_ops later) - - -Files -~~~~~ - -struct attribute { - char * name; - mode_t mode; -}; - - -int -driverfs_create_file(struct attribute * attr, struct driver_dir_entry * parent); - -void -driverfs_remove_file(struct driver_dir_entry *, const char * name); - - -The attribute structure is a simple, common token that the driverfs -core handles. It has little use on its own outside of the -core. Objects cannot use a plain struct attribute to export -attributes, since there are no callbacks for reading and writing data. - -Therefore, the subsystem is required to define a data structure that -encapsulates the attribute structure, and provides type-safe callbacks -for reading and writing data. - -An example looks like this: - -struct device_attribute { - struct attribute attr; - ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off); - ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off); -}; - - -Note that there is a struct attribute embedded in the structure. In -order to relieve pain in declaring attributes, the subsystem should -also define a macro, like: - -#define DEVICE_ATTR(_name,_mode,_show,_store) \ -struct device_attribute dev_attr_##_name = { \ - .attr = {.name = __stringify(_name) , .mode = _mode }, \ - .show = _show, \ - .store = _store, \ -}; - -This hides the initialization of the embedded struct, and in general, -the internals of each structure. It yields a structure by the name of -dev_attr_. - -In order for objects to create files, the subsystem should create -wrapper functions, like this: - -int device_create_file(struct device *device, struct device_attribute * entry); -void device_remove_file(struct device * dev, struct device_attribute * attr); - -..and forward the call on to the driverfs functions. - -Note that there is no unique information in the attribute structures, -so the same structure can be used to describe files of several -different object instances. - - -Operations -~~~~~~~~~~ - -struct driverfs_ops { - int (*open)(struct driver_dir_entry *); - int (*close)(struct driver_dir_entry *); - ssize_t (*show)(struct driver_dir_entry *, struct attribute *,char *, size_t, loff_t); - ssize_t (*store)(struct driver_dir_entry *,struct attribute *,const char *, size_t, loff_t); -}; - - -Subsystems are required to implement this set of callbacks. Their -purpose is to translate the generic data structures into the specific -objects, and operate on them. This can be done by defining macros like -this: - -#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr) - -#define to_device(d) container_of(d, struct device, dir) - - -Since the directories are statically allocated in the object, you can -derive the pointer to the object that owns the file. Ditto for the -attribute structures. - -Current Interfaces -~~~~~~~~~~~~~~~~~~ - -The following interface layers currently exist in driverfs: - - -- devices (include/linux/device.h) ----------------------------------- -Structure: - -struct device_attribute { - struct attribute attr; - ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off); - ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off); -}; - -Declaring: - -DEVICE_ATTR(_name,_str,_mode,_show,_store); - -Creation/Removal: - -int device_create_file(struct device *device, struct device_attribute * entry); -void device_remove_file(struct device * dev, struct device_attribute * attr); - - -- bus drivers (include/linux/device.h) --------------------------------------- -Structure: - -struct bus_attribute { - struct attribute attr; - ssize_t (*show)(struct bus_type *, char * buf, size_t count, loff_t off); - ssize_t (*store)(struct bus_type *, const char * buf, size_t count, loff_t off); -}; - -Declaring: - -BUS_ATTR(_name,_mode,_show,_store) - -Creation/Removal: - -int bus_create_file(struct bus_type *, struct bus_attribute *); -void bus_remove_file(struct bus_type *, struct bus_attribute *); - - -- device drivers (include/linux/device.h) ------------------------------------------ - -Structure: - -struct driver_attribute { - struct attribute attr; - ssize_t (*show)(struct device_driver *, char * buf, size_t count, loff_t off); - ssize_t (*store)(struct device_driver *, const char * buf, size_t count, loff_t off); -}; - -Declaring: - -DRIVER_ATTR(_name,_mode,_show,_store) - -Creation/Removal: - -int driver_create_file(struct device_driver *, struct driver_attribute *); -void driver_remove_file(struct device_driver *, struct driver_attribute *); - - -Reading/Writing Data -~~~~~~~~~~~~~~~~~~~~ -The callback functionality is similar to the way procfs works. When a -user performs a read(2) or write(2) on the file, it first calls a -driverfs function. This calls to the subsystem, which then calls to -the object's show() or store() function. - -The buffer pointer, offset, and length should be passed to each -function. The downstream callback should fill the buffer and return -the number of bytes read/written. - - -What driverfs is not: -~~~~~~~~~~~~~~~~~~~~~ -It is not a replacement for either devfs or procfs. - -It does not handle device nodes, like devfs is intended to do. I think -this functionality is possible, but indeed think that integration of -the device nodes and control files should be done. Whether driverfs or -devfs, or something else, is the place to do it, I don't know. - -It is not intended to be a replacement for all of the procfs -functionality. I think that many of the driver files should be moved -out of /proc (and maybe a few other things as well ;). - - - -Limitations: -~~~~~~~~~~~~ -The driverfs functions assume that at most a page is being either read -or written each time. - -There is a race condition that is really, really hard to fix; if not -impossible. There exists a race between a driverfs file being opened -and the object that owns the file going away. During the driverfs -open() callback, the reference count for the owning object needs to be -incremented. - -For drivers, we can put a struct module * owner in struct driver_dir_entry -and do try_inc_mod_count() when we open a file. However, this won't -work for devices, that aren't tied to a module. And, it is still not -guaranteed to solve the race. - -I'm looking into fixing this, but it may not be doable without making -a separate filesystem instance for each object. It's fun stuff. Please -mail me with creative ideas that you know will work. - - -Possible bugs: -~~~~~~~~~~~~~~ -It may not deal with offsets and/or seeks very well, especially if -they cross a page boundary. - diff -Nru a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt --- a/Documentation/filesystems/proc.txt Mon Nov 4 14:31:01 2002 +++ b/Documentation/filesystems/proc.txt Mon Nov 4 14:31:01 2002 @@ -130,6 +130,7 @@ stat Process status statm Process memory status information status Process status in human readable form + wchan If CONFIG_KALLSYMS is set, a pre-decoded wchan .............................................................................. For example, to get the status information of a process, all you have to do is diff -Nru a/Documentation/video4linux/bttv/CARDLIST b/Documentation/video4linux/bttv/CARDLIST --- a/Documentation/video4linux/bttv/CARDLIST Mon Nov 4 14:31:00 2002 +++ b/Documentation/video4linux/bttv/CARDLIST Mon Nov 4 14:31:00 2002 @@ -2,13 +2,13 @@ card=0 - *** UNKNOWN/GENERIC *** card=1 - MIRO PCTV card=2 - Hauppauge (bt848) - card=3 - STB + card=3 - STB, Gateway P/N 6000699 (bt848) card=4 - Intel Create and Share PCI/ Smart Video Recorder III card=5 - Diamond DTV2000 card=6 - AVerMedia TVPhone card=7 - MATRIX-Vision MV-Delta card=8 - Lifeview FlyVideo II (Bt848) LR26 - card=9 - IXMicro TurboTV + card=9 - IMS/IXmicro TurboTV card=10 - Hauppauge (bt878) card=11 - MIRO PCTV pro card=12 - ADS Technologies Channel Surfer TV (bt848) @@ -24,22 +24,22 @@ card=22 - Askey CPH050/ Phoebe Tv Master + FM card=23 - Modular Technology MM205 PCTV, bt878 card=24 - Askey CPH05X/06X (bt878) [many vendors] - card=25 - Terratec Terra TV+ Version 1.0 (Bt848)/Vobis TV-Boostar + card=25 - Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar card=26 - Hauppauge WinCam newer (bt878) card=27 - Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50 - card=28 - Terratec TerraTV+ + card=28 - Terratec TerraTV+ Version 1.1 (bt878) card=29 - Imagenation PXC200 card=30 - Lifeview FlyVideo 98 LR50 card=31 - Formac iProTV card=32 - Intel Create and Share PCI/ Smart Video Recorder III - card=33 - Terratec TerraTValue - card=34 - Leadtek WinFast 2000 + card=33 - Terratec TerraTValue Version Bt878 + card=34 - Leadtek WinFast 2000/ WinFast 2000 XP card=35 - Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II card=36 - Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner card=37 - Prolink PixelView PlayTV pro card=38 - Askey CPH06X TView99 card=39 - Pinnacle PCTV Studio/Rave - card=40 - STB2 + card=40 - STB TV PCI FM, Gateway P/N 6000704 (bt878) card=41 - AVerMedia TVPhone 98 card=42 - ProVideo PV951 card=43 - Little OnAir TV @@ -78,14 +78,17 @@ card=76 - Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP) card=77 - GrandTec Multi Capture Card (Bt878) card=78 - Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF + card=79 - DSP Design TCVIDEO + card=80 - Hauppauge WinTV PVR + card=81 - GV-BCTV5/PCI tuner.o type=0 - Temic PAL (4002 FH5) - type=1 - Philips PAL_I - type=2 - Philips NTSC - type=3 - Philips SECAM + type=1 - Philips PAL_I (FI1246 and compatibles) + type=2 - Philips NTSC (FI1236 and compatibles) + type=3 - Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF) type=4 - NoTuner - type=5 - Philips PAL + type=5 - Philips PAL_BG (FI1216 and compatibles) type=6 - Temic NTSC (4032 FY5) type=7 - Temic PAL_I (4062 FY5) type=8 - Temic NTSC (4036 FY5) @@ -103,7 +106,7 @@ type=20 - Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5) type=21 - Temic NTSC (4039 FR5) type=22 - Temic PAL/SECAM multi (4046 FM5) - type=23 - Philips PAL_DK + type=23 - Philips PAL_DK (FI1256 and compatibles) type=24 - Philips PAL/SECAM multi (FQ1216ME) type=25 - LG PAL_I+FM (TAPC-I001D) type=26 - LG PAL_I (TAPC-I701D) @@ -118,3 +121,5 @@ type=35 - Temic PAL_DK/SECAM_L (4012 FY5) type=36 - Temic NTSC (4136 FY5) type=37 - LG PAL (newer TAPC series) + type=38 - Philips PAL/SECAM multi (FM1216ME MK3) + type=39 - LG NTSC (newer TAPC series) diff -Nru a/Documentation/video4linux/bttv/Cards b/Documentation/video4linux/bttv/Cards --- a/Documentation/video4linux/bttv/Cards Mon Nov 4 14:31:01 2002 +++ b/Documentation/video4linux/bttv/Cards Mon Nov 4 14:31:01 2002 @@ -157,6 +157,7 @@ Flyvideo 2000S (Bt878) w/Stereo TV (Package incl. LR91 daughterboard) LR91 = Stereo daughter card for LR90 LR97 = Flyvideo DVBS + LR99 Rev.E = Low profile card for OEM integration (only internal audio!) bt878 LR136 = Flyvideo 2100/3100 (Low profile, SAA7130/SAA7134) LR137 = Flyvideo DV2000/DV3000 (SAA7130/SAA7134 + IEEE1394) LR138 Rev.C= Flyvideo 2000 (SAA7130) @@ -236,6 +237,7 @@ Further Cards: PV-BT878P+rev.9B (Play TV Pro, opt. w/FM w/NICAM) PV-BT878P+rev.2F + PV-BT878P Rev.1D (bt878, capture only) Video Conferencing: PixelView Meeting PAK - (Model: PV-BT878P) @@ -273,6 +275,7 @@ WinView 601 (Bt848) WinView 610 (Zoran) WinFast2000 + WinFast2000 XP KNC One ------- @@ -282,15 +285,19 @@ TV-Station FM (+Radio) TV-Station RDS (+RDS) -Provideo PV951 --------------- - These are sold as: + newer Cards have saa7134, but model name stayed the same? + +Provideo +-------- + PV951 or PV-951 (also are sold as: Boeder TV-FM Video Capture Card Titanmedia Supervision TV-2400 Provideo PV951 TF 3DeMon PV951 MediaForte TV-Vision PV951 Yoko PV951 + ) + PV-148 (capture only) Highscreen ---------- @@ -320,15 +327,47 @@ PCB PCI-ID Model-Name Eeprom Tuner Sound Country -------------------------------------------------------------------- - M1A8-A -- AVer TV-Phone FM1216 -- + M101.C ISA ! + M108-B Bt848 -- FR1236 US (2),(3) + M1A8-A Bt848 AVer TV-Phone FM1216 -- M168-T 1461:0003 AVerTV Studio 48:17 FM1216 TDA9840T D (1) w/FM w/Remote M168-U 1461:0004 TVCapture98 40:11 FI1216 -- D w/Remote M168II-B 1461:0003 Medion MD9592 48:16 FM1216 TDA9873H D w/FM (1) Daughterboard MB68-A with TDA9820T and TDA9840T + (2) Sony NE41S soldered (stereo sound?) + (3) Daughterboard M118-A w/ pic 16c54 and 4 MHz quartz + + US site has different drivers for (as of 09/2002): + EZ Capture/InterCam PCI (BT-848 chip) + EZ Capture/InterCam PCI (BT-878 chip) + TV-Phone (BT-848 chip) + TV98 (BT-848 chip) + TV98 With Remote (BT-848 chip) + TV98 (BT-878 chip) + TV98 With Remote (BT-878) + TV/FM98 (BT-878 chip) + AVerTV + AverTV Stereo + AVerTV Studio + + DE hat diverse Treiber fuer diese Modelle (Stand 09/2002): + TVPhone (848) mit Philips tuner FR12X6 (w/ FM radio) + TVPhone (848) mit Philips tuner FM12X6 (w/ FM radio) + TVCapture (848) w/Philips tuner FI12X6 + TVCapture (848) non-Philips tuner + TVCapture98 (Bt878) + TVPhone98 (Bt878) + AVerTV und TVCapture98 w/VCR (Bt 878) + AVerTVStudio und TVPhone98 w/VCR (Bt878) + AVerTV GO Serie (Kein SVideo Input) + AVerTV98 (BT-878 chip) + AVerTV98 mit Fernbedienung (BT-878 chip) + AVerTV/FM98 (BT-878 chip) Aimslab ------- + Video Highway or "Video Highway TR200" (ISA) Video Highway Xtreme (aka "VHX") (Bt848, FM w/ TEA5757) IXMicro (former: IMS=Integrated Micro Solutions) @@ -364,6 +403,9 @@ LR74 is a newer PCB revision of ceb105 (both incl. connector for Active Radio Upgrade) + Cinergy 400 (saa7134), "E877 11(S)", "PM820092D" printed on PCB + Cinergy 600 (saa7134) + Technisat --------- Discos ADR PC-Karte ISA (no TV!) @@ -373,7 +415,7 @@ Mediafocus I (zr36120/zr36125, drp3510, Sat. analog + ADR Radio) Mediafocus II (saa7146, Sat. analog) SatADR Rev 2.1 (saa7146a, saa7113h, stv0056a, msp3400c, drp3510a, BSKE3-307A) - SkyStar 1 DVB (AV7110) + SkyStar 1 DVB (AV7110) = Technotrend Premium SkyStar 2 DVB (B2C2) (=Sky2PC) Siemens @@ -387,6 +429,9 @@ Powercolor ---------- MTV878 + Package comes with different contents: + a) pcb "MTV878" (CARD=75) + b) Pixelview Rev. 4_ MTV878R w/Remote Control MTV878F w/Remote Control w/FM radio @@ -394,10 +439,14 @@ -------- Mirovideo PCTV (Bt848) Mirovideo PCTV SE (Bt848) - Mirovideo PCTV Pro (Bt848 + Daughterboard) + Mirovideo PCTV Pro (Bt848 + Daughterboard for TV Stereo and FM) + Studio PCTV Rave (Bt848 Version = Mirovideo PCTV) Studio PCTV Rave (Bt878 package w/o infrared) Studio PCTV (Bt878) Studio PCTV Pro (Bt878 stereo w/ FM) + Pinnacle PCTV (Bt878, MT2032) + Pinnacle PCTV Pro (Bt878, MT2032) + Pinncale PCTV Sat M(J)PEG capture and playback: DC1+ (ISA) @@ -495,8 +544,10 @@ STB --- - TV PCI (Temic4032FY5, tda9850??) - other variants? + STB bt878 == Gateway 6000704 + STB Gateway 6000699 (bt848) + STB Gateway 6000402 (bt848) + STB TV130 PCI Videologic ---------- @@ -507,6 +558,16 @@ ------------ TT-SAT PCI (PCB "Sat-PCI Rev.:1.3.1"; zr36125, vpx3225d, stc0056a, Tuner:BSKE6-155A TT-DVB-Sat + This card is sold as OEM from: + Siemens DVB-s Card + Hauppauge WinTV DVB-S + Technisat SkyStar 1 DVB + Galaxis DVB Sat + Now this card is called TT-PCline Premium Family + TT-Budget + This card is sold as OEM from: + Hauppauge WinTV Nova + Satelco Standard PCI (DVB-S) TT-DVB-C PCI Teles @@ -546,10 +607,13 @@ Hauppauge --------- many many WinTV models ... - WinTV DVBs - WinTV NOVA + WinTV DVBs = Tehcnotrend Premium + WinTV NOVA = Technotrend Budget WinTV NOVA-CI WinTV-Nexus-s + WinTV PVR + WinTV PVR 250 + WinTV PVR 450 Matrix-Vision ------------- @@ -615,7 +679,7 @@ NoBrand ------- - TV Excel = Australian Name for "PV-BT878P+ 8E" or so + TV Excel = Australian Name for "PV-BT878P+ 8E" or "878TV Rev.3_" Mach www.machspeed.com ---- @@ -638,9 +702,51 @@ Satelco ------- TV-FM =KNC1 saa7134 + Standard PCI (DVB-S) = Technotrend Budget + Standard PCI (DVB-S) w/ CI + Satelco Hoghend PCI (DVB-S) = Technotrend Premium + Sensoray www.sensoray.com -------- Sensoray 311 (PC/104 bus) Sensoray 611 (PCI) +CEI (Chartered Electronics Industries Pte Ltd [CEI] [FCC ID HBY]) +--- + TV Tuner - HBY-33A-RAFFLES Brooktree Bt848KPF + Philips + TV Tuner MG9910 - HBY33A-TVO CEI + Philips SAA7110 + OKI M548262 + ST STV8438CV + Primetime TV (ISA) + acquired by Singapore Technologies + now operating as Chartered Semiconductor Manufacturing + Manufacturer of video cards is listed as: + Cogent Electronics Industries [CEI] + +AITech +------ + AITech WaveWatcher TV-PCI = LR26 + WaveWatcher TVR-202 TV/FM Radio Card (ISA) + +MAXRON +------ + Maxron MaxTV/FM Radio (KW-TV878-FNT) = Kworld or JW-TV878-FBK + +www.ids-imaging.de +------------------ + Falcon Series (capture only) + In USA: http://www.theimagingsource.com/ + DFG/LC1 + +www.sknet-web.co.jp +------------------- + SKnet Monster TV (saa7134) + +A-Max www.amaxhk.com (Colormax, Amax, Napa) +------------------- + APAC Viewcomp 878 + +Cybertainment +------------- + CyberMail AV Video Email Kit w/ PCI Capture Card (capture only) + CyberMail Xtreme + These are Flyvideo diff -Nru a/Documentation/video4linux/bttv/README b/Documentation/video4linux/bttv/README --- a/Documentation/video4linux/bttv/README Mon Nov 4 14:31:00 2002 +++ b/Documentation/video4linux/bttv/README Mon Nov 4 14:31:00 2002 @@ -76,6 +76,12 @@ video but no sound you've very likely specified the wrong (or no) card type. A list of supported cards is in CARDLIST. +For the WinTV/PVR you need one firmware file from the driver CD: +hcwamc.rbf. The file is in the pvr45xxx.exe archive (self-extracting +zip file, unzip can unpack it). Put it into the /etc/pvr directory or +use the firm_altera= insmod option to point the driver to the +location of the file. + If your card isn't listed in CARDLIST or if you have trouble making audio work, you should read the Sound-FAQ. diff -Nru a/Documentation/video4linux/bttv/README.freeze b/Documentation/video4linux/bttv/README.freeze --- a/Documentation/video4linux/bttv/README.freeze Mon Nov 4 14:31:00 2002 +++ b/Documentation/video4linux/bttv/README.freeze Mon Nov 4 14:31:00 2002 @@ -61,6 +61,9 @@ other ----- +If you use some binary-only yunk (like nvidia module) try to reproduce +the problem without. + IRQ sharing is known to cause problems in some cases. It works just fine in theory and many configurations. Neverless it might be worth a try to shuffle around the PCI cards to give bttv another IRQ or make diff -Nru a/Documentation/video4linux/bttv/Tuners b/Documentation/video4linux/bttv/Tuners --- a/Documentation/video4linux/bttv/Tuners Mon Nov 4 14:31:00 2002 +++ b/Documentation/video4linux/bttv/Tuners Mon Nov 4 14:31:00 2002 @@ -1,3 +1,16 @@ +1) Tuner Programming +==================== +There are some flavors of Tuner programming APIs. +These differ mainly by the bandswitch byte. + + L= LG_API (VHF_LO=0x01, VHF_HI=0x02, UHF=0x08, radio=0x04) + P= PHILIPS_API (VHF_LO=0xA0, VHF_HI=0x90, UHF=0x30, radio=0x04) + T= TEMIC_API (VHF_LO=0x02, VHF_HI=0x04, UHF=0x01) + A= ALPS_API (VHF_LO=0x14, VHF_HI=0x12, UHF=0x11) + M= PHILIPS_MK3 (VHF_LO=0x01, VHF_HI=0x02, UHF=0x04, radio=0x19) + +2) Tuner Manufacturers +====================== SAMSUNG Tuner identification: (e.g. TCPM9091PD27) TCP [ABCJLMNQ] 90[89][125] [DP] [ACD] 27 [ABCD] @@ -24,6 +37,8 @@ [ABCD]: 3-wire/I2C tuning, 2-band/3-band + These Tuners are PHILIPS_API compatible. + Philips Tuner identification: (e.g. FM1216MF) F[IRMQ]12[1345]6{MF|ME|MP} F[IRMQ]: @@ -39,15 +54,17 @@ 1246: PAL I 1256: Pal DK {MF|ME|MP} - MF: w/ Secam + MF: BG LL w/ Secam (Multi France) ME: BG DK I LL (Multi Europe) MP: BG DK I (Multi PAL) MR: BG DK M (?) MG: BG DKI M (?) + MK2 series PHILIPS_API, most tuners are compatible to this one ! + MK3 series introduced in 2002 w/ PHILIPS_MK3_API Temic Tuner identification: (.e.g 4006FH5) 4[01][0136][269]F[HYNR]5 - 40x2: Tuner (5V/33V), different I2C programming from Philips ! + 40x2: Tuner (5V/33V), TEMIC_API. 40x6: Tuner 5V 41xx: Tuner compact 40x9: Tuner+FM compact @@ -62,6 +79,7 @@ FN5: multistandard FR5: w/ FM radio 3X xxxx: order number with specific connector + Note: Only 40x2 series has TEMIC_API, all newer tuners have PHILIPS_API. LG Innotek Tuner: TPI8NSR11 : NTSC J/M (TPI8NSR01 w/FM) (P,210/497) @@ -78,12 +96,6 @@ TADC-H002F: NTSC (L,175/410?; 2-B, C-W+11, W+12-69) TADC-M201D: PAL D/K+B/G+I (L,143/425) (sound control at I2C address 0xc8) TADC-T003F: NTSC Taiwan (L,175/410?; 2-B, C-W+11, W+12-69) - - (API,Lo-Hi-takeover/Hi-UHF-takeover) - I2C APIs: - L= LG programming (VHF_LO=0x01, VHF_HI=0x02, UHF=0x08, radio=0x04) - P= Philips progr. (VHF_LO=0xA0, VHF_HI=0x90, UHF=0x30, radio=0x04) - T= Temic progr. (VHF_LO=0x02, VHF_HI=0x04, UHF=0x01) Suffix: P= Standard phono female socket D= IEC female socket @@ -93,3 +105,11 @@ TCL2002MB-1 : PAL BG + DK =TUNER_LG_PAL_NEW_TAPC TCL2002MB-1F: PAL BG + DK w/FM =PHILIPS_PAL TCL2002MI-2 : PAL I = ?? + +ALPS Tuners: + Most are LG_API compatible + TSCH6 has ALPS_API (TSCH5 ?) + TSBE1 has extra API 05,02,08 Control_byte=0xCB Source:(1) + +Lit. +(1) conexant100029b-PCI-Decoder-ApplicationNote.pdf diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS Mon Nov 4 14:31:02 2002 +++ b/MAINTAINERS Mon Nov 4 14:31:02 2002 @@ -444,6 +444,13 @@ W: http://www.debian.org/~dz/i8k/ S: Maintained +DEVICE-MAPPER +P: Joe Thornber +M: dm@uk.sistina.com +L: linux-lvm@sistina.com +W: http://www.sistina.com/lvm +S: Maintained + DEVICE NUMBER REGISTRY P: H. Peter Anvin M: hpa@zytor.com @@ -457,23 +464,24 @@ S: Maintained DIGI INTL. EPCA DRIVER -P: Chad Schwartz -M: support@dgii.com -L: digilnux@dgii.com +P: Digi International, Inc +M: Eng.Linux@digi.com +L: Eng.Linux@digi.com +W: http://www.digi.com S: Maintained DIGI RIGHTSWITCH NETWORK DRIVER P: Rick Richardson L: linux-net@vger.kernel.org -W: http://www.dgii.com/linux/ -S: Maintained +W: http://www.digi.com +S: Orphaned DIGIBOARD PC/XE AND PC/XI DRIVER P: Christoph Lameter M: christoph@lameter.com -W: http://www.dgii.com/linux,http://lameter.com/digi +W: http://www.digi.com L: digilnux@dgii.com -S: Maintained +S: Orphaned DIRECTORY NOTIFICATION P: Stephen Rothwell @@ -852,9 +860,8 @@ S: Maintained IRDA SUBSYSTEM -P: Dag Brattli -M: Dag Brattli -L: linux-irda@pasta.cs.uit.no +P: Jean Tourrilhes +L: irda-users@lists.sourceforge.net W: http://irda.sourceforge.net/ S: Maintained @@ -958,6 +965,12 @@ W: http://www.ibm.com/linux/ltc/projects/ppc S: Supported +LINUX FOR NCR VOYAGER +P: James Bottomley +M: James.Bottomley@HansenPartnership.com +W: http://www.hansenpartnership.com/voyager +S: Maintained + LINUX FOR POWERPC P: Paul Mackerras M: paulus@samba.org @@ -1571,6 +1584,13 @@ W: http://www.rr.iij4u.or.jp/~kkojima/linux-sh4.html S: Maintained +SUN3/3X +P: Sam Creasey +M: sammy@sammy.net +L: sun3-list@redhat.com +W: http://sammy.net/sun3/ +S: Maintained + SVGA HANDLING P: Martin Mares M: mj@ucw.cz @@ -1895,6 +1915,24 @@ P: Jeff Garzik L: linux-via@gtf.org S: Odd fixes + +UCLINUX +P: Greg Ungerer +M: gerg@snapgear.com +P: David McCullough +M: davidm@snapgear.com +P: D. Jeff Dionne (created first uClinux port) +M: jeff@uclinux.org +W: http://www.uclinux.org/ +L: uclinux-dev@uclinux.org +S: Maintained + +UCLINUX FOR NEC V850 +P: Miles Bader +M: uclinux-v850@lsi.nec.co.jp +W: http://www.ic.nec.co.jp/micro/uclinux/eng/ +W: http://www.ee.nec.de/uclinux/ +S: Supported USB DIAMOND RIO500 DRIVER P: Cesar Miquel diff -Nru a/Makefile b/Makefile --- a/Makefile Mon Nov 4 14:31:00 2002 +++ b/Makefile Mon Nov 4 14:31:00 2002 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 5 -SUBLEVEL = 45 +SUBLEVEL = 46 EXTRAVERSION = # *DOCUMENTATION* @@ -155,6 +155,7 @@ STRIP = $(CROSS_COMPILE)strip OBJCOPY = $(CROSS_COMPILE)objcopy OBJDUMP = $(CROSS_COMPILE)objdump +AWK = awk GENKSYMS = /sbin/genksyms DEPMOD = /sbin/depmod KALLSYMS = /sbin/kallsyms @@ -173,7 +174,7 @@ export VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \ CONFIG_SHELL TOPDIR HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \ - CPP AR NM STRIP OBJCOPY OBJDUMP MAKE GENKSYMS PERL UTS_MACHINE \ + CPP AR NM STRIP OBJCOPY OBJDUMP MAKE AWK GENKSYMS PERL UTS_MACHINE \ HOSTCXX HOSTCXXFLAGS export CPPFLAGS NOSTDINC_FLAGS OBJCOPYFLAGS LDFLAGS @@ -209,12 +210,12 @@ drivers-y := drivers/ sound/ net-y := net/ libs-y := lib/ -core-y := +core-y := usr/ SUBDIRS := ifeq ($(filter $(noconfig_targets),$(MAKECMDGOALS)),) -export include-config := 1 +export include_config := 1 -include .config @@ -228,9 +229,10 @@ $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ $(net-y) $(net-m) $(libs-y) $(libs-m))) -ALL_SUBDIRS := $(SUBDIRS) $(patsubst %/,%,$(filter %/, $(init-n) $(init-) \ +ALL_SUBDIRS := $(sort $(SUBDIRS) $(patsubst %/,%,$(filter %/, \ + $(init-n) $(init-) \ $(core-n) $(core-) $(drivers-n) $(drivers-) \ - $(net-n) $(net-) $(libs-n) $(libs-))) + $(net-n) $(net-) $(libs-n) $(libs-)))) init-y := $(patsubst %/, %/built-in.o, $(init-y)) core-y := $(patsubst %/, %/built-in.o, $(core-y)) @@ -238,7 +240,7 @@ net-y := $(patsubst %/, %/built-in.o, $(net-y)) libs-y := $(patsubst %/, %/lib.a, $(libs-y)) -ifdef include-config +ifdef include_config # Here goes the main Makefile # =========================================================================== @@ -602,7 +604,7 @@ rpm -ta $(TOPDIR)/../$(KERNELPATH).tar.gz ; \ rm $(TOPDIR)/../$(KERNELPATH).tar.gz -else # ifdef include-config +else # ifdef include_config ifeq ($(filter-out $(noconfig_targets),$(MAKECMDGOALS)),) @@ -764,8 +766,7 @@ help: @echo 'Cleaning targets:' @echo ' clean - remove most generated files but keep the config' - @echo ' mrproper - remove all generated files including the config' - @echo ' distclean - mrproper + remove files generated by editors and patch' + @echo ' mrproper - remove all generated files + config + various backup files' @echo '' @echo 'Configuration targets:' @echo ' oldconfig - Update current config utilising a line-oriented program' @@ -798,7 +799,7 @@ # Documentation targets # --------------------------------------------------------------------------- sgmldocs psdocs pdfdocs htmldocs: scripts - $(Q)$(MAKE) -f Documentation/DocBook/Makefile $@ + $(Q)$(MAKE) -f scripts/Makefile.build obj=Documentation/DocBook $@ # Scripts to check various things for consistency # --------------------------------------------------------------------------- @@ -828,7 +829,7 @@ $(MAKE) $@ endif # ifeq ($(filter-out $(noconfig_targets),$(MAKECMDGOALS)),) -endif # ifdef include-config +endif # ifdef include_config # FIXME Should go into a make.lib or something # =========================================================================== diff -Nru a/arch/alpha/Kconfig b/arch/alpha/Kconfig --- a/arch/alpha/Kconfig Mon Nov 4 14:31:02 2002 +++ b/arch/alpha/Kconfig Mon Nov 4 14:31:02 2002 @@ -12,6 +12,14 @@ port. The Alpha Linux project has a home page at . +config MMU + bool + default y + +config SWAP + bool + default y + config UID16 bool @@ -521,6 +529,9 @@ much vmalloc space as is available. Say N unless you know you need gobs and gobs of vmalloc space. + +config VERBOSE_MCHECK + bool "Verbose Machine Checks" source "drivers/pci/Kconfig" diff -Nru a/arch/alpha/Makefile b/arch/alpha/Makefile --- a/arch/alpha/Makefile Mon Nov 4 14:31:02 2002 +++ b/arch/alpha/Makefile Mon Nov 4 14:31:02 2002 @@ -12,6 +12,7 @@ LDFLAGS_vmlinux = -static -N #-relax CFLAGS := $(CFLAGS) -pipe -mno-fp-regs -ffixed-8 +ARCHBLOBLFLAGS := -I binary -O elf64-alpha -B alpha # Determine if we can use the BWX instructions with GAS. old_gas := $(shell if $(AS) --version 2>&1 | grep 'version 2.7' > /dev/null; then echo y; else echo n; fi) diff -Nru a/arch/alpha/defconfig b/arch/alpha/defconfig --- a/arch/alpha/defconfig Mon Nov 4 14:31:02 2002 +++ b/arch/alpha/defconfig Mon Nov 4 14:31:02 2002 @@ -59,6 +59,7 @@ # CONFIG_ALPHA_TAKARA is not set # CONFIG_ALPHA_TITAN is not set # CONFIG_ALPHA_WILDFIRE is not set +CONFIG_VERBOSE_MCHECK=y CONFIG_ISA=y CONFIG_EISA=y # CONFIG_SBUS is not set diff -Nru a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile --- a/arch/alpha/kernel/Makefile Mon Nov 4 14:31:01 2002 +++ b/arch/alpha/kernel/Makefile Mon Nov 4 14:31:01 2002 @@ -10,7 +10,7 @@ obj-y := entry.o traps.o process.o init_task.o osf_sys.o irq.o \ irq_alpha.o signal.o setup.o ptrace.o time.o semaphore.o \ - alpha_ksyms.o systbls.o + alpha_ksyms.o systbls.o err_common.o # # FIXME! diff -Nru a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c --- a/arch/alpha/kernel/asm-offsets.c Mon Nov 4 14:31:03 2002 +++ b/arch/alpha/kernel/asm-offsets.c Mon Nov 4 14:31:03 2002 @@ -22,6 +22,7 @@ BLANK(); DEFINE(PT_PTRACED, PT_PTRACED); DEFINE(CLONE_VM, CLONE_VM); + DEFINE(CLONE_UNTRACED, CLONE_UNTRACED); DEFINE(SIGCHLD, SIGCHLD); BLANK(); DEFINE(HAE_CACHE, offsetof(struct alpha_machine_vector, hae_cache)); diff -Nru a/arch/alpha/kernel/core_cia.c b/arch/alpha/kernel/core_cia.c --- a/arch/alpha/kernel/core_cia.c Mon Nov 4 14:31:02 2002 +++ b/arch/alpha/kernel/core_cia.c Mon Nov 4 14:31:02 2002 @@ -47,6 +47,15 @@ #define vip volatile int * +/* Save CIA configuration data as the console had it set up. */ + +struct +{ + unsigned int w_base; + unsigned int w_mask; + unsigned int t_base; +} saved_config[4] __attribute((common)); + /* * Given a bus, device, and function number, compute resulting * configuration space address. It is therefore not safe to have @@ -648,6 +657,24 @@ hose->dense_io_base = CIA_BW_IO - IDENT_ADDR; } + /* Save CIA configuration data as the console had it set up. */ + + saved_config[0].w_base = *(vip)CIA_IOC_PCI_W0_BASE; + saved_config[0].w_mask = *(vip)CIA_IOC_PCI_W0_MASK; + saved_config[0].t_base = *(vip)CIA_IOC_PCI_T0_BASE; + + saved_config[1].w_base = *(vip)CIA_IOC_PCI_W1_BASE; + saved_config[1].w_mask = *(vip)CIA_IOC_PCI_W1_MASK; + saved_config[1].t_base = *(vip)CIA_IOC_PCI_T1_BASE; + + saved_config[2].w_base = *(vip)CIA_IOC_PCI_W2_BASE; + saved_config[2].w_mask = *(vip)CIA_IOC_PCI_W2_MASK; + saved_config[2].t_base = *(vip)CIA_IOC_PCI_T2_BASE; + + saved_config[3].w_base = *(vip)CIA_IOC_PCI_W3_BASE; + saved_config[3].w_mask = *(vip)CIA_IOC_PCI_W3_MASK; + saved_config[3].t_base = *(vip)CIA_IOC_PCI_T3_BASE; + /* * Set up the PCI to main memory translation windows. * @@ -736,6 +763,26 @@ do_init_arch(1); } +void +cia_kill_arch(int mode) +{ + *(vip)CIA_IOC_PCI_W0_BASE = saved_config[0].w_base; + *(vip)CIA_IOC_PCI_W0_MASK = saved_config[0].w_mask; + *(vip)CIA_IOC_PCI_T0_BASE = saved_config[0].t_base; + + *(vip)CIA_IOC_PCI_W1_BASE = saved_config[1].w_base; + *(vip)CIA_IOC_PCI_W1_MASK = saved_config[1].w_mask; + *(vip)CIA_IOC_PCI_T1_BASE = saved_config[1].t_base; + + *(vip)CIA_IOC_PCI_W2_BASE = saved_config[2].w_base; + *(vip)CIA_IOC_PCI_W2_MASK = saved_config[2].w_mask; + *(vip)CIA_IOC_PCI_T2_BASE = saved_config[2].t_base; + + *(vip)CIA_IOC_PCI_W3_BASE = saved_config[3].w_base; + *(vip)CIA_IOC_PCI_W3_MASK = saved_config[3].w_mask; + *(vip)CIA_IOC_PCI_T3_BASE = saved_config[3].t_base; +} + void __init cia_init_pci(void) { @@ -755,6 +802,7 @@ *(vip)CIA_IOC_CIA_ERR; /* re-read to force write. */ } +#ifdef CONFIG_VERBOSE_MCHECK static void cia_decode_pci_error(struct el_CIA_sysdata_mcheck *cia, const char *msg) { @@ -1022,13 +1070,13 @@ printk(KERN_CRIT " Command: %s, Parity bit: %d\n", cmd, par); printk(KERN_CRIT " Address: %#010lx, Mask: %#lx\n", addr, mask); } +#endif static int cia_decode_mchk(unsigned long la_ptr) { struct el_common *com; struct el_CIA_sysdata_mcheck *cia; - int which; com = (void *)la_ptr; cia = (void *)(la_ptr + com->sys_offset); @@ -1036,8 +1084,8 @@ if ((cia->cia_err & CIA_ERR_VALID) == 0) return 0; - which = cia->cia_err & 0xfff; - switch (ffs(which) - 1) { +#ifdef CONFIG_VERBOSE_MCHECK + switch (ffs(cia->cia_err & 0xfff) - 1) { case 0: /* CIA_ERR_COR_ERR */ cia_decode_ecc_error(cia, "Corrected ECC error"); break; @@ -1109,6 +1157,7 @@ if (cia->cia_err & CIA_ERR_LOST_IOA_TIMEOUT) printk(KERN_CRIT "CIA lost machine check: " "I/O timeout\n"); +#endif return 1; } diff -Nru a/arch/alpha/kernel/core_titan.c b/arch/alpha/kernel/core_titan.c --- a/arch/alpha/kernel/core_titan.c Mon Nov 4 14:31:01 2002 +++ b/arch/alpha/kernel/core_titan.c Mon Nov 4 14:31:01 2002 @@ -27,12 +27,14 @@ unsigned TITAN_agp = 0; -static struct +/* Save Titan configuration data as the console had it set up. */ + +struct { unsigned long wsba[4]; unsigned long wsm[4]; unsigned long tba[4]; -} saved_pachip_port[4]; +} saved_config[4] __attribute__((common)); /* * BIOS32-style PCI interface: @@ -289,21 +291,21 @@ * Save the existing PCI window translations. SRM will * need them when we go to reboot. */ - saved_pachip_port[index].wsba[0] = port->wsba[0].csr; - saved_pachip_port[index].wsm[0] = port->wsm[0].csr; - saved_pachip_port[index].tba[0] = port->tba[0].csr; - - saved_pachip_port[index].wsba[1] = port->wsba[1].csr; - saved_pachip_port[index].wsm[1] = port->wsm[1].csr; - saved_pachip_port[index].tba[1] = port->tba[1].csr; - - saved_pachip_port[index].wsba[2] = port->wsba[2].csr; - saved_pachip_port[index].wsm[2] = port->wsm[2].csr; - saved_pachip_port[index].tba[2] = port->tba[2].csr; - - saved_pachip_port[index].wsba[3] = port->wsba[3].csr; - saved_pachip_port[index].wsm[3] = port->wsm[3].csr; - saved_pachip_port[index].tba[3] = port->tba[3].csr; + saved_config[index].wsba[0] = port->wsba[0].csr; + saved_config[index].wsm[0] = port->wsm[0].csr; + saved_config[index].tba[0] = port->tba[0].csr; + + saved_config[index].wsba[1] = port->wsba[1].csr; + saved_config[index].wsm[1] = port->wsm[1].csr; + saved_config[index].tba[1] = port->tba[1].csr; + + saved_config[index].wsba[2] = port->wsba[2].csr; + saved_config[index].wsm[2] = port->wsm[2].csr; + saved_config[index].tba[2] = port->tba[2].csr; + + saved_config[index].wsba[3] = port->wsba[3].csr; + saved_config[index].wsm[3] = port->wsm[3].csr; + saved_config[index].tba[3] = port->tba[3].csr; /* * Set up the PCI to main memory translation windows. @@ -392,21 +394,21 @@ static void titan_kill_one_pachip_port(titan_pachip_port *port, int index) { - port->wsba[0].csr = saved_pachip_port[index].wsba[0]; - port->wsm[0].csr = saved_pachip_port[index].wsm[0]; - port->tba[0].csr = saved_pachip_port[index].tba[0]; - - port->wsba[1].csr = saved_pachip_port[index].wsba[1]; - port->wsm[1].csr = saved_pachip_port[index].wsm[1]; - port->tba[1].csr = saved_pachip_port[index].tba[1]; - - port->wsba[2].csr = saved_pachip_port[index].wsba[2]; - port->wsm[2].csr = saved_pachip_port[index].wsm[2]; - port->tba[2].csr = saved_pachip_port[index].tba[2]; - - port->wsba[3].csr = saved_pachip_port[index].wsba[3]; - port->wsm[3].csr = saved_pachip_port[index].wsm[3]; - port->tba[3].csr = saved_pachip_port[index].tba[3]; + port->wsba[0].csr = saved_config[index].wsba[0]; + port->wsm[0].csr = saved_config[index].wsm[0]; + port->tba[0].csr = saved_config[index].tba[0]; + + port->wsba[1].csr = saved_config[index].wsba[1]; + port->wsm[1].csr = saved_config[index].wsm[1]; + port->tba[1].csr = saved_config[index].tba[1]; + + port->wsba[2].csr = saved_config[index].wsba[2]; + port->wsm[2].csr = saved_config[index].wsm[2]; + port->tba[2].csr = saved_config[index].tba[2]; + + port->wsba[3].csr = saved_config[index].wsba[3]; + port->wsm[3].csr = saved_config[index].wsm[3]; + port->tba[3].csr = saved_config[index].tba[3]; } static void diff -Nru a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c --- a/arch/alpha/kernel/core_tsunami.c Mon Nov 4 14:31:01 2002 +++ b/arch/alpha/kernel/core_tsunami.c Mon Nov 4 14:31:01 2002 @@ -26,13 +26,14 @@ #include "proto.h" #include "pci_impl.h" +/* Save Tsunami configuration data as the console had it set up. */ -static struct +struct { unsigned long wsba[4]; unsigned long wsm[4]; unsigned long tba[4]; -} saved_pchip[2]; +} saved_config[2] __attribute__((common)); /* * NOTE: Herein lie back-to-back mb instructions. They are magic. @@ -293,21 +294,21 @@ * need them when we go to reboot. */ - saved_pchip[index].wsba[0] = pchip->wsba[0].csr; - saved_pchip[index].wsm[0] = pchip->wsm[0].csr; - saved_pchip[index].tba[0] = pchip->tba[0].csr; - - saved_pchip[index].wsba[1] = pchip->wsba[1].csr; - saved_pchip[index].wsm[1] = pchip->wsm[1].csr; - saved_pchip[index].tba[1] = pchip->tba[1].csr; - - saved_pchip[index].wsba[2] = pchip->wsba[2].csr; - saved_pchip[index].wsm[2] = pchip->wsm[2].csr; - saved_pchip[index].tba[2] = pchip->tba[2].csr; - - saved_pchip[index].wsba[3] = pchip->wsba[3].csr; - saved_pchip[index].wsm[3] = pchip->wsm[3].csr; - saved_pchip[index].tba[3] = pchip->tba[3].csr; + saved_config[index].wsba[0] = pchip->wsba[0].csr; + saved_config[index].wsm[0] = pchip->wsm[0].csr; + saved_config[index].tba[0] = pchip->tba[0].csr; + + saved_config[index].wsba[1] = pchip->wsba[1].csr; + saved_config[index].wsm[1] = pchip->wsm[1].csr; + saved_config[index].tba[1] = pchip->tba[1].csr; + + saved_config[index].wsba[2] = pchip->wsba[2].csr; + saved_config[index].wsm[2] = pchip->wsm[2].csr; + saved_config[index].tba[2] = pchip->tba[2].csr; + + saved_config[index].wsba[3] = pchip->wsba[3].csr; + saved_config[index].wsm[3] = pchip->wsm[3].csr; + saved_config[index].tba[3] = pchip->tba[3].csr; /* * Set up the PCI to main memory translation windows. @@ -403,21 +404,21 @@ static void tsunami_kill_one_pchip(tsunami_pchip *pchip, int index) { - pchip->wsba[0].csr = saved_pchip[index].wsba[0]; - pchip->wsm[0].csr = saved_pchip[index].wsm[0]; - pchip->tba[0].csr = saved_pchip[index].tba[0]; - - pchip->wsba[1].csr = saved_pchip[index].wsba[1]; - pchip->wsm[1].csr = saved_pchip[index].wsm[1]; - pchip->tba[1].csr = saved_pchip[index].tba[1]; - - pchip->wsba[2].csr = saved_pchip[index].wsba[2]; - pchip->wsm[2].csr = saved_pchip[index].wsm[2]; - pchip->tba[2].csr = saved_pchip[index].tba[2]; - - pchip->wsba[3].csr = saved_pchip[index].wsba[3]; - pchip->wsm[3].csr = saved_pchip[index].wsm[3]; - pchip->tba[3].csr = saved_pchip[index].tba[3]; + pchip->wsba[0].csr = saved_config[index].wsba[0]; + pchip->wsm[0].csr = saved_config[index].wsm[0]; + pchip->tba[0].csr = saved_config[index].tba[0]; + + pchip->wsba[1].csr = saved_config[index].wsba[1]; + pchip->wsm[1].csr = saved_config[index].wsm[1]; + pchip->tba[1].csr = saved_config[index].tba[1]; + + pchip->wsba[2].csr = saved_config[index].wsba[2]; + pchip->wsm[2].csr = saved_config[index].wsm[2]; + pchip->tba[2].csr = saved_config[index].tba[2]; + + pchip->wsba[3].csr = saved_config[index].wsba[3]; + pchip->wsm[3].csr = saved_config[index].wsm[3]; + pchip->tba[3].csr = saved_config[index].tba[3]; } void diff -Nru a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S --- a/arch/alpha/kernel/entry.S Mon Nov 4 14:31:00 2002 +++ b/arch/alpha/kernel/entry.S Mon Nov 4 14:31:00 2002 @@ -212,7 +212,7 @@ stq $2, 152($30) /* HAE */ /* Shuffle FLAGS to the front; add CLONE_VM. */ - ldi $1, CLONE_VM + ldi $1, CLONE_VM|CLONE_UNTRACED or $18, $1, $16 bsr $26, sys_clone @@ -452,7 +452,8 @@ bsr $1,do_switch_stack bis $31,SIGCHLD,$16 mov $31,$17 - mov $30,$18 + mov $31,$18 + mov $30,$19 jsr $26,alpha_clone bsr $1,undo_switch_stack ret $31,($26),1 @@ -463,8 +464,9 @@ .ent sys_clone sys_clone: bsr $1,do_switch_stack - /* arg1 and arg2 come from the user */ - mov $30,$18 + /* $16, $17, $18, $19 come from the user; $19 is used later + via pt_regs->r19. */ + mov $30,$19 jsr $26,alpha_clone bsr $1,undo_switch_stack ret $31,($26),1 diff -Nru a/arch/alpha/kernel/err_common.c b/arch/alpha/kernel/err_common.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/alpha/kernel/err_common.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,772 @@ +/* + * linux/arch/alpha/kernel/err_common.c + * + * Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation) + * + * Error handling code supporting Alpha systems + */ + +#include +#include +#include + +#include +#include +#include + +#include "err_impl.h" +#include "proto.h" + +/* + * err_print_prefix -- error handling print routines should prefix + * all prints with this + */ +char *err_print_prefix = KERN_NOTICE; + +/* + * Forward references + */ +static void el_print_timestamp(union el_timestamp); +static void el_process_subpackets(struct el_subpacket *, int); + + +/* + * Generic + */ +void +mchk_dump_mem(void *data, int length, char **annotation) +{ + unsigned long *ldata = data; + int i; + + for(i = 0; (i * sizeof(*ldata)) < length; i++) { + if (annotation && !annotation[i]) + annotation = NULL; + printk("%s %08x: %016lx %s\n", + err_print_prefix, + (unsigned)(i * sizeof(*ldata)), ldata[i], + annotation ? annotation[i] : ""); + } +} + +void +mchk_dump_logout_frame(struct el_common *mchk_header) +{ + printk("%s -- Frame Header --\n" + " Frame Size: %d (0x%x) bytes\n" + " Flags: %s%s\n" + " MCHK Code: 0x%x\n" + " Frame Rev: %d\n" + " Proc Offset: 0x%08x\n" + " Sys Offset: 0x%08x\n" + " -- Processor Region --\n", + err_print_prefix, + mchk_header->size, mchk_header->size, + mchk_header->retry ? "RETRY " : "", + mchk_header->err2 ? "SECOND_ERR " : "", + mchk_header->code, + mchk_header->frame_rev, + mchk_header->proc_offset, + mchk_header->sys_offset); + + mchk_dump_mem((void *) + ((unsigned long)mchk_header + mchk_header->proc_offset), + mchk_header->sys_offset - mchk_header->proc_offset, + NULL); + + printk("%s -- System Region --\n", err_print_prefix); + mchk_dump_mem((void *) + ((unsigned long)mchk_header + mchk_header->sys_offset), + mchk_header->size - mchk_header->sys_offset, + NULL); + printk("%s -- End of Frame --\n", err_print_prefix); +} + + +/* + * EV7 generic + */ +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EV7) + +void +ev7_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs) +{ + /* + * Sync the processor + */ + mb(); + draina(); + + /* + * Parse the logout frame without printing first. If the only error(s) + * found are have a disposition of "dismiss", then just dismiss them + * and don't print any message + */ + printk("%sEV7 MACHINE CHECK vector %lx\n", err_print_prefix, vector); + + /* + * Release the logout frame + */ + wrmces(0x7); + mb(); +} + +struct ev7_pal_subpacket { + union { + struct { + u32 mchk_code; + u32 subpacket_count; + u64 whami; + u64 rbox_whami; + u64 rbox_int; + u64 exc_addr; + union el_timestamp timestamp; + u64 halt_code; + u64 reserved; + } logout; + } by_type; +}; + +static char *el_ev7_processor_subpacket_annotation[] = { + "Subpacket Header", "I_STAT", "DC_STAT", + "C_ADDR", "C_SYNDROME_1", "C_SYNDROME_0", + "C_STAT", "C_STS", "MM_STAT", + "EXC_ADDR", "IER_CM", "ISUM", + "PAL_BASE", "I_CTL", "PROCESS_CONTEXT", + "CBOX_CTL", "CBOX_STP_CTL", "CBOX_ACC_CTL", + "CBOX_LCL_SET", "CBOX_GLB_SET", "BBOX_CTL", + "BBOX_ERR_STS", "BBOX_ERR_IDX", "CBOX_DDP_ERR_STS", + "BBOX_DAT_RMP", NULL +}; + +static char *el_ev7_zbox_subpacket_annotation[] = { + "Subpacket Header", + "ZBOX(0): DRAM_ERR_STATUS_2 / DRAM_ERR_STATUS_1", + "ZBOX(0): DRAM_ERROR_CTL / DRAM_ERR_STATUS_3", + "ZBOX(0): DIFT_TIMEOUT / DRAM_ERR_ADR", + "ZBOX(0): FRC_ERR_ADR / DRAM_MAPPER_CTL", + "ZBOX(0): reserved / DIFT_ERR_STATUS", + "ZBOX(1): DRAM_ERR_STATUS_2 / DRAM_ERR_STATUS_1", + "ZBOX(1): DRAM_ERROR_CTL / DRAM_ERR_STATUS_3", + "ZBOX(1): DIFT_TIMEOUT / DRAM_ERR_ADR", + "ZBOX(1): FRC_ERR_ADR / DRAM_MAPPER_CTL", + "ZBOX(1): reserved / DIFT_ERR_STATUS", + "CBOX_CTL", "CBOX_STP_CTL", + "ZBOX(0)_ERROR_PA", "ZBOX(1)_ERROR_PA", + "ZBOX(0)_ORED_SYNDROME","ZBOX(1)_ORED_SYNDROME", + NULL +}; + +static char *el_ev7_rbox_subpacket_annotation[] = { + "Subpacket Header", "RBOX_CFG", "RBOX_N_CFG", + "RBOX_S_CFG", "RBOX_E_CFG", "RBOX_W_CFG", + "RBOX_N_ERR", "RBOX_S_ERR", "RBOX_E_ERR", + "RBOX_W_ERR", "RBOX_IO_CFG", "RBOX_IO_ERR", + "RBOX_L_ERR", "RBOX_WHOAMI", "RBOX_IMASL", + "RBOX_INTQ", "RBOX_INT", NULL +}; + +static char *el_ev7_io_subpacket_annotation[] = { + "Subpacket Header", "IO_ASIC_REV", "IO_SYS_REV", + "IO7_UPH", "HPI_CTL", "CRD_CTL", + "HEI_CTL", "PO7_ERROR_SUM","PO7_UNCRR_SYM", + "PO7_CRRCT_SYM", "PO7_UGBGE_SYM","PO7_ERR_PKT0", + "PO7_ERR_PKT1", "reserved", "reserved", + "PO0_ERR_SUM", "PO0_TLB_ERR", "PO0_SPL_COMPLT", + "PO0_TRANS_SUM", "PO0_FIRST_ERR","PO0_MULT_ERR", + "DM CSR PH", "DM CSR PH", "DM CSR PH", + "DM CSR PH", "reserved", + "PO1_ERR_SUM", "PO1_TLB_ERR", "PO1_SPL_COMPLT", + "PO1_TRANS_SUM", "PO1_FIRST_ERR","PO1_MULT_ERR", + "DM CSR PH", "DM CSR PH", "DM CSR PH", + "DM CSR PH", "reserved", + "PO2_ERR_SUM", "PO2_TLB_ERR", "PO2_SPL_COMPLT", + "PO2_TRANS_SUM", "PO2_FIRST_ERR","PO2_MULT_ERR", + "DM CSR PH", "DM CSR PH", "DM CSR PH", + "DM CSR PH", "reserved", + "PO3_ERR_SUM", "PO3_TLB_ERR", "PO3_SPL_COMPLT", + "PO3_TRANS_SUM", "PO3_FIRST_ERR","PO3_MULT_ERR", + "DM CSR PH", "DM CSR PH", "DM CSR PH", + "DM CSR PH", "reserved", + NULL +}; + +static struct el_subpacket_annotation el_ev7_pal_annotations[] = { + SUBPACKET_ANNOTATION(EL_CLASS__PAL, + EL_TYPE__PAL__EV7_PROCESSOR, + 1, + "EV7 Processor Subpacket", + el_ev7_processor_subpacket_annotation), + SUBPACKET_ANNOTATION(EL_CLASS__PAL, + EL_TYPE__PAL__EV7_ZBOX, + 1, + "EV7 ZBOX Subpacket", + el_ev7_zbox_subpacket_annotation), + SUBPACKET_ANNOTATION(EL_CLASS__PAL, + EL_TYPE__PAL__EV7_RBOX, + 1, + "EV7 RBOX Subpacket", + el_ev7_rbox_subpacket_annotation), + SUBPACKET_ANNOTATION(EL_CLASS__PAL, + EL_TYPE__PAL__EV7_IO, + 1, + "EV7 IO Subpacket", + el_ev7_io_subpacket_annotation) +}; + +static struct el_subpacket * +ev7_process_pal_subpacket(struct el_subpacket *header) +{ + struct ev7_pal_subpacket *packet; + + if (header->class != EL_CLASS__PAL) { + printk("%s ** Unexpected header CLASS %d TYPE %d, aborting\n", + err_print_prefix, + header->class, header->type); + return NULL; + } + + packet = (struct ev7_pal_subpacket *)header->by_type.raw.data_start; + + switch(header->type) { + case EL_TYPE__PAL__LOGOUT_FRAME: + printk("%s*** MCHK occurred on LPID %ld (RBOX %lx)\n", + err_print_prefix, + packet->by_type.logout.whami, + packet->by_type.logout.rbox_whami); + el_print_timestamp(packet->by_type.logout.timestamp); + printk("%s EXC_ADDR: %016lx\n" + " HALT_CODE: %lx\n", + err_print_prefix, + packet->by_type.logout.exc_addr, + packet->by_type.logout.halt_code); + el_process_subpackets(header, + packet->by_type.logout.subpacket_count); + break; + default: + printk("%s ** PAL TYPE %d SUBPACKET\n", + err_print_prefix, + header->type); + el_annotate_subpacket(header); + break; + } + + return (struct el_subpacket *)((unsigned long)header + header->length); +} + +struct el_subpacket_handler ev7_pal_subpacket_handler = + SUBPACKET_HANDLER_INIT(EL_CLASS__PAL, ev7_process_pal_subpacket); + +void +ev7_register_error_handlers(void) +{ + int i; + + for(i = 0; + iI_STAT, print); + status |= ev6_parse_mbox(ev6mchk->MM_STAT, ev6mchk->DC_STAT, + ev6mchk->C_STAT, print); + status |= ev6_parse_cbox(ev6mchk->C_ADDR, ev6mchk->DC1_SYNDROME, + ev6mchk->DC0_SYNDROME, ev6mchk->C_STAT, + ev6mchk->C_STS, print); + + if (!print) + return status; + + if (status != MCHK_DISPOSITION_DISMISS) { + char *saved_err_prefix = err_print_prefix; + + /* + * Dump some additional information from the frame + */ + printk("%s EXC_ADDR: 0x%016lx IER_CM: 0x%016lx" + " ISUM: 0x%016lx\n" + " PAL_BASE: 0x%016lx I_CTL: 0x%016lx" + " PCTX: 0x%016lx\n", + err_print_prefix, + ev6mchk->EXC_ADDR, ev6mchk->IER_CM, ev6mchk->ISUM, + ev6mchk->PAL_BASE, ev6mchk->I_CTL, ev6mchk->PCTX); + + if (status == MCHK_DISPOSITION_UNKNOWN_ERROR) { + printk("%s UNKNOWN error, frame follows:\n", + err_print_prefix); + } else { + /* had decode -- downgrade print level for frame */ + err_print_prefix = KERN_NOTICE; + } + + mchk_dump_logout_frame(mchk_header); + + err_print_prefix = saved_err_prefix; + } + + return status; +} + +void +ev6_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs) +{ + struct el_common *mchk_header = (struct el_common *)la_ptr; + + /* + * Sync the processor + */ + mb(); + draina(); + + /* + * Parse the logout frame without printing first. If the only error(s) + * found are have a disposition of "dismiss", then just dismiss them + * and don't print any message + */ + if (ev6_process_logout_frame(mchk_header, 0) != + MCHK_DISPOSITION_DISMISS) { + char *saved_err_prefix = err_print_prefix; + err_print_prefix = KERN_CRIT; + + /* + * Either a nondismissable error was detected or no + * recognized error was detected in the logout frame + * -- report the error in either case + */ + printk("%s*CPU %s Error (Vector 0x%x) reported on CPU %d:\n", + err_print_prefix, + (vector == SCB_Q_PROCERR)?"Correctable":"Uncorrectable", + (unsigned int)vector, (int)smp_processor_id()); + + ev6_process_logout_frame(mchk_header, 1); + dik_show_regs(regs, NULL); + + err_print_prefix = saved_err_prefix; + } + + /* + * Release the logout frame + */ + wrmces(0x7); + mb(); +} + +#endif /* CONFIG_ALPHA_GENERIC || CONFIG_ALPHA_EV6 */ + + +/* + * Console Data Log + */ +/* Data */ +static struct el_subpacket_handler *subpacket_handler_list = NULL; +static struct el_subpacket_annotation *subpacket_annotation_list = NULL; + +static void +el_print_timestamp(union el_timestamp timestamp) +{ + if (timestamp.as_int) + printk("%s TIMESTAMP: %d/%d/%02d %d:%02d:%0d\n", + err_print_prefix, + timestamp.b.month, timestamp.b.day, + timestamp.b.year, timestamp.b.hour, + timestamp.b.minute, timestamp.b.second); +} + +static struct el_subpacket * +el_process_header_subpacket(struct el_subpacket *header) +{ + union el_timestamp timestamp; + char *name = "UNKNOWN EVENT"; + int packet_count = 0; + int length = 0; + + if (header->class != EL_CLASS__HEADER) { + printk("%s** Unexpected header CLASS %d TYPE %d, aborting\n", + err_print_prefix, + header->class, header->type); + return NULL; + } + + switch(header->type) { + case EL_TYPE__HEADER__SYSTEM_ERROR_FRAME: + name = "SYSTEM ERROR"; + length = header->by_type.sys_err.frame_length; + packet_count = + header->by_type.sys_err.frame_packet_count; + timestamp.as_int = 0; + break; + case EL_TYPE__HEADER__SYSTEM_EVENT_FRAME: + name = "SYSTEM EVENT"; + length = header->by_type.sys_event.frame_length; + packet_count = + header->by_type.sys_event.frame_packet_count; + timestamp = header->by_type.sys_event.timestamp; + break; + case EL_TYPE__HEADER__HALT_FRAME: + name = "ERROR HALT"; + length = header->by_type.err_halt.frame_length; + packet_count = + header->by_type.err_halt.frame_packet_count; + timestamp = header->by_type.err_halt.timestamp; + break; + case EL_TYPE__HEADER__LOGOUT_FRAME: + name = "LOGOUT FRAME"; + length = header->by_type.logout_header.frame_length; + packet_count = 1; + timestamp.as_int = 0; + break; + default: /* Unknown */ + printk("%s** Unknown header - CLASS %d TYPE %d, aborting\n", + err_print_prefix, + header->class, header->type); + return NULL; + } + + printk("%s*** %s:\n" + " CLASS %d, TYPE %d\n", + err_print_prefix, + name, + header->class, header->type); + el_print_timestamp(timestamp); + + /* + * Process the subpackets + */ + el_process_subpackets(header, packet_count); + + /* return the next header */ + header = (struct el_subpacket *) + ((unsigned long)header + header->length + length); + return header; +} + +static void +el_process_subpackets(struct el_subpacket *header, int packet_count) +{ + struct el_subpacket *subpacket; + int i; + + subpacket = (struct el_subpacket *) + ((unsigned long)header + header->length); + + for(i = 0; subpacket && i < packet_count; i++) { + printk("%sPROCESSING SUBPACKET %d\n", err_print_prefix, i); + subpacket = el_process_subpacket(subpacket); + } +} + +static struct el_subpacket * +el_process_subpacket_reg(struct el_subpacket *header) +{ + struct el_subpacket *next = NULL; + struct el_subpacket_handler *h = subpacket_handler_list; + + for(; h && h->class != header->class; h = h->next); + if (h) next = h->handler(header); + + return next; +} + +struct el_subpacket * +el_process_subpacket(struct el_subpacket *header) +{ + struct el_subpacket *next = NULL; + + switch(header->class) { + case EL_CLASS__TERMINATION: + /* Termination packet, there are no more */ + break; + case EL_CLASS__HEADER: + next = el_process_header_subpacket(header); + break; + default: + if (NULL == (next = el_process_subpacket_reg(header))) { + printk("%s** Unexpected header CLASS %d TYPE %d" + " -- aborting.\n", + err_print_prefix, + header->class, header->type); + } + break; + } + + return next; +} + +void +el_annotate_subpacket(struct el_subpacket *header) +{ + struct el_subpacket_annotation *a; + char **annotation = NULL; + + for(a = subpacket_annotation_list; a; a = a->next) { + if (a->class == header->class && + a->type == header->type && + a->revision == header->revision) { + /* + * We found the annotation + */ + annotation = a->annotation; + printk("%s %s\n", err_print_prefix, a->description); + break; + } + } + + mchk_dump_mem(header, header->length, annotation); +} + +static void __init +cdl_process_console_data_log(int cpu, struct percpu_struct *pcpu) +{ + struct el_subpacket *header = (struct el_subpacket *) + (IDENT_ADDR | pcpu->console_data_log_pa); + int err; + + printk("%s******* CONSOLE DATA LOG FOR CPU %d. *******\n" + "*** Error(s) were logged on a previous boot\n", + err_print_prefix, cpu); + + for(err = 0; header && (header->class != EL_CLASS__TERMINATION); err++) + header = el_process_subpacket(header); + + /* let the console know it's ok to clear the error(s) at restart */ + pcpu->console_data_log_pa = 0; + + printk("%s*** %d total error(s) logged\n" + "**** END OF CONSOLE DATA LOG FOR CPU %d ****\n", + err_print_prefix, err, cpu); +} + +void __init +cdl_check_console_data_log(void) +{ + struct percpu_struct *pcpu; + int cpu; + + for(cpu = 0; cpu < hwrpb->nr_processors; cpu++) { + pcpu = (struct percpu_struct *) + ((unsigned long)hwrpb + hwrpb->processor_offset + + cpu * hwrpb->processor_size); + if (pcpu->console_data_log_pa) + cdl_process_console_data_log(cpu, pcpu); + } + +} + +int __init +cdl_register_subpacket_annotation(struct el_subpacket_annotation *new) +{ + struct el_subpacket_annotation *a = subpacket_annotation_list; + + if (a == NULL) subpacket_annotation_list = new; + else { + for(; a->next != NULL; a = a->next) { + if ((a->class == new->class && a->type == new->type) || + a == new) { + printk("Attempted to re-register " + "subpacket annotation\n"); + return -EINVAL; + } + } + a->next = new; + } + new->next = NULL; + + return 0; +} + +int __init +cdl_register_subpacket_handler(struct el_subpacket_handler *new) +{ + struct el_subpacket_handler *h = subpacket_handler_list; + + if (h == NULL) subpacket_handler_list = new; + else { + for(; h->next != NULL; h = h->next) { + if (h->class == new->class || h == new) { + printk("Attempted to re-register " + "subpacket handler\n"); + return -EINVAL; + } + } + h->next = new; + } + new->next = NULL; + + return 0; +} + diff -Nru a/arch/alpha/kernel/err_impl.h b/arch/alpha/kernel/err_impl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/alpha/kernel/err_impl.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,148 @@ +/* + * linux/arch/alpha/kernel/err_impl.h + * + * Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation) + * + * Contains declarations and macros to support Alpha error handling + * implementations. + */ + +/* + * SCB Vector definitions + */ +#define SCB_Q_SYSERR 0x620 +#define SCB_Q_PROCERR 0x630 +#define SCB_Q_SYSMCHK 0x660 +#define SCB_Q_PROCMCHK 0x670 +#define SCB_Q_SYSEVENT 0x680 + +/* + * Disposition definitions for logout frame parser + */ +#define MCHK_DISPOSITION_UNKNOWN_ERROR 0x00 +#define MCHK_DISPOSITION_REPORT 0x01 +#define MCHK_DISPOSITION_DISMISS 0x02 + +/* + * Error Log definitions + */ +/* + * Types + */ + +#define EL_CLASS__TERMINATION (0) +# define EL_TYPE__TERMINATION__TERMINATION (0) +#define EL_CLASS__HEADER (5) +# define EL_TYPE__HEADER__SYSTEM_ERROR_FRAME (1) +# define EL_TYPE__HEADER__SYSTEM_EVENT_FRAME (2) +# define EL_TYPE__HEADER__HALT_FRAME (3) +# define EL_TYPE__HEADER__LOGOUT_FRAME (19) +#define EL_CLASS__GENERAL_NOTIFICATION (9) +#define EL_CLASS__PCI_ERROR_FRAME (11) +#define EL_CLASS__REGATTA_FAMILY (12) +# define EL_TYPE__REGATTA__PROCESSOR_ERROR_FRAME (1) +# define EL_TYPE__REGATTA__SYSTEM_ERROR_FRAME (2) +# define EL_TYPE__REGATTA__ENVIRONMENTAL_FRAME (3) +# define EL_TYPE__REGATTA__TITAN_PCHIP0_EXTENDED (8) +# define EL_TYPE__REGATTA__TITAN_PCHIP1_EXTENDED (9) +# define EL_TYPE__REGATTA__TITAN_MEMORY_EXTENDED (10) +# define EL_TYPE__REGATTA__PROCESSOR_DBL_ERROR_HALT (11) +# define EL_TYPE__REGATTA__SYSTEM_DBL_ERROR_HALT (12) +#define EL_CLASS__PAL (14) +# define EL_TYPE__PAL__LOGOUT_FRAME (1) +# define EL_TYPE__PAL__EV7_PROCESSOR (4) +# define EL_TYPE__PAL__EV7_ZBOX (5) +# define EL_TYPE__PAL__EV7_RBOX (6) +# define EL_TYPE__PAL__EV7_IO (7) + +union el_timestamp { + struct { + u8 second; + u8 minute; + u8 hour; + u8 day; + u8 month; + u8 year; + } b; + u64 as_int; +}; + +struct el_subpacket { + u16 length; /* length of header (in bytes) */ + u16 class; /* header class and type... */ + u16 type; /* ...determine content */ + u16 revision; /* header revision */ + union { + struct { /* Class 5, Type 1 - System Error */ + u32 frame_length; + u32 frame_packet_count; + } sys_err; + struct { /* Class 5, Type 2 - System Event */ + union el_timestamp timestamp; + u32 frame_length; + u32 frame_packet_count; + } sys_event; + struct { /* Class 5, Type 3 - Double Error Halt */ + u16 halt_code; + u16 reserved; + union el_timestamp timestamp; + u32 frame_length; + u32 frame_packet_count; + } err_halt; + struct { /* Clasee 5, Type 19 - Logout Frame Header */ + u32 frame_length; + u32 frame_flags; + u32 cpu_offset; + u32 system_offset; + } logout_header; + struct { /* Class 12 - Regatta */ + u64 cpuid; + u64 data_start[1]; + } regatta_frame; + struct { /* Raw */ + u64 data_start[1]; + } raw; + } by_type; +}; + +struct el_subpacket_annotation { + struct el_subpacket_annotation *next; + u16 class; + u16 type; + u16 revision; + char *description; + char **annotation; +}; +#define SUBPACKET_ANNOTATION(c, t, r, d, a) {NULL, (c), (t), (r), (d), (a)} + +struct el_subpacket_handler { + struct el_subpacket_handler *next; + u16 class; + struct el_subpacket *(*handler)(struct el_subpacket *); +}; +#define SUBPACKET_HANDLER_INIT(c, h) {NULL, (c), (h)} + +/* + * Extract a field from a register given it's name. defines + * for the LSB (__S - shift count) and bitmask (__M) are required + */ +#define EXTRACT(u, f) (((u) >> f##__S) & f##__M) + +/* + * err_common.c + */ +extern char *err_print_prefix; + +extern void mchk_dump_mem(void *, int, char **); +extern void mchk_dump_logout_frame(struct el_common *); +extern void ev7_register_error_handlers(void); +extern void ev7_machine_check(u64, u64, struct pt_regs *); +extern void ev6_register_error_handlers(void); +extern int ev6_process_logout_frame(struct el_common *, int); +extern void ev6_machine_check(u64, u64, struct pt_regs *); +extern struct el_subpacket *el_process_subpacket(struct el_subpacket *); +extern void el_annotate_subpacket(struct el_subpacket *); +extern void cdl_check_console_data_log(void); +extern int cdl_register_subpacket_annotation(struct el_subpacket_annotation *); +extern int cdl_register_subpacket_handler(struct el_subpacket_handler *); + diff -Nru a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c --- a/arch/alpha/kernel/irq.c Mon Nov 4 14:31:02 2002 +++ b/arch/alpha/kernel/irq.c Mon Nov 4 14:31:02 2002 @@ -528,7 +528,7 @@ #else for (j = 0; j < NR_CPUS; j++) if (cpu_online(j)) - seq_printf(p, "%10u ", kstat.irqs[j][i]); + seq_printf(p, "%10u ", kstat_cpu(i).irqs[j]); #endif seq_printf(p, " %14s", irq_desc[i].handler->typename); seq_printf(p, " %c%s", @@ -590,7 +590,7 @@ } irq_enter(); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; spin_lock_irq(&desc->lock); /* mask also the higher prio events */ desc->handler->ack(irq); /* diff -Nru a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c --- a/arch/alpha/kernel/irq_alpha.c Mon Nov 4 14:31:01 2002 +++ b/arch/alpha/kernel/irq_alpha.c Mon Nov 4 14:31:01 2002 @@ -59,7 +59,7 @@ smp_percpu_timer_interrupt(®s); cpu = smp_processor_id(); if (cpu != boot_cpuid) { - kstat.irqs[cpu][RTC_IRQ]++; + kstat_cpu(cpu).irqs[RTC_IRQ]++; } else { handle_irq(RTC_IRQ, ®s); } @@ -147,10 +147,10 @@ mchk_header = (struct el_common *)la_ptr; - printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%lx\n", + printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%x\n", machine, vector, regs->pc, mchk_header->code); - switch ((unsigned int) mchk_header->code) { + switch (mchk_header->code) { /* Machine check reasons. Defined according to PALcode sources. */ case 0x80: reason = "tag parity error"; break; case 0x82: reason = "tag control parity error"; break; diff -Nru a/arch/alpha/kernel/irq_impl.h b/arch/alpha/kernel/irq_impl.h --- a/arch/alpha/kernel/irq_impl.h Mon Nov 4 14:31:03 2002 +++ b/arch/alpha/kernel/irq_impl.h Mon Nov 4 14:31:03 2002 @@ -10,6 +10,7 @@ #include #include +#include #define RTC_IRQ 8 diff -Nru a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c --- a/arch/alpha/kernel/osf_sys.c Mon Nov 4 14:31:00 2002 +++ b/arch/alpha/kernel/osf_sys.c Mon Nov 4 14:31:00 2002 @@ -844,7 +844,7 @@ { switch (op) { case SSI_IEEE_FP_CONTROL: { - unsigned long swcr, fpcr; + unsigned long swcr, fpcr, fex; /* * Alpha Architecture Handbook 4.7.7.3: @@ -867,9 +867,24 @@ wrfpcr(fpcr); /* If any exceptions are now unmasked, send a signal. */ - if (((swcr & IEEE_STATUS_MASK) - >> IEEE_STATUS_TO_EXCSUM_SHIFT) & swcr) { - send_sig(SIGFPE, current, 1); + fex = ((swcr & IEEE_STATUS_MASK) + >> IEEE_STATUS_TO_EXCSUM_SHIFT) & swcr; + if (fex) { + siginfo_t info; + int si_code = 0; + + if (fex & IEEE_TRAP_ENABLE_DNO) si_code = FPE_FLTUND; + if (fex & IEEE_TRAP_ENABLE_INE) si_code = FPE_FLTRES; + if (fex & IEEE_TRAP_ENABLE_UNF) si_code = FPE_FLTUND; + if (fex & IEEE_TRAP_ENABLE_OVF) si_code = FPE_FLTOVF; + if (fex & IEEE_TRAP_ENABLE_DZE) si_code = FPE_FLTDIV; + if (fex & IEEE_TRAP_ENABLE_INV) si_code = FPE_FLTINV; + + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = si_code; + info.si_addr = 0; /* FIXME */ + send_sig_info(SIGFPE, &info, current); } return 0; diff -Nru a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c --- a/arch/alpha/kernel/pci.c Mon Nov 4 14:31:00 2002 +++ b/arch/alpha/kernel/pci.c Mon Nov 4 14:31:00 2002 @@ -117,6 +117,18 @@ } } +/* Called for each device after PCI setup is done. */ +static void __init +pcibios_fixup_final(struct pci_dev *dev) +{ + unsigned int class = dev->class >> 8; + + if (class == PCI_CLASS_BRIDGE_ISA || class == PCI_CLASS_BRIDGE_ISA) { + dev->dma_mask = MAX_ISA_DMA_ADDRESS - 1; + isa_bridge = dev; + } +} + struct pci_fixup pcibios_fixups[] __initdata = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge }, @@ -126,6 +138,8 @@ quirk_ali_ide_ports }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, quirk_cypress }, + { PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, + pcibios_fixup_final }, { 0 } }; diff -Nru a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c --- a/arch/alpha/kernel/pci_iommu.c Mon Nov 4 14:31:02 2002 +++ b/arch/alpha/kernel/pci_iommu.c Mon Nov 4 14:31:02 2002 @@ -30,9 +30,7 @@ #define DEBUG_NODIRECT 0 #define DEBUG_FORCEDAC 0 -/* Most Alphas support 32-bit ISA DMA. Exceptions are XL, Ruffian, - Nautilus, Sable, and Alcor (see asm-alpha/dma.h for details). */ -#define ISA_DMA_MASK (MAX_DMA_ADDRESS - IDENT_ADDR - 1) +#define ISA_DMA_MASK 0x00ffffff static inline unsigned long mk_iommu_pte(unsigned long paddr) @@ -189,6 +187,7 @@ long npages, dma_ofs, i; unsigned long paddr; dma_addr_t ret; + unsigned int align = 0; paddr = __pa(cpu_addr); @@ -216,27 +215,27 @@ } /* If the machine doesn't define a pci_tbi routine, we have to - assume it doesn't support sg mapping. */ + assume it doesn't support sg mapping, and, since we tried to + use direct_map above, it now must be considered an error. */ if (! alpha_mv.mv_pci_tbi) { - static int been_here = 0; + static int been_here = 0; /* Only print the message once. */ if (!been_here) { - printk(KERN_WARNING "pci_map_single: no hw sg, using " - "direct map when possible\n"); + printk(KERN_WARNING "pci_map_single: no HW sg\n"); been_here = 1; } - if (paddr + size <= __direct_map_size) - return (paddr + __direct_map_base); - else - return 0; + return 0; } - + arena = hose->sg_pci; if (!arena || arena->dma_base + arena->size - 1 > max_dma) arena = hose->sg_isa; npages = calc_npages((paddr & ~PAGE_MASK) + size); - /* Force allocation to 64KB boundary for all ISA devices. */ - dma_ofs = iommu_arena_alloc(arena, npages, pdev ? 8 : 0); + + /* Force allocation to 64KB boundary for ISA bridges. */ + if (pdev && pdev == isa_bridge) + align = 8; + dma_ofs = iommu_arena_alloc(arena, npages, align); if (dma_ofs < 0) { printk(KERN_WARNING "pci_map_single failed: " "could not allocate dma page tables\n"); @@ -364,8 +363,10 @@ { void *cpu_addr; long order = get_order(size); + int gfp = GFP_ATOMIC; - cpu_addr = (void *)__get_free_pages(GFP_ATOMIC, order); +try_again: + cpu_addr = (void *)__get_free_pages(gfp, order); if (! cpu_addr) { printk(KERN_INFO "pci_alloc_consistent: " "get_free_pages failed from %p\n", @@ -379,7 +380,12 @@ *dma_addrp = pci_map_single_1(pdev, cpu_addr, size, 0); if (*dma_addrp == 0) { free_pages((unsigned long)cpu_addr, order); - return NULL; + if (alpha_mv.mv_pci_tbi || (gfp & GFP_DMA)) + return NULL; + /* The address doesn't fit required mask and we + do not have iommu. Try again with GFP_DMA. */ + gfp |= GFP_DMA; + goto try_again; } DBGA2("pci_alloc_consistent: %lx -> [%p,%x] from %p\n", @@ -727,8 +733,8 @@ the entire direct mapped space or the total system memory as shifted by the map base */ if (__direct_map_size != 0 - && (__direct_map_base + __direct_map_size - 1 <= mask - || __direct_map_base + (max_low_pfn<sg_pci; if (arena && arena->dma_base + arena->size - 1 <= mask) + return 1; + + /* As last resort try ZONE_DMA. */ + if (!__direct_map_base && MAX_DMA_ADDRESS - IDENT_ADDR - 1 <= mask) return 1; return 0; diff -Nru a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c --- a/arch/alpha/kernel/process.c Mon Nov 4 14:31:02 2002 +++ b/arch/alpha/kernel/process.c Mon Nov 4 14:31:02 2002 @@ -245,11 +245,10 @@ */ int alpha_clone(unsigned long clone_flags, unsigned long usp, - struct switch_stack * swstack) + int *user_tid, struct switch_stack * swstack) { struct task_struct *p; struct pt_regs *u_regs = (struct pt_regs *) (swstack+1); - int *user_tid = (int *)u_regs->r19; if (!usp) usp = rdusp(); @@ -313,6 +312,16 @@ childti->pcb.usp = usp; childti->pcb.ksp = (unsigned long) childstack; childti->pcb.flags = 1; /* set FEN, clear everything else */ + + /* Set a new TLS for the child thread? Peek back into the + syscall arguments that we saved on syscall entry. */ + /* Note: if CLONE_SETTLS is not set, then we must inherit the + value from the parent, which will have been set by the block + copy in dup_task_struct. This is non-intuitive, but is + required for proper operation in the case of a threaded + application calling fork. */ + if (clone_flags & CLONE_SETTLS) + childti->pcb.unique = regs->r19; return 0; } diff -Nru a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h --- a/arch/alpha/kernel/proto.h Mon Nov 4 14:31:01 2002 +++ b/arch/alpha/kernel/proto.h Mon Nov 4 14:31:01 2002 @@ -24,6 +24,7 @@ extern void cia_init_pci(void); extern void cia_init_arch(void); extern void pyxis_init_arch(void); +extern void cia_kill_arch(int); extern void cia_machine_check(u64, u64, struct pt_regs *); extern void cia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t); diff -Nru a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c --- a/arch/alpha/kernel/ptrace.c Mon Nov 4 14:31:02 2002 +++ b/arch/alpha/kernel/ptrace.c Mon Nov 4 14:31:02 2002 @@ -383,7 +383,7 @@ goto out; default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); goto out; } out: @@ -400,7 +400,8 @@ return; if (!(current->ptrace & PT_PTRACED)) return; - current->exit_code = SIGTRAP; + current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0); current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); diff -Nru a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c --- a/arch/alpha/kernel/signal.c Mon Nov 4 14:31:01 2002 +++ b/arch/alpha/kernel/signal.c Mon Nov 4 14:31:01 2002 @@ -293,8 +293,16 @@ goto give_sigsegv; /* Send SIGTRAP if we're single-stepping: */ - if (ptrace_cancel_bpt (current)) - send_sig(SIGTRAP, current, 1); + if (ptrace_cancel_bpt (current)) { + siginfo_t info; + + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_BRKPT; + info.si_addr = (void *) regs->pc; + info.si_trapno = 0; + send_sig_info(SIGTRAP, &info, current); + } return; give_sigsegv: @@ -330,8 +338,16 @@ do_sigaltstack(&st, NULL, rdusp()); /* Send SIGTRAP if we're single-stepping: */ - if (ptrace_cancel_bpt (current)) - send_sig(SIGTRAP, current, 1); + if (ptrace_cancel_bpt (current)) { + siginfo_t info; + + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_BRKPT; + info.si_addr = (void *) regs->pc; + info.si_trapno = 0; + send_sig_info(SIGTRAP, &info, current); + } return; give_sigsegv: diff -Nru a/arch/alpha/kernel/sys_alcor.c b/arch/alpha/kernel/sys_alcor.c --- a/arch/alpha/kernel/sys_alcor.c Mon Nov 4 14:31:01 2002 +++ b/arch/alpha/kernel/sys_alcor.c Mon Nov 4 14:31:01 2002 @@ -221,6 +221,8 @@ static void alcor_kill_arch(int mode) { + cia_kill_arch(mode); + switch(mode) { case LINUX_REBOOT_CMD_RESTART: /* Who said DEC engineer's have no sense of humor? ;-) */ @@ -251,7 +253,7 @@ DO_CIA_IO, DO_CIA_BUS, .machine_check = cia_machine_check, - .max_dma_address = ALPHA_ALCOR_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_ALCOR_MAX_ISA_DMA_ADDRESS, .min_io_address = EISA_DEFAULT_IO_BASE, .min_mem_address = CIA_DEFAULT_MEM_BASE, @@ -281,7 +283,7 @@ DO_CIA_IO, DO_CIA_BUS, .machine_check = cia_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = EISA_DEFAULT_IO_BASE, .min_mem_address = CIA_DEFAULT_MEM_BASE, diff -Nru a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c --- a/arch/alpha/kernel/sys_cabriolet.c Mon Nov 4 14:31:01 2002 +++ b/arch/alpha/kernel/sys_cabriolet.c Mon Nov 4 14:31:01 2002 @@ -327,7 +327,7 @@ DO_APECS_IO, DO_APECS_BUS, .machine_check = apecs_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, @@ -338,7 +338,6 @@ .init_irq = cabriolet_init_irq, .init_rtc = common_init_rtc, .init_pci = cabriolet_init_pci, - .kill_arch = NULL, .pci_map_irq = cabriolet_map_irq, .pci_swizzle = common_swizzle, }; @@ -355,7 +354,7 @@ DO_CIA_IO, DO_CIA_BUS, .machine_check = cia_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = CIA_DEFAULT_MEM_BASE, @@ -366,6 +365,7 @@ .init_irq = cabriolet_init_irq, .init_rtc = common_init_rtc, .init_pci = cia_cab_init_pci, + .kill_arch = cia_kill_arch, .pci_map_irq = cabriolet_map_irq, .pci_swizzle = common_swizzle, }; @@ -380,7 +380,7 @@ DO_LCA_IO, DO_LCA_BUS, .machine_check = lca_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, @@ -405,7 +405,7 @@ DO_PYXIS_IO, DO_CIA_BUS, .machine_check = cia_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = DEFAULT_MEM_BASE, .pci_dac_offset = PYXIS_DAC_OFFSET, @@ -417,6 +417,7 @@ .init_irq = cabriolet_init_irq, .init_rtc = common_init_rtc, .init_pci = alphapc164_init_pci, + .kill_arch = cia_kill_arch, .pci_map_irq = alphapc164_map_irq, .pci_swizzle = common_swizzle, }; @@ -431,7 +432,7 @@ DO_CIA_IO, DO_CIA_BUS, .machine_check = cia_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = CIA_DEFAULT_MEM_BASE, @@ -442,6 +443,7 @@ .init_irq = pc164_init_irq, .init_rtc = common_init_rtc, .init_pci = alphapc164_init_pci, + .kill_arch = cia_kill_arch, .pci_map_irq = alphapc164_map_irq, .pci_swizzle = common_swizzle, }; diff -Nru a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c --- a/arch/alpha/kernel/sys_dp264.c Mon Nov 4 14:31:01 2002 +++ b/arch/alpha/kernel/sys_dp264.c Mon Nov 4 14:31:01 2002 @@ -572,7 +572,7 @@ DO_TSUNAMI_IO, DO_TSUNAMI_BUS, .machine_check = tsunami_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = DEFAULT_MEM_BASE, .pci_dac_offset = TSUNAMI_DAC_OFFSET, @@ -597,7 +597,7 @@ DO_TSUNAMI_IO, DO_TSUNAMI_BUS, .machine_check = tsunami_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = DEFAULT_MEM_BASE, .pci_dac_offset = TSUNAMI_DAC_OFFSET, @@ -621,7 +621,7 @@ DO_TSUNAMI_IO, DO_TSUNAMI_BUS, .machine_check = tsunami_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = DEFAULT_MEM_BASE, .pci_dac_offset = TSUNAMI_DAC_OFFSET, @@ -645,7 +645,7 @@ DO_TSUNAMI_IO, DO_TSUNAMI_BUS, .machine_check = tsunami_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = DEFAULT_MEM_BASE, .pci_dac_offset = TSUNAMI_DAC_OFFSET, @@ -674,7 +674,7 @@ DO_TSUNAMI_IO, DO_TSUNAMI_BUS, .machine_check = tsunami_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = DEFAULT_MEM_BASE, .pci_dac_offset = TSUNAMI_DAC_OFFSET, diff -Nru a/arch/alpha/kernel/sys_eb64p.c b/arch/alpha/kernel/sys_eb64p.c --- a/arch/alpha/kernel/sys_eb64p.c Mon Nov 4 14:31:02 2002 +++ b/arch/alpha/kernel/sys_eb64p.c Mon Nov 4 14:31:02 2002 @@ -214,7 +214,7 @@ DO_APECS_IO, DO_APECS_BUS, .machine_check = apecs_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, @@ -240,7 +240,7 @@ DO_LCA_IO, DO_LCA_BUS, .machine_check = lca_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, diff -Nru a/arch/alpha/kernel/sys_eiger.c b/arch/alpha/kernel/sys_eiger.c --- a/arch/alpha/kernel/sys_eiger.c Mon Nov 4 14:31:00 2002 +++ b/arch/alpha/kernel/sys_eiger.c Mon Nov 4 14:31:00 2002 @@ -231,7 +231,7 @@ DO_TSUNAMI_IO, DO_TSUNAMI_BUS, .machine_check = tsunami_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = DEFAULT_MEM_BASE, .pci_dac_offset = TSUNAMI_DAC_OFFSET, diff -Nru a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c --- a/arch/alpha/kernel/sys_jensen.c Mon Nov 4 14:31:02 2002 +++ b/arch/alpha/kernel/sys_jensen.c Mon Nov 4 14:31:02 2002 @@ -219,6 +219,11 @@ jensen_init_arch(void) { struct pci_controller *hose; +#ifdef CONFIG_PCI + static struct pci_dev fake_isa_bridge = { dma_mask: 0xffffffffUL, }; + + isa_bridge = &fake_isa_bridge; +#endif /* Create a hose so that we can report i/o base addresses to userland. */ @@ -257,7 +262,7 @@ IO_LITE(JENSEN,jensen), BUS(jensen), .machine_check = jensen_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .rtc_port = 0x170, .nr_irqs = 16, diff -Nru a/arch/alpha/kernel/sys_miata.c b/arch/alpha/kernel/sys_miata.c --- a/arch/alpha/kernel/sys_miata.c Mon Nov 4 14:31:02 2002 +++ b/arch/alpha/kernel/sys_miata.c Mon Nov 4 14:31:02 2002 @@ -238,6 +238,8 @@ static void miata_kill_arch(int mode) { + cia_kill_arch(mode); + switch(mode) { case LINUX_REBOOT_CMD_RESTART: /* Who said DEC engineers have no sense of humor? ;-) */ @@ -267,7 +269,7 @@ DO_PYXIS_IO, DO_CIA_BUS, .machine_check = cia_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = DEFAULT_MEM_BASE, .pci_dac_offset = PYXIS_DAC_OFFSET, diff -Nru a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c --- a/arch/alpha/kernel/sys_mikasa.c Mon Nov 4 14:31:02 2002 +++ b/arch/alpha/kernel/sys_mikasa.c Mon Nov 4 14:31:02 2002 @@ -223,7 +223,7 @@ DO_APECS_IO, DO_APECS_BUS, .machine_check = mikasa_apecs_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, @@ -234,7 +234,6 @@ .init_irq = mikasa_init_irq, .init_rtc = common_init_rtc, .init_pci = common_init_pci, - .kill_arch = NULL, .pci_map_irq = mikasa_map_irq, .pci_swizzle = common_swizzle, }; @@ -249,7 +248,7 @@ DO_CIA_IO, DO_CIA_BUS, .machine_check = cia_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = CIA_DEFAULT_MEM_BASE, @@ -260,6 +259,7 @@ .init_irq = mikasa_init_irq, .init_rtc = common_init_rtc, .init_pci = cia_init_pci, + .kill_arch = cia_kill_arch, .pci_map_irq = mikasa_map_irq, .pci_swizzle = common_swizzle, }; diff -Nru a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c --- a/arch/alpha/kernel/sys_nautilus.c Mon Nov 4 14:31:01 2002 +++ b/arch/alpha/kernel/sys_nautilus.c Mon Nov 4 14:31:01 2002 @@ -46,6 +46,7 @@ #include #include "proto.h" +#include "err_impl.h" #include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" @@ -100,317 +101,6 @@ } } -/* Machine check handler code - * - * Perform analysis of a machine check that was triggered by the EV6 - * CPU's fault-detection mechanism. - */ - -/* IPR structures for EV6, containing the necessary data for the - * machine check handler to unpick the logout frame - */ - -/* I_STAT */ - -#define EV6__I_STAT__PAR ( 1 << 29 ) - -/* MM_STAT */ - -#define EV6__MM_STAT__DC_TAG_PERR ( 1 << 10 ) - -/* DC_STAT */ - -#define EV6__DC_STAT__SEO ( 1 << 4 ) -#define EV6__DC_STAT__ECC_ERR_LD ( 1 << 3 ) -#define EV6__DC_STAT__ECC_ERR_ST ( 1 << 2 ) -#define EV6__DC_STAT__TPERR_P1 ( 1 << 1 ) -#define EV6__DC_STAT__TPERR_P0 ( 1 ) - -/* C_STAT */ - -#define EV6__C_STAT__BC_PERR ( 0x01 ) -#define EV6__C_STAT__DC_PERR ( 0x02 ) -#define EV6__C_STAT__DSTREAM_MEM_ERR ( 0x03 ) -#define EV6__C_STAT__DSTREAM_BC_ERR ( 0x04 ) -#define EV6__C_STAT__DSTREAM_DC_ERR ( 0x05 ) -#define EV6__C_STAT__PROBE_BC_ERR0 ( 0x06 ) -#define EV6__C_STAT__PROBE_BC_ERR1 ( 0x07 ) -#define EV6__C_STAT__ISTREAM_MEM_ERR ( 0x0B ) -#define EV6__C_STAT__ISTREAM_BC_ERR ( 0x0C ) -#define EV6__C_STAT__DSTREAM_MEM_DBL ( 0x13 ) -#define EV6__C_STAT__DSTREAM_BC_DBL ( 0x14 ) -#define EV6__C_STAT__ISTREAM_MEM_DBL ( 0x1B ) -#define EV6__C_STAT__ISTREAM_BC_DBL ( 0x1C ) - - -/* Take the two syndromes from the CBOX error chain and convert them - * into a bit number. */ - -/* NOTE - since I don't know of any difference between C0 and C1 I - just ignore C1, since in all cases I've seen so far they are - identical. */ - -static const unsigned char ev6_bit_to_syndrome[72] = -{ - 0xce, 0xcb, 0xd3, 0xd5, 0xd6, 0xd9, 0xda, 0xdc, /* 0 */ - 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x31, 0x34, /* 8 */ - 0x0e, 0x0b, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c, /* 16 */ - 0xe3, 0xe5, 0xe6, 0xe9, 0xea, 0xec, 0xf1, 0xf4, /* 24 */ - 0x4f, 0x4a, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d, /* 32 */ - 0xa2, 0xa4, 0xa7, 0xa8, 0xab, 0xad, 0xb0, 0xb5, /* 40 */ - 0x8f, 0x8a, 0x92, 0x94, 0x97, 0x98, 0x9b, 0x9d, /* 48 */ - 0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x70, 0x75, /* 56 */ - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 /* 64 */ -}; - - -static int ev6_syn2bit(unsigned long c0, unsigned long c1) -{ - int bit; - - for (bit = 0; bit < 72; bit++) - if (ev6_bit_to_syndrome[bit] == c0) return bit; - for (bit = 0; bit < 72; bit++) - if (ev6_bit_to_syndrome[bit] == c1) return bit + 64; - - return -1; /* not found */ -} - - -/* Single bit ECC errors are categorized here. */ - -#if 0 -static const char *interr = "CPU internal error"; -static const char *slotb= "Slot-B error"; -static const char *membus= "Memory/EV6-bus error"; -#else -static const char *interr = ""; -static const char *slotb = ""; -static const char *membus = ""; -#endif - -static void -ev6_crd_interp(char *interp, struct el_common_EV6_mcheck * L) -{ - /* Icache data or tag parity error. */ - if (L->I_STAT & EV6__I_STAT__PAR) { - sprintf(interp, "%s: I_STAT[PAR]\n " - "Icache data or tag parity error", interr); - return; - } - - /* Dcache tag parity error (on issue) (DFAULT). */ - if (L->MM_STAT & EV6__MM_STAT__DC_TAG_PERR) { - sprintf(interp, "%s: MM_STAT[DC_TAG_PERR]\n " - "Dcache tag parity error(on issue)", interr); - return; - } - - /* Errors relating to D-stream set non-zero DC_STAT. - Mask CRD bits. */ - switch (L->DC_STAT & (EV6__DC_STAT__ECC_ERR_ST - | EV6__DC_STAT__ECC_ERR_LD)) { - case EV6__DC_STAT__ECC_ERR_ST: - /* Dcache single-bit ECC error on small store */ - sprintf(interp, "%s: DC_STAT[ECC_ERR_ST]\n " - "Dcache single-bit ECC error on small store", interr); - return; - - case EV6__DC_STAT__ECC_ERR_LD: - switch (L->C_STAT) { - case 0: - /* Dcache single-bit error on speculative load */ - /* Bcache victim read on Dcache/Bcache miss */ - sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT=0\n " - "Dcache single-bit ECC error on speculative load", - slotb); - return; - - case EV6__C_STAT__DSTREAM_DC_ERR: - /* Dcache single bit error on load */ - sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT[DSTREAM_DC_ERR]\n" - " Dcache single-bit ECC error on speculative load, bit %d", - interr, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME)); - return; - - case EV6__C_STAT__DSTREAM_BC_ERR: - /* Bcache single-bit error on Dcache fill */ - sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT[DSTREAM_BC_ERR]\n" - " Bcache single-bit error on Dcache fill, bit %d", - slotb, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME)); - return; - - case EV6__C_STAT__DSTREAM_MEM_ERR: - /* Memory single-bit error on Dcache fill */ - sprintf(interp, "%s (to Dcache): DC_STAT[ECC_ERR_LD] " - "C_STAT[DSTREAM_MEM_ERR]\n " - "Memory single-bit error on Dcache fill, " - "Address 0x%lX, bit %d", - membus, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME, - L->DC1_SYNDROME)); - return; - } - } - - /* I-stream, other misc errors go on C_STAT alone */ - switch (L->C_STAT) { - case EV6__C_STAT__ISTREAM_BC_ERR: - /* Bcache single-bit error on Icache fill (also MCHK) */ - sprintf(interp, "%s: C_STAT[ISTREAM_BC_ERR]\n " - "Bcache single-bit error on Icache fill, bit %d", - slotb, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME)); - return; - - case EV6__C_STAT__ISTREAM_MEM_ERR: - /* Memory single-bit error on Icache fill (also MCHK) */ - sprintf(interp, "%s : C_STATISTREAM_MEM_ERR]\n " - "Memory single-bit error on Icache fill " - "addr 0x%lX, bit %d", - membus, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME, - L->DC1_SYNDROME)); - return; - - case EV6__C_STAT__PROBE_BC_ERR0: - case EV6__C_STAT__PROBE_BC_ERR1: - /* Bcache single-bit error on a probe hit */ - sprintf(interp, "%s: C_STAT[PROBE_BC_ERR]\n " - "Bcache single-bit error on a probe hit, " - "addr 0x%lx, bit %d", - slotb, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME, - L->DC1_SYNDROME)); - return; - } -} - -static void -ev6_mchk_interp(char *interp, struct el_common_EV6_mcheck * L) -{ - /* Machine check errors described by DC_STAT */ - switch (L->DC_STAT) { - case EV6__DC_STAT__TPERR_P0: - case EV6__DC_STAT__TPERR_P1: - /* Dcache tag parity error (on retry) */ - sprintf(interp, "%s: DC_STAT[TPERR_P0|TPERR_P1]\n " - "Dcache tag parity error(on retry)", interr); - return; - - case EV6__DC_STAT__SEO: - /* Dcache second error on store */ - sprintf(interp, "%s: DC_STAT[SEO]\n " - "Dcache second error during mcheck", interr); - return; - } - - /* Machine check errors described by C_STAT */ - switch (L->C_STAT) { - case EV6__C_STAT__DC_PERR: - /* Dcache duplicate tag parity error */ - sprintf(interp, "%s: C_STAT[DC_PERR]\n " - "Dcache duplicate tag parity error at 0x%lX", - interr, L->C_ADDR); - return; - - case EV6__C_STAT__BC_PERR: - /* Bcache tag parity error */ - sprintf(interp, "%s: C_STAT[BC_PERR]\n " - "Bcache tag parity error at 0x%lX", - slotb, L->C_ADDR); - return; - - case EV6__C_STAT__ISTREAM_BC_ERR: - /* Bcache single-bit error on Icache fill (also CRD) */ - sprintf(interp, "%s: C_STAT[ISTREAM_BC_ERR]\n " - "Bcache single-bit error on Icache fill 0x%lX bit %d", - slotb, L->C_ADDR, - ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME)); - return; - - - case EV6__C_STAT__ISTREAM_MEM_ERR: - /* Memory single-bit error on Icache fill (also CRD) */ - sprintf(interp, "%s: C_STAT[ISTREAM_MEM_ERR]\n " - "Memory single-bit error on Icache fill 0x%lX, bit %d", - membus, L->C_ADDR, - ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME)); - return; - - - case EV6__C_STAT__ISTREAM_BC_DBL: - /* Bcache double-bit error on Icache fill */ - sprintf(interp, "%s: C_STAT[ISTREAM_BC_DBL]\n " - "Bcache double-bit error on Icache fill at 0x%lX", - slotb, L->C_ADDR); - return; - case EV6__C_STAT__DSTREAM_BC_DBL: - /* Bcache double-bit error on Dcache fill */ - sprintf(interp, "%s: C_STAT[DSTREAM_BC_DBL]\n " - "Bcache double-bit error on Dcache fill at 0x%lX", - slotb, L->C_ADDR); - return; - - case EV6__C_STAT__ISTREAM_MEM_DBL: - /* Memory double-bit error on Icache fill */ - sprintf(interp, "%s: C_STAT[ISTREAM_MEM_DBL]\n " - "Memory double-bit error on Icache fill at 0x%lX", - membus, L->C_ADDR); - return; - - case EV6__C_STAT__DSTREAM_MEM_DBL: - /* Memory double-bit error on Dcache fill */ - sprintf(interp, "%s: C_STAT[DSTREAM_MEM_DBL]\n " - "Memory double-bit error on Dcache fill at 0x%lX", - membus, L->C_ADDR); - return; - } -} - -static void -ev6_cpu_machine_check(unsigned long vector, struct el_common_EV6_mcheck *L, - struct pt_regs *regs) -{ - char interp[80]; - - /* This is verbose and looks intimidating. Should it be printed for - corrected (CRD) machine checks? */ - - printk(KERN_CRIT "PALcode logout frame: " - "MCHK_Code %d " - "MCHK_Frame_Rev %d\n" - "I_STAT %016lx " - "DC_STAT %016lx " - "C_ADDR %016lx\n" - "SYND1 %016lx " - "SYND0 %016lx " - "C_STAT %016lx\n" - "C_STS %016lx " - "RES %016lx " - "EXC_ADDR%016lx\n" - "IER_CM %016lx " - "ISUM %016lx " - "MM_STAT %016lx\n" - "PALBASE %016lx " - "I_CTL %016lx " - "PCTX %016lx\n" - "CPU registers: " - "PC %016lx " - "Return %016lx\n", - L->MCHK_Code, L->MCHK_Frame_Rev, L->I_STAT, L->DC_STAT, - L->C_ADDR, L->DC1_SYNDROME, L->DC0_SYNDROME, L->C_STAT, - L->C_STS, L->RESERVED0, L->EXC_ADDR, L->IER_CM, L->ISUM, - L->MM_STAT, L->PAL_BASE, L->I_CTL, L->PCTX, - regs->pc, regs->r26); - - /* Attempt an interpretation on the meanings of the fields above. */ - sprintf(interp, "No interpretation available!" ); - if (vector == SCB_Q_PROCERR) - ev6_crd_interp(interp, L); - else if (vector == SCB_Q_PROCMCHK) - ev6_mchk_interp(interp, L); - - printk(KERN_CRIT "interpretation: %s\n\n", interp); -} - - /* Perform analysis of a machine check that arrived from the system (NMI) */ static void @@ -430,7 +120,6 @@ struct pt_regs *regs) { char *mchk_class; - unsigned cpu_analysis=0, sys_analysis=0; /* Now for some analysis. Machine checks fall into two classes -- those picked up by the system, and those picked up by the CPU. @@ -463,39 +152,20 @@ return; } - switch (vector) { - case SCB_Q_SYSERR: - mchk_class = "Correctable System Machine Check (NMI)"; - sys_analysis = 1; - break; - case SCB_Q_SYSMCHK: - mchk_class = "Fatal System Machine Check (NMI)"; - sys_analysis = 1; - break; - - case SCB_Q_PROCERR: - mchk_class = "Correctable Processor Machine Check"; - cpu_analysis = 1; - break; - case SCB_Q_PROCMCHK: - mchk_class = "Fatal Processor Machine Check"; - cpu_analysis = 1; - break; - - default: - mchk_class = "Unknown vector!"; - break; + if (vector == SCB_Q_SYSERR) + mchk_class = "Correctable"; + else if (vector == SCB_Q_SYSMCHK) + mchk_class = "Fatal"; + else { + ev6_machine_check(vector, la_ptr, regs); + return; } - printk(KERN_CRIT "NAUTILUS Machine check 0x%lx [%s]\n", + printk(KERN_CRIT "NAUTILUS Machine check 0x%lx " + "[%s System Machine Check (NMI)]\n", vector, mchk_class); - if (cpu_analysis) - ev6_cpu_machine_check(vector, - (struct el_common_EV6_mcheck *)la_ptr, - regs); - if (sys_analysis) - naut_sys_machine_check(vector, la_ptr, regs); + naut_sys_machine_check(vector, la_ptr, regs); /* Tell the PALcode to clear the machine check */ draina(); @@ -504,7 +174,6 @@ } - /* * The System Vectors */ @@ -516,7 +185,7 @@ DO_IRONGATE_IO, DO_IRONGATE_BUS, .machine_check = nautilus_machine_check, - .max_dma_address = ALPHA_NAUTILUS_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = IRONGATE_DEFAULT_MEM_BASE, diff -Nru a/arch/alpha/kernel/sys_noritake.c b/arch/alpha/kernel/sys_noritake.c --- a/arch/alpha/kernel/sys_noritake.c Mon Nov 4 14:31:01 2002 +++ b/arch/alpha/kernel/sys_noritake.c Mon Nov 4 14:31:01 2002 @@ -305,7 +305,7 @@ DO_APECS_IO, DO_APECS_BUS, .machine_check = noritake_apecs_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = EISA_DEFAULT_IO_BASE, .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, @@ -316,7 +316,6 @@ .init_irq = noritake_init_irq, .init_rtc = common_init_rtc, .init_pci = common_init_pci, - .kill_arch = NULL, .pci_map_irq = noritake_map_irq, .pci_swizzle = noritake_swizzle, }; @@ -331,7 +330,7 @@ DO_CIA_IO, DO_CIA_BUS, .machine_check = cia_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = EISA_DEFAULT_IO_BASE, .min_mem_address = CIA_DEFAULT_MEM_BASE, @@ -342,6 +341,7 @@ .init_irq = noritake_init_irq, .init_rtc = common_init_rtc, .init_pci = cia_init_pci, + .kill_arch = cia_kill_arch, .pci_map_irq = noritake_map_irq, .pci_swizzle = noritake_swizzle, }; diff -Nru a/arch/alpha/kernel/sys_rawhide.c b/arch/alpha/kernel/sys_rawhide.c --- a/arch/alpha/kernel/sys_rawhide.c Mon Nov 4 14:31:02 2002 +++ b/arch/alpha/kernel/sys_rawhide.c Mon Nov 4 14:31:02 2002 @@ -252,7 +252,7 @@ DO_MCPCIA_IO, DO_MCPCIA_BUS, .machine_check = mcpcia_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = MCPCIA_DEFAULT_MEM_BASE, .pci_dac_offset = MCPCIA_DAC_OFFSET, diff -Nru a/arch/alpha/kernel/sys_ruffian.c b/arch/alpha/kernel/sys_ruffian.c --- a/arch/alpha/kernel/sys_ruffian.c Mon Nov 4 14:31:02 2002 +++ b/arch/alpha/kernel/sys_ruffian.c Mon Nov 4 14:31:02 2002 @@ -85,6 +85,7 @@ static void ruffian_kill_arch (int mode) { + cia_kill_arch(mode); #if 0 /* This only causes re-entry to ARCSBIOS */ /* Perhaps this works for other PYXIS as well? */ @@ -218,7 +219,7 @@ DO_PYXIS_IO, DO_CIA_BUS, .machine_check = cia_machine_check, - .max_dma_address = ALPHA_RUFFIAN_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_RUFFIAN_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = DEFAULT_MEM_BASE, .pci_dac_offset = PYXIS_DAC_OFFSET, diff -Nru a/arch/alpha/kernel/sys_rx164.c b/arch/alpha/kernel/sys_rx164.c --- a/arch/alpha/kernel/sys_rx164.c Mon Nov 4 14:31:00 2002 +++ b/arch/alpha/kernel/sys_rx164.c Mon Nov 4 14:31:00 2002 @@ -203,7 +203,7 @@ DO_POLARIS_IO, DO_POLARIS_BUS, .machine_check = polaris_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = DEFAULT_MEM_BASE, diff -Nru a/arch/alpha/kernel/sys_sable.c b/arch/alpha/kernel/sys_sable.c --- a/arch/alpha/kernel/sys_sable.c Mon Nov 4 14:31:00 2002 +++ b/arch/alpha/kernel/sys_sable.c Mon Nov 4 14:31:00 2002 @@ -290,7 +290,7 @@ DO_T2_IO, DO_T2_BUS, .machine_check = t2_machine_check, - .max_dma_address = ALPHA_SABLE_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_SABLE_MAX_ISA_DMA_ADDRESS, .min_io_address = EISA_DEFAULT_IO_BASE, .min_mem_address = T2_DEFAULT_MEM_BASE, @@ -322,7 +322,7 @@ DO_T2_IO, DO_T2_BUS, .machine_check = t2_machine_check, - .max_dma_address = ALPHA_SABLE_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_SABLE_MAX_ISA_DMA_ADDRESS, .min_io_address = EISA_DEFAULT_IO_BASE, .min_mem_address = T2_DEFAULT_MEM_BASE, diff -Nru a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c --- a/arch/alpha/kernel/sys_sio.c Mon Nov 4 14:31:00 2002 +++ b/arch/alpha/kernel/sys_sio.c Mon Nov 4 14:31:00 2002 @@ -258,7 +258,7 @@ DO_LCA_IO, DO_LCA_BUS, .machine_check = lca_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, @@ -289,7 +289,7 @@ DO_APECS_IO, DO_APECS_BUS, .machine_check = apecs_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, @@ -318,7 +318,7 @@ DO_LCA_IO, DO_LCA_BUS, .machine_check = lca_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, @@ -356,7 +356,7 @@ DO_LCA_IO, DO_LCA_BUS, .machine_check = lca_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, @@ -385,7 +385,7 @@ DO_APECS_IO, BUS(apecs), .machine_check = apecs_machine_check, - .max_dma_address = ALPHA_XL_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_XL_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = XL_DEFAULT_MEM_BASE, diff -Nru a/arch/alpha/kernel/sys_sx164.c b/arch/alpha/kernel/sys_sx164.c --- a/arch/alpha/kernel/sys_sx164.c Mon Nov 4 14:31:01 2002 +++ b/arch/alpha/kernel/sys_sx164.c Mon Nov 4 14:31:01 2002 @@ -160,7 +160,7 @@ DO_PYXIS_IO, DO_CIA_BUS, .machine_check = cia_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = DEFAULT_MEM_BASE, .pci_dac_offset = PYXIS_DAC_OFFSET, @@ -172,7 +172,7 @@ .init_irq = sx164_init_irq, .init_rtc = common_init_rtc, .init_pci = sx164_init_pci, - .kill_arch = NULL, + .kill_arch = cia_kill_arch, .pci_map_irq = sx164_map_irq, .pci_swizzle = common_swizzle, }; diff -Nru a/arch/alpha/kernel/sys_takara.c b/arch/alpha/kernel/sys_takara.c --- a/arch/alpha/kernel/sys_takara.c Mon Nov 4 14:31:01 2002 +++ b/arch/alpha/kernel/sys_takara.c Mon Nov 4 14:31:01 2002 @@ -275,7 +275,7 @@ DO_CIA_IO, DO_CIA_BUS, .machine_check = cia_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = CIA_DEFAULT_MEM_BASE, @@ -286,7 +286,7 @@ .init_irq = takara_init_irq, .init_rtc = common_init_rtc, .init_pci = takara_init_pci, - .kill_arch = NULL, + .kill_arch = cia_kill_arch, .pci_map_irq = takara_map_irq, .pci_swizzle = takara_swizzle, }; diff -Nru a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c --- a/arch/alpha/kernel/sys_titan.c Mon Nov 4 14:31:02 2002 +++ b/arch/alpha/kernel/sys_titan.c Mon Nov 4 14:31:02 2002 @@ -306,10 +306,7 @@ { u8 irq; - pcibios_read_config_byte(dev->bus->number, - dev->devfn, - PCI_INTERRUPT_LINE, - &irq); + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); /* is it routed through ISA? */ if ((irq & 0xF0) == 0xE0) @@ -373,7 +370,7 @@ DO_TITAN_IO, DO_TITAN_BUS, .machine_check = privateer_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = DEFAULT_MEM_BASE, .pci_dac_offset = TITAN_DAC_OFFSET, diff -Nru a/arch/alpha/kernel/sys_wildfire.c b/arch/alpha/kernel/sys_wildfire.c --- a/arch/alpha/kernel/sys_wildfire.c Mon Nov 4 14:31:01 2002 +++ b/arch/alpha/kernel/sys_wildfire.c Mon Nov 4 14:31:01 2002 @@ -339,7 +339,7 @@ DO_WILDFIRE_IO, DO_WILDFIRE_BUS, .machine_check = wildfire_machine_check, - .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .min_io_address = DEFAULT_IO_BASE, .min_mem_address = DEFAULT_MEM_BASE, diff -Nru a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c --- a/arch/alpha/kernel/traps.c Mon Nov 4 14:31:02 2002 +++ b/arch/alpha/kernel/traps.c Mon Nov 4 14:31:02 2002 @@ -213,25 +213,25 @@ unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs) { + long si_code = FPE_FLTINV; + siginfo_t info; + if (summary & 1) { /* Software-completion summary bit is set, so try to - emulate the instruction. */ - if (!amask(AMASK_PRECISE_TRAP)) { - /* 21264 (except pass 1) has precise exceptions. */ - if (alpha_fp_emul(regs.pc - 4)) - return; - } else { - if (alpha_fp_emul_imprecise(®s, write_mask)) - return; - } + emulate the instruction. If the processor supports + precise exceptions, we don't have to search. */ + if (!amask(AMASK_PRECISE_TRAP)) + si_code = alpha_fp_emul(regs.pc - 4); + else + si_code = alpha_fp_emul_imprecise(®s, write_mask); } - -#if 0 - printk("%s: arithmetic trap at %016lx: %02lx %016lx\n", - current->comm, regs.pc, summary, write_mask); -#endif die_if_kernel("Arithmetic fault", ®s, 0, 0); - send_sig(SIGFPE, current, 1); + + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = si_code; + info.si_addr = (void *) regs.pc; + send_sig_info(SIGFPE, &info, current); } asmlinkage void @@ -239,6 +239,9 @@ unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs) { + siginfo_t info; + int signo, code; + if (!opDEC_testing || type != 4) { if (type == 1) { const unsigned int *data @@ -253,55 +256,99 @@ switch (type) { case 0: /* breakpoint */ + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_BRKPT; + info.si_trapno = 0; + info.si_addr = (void *) regs.pc; + if (ptrace_cancel_bpt(current)) { regs.pc -= 4; /* make pc point to former bpt */ } - send_sig(SIGTRAP, current, 1); + + send_sig_info(SIGTRAP, &info, current); return; case 1: /* bugcheck */ - send_sig(SIGTRAP, current, 1); + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = __SI_FAULT; + info.si_addr = (void *) regs.pc; + info.si_trapno = 0; + send_sig_info(SIGTRAP, &info, current); return; - + case 2: /* gentrap */ - /* - * The exception code should be passed on to the signal - * handler as the second argument. Linux doesn't do that - * yet (also notice that Linux *always* behaves like - * DEC Unix with SA_SIGINFO off; see DEC Unix man page - * for sigaction(2)). - */ + info.si_addr = (void *) regs.pc; + info.si_trapno = regs.r16; switch ((long) regs.r16) { - case GEN_INTOVF: case GEN_INTDIV: case GEN_FLTOVF: - case GEN_FLTDIV: case GEN_FLTUND: case GEN_FLTINV: - case GEN_FLTINE: case GEN_ROPRAND: - send_sig(SIGFPE, current, 1); - return; - - case GEN_DECOVF: - case GEN_DECDIV: - case GEN_DECINV: - case GEN_ASSERTERR: - case GEN_NULPTRERR: - case GEN_STKOVF: - case GEN_STRLENERR: - case GEN_SUBSTRERR: - case GEN_RANGERR: - case GEN_SUBRNG: - case GEN_SUBRNG1: - case GEN_SUBRNG2: - case GEN_SUBRNG3: - case GEN_SUBRNG4: - case GEN_SUBRNG5: - case GEN_SUBRNG6: - case GEN_SUBRNG7: - send_sig(SIGTRAP, current, 1); - return; + case GEN_INTOVF: + signo = SIGFPE; + code = FPE_INTOVF; + break; + case GEN_INTDIV: + signo = SIGFPE; + code = FPE_INTDIV; + break; + case GEN_FLTOVF: + signo = SIGFPE; + code = FPE_FLTOVF; + break; + case GEN_FLTDIV: + signo = SIGFPE; + code = FPE_FLTDIV; + break; + case GEN_FLTUND: + signo = SIGFPE; + code = FPE_FLTUND; + break; + case GEN_FLTINV: + signo = SIGFPE; + code = FPE_FLTINV; + break; + case GEN_FLTINE: + signo = SIGFPE; + code = FPE_FLTRES; + break; + case GEN_ROPRAND: + signo = SIGFPE; + code = __SI_FAULT; + break; + + case GEN_DECOVF: + case GEN_DECDIV: + case GEN_DECINV: + case GEN_ASSERTERR: + case GEN_NULPTRERR: + case GEN_STKOVF: + case GEN_STRLENERR: + case GEN_SUBSTRERR: + case GEN_RANGERR: + case GEN_SUBRNG: + case GEN_SUBRNG1: + case GEN_SUBRNG2: + case GEN_SUBRNG3: + case GEN_SUBRNG4: + case GEN_SUBRNG5: + case GEN_SUBRNG6: + case GEN_SUBRNG7: + default: + signo = SIGTRAP; + code = __SI_FAULT; + break; } - break; + + info.si_signo = signo; + info.si_errno = 0; + info.si_code = code; + info.si_addr = (void *) regs.pc; + send_sig_info(signo, &info, current); + return; case 4: /* opDEC */ if (implver() == IMPLVER_EV4) { + long si_code; + /* The some versions of SRM do not handle the opDEC properly - they return the PC of the opDEC fault, not the instruction after as the @@ -309,8 +356,7 @@ We do this by intentionally causing an opDEC fault during the boot sequence and testing if we get the correct PC. If not, we set a flag - to correct it every time through. - */ + to correct it every time through. */ if (opDEC_testing) { if (regs.pc == opDEC_test_pc) { opDEC_fix = 4; @@ -324,8 +370,17 @@ /* EV4 does not implement anything except normal rounding. Everything else will come here as an illegal instruction. Emulate them. */ - if (alpha_fp_emul(regs.pc-4)) + si_code = alpha_fp_emul(regs.pc - 4); + if (si_code == 0) return; + if (si_code > 0) { + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = si_code; + info.si_addr = (void *) regs.pc; + send_sig_info(SIGFPE, &info, current); + return; + } } break; @@ -347,7 +402,12 @@ default: /* unexpected instruction-fault type */ ; } - send_sig(SIGILL, current, 1); + + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_ILLOPC; + info.si_addr = regs.pc; + send_sig_info(SIGILL, &info, current); } /* There is an ifdef in the PALcode in MILO that enables a @@ -362,8 +422,15 @@ unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs) { + siginfo_t info; + die_if_kernel("Instruction fault", ®s, type, 0); - force_sig(SIGILL, current); + + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_ILLOPC; + info.si_addr = regs.pc; + force_sig_info(SIGILL, &info, current); } @@ -720,6 +787,7 @@ unsigned long tmp1, tmp2, tmp3, tmp4; unsigned long fake_reg, *reg_addr = &fake_reg; + siginfo_t info; long error; /* Check the UAC bits to decide what the user wants us to do @@ -984,12 +1052,34 @@ give_sigsegv: regs->pc -= 4; /* make pc point to faulting insn */ - send_sig(SIGSEGV, current, 1); + info.si_signo = SIGSEGV; + info.si_errno = 0; + + /* We need to replicate some of the logic in mm/fault.c, + since we don't have access to the fault code in the + exception handling return path. */ + if (!__access_ok((unsigned long)va, 0, USER_DS)) + info.si_code = SEGV_ACCERR; + else { + struct mm_struct *mm = current->mm; + down_read(&mm->mmap_sem); + if (find_vma(mm, (unsigned long)va)) + info.si_code = SEGV_ACCERR; + else + info.si_code = SEGV_MAPERR; + up_read(&mm->mmap_sem); + } + info.si_addr = va; + send_sig_info(SIGSEGV, &info, current); return; give_sigbus: regs->pc -= 4; - send_sig(SIGBUS, current, 1); + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRALN; + info.si_addr = va; + send_sig_info(SIGBUS, &info, current); return; } diff -Nru a/arch/alpha/lib/dbg_current.S b/arch/alpha/lib/dbg_current.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/alpha/lib/dbg_current.S Mon Nov 4 14:31:03 2002 @@ -0,0 +1,29 @@ +/* + * arch/alpha/lib/dbg_current.S + * Contributed by Richard Henderson (rth@cygnus.com) + * + * Trap if we find current not correct. + */ + +#include + + .text + .set noat + + .globl _mcount + .ent _mcount +_mcount: + .frame $30, 0, $28, 0 + .prologue 0 + + lda $0, -0x4000($30) + cmpult $8, $30, $1 + cmpule $0, $30, $2 + and $1, $2, $3 + bne $3, 1f + + call_pal PAL_bugchk + +1: ret $31, ($28), 1 + + .end _mcount diff -Nru a/arch/alpha/math-emu/math.c b/arch/alpha/math-emu/math.c --- a/arch/alpha/math-emu/math.c Mon Nov 4 14:31:03 2002 +++ b/arch/alpha/math-emu/math.c Mon Nov 4 14:31:03 2002 @@ -86,11 +86,13 @@ /* - * Emulate the floating point instruction at address PC. Returns 0 if - * emulation fails. Notice that the kernel does not and cannot use FP - * regs. This is good because it means that instead of - * saving/restoring all fp regs, we simply stick the result of the - * operation into the appropriate register. + * Emulate the floating point instruction at address PC. Returns -1 if the + * instruction to be emulated is illegal (such as with the opDEC trap), else + * the SI_CODE for a SIGFPE signal, else 0 if everything's ok. + * + * Notice that the kernel does not and cannot use FP regs. This is good + * because it means that instead of saving/restoring all fp regs, we simply + * stick the result of the operation into the appropriate register. */ long alpha_fp_emul (unsigned long pc) @@ -102,6 +104,7 @@ unsigned long fa, fb, fc, func, mode, src; unsigned long res, va, vb, vc, swcr, fpcr; __u32 insn; + long si_code; MOD_INC_USE_COUNT; @@ -306,10 +309,19 @@ wrfpcr(fpcr); /* Do we generate a signal? */ - if (_fex & swcr & IEEE_TRAP_ENABLE_MASK) { - MOD_DEC_USE_COUNT; - return 0; + _fex = _fex & swcr & IEEE_TRAP_ENABLE_MASK; + si_code = 0; + if (_fex) { + if (_fex & IEEE_TRAP_ENABLE_DNO) si_code = FPE_FLTUND; + if (_fex & IEEE_TRAP_ENABLE_INE) si_code = FPE_FLTRES; + if (_fex & IEEE_TRAP_ENABLE_UNF) si_code = FPE_FLTUND; + if (_fex & IEEE_TRAP_ENABLE_OVF) si_code = FPE_FLTOVF; + if (_fex & IEEE_TRAP_ENABLE_DZE) si_code = FPE_FLTDIV; + if (_fex & IEEE_TRAP_ENABLE_INV) si_code = FPE_FLTINV; } + + MOD_DEC_USE_COUNT; + return si_code; } /* We used to write the destination register here, but DEC FORTRAN @@ -317,20 +329,20 @@ immediately after the operations above. */ MOD_DEC_USE_COUNT; - return 1; + return 0; bad_insn: printk(KERN_ERR "alpha_fp_emul: Invalid FP insn %#x at %#lx\n", insn, pc); MOD_DEC_USE_COUNT; - return 0; + return -1; } long alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask) { unsigned long trigger_pc = regs->pc - 4; - unsigned long insn, opcode, rc, no_signal = 0; + unsigned long insn, opcode, rc, si_code = 0; MOD_INC_USE_COUNT; @@ -384,7 +396,7 @@ if (!write_mask) { /* Re-execute insns in the trap-shadow. */ regs->pc = trigger_pc + 4; - no_signal = alpha_fp_emul(trigger_pc); + si_code = alpha_fp_emul(trigger_pc); goto egress; } trigger_pc -= 4; @@ -392,5 +404,5 @@ egress: MOD_DEC_USE_COUNT; - return no_signal; + return si_code; } diff -Nru a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c --- a/arch/alpha/mm/fault.c Mon Nov 4 14:31:01 2002 +++ b/arch/alpha/mm/fault.c Mon Nov 4 14:31:01 2002 @@ -89,7 +89,8 @@ struct vm_area_struct * vma; struct mm_struct *mm = current->mm; unsigned int fixup; - int fault; + int fault, si_code = SEGV_MAPERR; + siginfo_t info; /* As of EV6, a load into $31/$f31 is a prefetch, and never faults (or is suppressed by the PALcode). Support that for older CPUs @@ -129,6 +130,7 @@ /* Ok, we have a good vm_area for this memory access, so we can handle it. */ good_area: + si_code = SEGV_ACCERR; if (cause < 0) { if (!(vma->vm_flags & VM_EXEC)) goto bad_area; @@ -148,10 +150,20 @@ fault = handle_mm_fault(mm, vma, address, cause > 0); up_read(&mm->mmap_sem); - if (fault < 0) - goto out_of_memory; - if (fault == 0) + switch (fault) { + case VM_FAULT_MINOR: + current->min_flt++; + break; + case VM_FAULT_MAJOR: + current->maj_flt++; + break; + case VM_FAULT_SIGBUS: goto do_sigbus; + case VM_FAULT_OOM: + goto out_of_memory; + default: + BUG(); + } return; /* Something tried to access memory that isn't in our memory map. @@ -159,20 +171,14 @@ bad_area: up_read(&mm->mmap_sem); - if (user_mode(regs)) { - force_sig(SIGSEGV, current); - return; - } + if (user_mode(regs)) + goto do_sigsegv; no_context: /* Are we prepared to handle this fault as an exception? */ if ((fixup = search_exception_table(regs->pc, regs->gp)) != 0) { unsigned long newpc; newpc = fixup_exception(dpf_reg, fixup, regs->pc); -#if 0 - printk("%s: Exception at [<%lx>] (%lx) handled successfully\n", - current->comm, regs->pc, newpc); -#endif regs->pc = newpc; return; } @@ -201,17 +207,28 @@ do_sigbus: /* Send a sigbus, regardless of whether we were in kernel or user mode. */ - force_sig(SIGBUS, current); + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void *) address; + force_sig_info(SIGBUS, &info, current); if (!user_mode(regs)) goto no_context; return; + do_sigsegv: + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = si_code; + info.si_addr = (void *) address; + force_sig_info(SIGSEGV, &info, current); + return; + #ifdef CONFIG_ALPHA_LARGE_VMALLOC vmalloc_fault: - if (user_mode(regs)) { - force_sig(SIGSEGV, current); - return; - } else { + if (user_mode(regs)) + goto do_sigsegv; + else { /* Synchronize this task's top level page-table with the "reference" page table from init. */ long offset = __pgd_offset(address); diff -Nru a/arch/alpha/vmlinux.lds.S b/arch/alpha/vmlinux.lds.S --- a/arch/alpha/vmlinux.lds.S Mon Nov 4 14:31:02 2002 +++ b/arch/alpha/vmlinux.lds.S Mon Nov 4 14:31:02 2002 @@ -31,18 +31,27 @@ *(__ksymtab) __stop___ksymtab = .; } + + /* All kernel symbols */ + __kallsyms ALIGN(8) : { + __start___kallsyms = .; + *(__kallsyms) + __stop___kallsyms = .; + } + .kstrtab : { *(.kstrtab) } + .rodata : { *(.rodata) *(.rodata.*) } /* Startup code */ - .text.init ALIGN(8192) : { + .init.text ALIGN(8192) : { __init_begin = .; - *(.text.init) + *(.init.text) } - .data.init : { *(.data.init) } + .init.data : { *(.init.data) } - .setup.init ALIGN(16): { + .init.setup ALIGN(16): { __setup_start = .; - *(.setup.init) + *(.init.setup) __setup_end = .; } @@ -58,6 +67,12 @@ __initcall_end = .; } + .init.ramfs ALIGN(8192): { + __initramfs_start = .; + *(.init.initramfs) + __initramfs_end = .; + } + .data.percpu ALIGN(64): { __per_cpu_start = .; *(.data.percpu) @@ -71,11 +86,11 @@ } /* Global data */ - .data.cacheline_aligned : { + .data.page_aligned ALIGN(8192) : { _data = .; - *(.data.cacheline_aligned) + *(.data.page_aligned) } - .rodata : { *(.rodata) *(.rodata.*) } + .data.cacheline_aligned : { *(.data.cacheline_aligned) } .data : { *(.data) CONSTRUCTORS } .got : { *(.got) } .sdata : { @@ -120,5 +135,5 @@ .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } - /DISCARD/ : { *(.text.exit) *(.data.exit) *(.exitcall.exit) } + /DISCARD/ : { *(.exit.text) *(.exit.data) *(.exitcall.exit) } } diff -Nru a/arch/arm/Kconfig b/arch/arm/Kconfig --- a/arch/arm/Kconfig Mon Nov 4 14:31:02 2002 +++ b/arch/arm/Kconfig Mon Nov 4 14:31:02 2002 @@ -16,6 +16,14 @@ Europe. There is an ARM Linux project with a web page at . +config MMU + bool + default y + +config SWAP + bool + default y + config EISA bool ---help--- @@ -1113,15 +1121,18 @@ menu "Kernel hacking" -# Always compile kernel with framepointer (until 2.4 real comes out) -# Bug reports aren't much use without this. -config NO_FRAME_POINTER - bool "Compile kernel without frame pointer" +# RMK wants arm kernels compiled with frame pointers so hardwire this to y. +# If you know what you are doing and are willing to live without stack +# traces, you can get a slightly smaller kernel by setting this option to +# n, but then RMK will have to kill you ;). +config FRAME_POINTER + bool + default y help - If you say Y here, the resulting kernel will be slightly smaller and + If you say N here, the resulting kernel will be slightly smaller and faster. However, when a problem occurs with the kernel, the information that is reported is severely limited. Most people - should say N here. + should say Y here. config DEBUG_USER bool "Verbose user fault messages" @@ -1132,7 +1143,7 @@ production system. Most people should say N here. config DEBUG_INFO - bool "Include debugging information in kernel binary" + bool "Include GDB debugging information in kernel binary" help Say Y here to include source-level debugging information in the `vmlinux' binary image. This is handy if you want to use gdb or @@ -1200,6 +1211,14 @@ but mostly meaningless to other people. It's safe to say Y unless you are concerned with the code size or don't want to see these messages. + +config KALLSYMS + bool "Load all symbols for debugging/kksymoops" + depends on DEBUG_KERNEL + help + Say Y here to let the kernel print out symbolic crash information and + symbolic stack backtraces. This increases the size of the kernel + somewhat, as all symbols have to be loaded into the kernel image. # These options are only for real kernel hackers who want to get their hands dirty. config DEBUG_LL diff -Nru a/arch/arm/Makefile b/arch/arm/Makefile --- a/arch/arm/Makefile Mon Nov 4 14:31:01 2002 +++ b/arch/arm/Makefile Mon Nov 4 14:31:01 2002 @@ -15,8 +15,8 @@ CFLAGS :=$(CFLAGS:-O2=-Os) -ifneq ($(CONFIG_NO_FRAME_POINTER),y) -CFLAGS :=$(CFLAGS: -fomit-frame-pointer=) +ifeq ($(CONFIG_FRAME_POINTER),y) +CFLAGS :=$(CFLAGS:-fomit-frame-pointer=-mapcs -mno-sched-prolog) endif ifeq ($(CONFIG_DEBUG_INFO),y) @@ -179,8 +179,10 @@ endif # If we have a machine-specific directory, then include it in the build. -core-y += arch/arm/mach-$(MACHINE)/ \ - arch/arm/kernel/ arch/arm/mm/ +ifneq ($(MACHINE),) +core-y += arch/arm/mach-$(MACHINE)/ +endif +core-y += arch/arm/kernel/ arch/arm/mm/ core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/ core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ) diff -Nru a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile --- a/arch/arm/boot/Makefile Mon Nov 4 14:31:00 2002 +++ b/arch/arm/boot/Makefile Mon Nov 4 14:31:00 2002 @@ -112,8 +112,8 @@ # from ROM or Flash must define ZTEXTADDR (preferably via the config) # ifeq ($(CONFIG_ZBOOT_ROM),y) -ZTEXTADDR =0x$(CONFIG_ZBOOT_ROM_TEXT) -ZBSSADDR =0x$(CONFIG_ZBOOT_ROM_BSS) +ZTEXTADDR =$(CONFIG_ZBOOT_ROM_TEXT) +ZBSSADDR =$(CONFIG_ZBOOT_ROM_BSS) else ZTEXTADDR =0 ZBSSADDR =ALIGN(4) diff -Nru a/arch/arm/boot/compressed/head-sa1100.S b/arch/arm/boot/compressed/head-sa1100.S --- a/arch/arm/boot/compressed/head-sa1100.S Mon Nov 4 14:31:00 2002 +++ b/arch/arm/boot/compressed/head-sa1100.S Mon Nov 4 14:31:00 2002 @@ -76,4 +76,3 @@ mov r0, #0x00200000 1: subs r0, r0, #1 bne 1b - diff -Nru a/arch/arm/def-configs/adi_evb b/arch/arm/def-configs/adi_evb --- a/arch/arm/def-configs/adi_evb Mon Nov 4 14:31:02 2002 +++ b/arch/arm/def-configs/adi_evb Mon Nov 4 14:31:02 2002 @@ -669,7 +669,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -Nru a/arch/arm/def-configs/adsbitsy b/arch/arm/def-configs/adsbitsy --- a/arch/arm/def-configs/adsbitsy Mon Nov 4 14:31:02 2002 +++ b/arch/arm/def-configs/adsbitsy Mon Nov 4 14:31:02 2002 @@ -654,7 +654,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set diff -Nru a/arch/arm/def-configs/anakin b/arch/arm/def-configs/anakin --- a/arch/arm/def-configs/anakin Mon Nov 4 14:31:00 2002 +++ b/arch/arm/def-configs/anakin Mon Nov 4 14:31:00 2002 @@ -610,7 +610,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_KERNEL is not set diff -Nru a/arch/arm/def-configs/assabet b/arch/arm/def-configs/assabet --- a/arch/arm/def-configs/assabet Mon Nov 4 14:31:01 2002 +++ b/arch/arm/def-configs/assabet Mon Nov 4 14:31:01 2002 @@ -954,7 +954,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -Nru a/arch/arm/def-configs/badge4 b/arch/arm/def-configs/badge4 --- a/arch/arm/def-configs/badge4 Mon Nov 4 14:31:02 2002 +++ b/arch/arm/def-configs/badge4 Mon Nov 4 14:31:02 2002 @@ -1141,7 +1141,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_INFO=y CONFIG_DEBUG_KERNEL=y diff -Nru a/arch/arm/def-configs/cerfcube b/arch/arm/def-configs/cerfcube --- a/arch/arm/def-configs/cerfcube Mon Nov 4 14:31:00 2002 +++ b/arch/arm/def-configs/cerfcube Mon Nov 4 14:31:00 2002 @@ -863,7 +863,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -Nru a/arch/arm/def-configs/cerfpda b/arch/arm/def-configs/cerfpda --- a/arch/arm/def-configs/cerfpda Mon Nov 4 14:31:01 2002 +++ b/arch/arm/def-configs/cerfpda Mon Nov 4 14:31:01 2002 @@ -957,7 +957,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -Nru a/arch/arm/def-configs/cerfpod b/arch/arm/def-configs/cerfpod --- a/arch/arm/def-configs/cerfpod Mon Nov 4 14:31:03 2002 +++ b/arch/arm/def-configs/cerfpod Mon Nov 4 14:31:03 2002 @@ -884,7 +884,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -Nru a/arch/arm/def-configs/ebsa110 b/arch/arm/def-configs/ebsa110 --- a/arch/arm/def-configs/ebsa110 Mon Nov 4 14:31:00 2002 +++ b/arch/arm/def-configs/ebsa110 Mon Nov 4 14:31:00 2002 @@ -595,7 +595,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set diff -Nru a/arch/arm/def-configs/epxa10db b/arch/arm/def-configs/epxa10db --- a/arch/arm/def-configs/epxa10db Mon Nov 4 14:31:01 2002 +++ b/arch/arm/def-configs/epxa10db Mon Nov 4 14:31:01 2002 @@ -678,7 +678,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set # CONFIG_NO_PGT_CACHE is not set diff -Nru a/arch/arm/def-configs/flexanet b/arch/arm/def-configs/flexanet --- a/arch/arm/def-configs/flexanet Mon Nov 4 14:31:02 2002 +++ b/arch/arm/def-configs/flexanet Mon Nov 4 14:31:02 2002 @@ -886,7 +886,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set # CONFIG_NO_PGT_CACHE is not set diff -Nru a/arch/arm/def-configs/fortunet b/arch/arm/def-configs/fortunet --- a/arch/arm/def-configs/fortunet Mon Nov 4 14:31:03 2002 +++ b/arch/arm/def-configs/fortunet Mon Nov 4 14:31:03 2002 @@ -577,7 +577,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set # CONFIG_NO_PGT_CACHE is not set diff -Nru a/arch/arm/def-configs/freebird b/arch/arm/def-configs/freebird --- a/arch/arm/def-configs/freebird Mon Nov 4 14:31:01 2002 +++ b/arch/arm/def-configs/freebird Mon Nov 4 14:31:01 2002 @@ -605,7 +605,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -Nru a/arch/arm/def-configs/freebird_new b/arch/arm/def-configs/freebird_new --- a/arch/arm/def-configs/freebird_new Mon Nov 4 14:31:00 2002 +++ b/arch/arm/def-configs/freebird_new Mon Nov 4 14:31:00 2002 @@ -625,7 +625,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set diff -Nru a/arch/arm/def-configs/graphicsclient b/arch/arm/def-configs/graphicsclient --- a/arch/arm/def-configs/graphicsclient Mon Nov 4 14:31:03 2002 +++ b/arch/arm/def-configs/graphicsclient Mon Nov 4 14:31:03 2002 @@ -722,7 +722,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -Nru a/arch/arm/def-configs/graphicsmaster b/arch/arm/def-configs/graphicsmaster --- a/arch/arm/def-configs/graphicsmaster Mon Nov 4 14:31:00 2002 +++ b/arch/arm/def-configs/graphicsmaster Mon Nov 4 14:31:00 2002 @@ -735,7 +735,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -Nru a/arch/arm/def-configs/h3600 b/arch/arm/def-configs/h3600 --- a/arch/arm/def-configs/h3600 Mon Nov 4 14:31:01 2002 +++ b/arch/arm/def-configs/h3600 Mon Nov 4 14:31:01 2002 @@ -939,7 +939,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set diff -Nru a/arch/arm/def-configs/integrator b/arch/arm/def-configs/integrator --- a/arch/arm/def-configs/integrator Mon Nov 4 14:31:00 2002 +++ b/arch/arm/def-configs/integrator Mon Nov 4 14:31:00 2002 @@ -653,7 +653,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -Nru a/arch/arm/def-configs/iq80310 b/arch/arm/def-configs/iq80310 --- a/arch/arm/def-configs/iq80310 Mon Nov 4 14:31:01 2002 +++ b/arch/arm/def-configs/iq80310 Mon Nov 4 14:31:01 2002 @@ -786,7 +786,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set # CONFIG_NO_PGT_CACHE is not set diff -Nru a/arch/arm/def-configs/jornada720 b/arch/arm/def-configs/jornada720 --- a/arch/arm/def-configs/jornada720 Mon Nov 4 14:31:01 2002 +++ b/arch/arm/def-configs/jornada720 Mon Nov 4 14:31:01 2002 @@ -881,7 +881,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set # CONFIG_NO_PGT_CACHE is not set diff -Nru a/arch/arm/def-configs/lart b/arch/arm/def-configs/lart --- a/arch/arm/def-configs/lart Mon Nov 4 14:31:01 2002 +++ b/arch/arm/def-configs/lart Mon Nov 4 14:31:01 2002 @@ -883,7 +883,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -Nru a/arch/arm/def-configs/lubbock b/arch/arm/def-configs/lubbock --- a/arch/arm/def-configs/lubbock Mon Nov 4 14:31:00 2002 +++ b/arch/arm/def-configs/lubbock Mon Nov 4 14:31:00 2002 @@ -860,7 +860,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_INFO=y CONFIG_DEBUG_KERNEL=y diff -Nru a/arch/arm/def-configs/lusl7200 b/arch/arm/def-configs/lusl7200 --- a/arch/arm/def-configs/lusl7200 Mon Nov 4 14:31:01 2002 +++ b/arch/arm/def-configs/lusl7200 Mon Nov 4 14:31:01 2002 @@ -466,7 +466,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_INFO=y # CONFIG_DEBUG_KERNEL is not set diff -Nru a/arch/arm/def-configs/neponset b/arch/arm/def-configs/neponset --- a/arch/arm/def-configs/neponset Mon Nov 4 14:31:01 2002 +++ b/arch/arm/def-configs/neponset Mon Nov 4 14:31:01 2002 @@ -1104,7 +1104,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set CONFIG_DEBUG_KERNEL=y diff -Nru a/arch/arm/def-configs/pangolin b/arch/arm/def-configs/pangolin --- a/arch/arm/def-configs/pangolin Mon Nov 4 14:31:02 2002 +++ b/arch/arm/def-configs/pangolin Mon Nov 4 14:31:02 2002 @@ -732,7 +732,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_INFO=y diff -Nru a/arch/arm/def-configs/pfs168_mqtft b/arch/arm/def-configs/pfs168_mqtft --- a/arch/arm/def-configs/pfs168_mqtft Mon Nov 4 14:31:02 2002 +++ b/arch/arm/def-configs/pfs168_mqtft Mon Nov 4 14:31:02 2002 @@ -773,7 +773,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_INFO=y diff -Nru a/arch/arm/def-configs/pfs168_mqvga b/arch/arm/def-configs/pfs168_mqvga --- a/arch/arm/def-configs/pfs168_mqvga Mon Nov 4 14:31:00 2002 +++ b/arch/arm/def-configs/pfs168_mqvga Mon Nov 4 14:31:00 2002 @@ -773,7 +773,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_INFO=y diff -Nru a/arch/arm/def-configs/pfs168_sastn b/arch/arm/def-configs/pfs168_sastn --- a/arch/arm/def-configs/pfs168_sastn Mon Nov 4 14:31:00 2002 +++ b/arch/arm/def-configs/pfs168_sastn Mon Nov 4 14:31:00 2002 @@ -764,7 +764,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_INFO=y diff -Nru a/arch/arm/def-configs/pfs168_satft b/arch/arm/def-configs/pfs168_satft --- a/arch/arm/def-configs/pfs168_satft Mon Nov 4 14:31:00 2002 +++ b/arch/arm/def-configs/pfs168_satft Mon Nov 4 14:31:00 2002 @@ -773,7 +773,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_INFO=y diff -Nru a/arch/arm/def-configs/pleb b/arch/arm/def-configs/pleb --- a/arch/arm/def-configs/pleb Mon Nov 4 14:31:02 2002 +++ b/arch/arm/def-configs/pleb Mon Nov 4 14:31:02 2002 @@ -525,7 +525,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -Nru a/arch/arm/def-configs/rpc b/arch/arm/def-configs/rpc --- a/arch/arm/def-configs/rpc Mon Nov 4 14:31:00 2002 +++ b/arch/arm/def-configs/rpc Mon Nov 4 14:31:00 2002 @@ -830,7 +830,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -Nru a/arch/arm/def-configs/shannon b/arch/arm/def-configs/shannon --- a/arch/arm/def-configs/shannon Mon Nov 4 14:31:00 2002 +++ b/arch/arm/def-configs/shannon Mon Nov 4 14:31:00 2002 @@ -726,7 +726,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set diff -Nru a/arch/arm/def-configs/shark b/arch/arm/def-configs/shark --- a/arch/arm/def-configs/shark Mon Nov 4 14:31:00 2002 +++ b/arch/arm/def-configs/shark Mon Nov 4 14:31:00 2002 @@ -917,7 +917,7 @@ # # Kernel hacking # -CONFIG_NO_FRAME_POINTER=y +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_KERNEL is not set diff -Nru a/arch/arm/def-configs/stork b/arch/arm/def-configs/stork --- a/arch/arm/def-configs/stork Mon Nov 4 14:31:02 2002 +++ b/arch/arm/def-configs/stork Mon Nov 4 14:31:02 2002 @@ -946,7 +946,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y # CONFIG_DEBUG_USER is not set # CONFIG_DEBUG_INFO is not set # CONFIG_NO_PGT_CACHE is not set diff -Nru a/arch/arm/def-configs/system3 b/arch/arm/def-configs/system3 --- a/arch/arm/def-configs/system3 Mon Nov 4 14:31:01 2002 +++ b/arch/arm/def-configs/system3 Mon Nov 4 14:31:01 2002 @@ -952,7 +952,7 @@ # # Kernel hacking # -# CONFIG_NO_FRAME_POINTER is not set +CONFIG_FRAME_POINTER=y CONFIG_DEBUG_USER=y CONFIG_DEBUG_INFO=y # CONFIG_NO_PGT_CACHE is not set diff -Nru a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c --- a/arch/arm/kernel/armksyms.c Mon Nov 4 14:31:01 2002 +++ b/arch/arm/kernel/armksyms.c Mon Nov 4 14:31:01 2002 @@ -127,6 +127,7 @@ EXPORT_SYMBOL(__readwrite_bug); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(probe_irq_mask); EXPORT_SYMBOL(set_irq_type); EXPORT_SYMBOL(pm_idle); EXPORT_SYMBOL(pm_power_off); diff -Nru a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c --- a/arch/arm/kernel/bios32.c Mon Nov 4 14:31:01 2002 +++ b/arch/arm/kernel/bios32.c Mon Nov 4 14:31:01 2002 @@ -259,7 +259,7 @@ }, { 0 } }; -void __init +void __devinit pcibios_update_resource(struct pci_dev *dev, struct resource *root, struct resource *res, int resource) { @@ -300,7 +300,7 @@ } } -void __init pcibios_update_irq(struct pci_dev *dev, int irq) +void __devinit pcibios_update_irq(struct pci_dev *dev, int irq) { if (debug_pci) printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name); @@ -321,7 +321,7 @@ /* * Adjust the device resources from bus-centric to Linux-centric. */ -static void __init +static void __devinit pdev_fixup_device_resources(struct pci_sys_data *root, struct pci_dev *dev) { unsigned long offset; @@ -340,7 +340,7 @@ } } -static void __init +static void __devinit pbus_assign_bus_resources(struct pci_bus *bus, struct pci_sys_data *root) { struct pci_dev *dev = bus->self; @@ -359,7 +359,7 @@ * pcibios_fixup_bus - Called after each bus is probed, * but before its children are examined. */ -void __init pcibios_fixup_bus(struct pci_bus *bus) +void __devinit pcibios_fixup_bus(struct pci_bus *bus) { struct pci_sys_data *root = bus->sysdata; struct list_head *walk; @@ -428,7 +428,7 @@ /* * Convert from Linux-centric to bus-centric addresses for bridge devices. */ -void __init +void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges) { struct pci_sys_data *root = bus->sysdata; @@ -587,12 +587,12 @@ void pcibios_align_resource(void *data, struct resource *res, unsigned long size, unsigned long align) { - if (res->flags & IORESOURCE_IO) { - unsigned long start = res->start; + unsigned long start = res->start; - if (start & 0x300) - res->start = (start + 0x3ff) & ~0x3ff; - } + if (res->flags & IORESOURCE_IO && start & 0x300) + start = (start + 0x3ff) & ~0x3ff; + + res->start = (start + align - 1) & ~(align - 1); } /** @@ -623,6 +623,13 @@ if (r->flags & IORESOURCE_MEM) cmd |= PCI_COMMAND_MEMORY; } + + /* + * Bridges (eg, cardbus bridges) need to be fully enabled + */ + if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) + cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY; + if (cmd != old_cmd) { printk("PCI: enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); diff -Nru a/arch/arm/kernel/entry-armo.S b/arch/arm/kernel/entry-armo.S --- a/arch/arm/kernel/entry-armo.S Mon Nov 4 14:31:01 2002 +++ b/arch/arm/kernel/entry-armo.S Mon Nov 4 14:31:01 2002 @@ -26,6 +26,7 @@ * adhering to the above criteria. */ #include +#include #include "entry-header.S" .text @@ -597,7 +598,7 @@ * What we need to put into 0-0x1c are branches to branch to the kernel. */ - .section ".text.init",#alloc,#execinstr + __INIT .Ljump_addresses: swi SYS_ERROR0 diff -Nru a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S --- a/arch/arm/kernel/entry-armv.S Mon Nov 4 14:31:01 2002 +++ b/arch/arm/kernel/entry-armv.S Mon Nov 4 14:31:01 2002 @@ -14,6 +14,7 @@ * it to save wrong values... Be aware! */ #include +#include #include "entry-header.S" #include #include @@ -593,23 +594,12 @@ add \base, \base, #0x00d00000 ldr \irqstat, [\base, #0] @ ICIP ldr \irqnr, [\base, #4] @ ICMR - ands \irqstat, \irqstat, \irqnr - mov \irqnr, #0 + ands \irqnr, \irqstat, \irqnr beq 1001f - tst \irqstat, #0xff00 - moveq \irqstat, \irqstat, lsr #8 - addeq \irqnr, \irqnr, #8 - tsteq \irqstat, #0xff00 - moveq \irqstat, \irqstat, lsr #8 - addeq \irqnr, \irqnr, #8 - tst \irqstat, #0x0f00 - moveq \irqstat, \irqstat, lsr #4 - addeq \irqnr, \irqnr, #4 - tst \irqstat, #0x0300 - moveq \irqstat, \irqstat, lsr #2 - addeq \irqnr, \irqnr, #2 - tst \irqstat, #0x0100 - addeqs \irqnr, \irqnr, #1 + rsb \irqstat, \irqnr, #0 + and \irqstat, \irqstat, \irqnr + clz \irqnr, \irqstat + rsb \irqnr, \irqnr, #23 1001: .endm @@ -1013,7 +1003,7 @@ mcr p15, 0, r2, c3, c0 @ Set domain register ldmib r1, {r4 - sl, fp, sp, pc} @ Load all regs saved previously - .section ".text.init",#alloc,#execinstr + __INIT /* * Vector stubs. NOTE that we only align 'vector_IRQ' to a cache line boundary, * and we rely on each stub being exactly 48 (1.5 cache lines) in size. This diff -Nru a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S --- a/arch/arm/kernel/entry-header.S Mon Nov 4 14:31:01 2002 +++ b/arch/arm/kernel/entry-header.S Mon Nov 4 14:31:01 2002 @@ -12,7 +12,7 @@ #endif .macro zero_fp -#ifndef CONFIG_NO_FRAME_POINTER +#ifdef CONFIG_FRAME_POINTER mov fp, #0 #endif .endm diff -Nru a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c --- a/arch/arm/kernel/fiq.c Mon Nov 4 14:31:02 2002 +++ b/arch/arm/kernel/fiq.c Mon Nov 4 14:31:02 2002 @@ -37,6 +37,7 @@ */ #include #include +#include #include #include #include @@ -203,9 +204,7 @@ if (current_fiq != f) { printk(KERN_ERR "%s FIQ trying to release %s FIQ\n", f->name, current_fiq->name); -#ifdef CONFIG_DEBUG_ERRORS - __backtrace(); -#endif + dump_stack(); return; } diff -Nru a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S --- a/arch/arm/kernel/head.S Mon Nov 4 14:31:00 2002 +++ b/arch/arm/kernel/head.S Mon Nov 4 14:31:00 2002 @@ -11,6 +11,7 @@ */ #include #include +#include #include #include @@ -68,7 +69,7 @@ * crap here - that's what the boot loader (or in extreme, well justified * circumstances, zImage) is for. */ - .section ".text.init",#alloc,#execinstr + __INIT .type stext, #function ENTRY(stext) mov r12, r0 diff -Nru a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c --- a/arch/arm/kernel/irq.c Mon Nov 4 14:31:00 2002 +++ b/arch/arm/kernel/irq.c Mon Nov 4 14:31:00 2002 @@ -217,7 +217,7 @@ desc->triggered = 1; - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; action = desc->action; if (action) @@ -253,7 +253,7 @@ */ desc->running = 1; - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; do { struct irqaction *action; @@ -305,7 +305,7 @@ desc->chip->ack(irq); if (likely(desc->enabled)) { - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; /* * Return with this interrupt masked if no action @@ -578,9 +578,7 @@ if (irq >= NR_IRQS || !irq_desc[irq].valid) { printk(KERN_ERR "Trying to free IRQ%d\n",irq); -#ifdef CONFIG_DEBUG_ERRORS - __backtrace(); -#endif + dump_stack(); return; } @@ -597,15 +595,15 @@ if (!action) { printk(KERN_ERR "Trying to free free IRQ%d\n",irq); -#ifdef CONFIG_DEBUG_ERRORS - __backtrace(); -#endif + dump_stack(); } else { synchronize_irq(irq); kfree(action); } } +static DECLARE_MUTEX(probe_sem); + /* Start the interrupt probing. Unlike other architectures, * we don't return a mask of interrupts from probe_irq_on, * but return the number of interrupts enabled for the probe. @@ -617,6 +615,8 @@ unsigned int i, irqs = 0; unsigned long delay; + down(&probe_sem); + /* * first snaffle up any unassigned but * probe-able interrupts @@ -656,6 +656,21 @@ return irqs; } +unsigned int probe_irq_mask(unsigned long irqs) +{ + unsigned int mask = 0, i; + + spin_lock_irq(&irq_controller_lock); + for(i = 0; i < 16 && i < NR_IRQS; i++) + if (irq_desc[i].probing && irq_desc[i].triggered) + mask |= 1 << i; + spin_unlock_irq(&irq_controller_lock); + + up(&probe_sem); + + return mask; +} + /* * Possible return values: * >= 0 - interrupt number @@ -686,6 +701,8 @@ irq_found = NO_IRQ; out: spin_unlock_irq(&irq_controller_lock); + + up(&probe_sem); return irq_found; } diff -Nru a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c --- a/arch/arm/kernel/process.c Mon Nov 4 14:31:02 2002 +++ b/arch/arm/kernel/process.c Mon Nov 4 14:31:02 2002 @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -158,6 +159,8 @@ flags = condition_codes(regs); + print_symbol("PC is at %s\n", instruction_pointer(regs)); + print_symbol("LR is at %s\n", regs->ARM_lr); printk("pc : [<%08lx>] lr : [<%08lx>] %s\n" "sp : %08lx ip : %08lx fp : %08lx\n", instruction_pointer(regs), @@ -403,7 +406,7 @@ b sys_exit \n\ 1: " : "=r" (__ret) - : "Ir" (flags), "I" (CLONE_VM), "r" (fn), "r" (arg) + : "Ir" (flags), "r" (CLONE_VM | CLONE_UNTRACED), "r" (fn), "r" (arg) : "r0", "r1", "lr"); return __ret; } diff -Nru a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c --- a/arch/arm/kernel/ptrace.c Mon Nov 4 14:31:00 2002 +++ b/arch/arm/kernel/ptrace.c Mon Nov 4 14:31:00 2002 @@ -692,16 +692,8 @@ ret = ptrace_setfpregs(child, (void *)data); break; - case PTRACE_SETOPTIONS: - if (data & PTRACE_O_TRACESYSGOOD) - child->ptrace |= PT_TRACESYSGOOD; - else - child->ptrace &= ~PT_TRACESYSGOOD; - ret = 0; - break; - default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); break; } diff -Nru a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c --- a/arch/arm/kernel/setup.c Mon Nov 4 14:31:02 2002 +++ b/arch/arm/kernel/setup.c Mon Nov 4 14:31:02 2002 @@ -170,6 +170,26 @@ "undefined 15", }; +static const char *proc_arch[] = { + "undefined/unknown", + "3", + "4", + "4T", + "5", + "5T", + "5TE", + "?(8)", + "?(9)", + "?(10)", + "?(11)", + "?(12)", + "?(13)", + "?(14)", + "?(15)", + "?(16)", + "?(17)", +}; + #define CACHE_TYPE(x) (((x) >> 25) & 15) #define CACHE_S(x) ((x) & (1 << 24)) #define CACHE_DSIZE(x) (((x) >> 12) & 4095) /* only if S=1 */ @@ -214,6 +234,23 @@ #define dump_cpu_info() do { } while (0) #endif +int cpu_architecture(void) +{ + int cpu_arch; + + if ((processor_id & 0x0000f000) == 0) { + cpu_arch = CPU_ARCH_UNKNOWN; + } else if ((processor_id & 0x0000f000) == 0x00007000) { + cpu_arch = (processor_id & (1 << 23)) ? CPU_ARCH_ARMv4T : CPU_ARCH_ARMv3; + } else { + cpu_arch = (processor_id >> 16) & 15; + if (cpu_arch) + cpu_arch += CPU_ARCH_ARMv3; + } + + return cpu_arch; +} + static void __init setup_processor(void) { extern struct proc_info_list __proc_info_begin, __proc_info_end; @@ -250,9 +287,9 @@ cpu_user = *list->user; #endif - printk("CPU: %s %s revision %d\n", + printk("CPU: %s %s revision %d (ARMv%s)\n", proc_info.manufacturer, proc_info.cpu_name, - (int)processor_id & 15); + (int)processor_id & 15, proc_arch[cpu_architecture()]); dump_cpu_info(); @@ -666,25 +703,6 @@ NULL }; -static const char *proc_arch[16] = { - "undefined 0", - "4", - "4T", - "5", - "5T", - "5TE", - "undefined 6", - "undefined 7", - "undefined 8", - "undefined 9", - "undefined 10", - "undefined 11", - "undefined 12", - "undefined 13", - "undefined 14", - "undefined 15" -}; - static void c_show_cache(struct seq_file *m, const char *type, unsigned int cache) { @@ -720,30 +738,23 @@ if (elf_hwcap & (1 << i)) seq_printf(m, "%s ", hwcap_str[i]); - seq_puts(m, "\n"); + seq_printf(m, "\nCPU implementer\t: 0x%02x\n", processor_id >> 24); + seq_printf(m, "CPU architecture: %s\n", proc_arch[cpu_architecture()]); if ((processor_id & 0x0000f000) == 0x00000000) { /* pre-ARM7 */ seq_printf(m, "CPU part\t\t: %07x\n", processor_id >> 4); - } else if ((processor_id & 0x0000f000) == 0x00007000) { - /* ARM7 */ - seq_printf(m, "CPU implementor\t: 0x%02x\n" - "CPU architecture: %s\n" - "CPU variant\t: 0x%02x\n" - "CPU part\t: 0x%03x\n", - processor_id >> 24, - processor_id & (1 << 23) ? "4T" : "3", - (processor_id >> 16) & 127, - (processor_id >> 4) & 0xfff); } else { - /* post-ARM7 */ - seq_printf(m, "CPU implementor\t: 0x%02x\n" - "CPU architecture: %s\n" - "CPU variant\t: 0x%x\n" - "CPU part\t: 0x%03x\n", - processor_id >> 24, - proc_arch[(processor_id >> 16) & 15], - (processor_id >> 20) & 15, + if ((processor_id & 0x0000f000) == 0x00007000) { + /* ARM7 */ + seq_printf(m, "CPU variant\t: 0x%02x\n", + (processor_id >> 16) & 127); + } else { + /* post-ARM7 */ + seq_printf(m, "CPU variant\t: 0x%x\n", + (processor_id >> 20) & 15); + } + seq_printf(m, "CPU part\t: 0x%03x\n", (processor_id >> 4) & 0xfff); } seq_printf(m, "CPU revision\t: %d\n", processor_id & 15); diff -Nru a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c --- a/arch/arm/kernel/traps.c Mon Nov 4 14:31:01 2002 +++ b/arch/arm/kernel/traps.c Mon Nov 4 14:31:01 2002 @@ -13,6 +13,7 @@ * kill the offending process. */ #include +#include #include #include #include @@ -48,6 +49,12 @@ static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; +void dump_backtrace_entry(unsigned long where, unsigned long from) +{ + printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from); + print_symbol(" %s\n", where); +} + /* * Stack pointers should always be within the kernels view of * physical memory. If it is not there, then we can't dump @@ -162,6 +169,13 @@ c_backtrace(fp, processor_mode(regs)); } +void dump_stack(void) +{ +#ifdef CONFIG_DEBUG_ERRORS + __backtrace(); +#endif +} + /* * This is called from SysRq-T (show_task) to display the current call * trace for each process. This version will also display the running @@ -190,8 +204,10 @@ console_verbose(); spin_lock_irq(&die_lock); + bust_spinlocks(1); printk("Internal error: %s: %x\n", str, err); + print_modules(); printk("CPU: %d\n", smp_processor_id()); show_regs(regs); printk("Process %s (pid: %d, stack limit = 0x%p)\n", @@ -203,6 +219,7 @@ dump_instr(regs); } + bust_spinlocks(0); spin_unlock_irq(&die_lock); do_exit(SIGSEGV); } @@ -517,7 +534,7 @@ asmlinkage void __div0(void) { printk("Division by zero in kernel.\n"); - __backtrace(); + dump_stack(); } void abort(void) diff -Nru a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile --- a/arch/arm/lib/Makefile Mon Nov 4 14:31:02 2002 +++ b/arch/arm/lib/Makefile Mon Nov 4 14:31:02 2002 @@ -26,12 +26,12 @@ obj-y += $(obj-$(MACHINE)) -ifeq ($(CONFIG_CPU_32v4),y) - v3 := n - v4 := y -else +ifeq ($(CONFIG_CPU_32v3),y) v3 := y v4 := n +else + v3 := n + v4 := y endif obj-y += io-readsb.o io-writesb.o diff -Nru a/arch/arm/lib/backtrace.S b/arch/arm/lib/backtrace.S --- a/arch/arm/lib/backtrace.S Mon Nov 4 14:31:01 2002 +++ b/arch/arm/lib/backtrace.S Mon Nov 4 14:31:01 2002 @@ -26,7 +26,7 @@ ENTRY(c_backtrace) -#ifdef CONFIG_NO_FRAME_POINTER +#ifndef CONFIG_FRAME_POINTER mov pc, lr #else @@ -62,10 +62,9 @@ ldr r3, .Ldsi+4 teq r1, r3 subeq save, save, #4 - adr r0, .Lfe - mov r1, save - bic r2, r2, mask - bl printk @ print pc and link register + mov r0, save + bic r1, r2, mask + bl dump_backtrace_entry ldr r0, [frame, #-8] @ get sp sub r0, r0, #4 @@ -140,7 +139,6 @@ mov r0, stack LOADREGS(fd, sp!, {instr, reg, stack, r7, pc}) -.Lfe: .asciz "Function entered at [<%p>] from [<%p>]\n" .Lfp: .asciz " r%d = %08X%c" .Lcr: .asciz "\n" .Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n" diff -Nru a/arch/arm/mach-arc/head.S b/arch/arm/mach-arc/head.S --- a/arch/arm/mach-arc/head.S Mon Nov 4 14:31:02 2002 +++ b/arch/arm/mach-arc/head.S Mon Nov 4 14:31:02 2002 @@ -11,6 +11,7 @@ */ #include #include +#include #include .globl swapper_pg_dir @@ -19,7 +20,7 @@ /* * Entry point. */ - .section ".text.init",#alloc,#execinstr + __INIT ENTRY(stext) __entry: cmp pc, #0x02000000 ldrlt pc, LC0 @ if 0x01800000, call at 0x02080000 diff -Nru a/arch/arm/mach-clps711x/time.c b/arch/arm/mach-clps711x/time.c --- a/arch/arm/mach-clps711x/time.c Mon Nov 4 14:31:00 2002 +++ b/arch/arm/mach-clps711x/time.c Mon Nov 4 14:31:00 2002 @@ -35,7 +35,7 @@ { unsigned long hwticks; hwticks = LATCH - (clps_readl(TC2D) & 0xffff); /* since last underflow */ - return (hwticks * tick) / LATCH; + return (hwticks * (tick_nsec / 1000)) / LATCH; } void __init clps711x_setup_timer(void) diff -Nru a/arch/arm/mach-footbridge/mm.c b/arch/arm/mach-footbridge/mm.c --- a/arch/arm/mach-footbridge/mm.c Mon Nov 4 14:31:02 2002 +++ b/arch/arm/mach-footbridge/mm.c Mon Nov 4 14:31:02 2002 @@ -84,12 +84,8 @@ */ unsigned long __virt_to_bus(unsigned long res) { -#ifdef CONFIG_DEBUG_ERRORS - if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) { - printk("__virt_to_bus: invalid virtual address 0x%08lx\n", res); - __backtrace(); - } -#endif + WARN_ON(res < PAGE_OFFSET || res >= (unsigned long)high_memory); + return (res - PAGE_OFFSET) + (*CSR_PCISDRAMBASE & 0xfffffff0); } @@ -98,12 +94,8 @@ res -= (*CSR_PCISDRAMBASE & 0xfffffff0); res += PAGE_OFFSET; -#ifdef CONFIG_DEBUG_ERRORS - if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) { - printk("__bus_to_virt: invalid virtual address 0x%08lx\n", res); - __backtrace(); - } -#endif + WARN_ON(res < PAGE_OFFSET || res >= (unsigned long)high_memory); + return res; } diff -Nru a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c --- a/arch/arm/mach-pxa/generic.c Mon Nov 4 14:31:01 2002 +++ b/arch/arm/mach-pxa/generic.c Mon Nov 4 14:31:01 2002 @@ -31,31 +31,63 @@ #include "generic.h" /* - * Return the current lclk requency in units of 10kHz + * Various clock factors driven by the CCCR register. */ -unsigned int get_lclk_frequency_10khz(void) + +/* Crystal Frequency to Memory Frequency Multiplier (L) */ +static unsigned char L_clk_mult[32] = { 0, 27, 32, 36, 40, 45, 0, }; + +/* Memory Frequency to Run Mode Frequency Multiplier (M) */ +static unsigned char M_clk_mult[4] = { 0, 1, 2, 0 }; + +/* Run Mode Frequency to Turbo Mode Frequency Multiplier (N) */ +/* Note: we store the value N * 2 here. */ +static unsigned char N2_clk_mult[8] = { 0, 0, 2, 3, 4, 0, 6, 0 }; + +/* Crystal clock */ +#define BASE_CLK 3686400 + + +/* + * Display what we were booted with. + */ +static int __init pxa_display_clocks(void) { - unsigned int l; + unsigned long cccr, turbo; + unsigned int l, L, m, M, n2, N; - l = CCCR & 0x1f; + cccr = CCCR; + asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (turbo) ); - switch(l) - { - case 1: - return 9953; - case 2: - return 11796; - case 3: - return 13271; - case 4: - return 14746; - case 5: - return 16589; - case 0xf: - return 3320; - default: - return 0; - } + l = L_clk_mult[(cccr >> 0) & 0x1f]; + m = M_clk_mult[(cccr >> 5) & 0x03]; + n2 = N2_clk_mult[(cccr >> 7) & 0x07]; + + L = l * BASE_CLK; + M = m * L; + N = n2 * M / 2; + + L += 5000; + printk( KERN_INFO "Memory clock: %d.%02dMHz (*%d)\n", + L / 1000000, (L % 1000000) / 10000, l ); + M += 5000; + printk( KERN_INFO "Run Mode clock: %d.%02dMHz (*%d)\n", + M / 1000000, (M % 1000000) / 10000, m ); + N += 5000; + printk( KERN_INFO "Turbo Mode clock: %d.%02dMHz (*%d.%d, %sactive)\n", + N / 1000000, (N % 1000000) / 10000, n2 / 2, (n2 % 2) * 5, + (turbo & 1) ? "" : "in" ); + + return 0; +} + + +/* + * Return the current lclk requency in units of 10kHz + */ +unsigned int get_lclk_frequency_10khz(void) +{ + return L_clk_mult[(CCCR >> 0) & 0x1f] * BASE_CLK / 10000; } EXPORT_SYMBOL(get_lclk_frequency_10khz); @@ -100,4 +132,5 @@ void __init pxa_map_io(void) { iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc)); + pxa_display_clocks(); } diff -Nru a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c --- a/arch/arm/mach-sa1100/badge4.c Mon Nov 4 14:31:00 2002 +++ b/arch/arm/mach-sa1100/badge4.c Mon Nov 4 14:31:00 2002 @@ -31,6 +31,8 @@ #include #include +#include + #include "generic.h" static int __init badge4_sa1111_init(void) @@ -47,6 +49,17 @@ return sa1111_init(BADGE4_SA1111_BASE, BADGE4_IRQ_GPIO_SA1111); } + +static int five_v_on __initdata = 0; + +static int __init five_v_on_setup(char *ignore) +{ + five_v_on = 1; + return 1; +} +__setup("five_v_on", five_v_on_setup); + + static int __init badge4_init(void) { int ret; @@ -54,24 +67,18 @@ if (!machine_is_badge4()) return -ENODEV; - ret = badge4_sa1111_init(); - if (ret < 0) - printk(KERN_ERR - "%s: SA-1111 initialization failed (%d)\n", - __FUNCTION__, ret); - - /* N.B, according to rmk this is the singular place that GPDR - should be set */ - - /* Video expansion */ - GPCR = (BADGE4_GPIO_INT_VID | BADGE4_GPIO_LGP2 | BADGE4_GPIO_LGP3 | - BADGE4_GPIO_LGP4 | BADGE4_GPIO_LGP5 | BADGE4_GPIO_LGP6 | - BADGE4_GPIO_LGP7 | BADGE4_GPIO_LGP8 | BADGE4_GPIO_LGP9 | + /* LCD */ + GPCR = (BADGE4_GPIO_LGP2 | BADGE4_GPIO_LGP3 | + BADGE4_GPIO_LGP4 | BADGE4_GPIO_LGP5 | + BADGE4_GPIO_LGP6 | BADGE4_GPIO_LGP7 | + BADGE4_GPIO_LGP8 | BADGE4_GPIO_LGP9 | BADGE4_GPIO_GPA_VID | BADGE4_GPIO_GPB_VID | BADGE4_GPIO_GPC_VID); - GPDR |= (BADGE4_GPIO_INT_VID | BADGE4_GPIO_LGP2 | BADGE4_GPIO_LGP3 | - BADGE4_GPIO_LGP4 | BADGE4_GPIO_LGP5 | BADGE4_GPIO_LGP6 | - BADGE4_GPIO_LGP7 | BADGE4_GPIO_LGP8 | BADGE4_GPIO_LGP9 | + GPDR &= ~BADGE4_GPIO_INT_VID; + GPDR |= (BADGE4_GPIO_LGP2 | BADGE4_GPIO_LGP3 | + BADGE4_GPIO_LGP4 | BADGE4_GPIO_LGP5 | + BADGE4_GPIO_LGP6 | BADGE4_GPIO_LGP7 | + BADGE4_GPIO_LGP8 | BADGE4_GPIO_LGP9 | BADGE4_GPIO_GPA_VID | BADGE4_GPIO_GPB_VID | BADGE4_GPIO_GPC_VID); @@ -83,28 +90,55 @@ GPCR = (BADGE4_GPIO_UART_HS1 | BADGE4_GPIO_UART_HS2); GPDR |= (BADGE4_GPIO_UART_HS1 | BADGE4_GPIO_UART_HS2); - /* drives CPLD muxsel0 input */ + /* CPLD muxsel0 input for mux/adc chip select */ GPCR = BADGE4_GPIO_MUXSEL0; GPDR |= BADGE4_GPIO_MUXSEL0; - /* test points */ - GPCR = (BADGE4_GPIO_TESTPT_J7 | BADGE4_GPIO_TESTPT_J6 | - BADGE4_GPIO_TESTPT_J5); - GPDR |= (BADGE4_GPIO_TESTPT_J7 | BADGE4_GPIO_TESTPT_J6 | - BADGE4_GPIO_TESTPT_J5); - - /* drives CPLD sdram type inputs; this shouldn't be needed; - bootloader left it this way. */ - GPDR |= (BADGE4_GPIO_SDTYP0 | BADGE4_GPIO_SDTYP1); + /* test points: J5, J6 as inputs, J7 outputs */ + GPDR &= ~(BADGE4_GPIO_TESTPT_J5 | BADGE4_GPIO_TESTPT_J6); + GPCR = BADGE4_GPIO_TESTPT_J7; + GPDR |= BADGE4_GPIO_TESTPT_J7; /* 5V supply rail. */ GPCR = BADGE4_GPIO_PCMEN5V; /* initially off */ GPDR |= BADGE4_GPIO_PCMEN5V; - /* drives SA1111 reset pin; this shouldn't be needed; - bootloader left it this way. */ - GPSR = BADGE4_GPIO_SA1111_NRST; - GPDR |= BADGE4_GPIO_SA1111_NRST; + /* CPLD sdram type inputs; set up by blob */ + //GPDR |= (BADGE4_GPIO_SDTYP1 | BADGE4_GPIO_SDTYP0); + printk(KERN_DEBUG __FILE__ ": SDRAM CPLD typ1=%d typ0=%d\n", + !!(GPLR & BADGE4_GPIO_SDTYP1), + !!(GPLR & BADGE4_GPIO_SDTYP0)); + + /* SA1111 reset pin; set up by blob */ + //GPSR = BADGE4_GPIO_SA1111_NRST; + //GPDR |= BADGE4_GPIO_SA1111_NRST; + + + /* power management cruft */ + PGSR = 0; + PWER = 0; + PCFR = 0; + PSDR = 0; + + PWER |= PWER_GPIO26; /* wake up on an edge from TESTPT_J5 */ + PWER |= PWER_RTC; /* wake up if rtc fires */ + + /* drive sa1111_nrst during sleep */ + PGSR |= BADGE4_GPIO_SA1111_NRST; + /* drive CPLD as is during sleep */ + PGSR |= (GPLR & (BADGE4_GPIO_SDTYP0|BADGE4_GPIO_SDTYP1)); + + + /* Now bring up the SA-1111. */ + ret = badge4_sa1111_init(); + if (ret < 0) + printk(KERN_ERR + "%s: SA-1111 initialization failed (%d)\n", + __FUNCTION__, ret); + + + /* maybe turn on 5v0 from the start */ + badge4_set_5V(BADGE4_5V_INITIALLY, five_v_on); return 0; } diff -Nru a/arch/arm/mm/copypage-v3.S b/arch/arm/mm/copypage-v3.S --- a/arch/arm/mm/copypage-v3.S Mon Nov 4 14:31:02 2002 +++ b/arch/arm/mm/copypage-v3.S Mon Nov 4 14:31:02 2002 @@ -10,6 +10,7 @@ * ASM optimised string functions */ #include +#include #include #include @@ -57,7 +58,7 @@ bne 1b @ 1 ldr pc, [sp], #4 - .section ".text.init", #alloc, #execinstr + __INIT ENTRY(v3_user_fns) .long v3_clear_user_page diff -Nru a/arch/arm/mm/copypage-v4mc.S b/arch/arm/mm/copypage-v4mc.S --- a/arch/arm/mm/copypage-v4mc.S Mon Nov 4 14:31:02 2002 +++ b/arch/arm/mm/copypage-v4mc.S Mon Nov 4 14:31:02 2002 @@ -10,6 +10,7 @@ * ASM optimised string functions */ #include +#include #include .text @@ -70,7 +71,7 @@ bne 1b @ 1 ldr pc, [sp], #4 - .section ".text.init", #alloc, #execinstr + __INIT ENTRY(v4_mc_user_fns) .long v4_mc_clear_user_page diff -Nru a/arch/arm/mm/copypage-v4wb.S b/arch/arm/mm/copypage-v4wb.S --- a/arch/arm/mm/copypage-v4wb.S Mon Nov 4 14:31:02 2002 +++ b/arch/arm/mm/copypage-v4wb.S Mon Nov 4 14:31:02 2002 @@ -10,6 +10,7 @@ * ASM optimised string functions */ #include +#include #include .text @@ -69,7 +70,7 @@ mcr p15, 0, r1, c7, c10, 4 @ 1 drain WB ldr pc, [sp], #4 - .section ".text.init", #alloc, #execinstr + __INIT ENTRY(v4wb_user_fns) .long v4wb_clear_user_page diff -Nru a/arch/arm/mm/copypage-v4wt.S b/arch/arm/mm/copypage-v4wt.S --- a/arch/arm/mm/copypage-v4wt.S Mon Nov 4 14:31:01 2002 +++ b/arch/arm/mm/copypage-v4wt.S Mon Nov 4 14:31:01 2002 @@ -13,6 +13,7 @@ * the only supported cache operation. */ #include +#include #include .text @@ -63,7 +64,7 @@ mcr p15, 0, r2, c7, c7, 0 @ flush ID cache ldr pc, [sp], #4 - .section ".text.init", #alloc, #execinstr + __INIT ENTRY(v4wt_user_fns) .long v4wt_clear_user_page diff -Nru a/arch/arm/mm/copypage-xscale.S b/arch/arm/mm/copypage-xscale.S --- a/arch/arm/mm/copypage-xscale.S Mon Nov 4 14:31:02 2002 +++ b/arch/arm/mm/copypage-xscale.S Mon Nov 4 14:31:02 2002 @@ -8,6 +8,7 @@ * published by the Free Software Foundation. */ #include +#include #include /* @@ -78,7 +79,7 @@ bne 1b ldr pc, [sp], #4 - .section ".text.init", #alloc, #execinstr + __INIT ENTRY(xscale_mc_user_fns) .long xscale_mc_clear_user_page diff -Nru a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c --- a/arch/arm/mm/ioremap.c Mon Nov 4 14:31:02 2002 +++ b/arch/arm/mm/ioremap.c Mon Nov 4 14:31:02 2002 @@ -8,9 +8,7 @@ * Hacked for ARM by Phil Blundell * Hacked to allow all architectures to build, and various cleanups * by Russell King - */ - -/* + * * This allows a driver to remap an arbitrary region of bus memory into * virtual space. One should *only* use readl, writel, memcpy_toio and * so on with such remapped areas. @@ -21,11 +19,6 @@ * two 2GB chunks and mapping only one at a time into processor memory. * We use MMU protection domains to trap any attempt to access the bank * that is not currently mapped. (This isn't fully implemented yet.) - * - * DC21285 currently has a bug in that the PCI address extension - * register affects the address of any writes waiting in the outbound - * FIFO. Unfortunately, it is not possible to tell the DC21285 to - * flush this - flushing the area causes the bus to lock. */ #include #include @@ -34,6 +27,7 @@ #include #include #include +#include static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, unsigned long phys_addr, pgprot_t pgprot) @@ -76,7 +70,7 @@ pgprot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE | flags); do { - pte_t * pte = pte_alloc(&init_mm, pmd, address); + pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address); if (!pte) return -ENOMEM; remap_area_pte(pte, address, end - address, address + phys_addr, pgprot); @@ -129,7 +123,9 @@ * 'flags' are the extra L_PTE_ flags that you want to specify for this * mapping. See include/asm-arm/proc-armv/pgtable.h for more information. */ -void * __ioremap(unsigned long phys_addr, size_t size, unsigned long flags) +void * +__ioremap(unsigned long phys_addr, size_t size, unsigned long flags, + unsigned long align) { void * addr; struct vm_struct * area; diff -Nru a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c --- a/arch/arm/mm/mm-armv.c Mon Nov 4 14:31:02 2002 +++ b/arch/arm/mm/mm-armv.c Mon Nov 4 14:31:02 2002 @@ -169,7 +169,7 @@ pmd_t *pmdp, pmd; pmdp = pmd_offset(pgd_offset_k(virt), virt); - if (virt & (1 << PMD_SHIFT)) + if (virt & (1 << 20)) pmdp++; pmd_val(pmd) = phys | prot; @@ -184,7 +184,7 @@ * the hardware pte table. */ static inline void -alloc_init_page(unsigned long virt, unsigned long phys, int domain, int prot) +alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot) { pmd_t *pmdp, pmd; pte_t *ptep; @@ -195,14 +195,14 @@ ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t)); - pmd_val(pmd) = __pa(ptep) | PMD_TYPE_TABLE | PMD_DOMAIN(domain); + pmd_val(pmd) = __pa(ptep) | prot_l1; set_pmd(pmdp, pmd); pmd_val(pmd) += 256 * sizeof(pte_t); set_pmd(pmdp + 1, pmd); } ptep = pte_offset_kernel(pmdp, virt); - set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, __pgprot(prot))); + set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot)); } /* @@ -217,6 +217,7 @@ struct mem_types { unsigned int prot_pte; + unsigned int prot_l1; unsigned int prot_sect; unsigned int domain; }; @@ -225,41 +226,83 @@ [MT_DEVICE] = { .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE, - .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, + .prot_l1 = PMD_TYPE_TABLE | PMD_BIT4, + .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_UNCACHED | + PMD_SECT_AP_WRITE, .domain = DOMAIN_IO, }, [MT_CACHECLEAN] = { .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_CACHEABLE | L_PTE_BUFFERABLE, - .prot_sect = PMD_TYPE_SECT | PMD_SECT_CACHEABLE | - PMD_SECT_BUFFERABLE, + .prot_l1 = PMD_TYPE_TABLE | PMD_BIT4, + .prot_sect = PMD_TYPE_SECT | PMD_BIT4, .domain = DOMAIN_KERNEL, }, [MT_MINICLEAN] = { .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_CACHEABLE, - .prot_sect = PMD_TYPE_SECT | PMD_SECT_CACHEABLE, + .prot_l1 = PMD_TYPE_TABLE | PMD_BIT4, + .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_MINICACHE, .domain = DOMAIN_KERNEL, }, [MT_VECTORS] = { .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_CACHEABLE | L_PTE_BUFFERABLE | L_PTE_EXEC, - .prot_sect = PMD_TYPE_SECT | PMD_SECT_CACHEABLE | - PMD_SECT_BUFFERABLE, + .prot_l1 = PMD_TYPE_TABLE | PMD_BIT4, + .prot_sect = PMD_TYPE_SECT | PMD_BIT4, .domain = DOMAIN_USER, }, [MT_MEMORY] = { .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_CACHEABLE | L_PTE_BUFFERABLE | L_PTE_EXEC | L_PTE_WRITE, - .prot_sect = PMD_TYPE_SECT | PMD_SECT_CACHEABLE | - PMD_SECT_BUFFERABLE | PMD_SECT_AP_WRITE, + .prot_l1 = PMD_TYPE_TABLE | PMD_BIT4, + .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_AP_WRITE, .domain = DOMAIN_KERNEL, } }; /* + * Adjust the PMD section entries according to the CPU in use. + */ +static void __init build_mem_type_table(void) +{ + int cpu_arch = cpu_architecture(); +#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH + int writethrough = 1; +#else + int writethrough = 0; +#endif + int writealloc = 0, ecc = 0; + + if (cpu_arch < CPU_ARCH_ARMv5) { + writealloc = 0; + ecc = 0; + mem_types[MT_MINICLEAN].prot_sect &= ~PMD_SECT_TEX(1); + } + + if (writethrough) { + mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WT; + mem_types[MT_VECTORS].prot_sect |= PMD_SECT_WT; + mem_types[MT_MEMORY].prot_sect |= PMD_SECT_WT; + } else { + mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WB; + mem_types[MT_VECTORS].prot_sect |= PMD_SECT_WB; + + if (writealloc) + mem_types[MT_MEMORY].prot_sect |= PMD_SECT_WBWA; + else + mem_types[MT_MEMORY].prot_sect |= PMD_SECT_WB; + } + + if (ecc) { + mem_types[MT_VECTORS].prot_sect |= PMD_PROTECTION; + mem_types[MT_MEMORY].prot_sect |= PMD_PROTECTION; + } +} + +/* * Create the page directory entries and any necessary * page tables for the mapping specified by `md'. We * are able to cope here with varying sizes and address @@ -268,7 +311,8 @@ static void __init create_mapping(struct map_desc *md) { unsigned long virt, length; - int prot_sect, prot_pte, domain; + int prot_sect, prot_l1, domain; + pgprot_t prot_pte; long off; if (md->virtual != vectors_base() && md->virtual < PAGE_OFFSET) { @@ -279,7 +323,8 @@ } domain = mem_types[md->type].domain; - prot_pte = mem_types[md->type].prot_pte; + prot_pte = __pgprot(mem_types[md->type].prot_pte); + prot_l1 = mem_types[md->type].prot_l1 | PMD_DOMAIN(domain); prot_sect = mem_types[md->type].prot_sect | PMD_DOMAIN(domain); virt = md->virtual; @@ -287,7 +332,7 @@ length = md->length; while ((virt & 0xfffff || (virt + off) & 0xfffff) && length >= PAGE_SIZE) { - alloc_init_page(virt, virt + off, domain, prot_pte); + alloc_init_page(virt, virt + off, prot_l1, prot_pte); virt += PAGE_SIZE; length -= PAGE_SIZE; @@ -301,7 +346,7 @@ } while (length >= PAGE_SIZE) { - alloc_init_page(virt, virt + off, domain, prot_pte); + alloc_init_page(virt, virt + off, prot_l1, prot_pte); virt += PAGE_SIZE; length -= PAGE_SIZE; @@ -342,6 +387,8 @@ struct map_desc *init_maps, *p, *q; unsigned long address = 0; int i; + + build_mem_type_table(); init_maps = p = alloc_bootmem_low_pages(PAGE_SIZE); diff -Nru a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S --- a/arch/arm/mm/proc-arm1020.S Mon Nov 4 14:31:00 2002 +++ b/arch/arm/mm/proc-arm1020.S Mon Nov 4 14:31:00 2002 @@ -26,6 +26,7 @@ */ #include #include +#include #include #include #include @@ -374,11 +375,6 @@ */ .align 5 ENTRY(cpu_arm1020_set_pmd) -#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH - eor r2, r1, #0x0a @ C & Section - tst r2, #0x0b - biceq r1, r1, #4 @ clear bufferable bit -#endif str r1, [r0] #ifndef CONFIG_CPU_DCACHE_DISABLE mcr p15, 0, r0, c7, c10, 4 @@ -450,7 +446,7 @@ .ascii "\0" .align - .section ".text.init", #alloc, #execinstr + __INIT __arm1020_setup: mov r0, #0 diff -Nru a/arch/arm/mm/proc-arm2_3.S b/arch/arm/mm/proc-arm2_3.S --- a/arch/arm/mm/proc-arm2_3.S Mon Nov 4 14:31:02 2002 +++ b/arch/arm/mm/proc-arm2_3.S Mon Nov 4 14:31:02 2002 @@ -13,6 +13,7 @@ * and memory functions on ARM2, ARM250 and ARM3 processors. */ #include +#include #include #include #include @@ -280,7 +281,7 @@ _arm250_name: .asciz "ARM 250" _arm3_name: .asciz "ARM 3" - .section ".text.init", #alloc, #execinstr + __INIT /* * Purpose : Function pointers used to access above functions - all calls * come through these diff -Nru a/arch/arm/mm/proc-arm6_7.S b/arch/arm/mm/proc-arm6_7.S --- a/arch/arm/mm/proc-arm6_7.S Mon Nov 4 14:31:02 2002 +++ b/arch/arm/mm/proc-arm6_7.S Mon Nov 4 14:31:02 2002 @@ -11,6 +11,7 @@ * functions on the ARM610 & ARM710. */ #include +#include #include #include #include @@ -316,7 +317,7 @@ .asciz "ARM 710" .align - .section ".text.init", #alloc, #execinstr + __INIT __arm6_setup: mov r0, #0 mcr p15, 0, r0, c7, c0 @ flush caches on v3 diff -Nru a/arch/arm/mm/proc-arm720.S b/arch/arm/mm/proc-arm720.S --- a/arch/arm/mm/proc-arm720.S Mon Nov 4 14:31:02 2002 +++ b/arch/arm/mm/proc-arm720.S Mon Nov 4 14:31:02 2002 @@ -31,6 +31,7 @@ * 08-25-2000 DBS Updated for integration of ARM Ltd version. */ #include +#include #include #include #include @@ -177,7 +178,7 @@ .asciz "ARM720T" .align - .section ".text.init", #alloc, #execinstr + __INIT __arm720_setup: mov r0, #0 mcr p15, 0, r0, c7, c7, 0 @ invalidate caches diff -Nru a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S --- a/arch/arm/mm/proc-arm920.S Mon Nov 4 14:31:00 2002 +++ b/arch/arm/mm/proc-arm920.S Mon Nov 4 14:31:00 2002 @@ -26,6 +26,7 @@ */ #include #include +#include #include #include #include @@ -377,11 +378,6 @@ */ .align 5 ENTRY(cpu_arm920_set_pmd) -#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH - eor r2, r1, #0x0a @ C & Section - tst r2, #0x0b - biceq r1, r1, #4 @ clear bufferable bit -#endif str r1, [r0] mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c10, 4 @ drain WB @@ -443,7 +439,7 @@ .ascii "\0" .align - .section ".text.init", #alloc, #execinstr + __INIT __arm920_setup: mov r0, #0 diff -Nru a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S --- a/arch/arm/mm/proc-arm922.S Mon Nov 4 14:31:02 2002 +++ b/arch/arm/mm/proc-arm922.S Mon Nov 4 14:31:02 2002 @@ -27,6 +27,7 @@ */ #include #include +#include #include #include #include @@ -378,11 +379,6 @@ */ .align 5 ENTRY(cpu_arm922_set_pmd) -#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH - eor r2, r1, #0x0a @ C & Section - tst r2, #0x0b - biceq r1, r1, #4 @ clear bufferable bit -#endif str r1, [r0] mcr p15, 0, r0, c7, c10, 1 @ clean D entry mcr p15, 0, r0, c7, c10, 4 @ drain WB @@ -442,7 +438,7 @@ .ascii "\0" .align - .section ".text.init", #alloc, #execinstr + __INIT __arm922_setup: mov r0, #0 diff -Nru a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S --- a/arch/arm/mm/proc-arm926.S Mon Nov 4 14:31:02 2002 +++ b/arch/arm/mm/proc-arm926.S Mon Nov 4 14:31:02 2002 @@ -26,6 +26,7 @@ */ #include #include +#include #include #include #include @@ -359,11 +360,6 @@ */ .align 5 ENTRY(cpu_arm926_set_pmd) -#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH - eor r2, r1, #0x0a @ C & Section - tst r2, #0x0b - biceq r1, r1, #4 @ clear bufferable bit -#endif str r1, [r0] #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH mcr p15, 0, r0, c7, c10, 1 @ clean D entry @@ -430,7 +426,7 @@ .ascii "\0" .align - .section ".text.init", #alloc, #execinstr + __INIT __arm926_setup: mov r0, #0 diff -Nru a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S --- a/arch/arm/mm/proc-sa110.S Mon Nov 4 14:31:01 2002 +++ b/arch/arm/mm/proc-sa110.S Mon Nov 4 14:31:01 2002 @@ -18,6 +18,7 @@ * Flush the read buffer at context switches */ #include +#include #include #include #include @@ -484,7 +485,7 @@ .asciz "StrongARM-1110" .align - .section ".text.init", #alloc, #execinstr + __INIT __sa1100_setup: @ Allow read-buffer operations from userland mcr p15, 0, r0, c9, c0, 5 @@ -560,7 +561,7 @@ */ .type sa1100_processor_functions, #object ENTRY(sa1100_processor_functions) - .word armv4_early_abort + .word v4_early_abort .word cpu_sa1100_check_bugs .word cpu_sa1100_proc_init .word cpu_sa1100_proc_fin diff -Nru a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S --- a/arch/arm/mm/proc-xscale.S Mon Nov 4 14:31:02 2002 +++ b/arch/arm/mm/proc-xscale.S Mon Nov 4 14:31:02 2002 @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -582,11 +583,6 @@ */ .align 5 ENTRY(cpu_xscale_set_pmd) -#if PMD_CACHE_WRITE_ALLOCATE - and r2, r1, #PMD_TYPE_MASK|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE - cmp r2, #PMD_TYPE_SECT|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE - orreq r1, r1, #PMD_SECT_TEX(1) -#endif str r1, [r0] mov ip, #0 mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line @@ -666,9 +662,12 @@ cpu_pxa250_name: .asciz "XScale-PXA250" +cpu_pxa210_name: + .asciz "XScale-PXA210" + .align - .section ".text.init", #alloc, #execinstr + __INIT __xscale_setup: mov r0, #PSR_F_BIT|PSR_I_BIT|SVC_MODE @@ -738,6 +737,12 @@ .long cpu_pxa250_name .size cpu_pxa250_info, . - cpu_pxa250_info + .type cpu_pxa210_info, #object +cpu_pxa210_info: + .long cpu_manu_name + .long cpu_pxa210_name + .size cpu_pxa210_info, . - cpu_pxa210_info + .type cpu_arch_name, #object cpu_arch_name: .asciz "armv5te" @@ -769,7 +774,7 @@ .type __pxa250_proc_info,#object __pxa250_proc_info: .long 0x69052100 - .long 0xfffff7f0 + .long 0xfffff3f0 .long 0x00000c0e b __xscale_setup .long cpu_arch_name @@ -780,4 +785,20 @@ .long v4wbi_tlb_fns .long xscale_mc_user_fns .size __pxa250_proc_info, . - __pxa250_proc_info + + .type __pxa210_proc_info,#object +__pxa210_proc_info: + .long 0x69052120 + .long 0xfffff3f0 + .long 0x00000c0e + b __xscale_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP + .long cpu_pxa210_info + .long xscale_processor_functions + .long v4wbi_tlb_fns + .long xscale_mc_user_fns + .long xscale_cache_fns + .size __pxa210_proc_info, . - __pxa210_proc_info diff -Nru a/arch/arm/mm/tlb-v3.S b/arch/arm/mm/tlb-v3.S --- a/arch/arm/mm/tlb-v3.S Mon Nov 4 14:31:00 2002 +++ b/arch/arm/mm/tlb-v3.S Mon Nov 4 14:31:00 2002 @@ -12,6 +12,7 @@ * Processors: ARM610, ARM710. */ #include +#include #include #include #include "proc-macros.S" @@ -41,7 +42,7 @@ blo 1b mov pc, lr - .section ".text.init", #alloc, #execinstr + __INIT .type v3_tlb_fns, #object ENTRY(v3_tlb_fns) diff -Nru a/arch/arm/mm/tlb-v4.S b/arch/arm/mm/tlb-v4.S --- a/arch/arm/mm/tlb-v4.S Mon Nov 4 14:31:01 2002 +++ b/arch/arm/mm/tlb-v4.S Mon Nov 4 14:31:01 2002 @@ -13,6 +13,7 @@ * Processors: ARM720T */ #include +#include #include #include #include "proc-macros.S" @@ -55,7 +56,7 @@ .globl v4_flush_kern_tlb_range .equ v4_flush_kern_tlb_range, .v4_flush_kern_tlb_range - .section ".text.init", #alloc, #execinstr + __INIT .type v4_tlb_fns, #object ENTRY(v4_tlb_fns) diff -Nru a/arch/arm/mm/tlb-v4wb.S b/arch/arm/mm/tlb-v4wb.S --- a/arch/arm/mm/tlb-v4wb.S Mon Nov 4 14:31:01 2002 +++ b/arch/arm/mm/tlb-v4wb.S Mon Nov 4 14:31:01 2002 @@ -13,6 +13,7 @@ * Processors: ARM920 ARM922 ARM926 SA110 SA1100 SA1110 XScale */ #include +#include #include #include #include "proc-macros.S" @@ -110,7 +111,7 @@ blo 1b mov pc, lr - .section ".text.init", #alloc, #execinstr + __INIT .type v4wb_tlb_fns, #object ENTRY(v4wb_tlb_fns) diff -Nru a/arch/arm/vmlinux-armo.lds.in b/arch/arm/vmlinux-armo.lds.in --- a/arch/arm/vmlinux-armo.lds.in Mon Nov 4 14:31:02 2002 +++ b/arch/arm/vmlinux-armo.lds.in Mon Nov 4 14:31:02 2002 @@ -11,7 +11,7 @@ .init : { /* Init code and data */ _stext = .; __init_begin = .; - *(.text.init) + *(.init.text) __proc_info_begin = .; *(.proc.info) __proc_info_end = .; @@ -21,10 +21,10 @@ __tagtable_begin = .; *(.taglist) __tagtable_end = .; - *(.data.init) + *(.init.data) . = ALIGN(16); __setup_start = .; - *(.setup.init) + *(.init.setup) __setup_end = .; __initcall_start = .; *(.initcall1.init) @@ -44,8 +44,8 @@ } /DISCARD/ : { /* Exit code and data */ - *(.text.exit) - *(.data.exit) + *(.exit.text) + *(.exit.data) *(.exitcall.exit) } diff -Nru a/arch/arm/vmlinux-armv.lds.in b/arch/arm/vmlinux-armv.lds.in --- a/arch/arm/vmlinux-armv.lds.in Mon Nov 4 14:31:01 2002 +++ b/arch/arm/vmlinux-armv.lds.in Mon Nov 4 14:31:01 2002 @@ -11,7 +11,7 @@ .init : { /* Init code and data */ _stext = .; __init_begin = .; - *(.text.init) + *(.init.text) __proc_info_begin = .; *(.proc.info) __proc_info_end = .; @@ -21,10 +21,10 @@ __tagtable_begin = .; *(.taglist) __tagtable_end = .; - *(.data.init) + *(.init.data) . = ALIGN(16); __setup_start = .; - *(.setup.init) + *(.init.setup) __setup_end = .; __initcall_start = .; *(.initcall1.init) @@ -35,13 +35,17 @@ *(.initcall6.init) *(.initcall7.init) __initcall_end = .; + . = ALIGN(32); + __initramfs_start = .; + *(.init.initramfs) + __initramfs_end = .; . = ALIGN(4096); __init_end = .; } /DISCARD/ : { /* Exit code and data */ - *(.text.exit) - *(.data.exit) + *(.exit.text) + *(.exit.data) *(.exitcall.exit) } @@ -72,6 +76,12 @@ __start___ksymtab = .; *(__ksymtab) __stop___ksymtab = .; + } + + __kallsyms : { /* All kernel symbols */ + __start___kallsyms = .; + *(__kallsyms) + __stop___kallsyms = .; } . = ALIGN(8192); diff -Nru a/arch/cris/Kconfig b/arch/cris/Kconfig --- a/arch/cris/Kconfig Mon Nov 4 14:31:02 2002 +++ b/arch/cris/Kconfig Mon Nov 4 14:31:02 2002 @@ -5,6 +5,14 @@ mainmenu "Linux/CRIS Kernel Configuration" +config MMU + bool + default y + +config SWAP + bool + default y + config UID16 bool default y diff -Nru a/arch/cris/kernel/entry.S b/arch/cris/kernel/entry.S --- a/arch/cris/kernel/entry.S Mon Nov 4 14:31:01 2002 +++ b/arch/cris/kernel/entry.S Mon Nov 4 14:31:01 2002 @@ -748,6 +748,7 @@ /* r11 is argument 2 to clone, the flags */ move.d $r12, $r11 or.w LCLONE_VM, $r11 + or.w LCLONE_UNTRACED, $r11 /* Save FN for later. */ move.d $r10, $r12 diff -Nru a/arch/cris/kernel/entryoffsets.c b/arch/cris/kernel/entryoffsets.c --- a/arch/cris/kernel/entryoffsets.c Mon Nov 4 14:31:02 2002 +++ b/arch/cris/kernel/entryoffsets.c Mon Nov 4 14:31:02 2002 @@ -57,5 +57,6 @@ /* linux/sched.h values - doesn't have an #ifdef __ASSEMBLY__ for these. */ VAL (LCLONE_VM, CLONE_VM) +VAL (LCLONE_UNTRACED, CLONE_UNTRACED) __asm__ (".endif"); diff -Nru a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c --- a/arch/cris/kernel/irq.c Mon Nov 4 14:31:03 2002 +++ b/arch/cris/kernel/irq.c Mon Nov 4 14:31:03 2002 @@ -234,7 +234,7 @@ if (!action) continue; seq_printf(p, "%2d: %10u %c %s", - i, kstat.irqs[0][i], + i, kstat_cpu(0).irqs[i], (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); for (action = action->next; action; action = action->next) { @@ -261,7 +261,7 @@ cpu = smp_processor_id(); irq_enter(cpu); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; action = irq_action[irq]; if (action) { diff -Nru a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c --- a/arch/cris/kernel/ptrace.c Mon Nov 4 14:31:01 2002 +++ b/arch/cris/kernel/ptrace.c Mon Nov 4 14:31:01 2002 @@ -292,7 +292,7 @@ } default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); break; } out_tsk: @@ -307,10 +307,8 @@ if ((current->ptrace & (PT_PTRACED | PT_TRACESYS)) != (PT_PTRACED | PT_TRACESYS)) return; - /* TODO: make a way to distinguish between a syscall stop and SIGTRAP - * delivery like in the i386 port ? - */ - current->exit_code = SIGTRAP; + current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0); current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig Mon Nov 4 14:31:01 2002 +++ b/arch/i386/Kconfig Mon Nov 4 14:31:01 2002 @@ -14,6 +14,14 @@ 486, 586, Pentiums, and various instruction-set-compatible chips by AMD, Cyrix, and others. +config MMU + bool + default y + +config SWAP + bool + default y + config SBUS bool @@ -471,26 +479,19 @@ If in doubt, say N. config CPU_FREQ_24_API - bool "/proc/sys/cpu/ interface (2.4.)" + bool "/proc/sys/cpu/ interface (2.4. / OLD)" depends on CPU_FREQ - ---help--- + help This enables the /proc/sys/cpu/ sysctl interface for controlling - CPUFreq, as known from the 2.4.-kernel patches for CPUFreq. Note - that some drivers do not support this interface or offer less - functionality. - - If you say N here, you'll be able to control CPUFreq using the - new /proc/cpufreq interface. + CPUFreq, as known from the 2.4.-kernel patches for CPUFreq. 2.5 + uses /proc/cpufreq instead. Please note that some drivers do not + work well with the 2.4. /proc/sys/cpu sysctl interface, so if in + doubt, say N here. For details, take a look at linux/Documentation/cpufreq. If in doubt, say N. -config CPU_FREQ_26_API - bool - depends on CPU_FREQ && !CPU_FREQ_24_API - default y - config X86_POWERNOW_K6 tristate "AMD Mobile K6-2/K6-3 PowerNow!" depends on CPU_FREQ @@ -554,7 +555,7 @@ config X86_LONGRUN tristate "Transmeta LongRun" - depends on CPU_FREQ && !CPU_FREQ_24_API + depends on CPU_FREQ help This adds the CPUFreq driver for Transmeta Crusoe processors which support LongRun. diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile --- a/arch/i386/Makefile Mon Nov 4 14:31:01 2002 +++ b/arch/i386/Makefile Mon Nov 4 14:31:01 2002 @@ -18,6 +18,7 @@ LDFLAGS := -m elf_i386 OBJCOPYFLAGS := -O binary -R .note -R .comment -S +ARCHBLOBLFLAGS := -I binary -O elf32-i386 -B i386 LDFLAGS_vmlinux := -e stext CFLAGS += -pipe diff -Nru a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c --- a/arch/i386/kernel/cpu/common.c Mon Nov 4 14:31:00 2002 +++ b/arch/i386/kernel/cpu/common.c Mon Nov 4 14:31:00 2002 @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -51,9 +50,16 @@ tsc_disable = 1; return 1; } +#else +#define tsc_disable 0 -__setup("notsc", tsc_setup); +static int __init tsc_setup(char *str) +{ + printk("notsc: Kernel compiled with CONFIG_X86_TSC, cannot disable TSC.\n"); + return 1; +} #endif +__setup("notsc", tsc_setup); int __init get_model_name(struct cpuinfo_x86 *c) { @@ -304,10 +310,8 @@ */ /* TSC disabled? */ -#ifndef CONFIG_X86_TSC if ( tsc_disable ) clear_bit(X86_FEATURE_TSC, c->x86_capability); -#endif /* FXSR disabled? */ if (disable_x86_fxsr) { @@ -315,9 +319,6 @@ clear_bit(X86_FEATURE_XMM, c->x86_capability); } - /* Init Machine Check Exception if available. */ - mcheck_init(c); - /* If the model name is still unset, do table lookup. */ if ( !c->x86_model_id[0] ) { char *p; @@ -355,6 +356,9 @@ boot_cpu_data.x86_capability[1], boot_cpu_data.x86_capability[2], boot_cpu_data.x86_capability[3]); + + /* Init Machine Check Exception if available. */ + mcheck_init(c); } /* * Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c @@ -443,14 +447,12 @@ if (cpu_has_vme || cpu_has_tsc || cpu_has_de) clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); -#ifndef CONFIG_X86_TSC if (tsc_disable && cpu_has_tsc) { printk(KERN_NOTICE "Disabling TSC...\n"); /**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/ clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability); set_in_cr4(X86_CR4_TSD); } -#endif /* * Initialize the per-CPU GDT with the boot GDT, @@ -507,37 +509,3 @@ current->used_math = 0; stts(); } - -/* - * Bulk registration of the cpu devices with the system. - * Some of this stuff could possibly be moved into a shared - * location.. - * Also, these devices should be integrated with other CPU data.. - */ - -static struct cpu cpu_devices[NR_CPUS]; - -static struct device_driver cpu_driver = { - .name = "cpu", - .bus = &system_bus_type, - .devclass = &cpu_devclass, -}; - -static int __init register_cpus(void) -{ - int i; - - driver_register(&cpu_driver); - - for (i = 0; i < NR_CPUS; i++) { - struct sys_device * sysdev = &cpu_devices[i].sysdev; - sysdev->name = "cpu"; - sysdev->id = i; - sysdev->dev.driver = &cpu_driver; - if (cpu_possible(i)) - sys_device_register(sysdev); - } - return 0; -} - -subsys_initcall(register_cpus); diff -Nru a/arch/i386/kernel/cpu/cpufreq/longrun.c b/arch/i386/kernel/cpu/cpufreq/longrun.c --- a/arch/i386/kernel/cpu/cpufreq/longrun.c Mon Nov 4 14:31:02 2002 +++ b/arch/i386/kernel/cpu/cpufreq/longrun.c Mon Nov 4 14:31:02 2002 @@ -251,6 +251,11 @@ longrun_get_policy(&driver->policy[0]); +#ifdef CONFIG_CPU_FREQ_24_API + driver->cpu_min_freq = longrun_low_freq; + driver->cpu_cur_freq[0] = longrun_high_freq; /* dummy value */ +#endif + driver->verify = &longrun_verify_policy; driver->setpolicy = &longrun_set_policy; result = cpufreq_register(driver); diff -Nru a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c --- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c Mon Nov 4 14:31:02 2002 +++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c Mon Nov 4 14:31:02 2002 @@ -50,32 +50,55 @@ MODULE_PARM(stock_freq, "i"); static struct cpufreq_driver *cpufreq_p4_driver; -static unsigned int cpufreq_p4_old_state = 0; static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) { u32 l, h; unsigned long cpus_allowed; - struct cpufreq_freqs freqs; + struct cpufreq_freqs freqs; + int hyperthreading = 0; + int affected_cpu_map = 0; + int sibling = 0; if (!cpu_online(cpu) || (newstate > DC_DISABLE) || (newstate == DC_RESV)) return -EINVAL; - cpu = cpu >> 1; /* physical CPU #nr */ + + /* switch to physical CPU where state is to be changed*/ + cpus_allowed = current->cpus_allowed; + + /* only run on CPU to be set, or on its sibling */ + affected_cpu_map = 1 << cpu; +#ifdef CONFIG_X86_HT + hyperthreading = ((cpu_has_ht) && (smp_num_siblings == 2)); + if (hyperthreading) { + sibling = cpu_sibling_map[cpu]; + affected_cpu_map |= (1 << sibling); + } +#endif + set_cpus_allowed(current, affected_cpu_map); + BUG_ON(!(smp_processor_id() & affected_cpu_map)); + + /* get current state */ + rdmsr(MSR_IA32_THERM_CONTROL, l, h); + l = l >> 1; + l &= 0x7; + + if (l == newstate) { + set_cpus_allowed(current, cpus_allowed); + return 0; + } /* notifiers */ - freqs.old = stock_freq * cpufreq_p4_old_state / 8; + freqs.old = stock_freq * l / 8; freqs.new = stock_freq * newstate / 8; - freqs.cpu = 2*cpu; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - freqs.cpu++; + freqs.cpu = cpu; cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - - /* switch to physical CPU where state is to be changed*/ - cpus_allowed = current->cpus_allowed; - set_cpus_allowed(current, 3 << (2 * cpu)); - BUG_ON(cpu != (smp_processor_id() >> 1)); + if (hyperthreading) { + freqs.cpu = sibling; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + } rdmsr(MSR_IA32_THERM_STATUS, l, h); if (l & 0x01) @@ -86,10 +109,10 @@ rdmsr(MSR_IA32_THERM_CONTROL, l, h); if (newstate == DC_DISABLE) { - printk(KERN_INFO PFX "CPU#%d,%d disabling modulation\n", cpu, (cpu + 1)); + printk(KERN_INFO PFX "CPU#%d disabling modulation\n", cpu); wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); } else { - printk(KERN_INFO PFX "CPU#%d,%d setting duty cycle to %d%%\n", cpu, (cpu + 1), ((125 * newstate) / 10)); + printk(KERN_INFO PFX "CPU#%d setting duty cycle to %d%%\n", cpu, ((125 * newstate) / 10)); /* bits 63 - 5 : reserved * bit 4 : enable/disable * bits 3-1 : duty cycle @@ -104,9 +127,10 @@ /* notifiers */ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - freqs.cpu--; - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - cpufreq_p4_old_state = newstate; + if (hyperthreading) { + freqs.cpu = cpu; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } return 0; } @@ -123,7 +147,7 @@ if (policy->policy == CPUFREQ_POLICY_POWERSAVE) { - for (i=8; i>0; i++) + for (i=8; i>0; i--) if ((policy->min <= ((stock_freq / 8) * i)) && (policy->max >= ((stock_freq / 8) * i))) { @@ -131,7 +155,7 @@ number_states++; } } else { - for (i=0; i<=8; i--) + for (i=1; i<=8; i++) if ((policy->min <= ((stock_freq / 8) * i)) && (policy->max >= ((stock_freq / 8) * i))) { @@ -143,9 +167,9 @@ /* if (number_states == 1) */ { if (policy->cpu == CPUFREQ_ALL_CPUS) { - for (i=0; i<(NR_CPUS/2); i++) - if (cpu_online(2*i)) - cpufreq_p4_setdc((2*i), newstate); + for (i=0; icpu, newstate); } @@ -235,7 +259,6 @@ for (i=0;icpu_cur_freq[i] = stock_freq; #endif - cpufreq_p4_old_state = DC_DISABLE; driver->verify = &cpufreq_p4_verify; driver->setpolicy = &cpufreq_p4_setpolicy; diff -Nru a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c --- a/arch/i386/kernel/cpu/mtrr/generic.c Mon Nov 4 14:31:02 2002 +++ b/arch/i386/kernel/cpu/mtrr/generic.c Mon Nov 4 14:31:02 2002 @@ -312,8 +312,6 @@ { prepare_set(); - printk("MTRR: setting reg %x\n",reg); - if (size == 0) { /* The invalid bit is kept in the mask, so we simply clear the relevant mask register to disable a range. */ diff -Nru a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c --- a/arch/i386/kernel/cpu/proc.c Mon Nov 4 14:31:02 2002 +++ b/arch/i386/kernel/cpu/proc.c Mon Nov 4 14:31:02 2002 @@ -74,6 +74,13 @@ /* Cache size */ if (c->x86_cache_size >= 0) seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size); +#ifdef CONFIG_SMP + if (cpu_has_ht) { + extern int phys_proc_id[NR_CPUS]; + seq_printf(m, "physical id\t: %d\n", phys_proc_id[n]); + seq_printf(m, "siblings\t: %d\n", smp_num_siblings); + } +#endif /* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */ fpu_exception = c->hard_math && (ignore_irq13 || cpu_has_fpu); diff -Nru a/arch/i386/kernel/edd.c b/arch/i386/kernel/edd.c --- a/arch/i386/kernel/edd.c Mon Nov 4 14:31:01 2002 +++ b/arch/i386/kernel/edd.c Mon Nov 4 14:31:01 2002 @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include #include @@ -63,20 +63,9 @@ #define left (count - (p - buf) - 1) -/* - * bios_dir may go away completely, - * and it definitely won't be at the root - * of driverfs forever. - */ -static struct driver_dir_entry bios_dir = { - .name = "bios", - .mode = (S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO), -}; - struct edd_device { - char name[EDD_DEVICE_NAME_SIZE]; struct edd_info *info; - struct driver_dir_entry dir; + struct kobject kobj; }; struct edd_attribute { @@ -112,13 +101,13 @@ } #define to_edd_attr(_attr) container_of(_attr,struct edd_attribute,attr) -#define to_edd_device(_dir) container_of(_dir,struct edd_device,dir) +#define to_edd_device(obj) container_of(obj,struct edd_device,kobj) static ssize_t -edd_attr_show(struct driver_dir_entry *dir, struct attribute *attr, +edd_attr_show(struct kobject * kobj, struct attribute *attr, char *buf, size_t count, loff_t off) { - struct edd_device *dev = to_edd_device(dir); + struct edd_device *dev = to_edd_device(kobj); struct edd_attribute *edd_attr = to_edd_attr(attr); ssize_t ret = 0; @@ -127,7 +116,7 @@ return ret; } -static struct driverfs_ops edd_attr_ops = { +static struct sysfs_ops edd_attr_ops = { .show = edd_attr_show, }; @@ -586,89 +575,26 @@ static EDD_DEVICE_ATTR(host_bus, 0444, edd_show_host_bus, edd_has_edd30); -static struct edd_attribute * def_attrs[] = { - &edd_attr_raw_data, - &edd_attr_version, - &edd_attr_extensions, - &edd_attr_info_flags, - &edd_attr_sectors, - &edd_attr_default_cylinders, - &edd_attr_default_heads, - &edd_attr_default_sectors_per_track, - &edd_attr_interface, - &edd_attr_host_bus, +static struct attribute * def_attrs[] = { + &edd_attr_raw_data.attr, + &edd_attr_version.attr, + &edd_attr_extensions.attr, + &edd_attr_info_flags.attr, + &edd_attr_sectors.attr, + &edd_attr_default_cylinders.attr, + &edd_attr_default_heads.attr, + &edd_attr_default_sectors_per_track.attr, + &edd_attr_interface.attr, + &edd_attr_host_bus.attr, NULL, }; -/* edd_get_devpath_length(), edd_fill_devpath(), and edd_device_link() - were taken from linux/drivers/base/fs/device.c. When these - or similar are exported to generic code, remove these. -*/ - -static int -edd_get_devpath_length(struct device *dev) -{ - int length = 1; - struct device *parent = dev; - - /* walk up the ancestors until we hit the root. - * Add 1 to strlen for leading '/' of each level. - */ - do { - length += strlen(parent->bus_id) + 1; - parent = parent->parent; - } while (parent); - return length; -} - -static void -edd_fill_devpath(struct device *dev, char *path, int length) -{ - struct device *parent; - --length; - for (parent = dev; parent; parent = parent->parent) { - int cur = strlen(parent->bus_id); - - /* back up enough to print this bus id with '/' */ - length -= cur; - strncpy(path + length, parent->bus_id, cur); - *(path + --length) = '/'; - } -} - -static int -edd_device_symlink(struct edd_device *edev, struct device *dev, char *name) -{ - char *path; - int length; - int error = 0; - - if (!dev->bus || !name) - return 0; - - length = edd_get_devpath_length(dev); - - /* now add the path from the edd_device directory - * It should be '../..' (one to get to the 'bios' directory, - * and one to get to the root of the fs.) - */ - length += strlen("../../root"); - - if (length > PATH_MAX) - return -ENAMETOOLONG; - - if (!(path = kmalloc(length, GFP_KERNEL))) - return -ENOMEM; - memset(path, 0, length); - - /* our relative position */ - strcpy(path, "../../root"); +static struct subsystem edd_subsys = { + .kobj = { .name = "edd" }, + .sysfs_ops = &edd_attr_ops, + .default_attrs = def_attrs, +}; - edd_fill_devpath(dev, path, length); - error = driverfs_create_symlink(&edev->dir, name, path); - kfree(path); - return error; -} /** * edd_dev_is_type() - is this EDD device a 'type' device? @@ -721,7 +647,7 @@ struct pci_dev *pci_dev = edd_get_pci_dev(edev); if (!pci_dev) return 1; - return edd_device_symlink(edev, &pci_dev->dev, "pci_dev"); + return sysfs_create_link(&edev->kobj,&pci_dev->dev.kobj,"pci_dev"); } /** @@ -833,61 +759,16 @@ return 1; get_device(&sdev->sdev_driverfs_dev); - rc = edd_device_symlink(edev, &sdev->sdev_driverfs_dev, "disc"); + rc = sysfs_create_link(&edev->kobj,&sdev->sdev_driverfs_dev.kobj, "disc"); put_device(&sdev->sdev_driverfs_dev); return rc; } -static inline int -edd_create_file(struct edd_device *edev, struct edd_attribute *attr) -{ - return driverfs_create_file(&attr->attr, &edev->dir); -} - static inline void edd_device_unregister(struct edd_device *edev) { - driverfs_remove_dir(&edev->dir); -} - -static int -edd_populate_dir(struct edd_device *edev) -{ - struct edd_attribute *attr; - int i; - int error = 0; - - for (i = 0; (attr=def_attrs[i]); i++) { - if (!attr->test || (attr->test && !attr->test(edev))) { - if ((error = edd_create_file(edev, attr))) { - break; - } - } - } - - if (error) - return error; - - edd_create_symlink_to_pcidev(edev); - edd_create_symlink_to_scsidev(edev); - - return 0; -} - -static int -edd_make_dir(struct edd_device *edev) -{ - int error; - - edev->dir.name = edev->name; - edev->dir.mode = (S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO); - edev->dir.ops = &edd_attr_ops; - - error = driverfs_create_dir(&edev->dir, &bios_dir); - if (!error) - error = edd_populate_dir(edev); - return error; + kobject_unregister(&edev->kobj); } static int @@ -899,9 +780,15 @@ return 1; memset(edev, 0, sizeof (*edev)); edd_dev_set_info(edev, &edd[i]); - snprintf(edev->name, EDD_DEVICE_NAME_SIZE, "int13_dev%02x", + kobject_init(&edev->kobj); + snprintf(edev->kobj.name, EDD_DEVICE_NAME_SIZE, "int13_dev%02x", edd[i].device); - error = edd_make_dir(edev); + edev->kobj.subsys = &edd_subsys; + error = kobject_register(&edev->kobj); + if (!error) { + edd_create_symlink_to_pcidev(edev); + edd_create_symlink_to_scsidev(edev); + } return error; } @@ -926,7 +813,7 @@ return 1; } - rc = driverfs_create_dir(&bios_dir, NULL); + rc = firmware_register(&edd_subsys); if (rc) return rc; @@ -943,12 +830,9 @@ edd_devices[i] = edev; } - if (rc) { - driverfs_remove_dir(&bios_dir); - return rc; - } - - return 0; + if (rc) + firmware_unregister(&edd_subsys); + return rc; } static void __exit @@ -963,8 +847,7 @@ kfree(edev); } } - - driverfs_remove_dir(&bios_dir); + firmware_unregister(&edd_subsys); } late_initcall(edd_init); diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S --- a/arch/i386/kernel/entry.S Mon Nov 4 14:31:01 2002 +++ b/arch/i386/kernel/entry.S Mon Nov 4 14:31:01 2002 @@ -740,6 +740,7 @@ .long sys_epoll_create .long sys_epoll_ctl /* 255 */ .long sys_epoll_wait + .long sys_remap_file_pages .rept NR_syscalls-(.-sys_call_table)/4 diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c --- a/arch/i386/kernel/i386_ksyms.c Mon Nov 4 14:31:03 2002 +++ b/arch/i386/kernel/i386_ksyms.c Mon Nov 4 14:31:03 2002 @@ -143,6 +143,11 @@ EXPORT_SYMBOL(mmx_copy_page); #endif +#ifdef CONFIG_X86_HT +EXPORT_SYMBOL(smp_num_siblings); +EXPORT_SYMBOL(cpu_sibling_map); +#endif + #ifdef CONFIG_SMP EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL(cpu_online_map); diff -Nru a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c --- a/arch/i386/kernel/ioport.c Mon Nov 4 14:31:01 2002 +++ b/arch/i386/kernel/ioport.c Mon Nov 4 14:31:01 2002 @@ -110,7 +110,7 @@ asmlinkage int sys_iopl(unsigned long unused) { - struct pt_regs * regs = (struct pt_regs *) &unused; + volatile struct pt_regs * regs = (struct pt_regs *) &unused; unsigned int level = regs->ebx; unsigned int old = (regs->eflags >> 12) & 3; diff -Nru a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c --- a/arch/i386/kernel/irq.c Mon Nov 4 14:31:00 2002 +++ b/arch/i386/kernel/irq.c Mon Nov 4 14:31:00 2002 @@ -153,7 +153,7 @@ for (j = 0; j < NR_CPUS; j++) if (cpu_online(j)) p += seq_printf(p, "%10u ", - kstat.irqs[j][i]); + kstat_cpu(j).irqs[i]); #endif seq_printf(p, " %14s", irq_desc[i].handler->typename); seq_printf(p, " %s", action->name); @@ -345,7 +345,7 @@ } } #endif - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; spin_lock(&desc->lock); desc->handler->ack(irq); /* diff -Nru a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c --- a/arch/i386/kernel/ldt.c Mon Nov 4 14:31:02 2002 +++ b/arch/i386/kernel/ldt.c Mon Nov 4 14:31:02 2002 @@ -104,7 +104,7 @@ /* * No need to lock the MM as we are the last user */ -void release_segments(struct mm_struct *mm) +void destroy_context(struct mm_struct *mm) { if (mm->context.size) { if (mm == current->active_mm) diff -Nru a/arch/i386/kernel/numaq.c b/arch/i386/kernel/numaq.c --- a/arch/i386/kernel/numaq.c Mon Nov 4 14:31:02 2002 +++ b/arch/i386/kernel/numaq.c Mon Nov 4 14:31:02 2002 @@ -52,6 +52,7 @@ numnodes = 0; for(node = 0; node < MAX_NUMNODES; node++) { if(scd->quads_present31_0 & (1 << node)) { + node_set_online(node); numnodes++; eq = &scd->eq[node]; /* Convert to pages */ diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c --- a/arch/i386/kernel/process.c Mon Nov 4 14:31:00 2002 +++ b/arch/i386/kernel/process.c Mon Nov 4 14:31:00 2002 @@ -224,7 +224,7 @@ regs.eflags = 0x286; /* Ok, create the new process.. */ - p = do_fork(flags | CLONE_VM, 0, ®s, 0, NULL); + p = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } @@ -247,6 +247,7 @@ struct task_struct *tsk = current; memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8); + memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); /* * Forget coprocessor state.. */ diff -Nru a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c --- a/arch/i386/kernel/ptrace.c Mon Nov 4 14:31:01 2002 +++ b/arch/i386/kernel/ptrace.c Mon Nov 4 14:31:01 2002 @@ -416,17 +416,8 @@ break; } - case PTRACE_SETOPTIONS: { - if (data & PTRACE_O_TRACESYSGOOD) - child->ptrace |= PT_TRACESYSGOOD; - else - child->ptrace &= ~PT_TRACESYSGOOD; - ret = 0; - break; - } - default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); break; } out_tsk: diff -Nru a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c --- a/arch/i386/kernel/smpboot.c Mon Nov 4 14:31:01 2002 +++ b/arch/i386/kernel/smpboot.c Mon Nov 4 14:31:01 2002 @@ -58,7 +58,7 @@ /* Number of siblings per CPU package */ int smp_num_siblings = 1; -int __initdata phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */ +int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */ /* Bitmask of currently online CPUs */ unsigned long cpu_online_map; @@ -118,7 +118,8 @@ struct cpuinfo_x86 *c = cpu_data + id; *c = boot_cpu_data; - identify_cpu(c); + if (id!=0) + identify_cpu(c); /* * Mask B, Pentium, but not Pentium MMX */ diff -Nru a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386.c --- a/arch/i386/kernel/sys_i386.c Mon Nov 4 14:31:01 2002 +++ b/arch/i386/kernel/sys_i386.c Mon Nov 4 14:31:01 2002 @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -248,91 +249,68 @@ } #ifdef CONFIG_HUGETLB_PAGE -#define HPAGE_ALIGN(x) (((unsigned long)x + (HPAGE_SIZE -1)) & HPAGE_MASK) -extern long sys_munmap(unsigned long, size_t); /* get_addr function gets the currently unused virtaul range in - * current process's address space. It returns the LARGE_PAGE_SIZE + * current process's address space. It returns the HPAGE_SIZE * aligned address (in cases of success). Other kernel generic - * routines only could gurantee that allocated address is PAGE_SIZSE aligned. + * routines only could gurantee that allocated address is PAGE_SIZE aligned. */ -static unsigned long -get_addr(unsigned long addr, unsigned long len) +static unsigned long get_addr(unsigned long addr, unsigned long len) { - struct vm_area_struct *vma; + struct vm_area_struct *vma; if (addr) { - addr = HPAGE_ALIGN(addr); + addr = (addr + HPAGE_SIZE - 1) & HPAGE_MASK; vma = find_vma(current->mm, addr); - if (((TASK_SIZE - len) >= addr) && - (!vma || addr + len <= vma->vm_start)) + if (TASK_SIZE > addr + len && !(vma && addr + len >= vma->vm_start)) goto found_addr; } - addr = HPAGE_ALIGN(TASK_UNMAPPED_BASE); - for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) { - if (TASK_SIZE - len < addr) - return -ENOMEM; - if (!vma || ((addr + len) < vma->vm_start)) + addr = TASK_UNMAPPED_BASE; + for (vma = find_vma(current->mm, addr); TASK_SIZE > addr + len; vma = vma->vm_next) { + if (!vma || addr + len < vma->vm_start) goto found_addr; - addr = HPAGE_ALIGN(vma->vm_end); + addr = (vma->vm_end + HPAGE_SIZE - 1) & HPAGE_MASK; } + return -ENOMEM; found_addr: return addr; } -asmlinkage unsigned long -sys_alloc_hugepages(int key, unsigned long addr, unsigned long len, int prot, int flag) +asmlinkage unsigned long sys_alloc_hugepages(int key, unsigned long addr, unsigned long len, int prot, int flag) { struct mm_struct *mm = current->mm; unsigned long raddr; int retval = 0; extern int alloc_hugetlb_pages(int, unsigned long, unsigned long, int, int); - if (!(cpu_has_pse)) - return -EINVAL; - if (key < 0) - return -EINVAL; - if (len & (HPAGE_SIZE - 1)) + if (!cpu_has_pse || key < 0 || len & ~HPAGE_MASK) return -EINVAL; down_write(&mm->mmap_sem); raddr = get_addr(addr, len); - if (raddr == -ENOMEM) - goto raddr_out; - retval = alloc_hugetlb_pages(key, raddr, len, prot, flag); - -raddr_out: up_write(&mm->mmap_sem); - if (retval < 0) - return (unsigned long) retval; - return raddr; + if (raddr != -ENOMEM) + retval = alloc_hugetlb_pages(key, raddr, len, prot, flag); + up_write(&mm->mmap_sem); + return (retval < 0) ? (unsigned long)retval : raddr; } -asmlinkage int -sys_free_hugepages(unsigned long addr) +asmlinkage int sys_free_hugepages(unsigned long addr) { struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - int retval; - extern int free_hugepages(struct vm_area_struct *); + struct vm_area_struct *vma; + int retval; vma = find_vma(current->mm, addr); - if ((!vma) || (!is_vm_hugetlb_page(vma)) || (vma->vm_start!=addr)) + if (!vma || !(vma->vm_flags & VM_HUGETLB) || vma->vm_start != addr) return -EINVAL; down_write(&mm->mmap_sem); - spin_lock(&mm->page_table_lock); - retval = free_hugepages(vma); - spin_unlock(&mm->page_table_lock); + retval = do_munmap(vma->vm_mm, addr, vma->vm_end - addr); up_write(&mm->mmap_sem); return retval; } - #else - -asmlinkage unsigned long -sys_alloc_hugepages(int key, unsigned long addr, size_t len, int prot, int flag) +asmlinkage unsigned long sys_alloc_hugepages(int key, unsigned long addr, size_t len, int prot, int flag) { return -ENOSYS; } -asmlinkage int -sys_free_hugepages(unsigned long addr) +asmlinkage int sys_free_hugepages(unsigned long addr) { return -ENOSYS; } - #endif diff -Nru a/arch/i386/kernel/timers/timer_pit.c b/arch/i386/kernel/timers/timer_pit.c --- a/arch/i386/kernel/timers/timer_pit.c Mon Nov 4 14:31:02 2002 +++ b/arch/i386/kernel/timers/timer_pit.c Mon Nov 4 14:31:02 2002 @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff -Nru a/arch/i386/mach-generic/Makefile b/arch/i386/mach-generic/Makefile --- a/arch/i386/mach-generic/Makefile Mon Nov 4 14:31:01 2002 +++ b/arch/i386/mach-generic/Makefile Mon Nov 4 14:31:01 2002 @@ -4,6 +4,6 @@ EXTRA_CFLAGS += -I../kernel -obj-y := setup.o +obj-y := setup.o topology.o include $(TOPDIR)/Rules.make diff -Nru a/arch/i386/mach-generic/topology.c b/arch/i386/mach-generic/topology.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/topology.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,67 @@ +/* + * arch/i386/mach-generic/topology.c - Populate driverfs with topology information + * + * Written by: Matthew Dobson, IBM Corporation + * Original Code: Paul Dorwin, IBM Corporation, Patrick Mochel, OSDL + * + * Copyright (C) 2002, IBM Corp. + * + * All rights reserved. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + */ +#include +#include + +struct i386_cpu cpu_devices[NR_CPUS]; + +#ifdef CONFIG_NUMA +#include +#include +#include + +struct i386_node node_devices[MAX_NUMNODES]; +struct i386_memblk memblk_devices[MAX_NR_MEMBLKS]; + +static int __init topology_init(void) +{ + int i; + + for (i = 0; i < num_online_nodes(); i++) + arch_register_node(i); + for (i = 0; i < NR_CPUS; i++) + if (cpu_possible(i)) arch_register_cpu(i); + for (i = 0; i < num_online_memblks(); i++) + arch_register_memblk(i); + return 0; +} + +#else /* !CONFIG_NUMA */ + +static int __init topology_init(void) +{ + int i; + + for (i = 0; i < NR_CPUS; i++) + if (cpu_possible(i)) arch_register_cpu(i); + return 0; +} + +#endif /* CONFIG_NUMA */ + +subsys_initcall(topology_init); diff -Nru a/arch/i386/mach-visws/visws_apic.c b/arch/i386/mach-visws/visws_apic.c --- a/arch/i386/mach-visws/visws_apic.c Mon Nov 4 14:31:00 2002 +++ b/arch/i386/mach-visws/visws_apic.c Mon Nov 4 14:31:00 2002 @@ -324,7 +324,7 @@ /* * handle this 'virtual interrupt' as a Cobalt one now. */ - kstat.irqs[smp_processor_id()][irq]++; + kstat_cpu(smp_processor_id()).irqs[irq]++; do_cobalt_IRQ(realirq, regs); spin_lock(&irq_controller_lock); diff -Nru a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c --- a/arch/i386/mm/hugetlbpage.c Mon Nov 4 14:31:02 2002 +++ b/arch/i386/mm/hugetlbpage.c Mon Nov 4 14:31:02 2002 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -17,7 +18,7 @@ #include #include -static struct vm_operations_struct hugetlb_vm_ops; +struct vm_operations_struct hugetlb_vm_ops; struct list_head htlbpage_freelist; spinlock_t htlbpage_lock = SPIN_LOCK_UNLOCKED; extern long htlbpagemem; @@ -30,8 +31,7 @@ int key; } htlbpagek[MAX_ID]; -static struct inode * -find_key_inode(int key) +static struct inode *find_key_inode(int key) { int i; @@ -41,8 +41,8 @@ } return NULL; } -static struct page * -alloc_hugetlb_page(void) + +static struct page *alloc_hugetlb_page(void) { int i; struct page *page; @@ -63,36 +63,7 @@ return page; } -static void -free_hugetlb_page(struct page *page) -{ - spin_lock(&htlbpage_lock); - if ((page->mapping != NULL) && (page_count(page) == 2)) { - struct inode *inode = page->mapping->host; - int i; - - ClearPageDirty(page); - remove_from_page_cache(page); - set_page_count(page, 1); - if ((inode->i_size -= HPAGE_SIZE) == 0) { - for (i = 0; i < MAX_ID; i++) - if (htlbpagek[i].key == inode->i_ino) { - htlbpagek[i].key = 0; - htlbpagek[i].in = NULL; - break; - } - kfree(inode); - } - } - if (put_page_testzero(page)) { - list_add(&page->list, &htlbpage_freelist); - htlbpagemem++; - } - spin_unlock(&htlbpage_lock); -} - -static pte_t * -huge_pte_alloc(struct mm_struct *mm, unsigned long addr) +static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) { pgd_t *pgd; pmd_t *pmd = NULL; @@ -102,8 +73,7 @@ return (pte_t *) pmd; } -static pte_t * -huge_pte_offset(struct mm_struct *mm, unsigned long addr) +static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) { pgd_t *pgd; pmd_t *pmd = NULL; @@ -115,9 +85,7 @@ #define mk_pte_huge(entry) {entry.pte_low |= (_PAGE_PRESENT | _PAGE_PSE);} -static void -set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma, - struct page *page, pte_t * page_table, int write_access) +static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma, struct page *page, pte_t * page_table, int write_access) { pte_t entry; @@ -130,24 +98,17 @@ entry = pte_mkyoung(entry); mk_pte_huge(entry); set_pte(page_table, entry); - return; } -static int -anon_get_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, - int write_access, pte_t * page_table) +static int anon_get_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, int write_access, pte_t *page_table) { - struct page *page; - - page = alloc_hugetlb_page(); - if (page == NULL) - return -1; - set_huge_pte(mm, vma, page, page_table, write_access); - return 1; + struct page *page = alloc_hugetlb_page(); + if (page) + set_huge_pte(mm, vma, page, page_table, write_access); + return page ? 1 : -1; } -int -make_hugetlb_pages_present(unsigned long addr, unsigned long end, int flags) +int make_hugetlb_pages_present(unsigned long addr, unsigned long end, int flags) { int write; struct mm_struct *mm = current->mm; @@ -253,31 +214,61 @@ return i; } -void -zap_hugetlb_resources(struct vm_area_struct *mpnt) +void free_huge_page(struct page *page) { - struct mm_struct *mm = mpnt->vm_mm; - unsigned long len, addr, end; - pte_t *ptep; + BUG_ON(page_count(page)); + BUG_ON(page->mapping); + + INIT_LIST_HEAD(&page->list); + + spin_lock(&htlbpage_lock); + list_add(&page->list, &htlbpage_freelist); + htlbpagemem++; + spin_unlock(&htlbpage_lock); +} + +void huge_page_release(struct page *page) +{ + if (!put_page_testzero(page)) + return; + + free_huge_page(page); +} + +void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long address; + pte_t *pte; struct page *page; - addr = mpnt->vm_start; - end = mpnt->vm_end; - len = end - addr; - do { - ptep = huge_pte_offset(mm, addr); - page = pte_page(*ptep); - pte_clear(ptep); - free_hugetlb_page(page); - addr += HPAGE_SIZE; - } while (addr < end); - mm->rss -= (len >> PAGE_SHIFT); - mpnt->vm_ops = NULL; - flush_tlb_range(mpnt, end - len, end); + BUG_ON(start & (HPAGE_SIZE - 1)); + BUG_ON(end & (HPAGE_SIZE - 1)); + + for (address = start; address < end; address += HPAGE_SIZE) { + pte = huge_pte_offset(mm, address); + page = pte_page(*pte); + huge_page_release(page); + pte_clear(pte); + } + mm->rss -= (end - start) >> PAGE_SHIFT; + flush_tlb_range(vma, start, end); } -static void -unlink_vma(struct vm_area_struct *mpnt) +void zap_hugepage_range(struct vm_area_struct *vma, unsigned long start, unsigned long length) +{ + struct mm_struct *mm = vma->vm_mm; + spin_lock(&mm->page_table_lock); + unmap_hugepage_range(vma, start, start + length); + spin_unlock(&mm->page_table_lock); +} + +void zap_hugetlb_resources(struct vm_area_struct *vma) +{ + zap_hugepage_range(vma, vma->vm_start, vma->vm_end); +} + +static void unlink_vma(struct vm_area_struct *mpnt) { struct mm_struct *mm = current->mm; struct vm_area_struct *vma; @@ -296,17 +287,7 @@ mm->map_count--; } -int -free_hugepages(struct vm_area_struct *mpnt) -{ - unlink_vma(mpnt); - zap_hugetlb_resources(mpnt); - kmem_cache_free(vm_area_cachep, mpnt); - return 1; -} - -static struct inode * -set_new_inode(unsigned long len, int prot, int flag, int key) +static struct inode *set_new_inode(unsigned long len, int prot, int flag, int key) { struct inode *inode; int i; @@ -336,8 +317,7 @@ return inode; } -static int -check_size_prot(struct inode *inode, unsigned long len, int prot, int flag) +static int check_size_prot(struct inode *inode, unsigned long len, int prot, int flag) { if (inode->i_uid != current->fsuid) return -1; @@ -348,15 +328,12 @@ return 0; } -static int -alloc_shared_hugetlb_pages(int key, unsigned long addr, unsigned long len, - int prot, int flag) +static int alloc_shared_hugetlb_pages(int key, unsigned long addr, unsigned long len, int prot, int flag) { struct mm_struct *mm = current->mm; struct vm_area_struct *vma; struct inode *inode; struct address_space *mapping; - struct page *page; int idx; int retval = -ENOMEM; int newalloc = 0; @@ -404,25 +381,10 @@ goto freeinode; } - spin_lock(&mm->page_table_lock); - do { - pte_t *pte = huge_pte_alloc(mm, addr); - if ((pte) && (pte_none(*pte))) { - idx = (addr - vma->vm_start) >> HPAGE_SHIFT; - page = find_get_page(mapping, idx); - if (page == NULL) { - page = alloc_hugetlb_page(); - if (page == NULL) - goto out; - add_to_page_cache(page, mapping, idx); - } - set_huge_pte(mm, vma, page, pte, - (vma->vm_flags & VM_WRITE)); - } else - goto out; - addr += HPAGE_SIZE; - } while (addr < vma->vm_end); - retval = 0; + retval = hugetlb_prefault(mapping, vma); + if (retval) + goto out; + vma->vm_flags |= (VM_HUGETLB | VM_RESERVED); vma->vm_ops = &hugetlb_vm_ops; spin_unlock(&mm->page_table_lock); @@ -457,9 +419,48 @@ return retval; } -static int -alloc_private_hugetlb_pages(int key, unsigned long addr, unsigned long len, - int prot, int flag) +int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) +{ + struct mm_struct *mm = current->mm; + unsigned long addr; + int ret = 0; + + BUG_ON(vma->vm_start & ~HPAGE_MASK); + BUG_ON(vma->vm_end & ~HPAGE_MASK); + + spin_lock(&mm->page_table_lock); + for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) { + unsigned long idx; + pte_t *pte = huge_pte_alloc(mm, addr); + struct page *page; + + if (!pte) { + ret = -ENOMEM; + goto out; + } + if (!pte_none(*pte)) + continue; + + idx = ((addr - vma->vm_start) >> HPAGE_SHIFT) + + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT)); + page = find_get_page(mapping, idx); + if (!page) { + page = alloc_hugetlb_page(); + if (!page) { + ret = -ENOMEM; + goto out; + } + add_to_page_cache(page, mapping, idx); + unlock_page(page); + } + set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE); + } +out: + spin_unlock(&mm->page_table_lock); + return ret; +} + +static int alloc_private_hugetlb_pages(int key, unsigned long addr, unsigned long len, int prot, int flag) { if (!capable(CAP_SYS_ADMIN)) { if (!in_group_p(0)) @@ -476,17 +477,14 @@ return 0; } -int -alloc_hugetlb_pages(int key, unsigned long addr, unsigned long len, int prot, - int flag) +int alloc_hugetlb_pages(int key, unsigned long addr, unsigned long len, int prot, int flag) { if (key > 0) return alloc_shared_hugetlb_pages(key, addr, len, prot, flag); return alloc_private_hugetlb_pages(key, addr, len, prot, flag); } -int -set_hugetlb_mem_size(int count) +int set_hugetlb_mem_size(int count) { int j, lcount; struct page *page, *map; @@ -529,7 +527,7 @@ map->flags &= ~(1 << PG_locked | 1 << PG_error | 1 << PG_referenced | 1 << PG_dirty | 1 << PG_active | 1 << PG_reserved | 1 << PG_private | 1<< PG_writeback); - set_page_count(page, 0); + set_page_count(map, 0); map++; } set_page_count(page, 1); @@ -538,6 +536,12 @@ return (int) htlbzone_pages; } -static struct vm_operations_struct hugetlb_vm_ops = { - .close = zap_hugetlb_resources, +static struct page * hugetlb_nopage(struct vm_area_struct * area, unsigned long address, int unused) +{ + BUG(); + return NULL; +} + +struct vm_operations_struct hugetlb_vm_ops = { + .nopage = hugetlb_nopage, }; diff -Nru a/arch/i386/mm/init.c b/arch/i386/mm/init.c --- a/arch/i386/mm/init.c Mon Nov 4 14:31:02 2002 +++ b/arch/i386/mm/init.c Mon Nov 4 14:31:02 2002 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff -Nru a/arch/i386/oprofile/Makefile b/arch/i386/oprofile/Makefile --- a/arch/i386/oprofile/Makefile Mon Nov 4 14:31:02 2002 +++ b/arch/i386/oprofile/Makefile Mon Nov 4 14:31:02 2002 @@ -1,5 +1,3 @@ -vpath %.c = . $(TOPDIR)/drivers/oprofile - obj-$(CONFIG_OPROFILE) += oprofile.o DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ @@ -9,8 +7,6 @@ oprofile-objs := $(DRIVER_OBJS) init.o timer_int.o -ifdef CONFIG_X86_LOCAL_APIC -oprofile-objs += nmi_int.o op_model_athlon.o op_model_ppro.o -endif +oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o op_model_ppro.o include $(TOPDIR)/Rules.make diff -Nru a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c --- a/arch/i386/oprofile/nmi_int.c Mon Nov 4 14:31:02 2002 +++ b/arch/i386/oprofile/nmi_int.c Mon Nov 4 14:31:02 2002 @@ -135,9 +135,19 @@ static void nmi_cpu_shutdown(void * dummy) { + unsigned int v; int cpu = smp_processor_id(); struct op_msrs * msrs = &cpu_msrs[cpu]; + + /* restoring APIC_LVTPC can trigger an apic error because the delivery + * mode and vector nr combination can be illegal. That's by design: on + * power on apic lvt contain a zero vector nr which are legal only for + * NMI delivery mode. So inhibit apic err before restoring lvtpc + */ + v = apic_read(APIC_LVTERR); + apic_write(APIC_LVTERR, v | APIC_LVT_MASKED); apic_write(APIC_LVTPC, saved_lvtpc[cpu]); + apic_write(APIC_LVTERR, v); nmi_restore_registers(msrs); } diff -Nru a/arch/i386/vmlinux.lds.S b/arch/i386/vmlinux.lds.S --- a/arch/i386/vmlinux.lds.S Mon Nov 4 14:31:01 2002 +++ b/arch/i386/vmlinux.lds.S Mon Nov 4 14:31:01 2002 @@ -77,6 +77,10 @@ *(.initcall7.init) } __initcall_end = .; + . = ALIGN(4096); + __initramfs_start = .; + .init.ramfs : { *(.init.initramfs) } + __initramfs_end = .; . = ALIGN(32); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } diff -Nru a/arch/ia64/Kconfig b/arch/ia64/Kconfig --- a/arch/ia64/Kconfig Mon Nov 4 14:31:02 2002 +++ b/arch/ia64/Kconfig Mon Nov 4 14:31:02 2002 @@ -1,61 +1,30 @@ - mainmenu "IA-64 Linux Kernel Configuration" source "init/Kconfig" - menu "Processor type and features" config IA64 bool default y help - The Itanium is Intel's 64-bit successor to the 32-bit X86 line. As - of early 2001 it is not yet in widespread production use. The Linux - IA-64 project has a home page at . - -config ISA - bool - help - Find out whether you have ISA slots on your motherboard. ISA is the - name of a bus system, i.e. the way the CPU talks to the other stuff - inside your box. Other bus systems are PCI, EISA, MicroChannel - (MCA) or VESA. ISA is an older system, now being displaced by PCI; - newer boards don't support it. If you have ISA, say Y, otherwise N. - -config EISA - bool - ---help--- - The Extended Industry Standard Architecture (EISA) bus was - developed as an open alternative to the IBM MicroChannel bus. - - The EISA bus provided some of the features of the IBM MicroChannel - bus while maintaining backward compatibility with cards made for - the older ISA bus. The EISA bus saw limited use between 1988 and - 1995 when it was made obsolete by the PCI bus. + The Itanium Processor Family is Intel's 64-bit successor to + the 32-bit X86 line. The IA-64 Linux project has a home + page at and a mailing list at + linux-ia64@linuxia64.org. - Say Y here if you are building a kernel for an EISA-based machine. - - Otherwise, say N. - -config MCA +config MMU bool - help - MicroChannel Architecture is found in some IBM PS/2 machines and - laptops. It is a bus system similar to PCI or ISA. See - (and especially the web page given - there) before attempting to build an MCA bus kernel. + default y -config SBUS +config SWAP bool + default y config RWSEM_GENERIC_SPINLOCK bool default y -config RWSEM_XCHGADD_ALGORITHM - bool - choice prompt "IA-64 processor type" default ITANIUM @@ -63,10 +32,12 @@ config ITANIUM bool "Itanium" help - Select your IA64 processor type. The default is Intel Itanium. + Select your IA-64 processor type. The default is Intel Itanium. + This choice is safe for all IA-64 systems, but may not perform + optimally on systems with, say, Itanium 2 or newer processors. config MCKINLEY - bool "Itanium-2" + bool "Itanium 2" help Select this to configure for an Itanium 2 (McKinley) processor. @@ -90,7 +61,7 @@ HP-simulator For the HP simulator (). - HP-zx1 For HP zx1 platforms. + HP-zx1 For HP zx1-based systems. SN1-simulator For the SGI SN1 simulator. DIG-compliant For DIG ("Developer's Interface Guide") compliant systems. @@ -107,8 +78,8 @@ bool "HP-zx1" help Build a kernel that runs on HP zx1-based systems. This adds support - for the zx1 IOMMU and makes root bus bridges appear in PCI config space - (required for zx1 agpgart support). + for the zx1 I/O MMU and makes root bus bridges appear in PCI config + space (required for zx1 agpgart support). config IA64_SGI_SN1 bool "SGI-SN1" @@ -129,15 +100,15 @@ performance, a page size of 8KB or 16KB is recommended. For best IA-32 compatibility, a page size of 4KB should be selected (the vast majority of IA-32 binaries work perfectly fine with a larger page - size). For Itanium systems, do NOT chose a page size larger than - 16KB. + size). For Itanium 2 or newer systems, a page size of 64KB can also + be selected. 4KB For best IA-32 compatibility 8KB For best IA-64 performance 16KB For best IA-64 performance - 64KB Not for Itanium. + 64KB Requires Itanium 2 or newer processor. - If you don't know what to do, choose 8KB. + If you don't know what to do, choose 16KB. config IA64_PAGE_SIZE_8KB bool "8KB" @@ -200,7 +171,7 @@ default y help If you say `Y' here, Linux's ACPI support will use the - hardware-level system descriptions found on IA64 machines. + hardware-level system descriptions found on IA-64 systems. config IA64_BRL_EMU bool @@ -226,15 +197,15 @@ bool "Enable McKinley A-step specific code" depends on MCKINLEY help - Select this option to build a kernel for an IA64 McKinley system - with any A-stepping CPU. + Select this option to build a kernel for an IA-64 McKinley prototype + system with any A-stepping CPU. config MCKINLEY_A0_SPECIFIC bool "Enable McKinley A0/A1-step specific code" depends on MCKINLEY_ASTEP_SPECIFIC help - Select this option to build a kernel for an IA64 McKinley system - with an A0 or A1 stepping CPU. + Select this option to build a kernel for an IA-64 McKinley prototype + system with an A0 or A1 stepping CPU. config NUMA bool "Enable NUMA support" if IA64_GENERIC || IA64_DIG || IA64_HP_ZX1 @@ -242,14 +213,14 @@ help Say Y to compile the kernel to support NUMA (Non-Uniform Memory Access). This option is for configuring high-end multiprocessor - server machines. If in doubt, say N. + server systems. If in doubt, say N. config DISCONTIGMEM bool depends on IA64_SGI_SN1 || IA64_SGI_SN2 || (IA64_GENERIC || IA64_DIG || IA64_HP_ZX1) && NUMA default y help - Say Y to upport efficient handling of discontiguous physical memory, + Say Y to support efficient handling of discontiguous physical memory, for architectures which are either NUMA (Non-Uniform Memory Access) or have huge holes in the physical address space for other reasons. See for more. @@ -298,14 +269,14 @@ depends on IA64_SGI_SN1 || IA64_SGI_SN2 help Turns on extra debugging code in the SGI SN (Scalable NUMA) platform - for IA64. Unless you are debugging problems on an SGI SN IA64 box, + for IA-64. Unless you are debugging problems on an SGI SN IA-64 box, say N. config IA64_SGI_SN_SIM bool "Enable SGI Medusa Simulator Support" depends on IA64_SGI_SN1 || IA64_SGI_SN2 help - If you are compiling a kernel that will run under SGI's IA64 + If you are compiling a kernel that will run under SGI's IA-64 simulator (Medusa) then say Y, otherwise say N. config IA64_SGI_AUTOTEST @@ -323,7 +294,7 @@ depends on IA64_SGI_SN1 || IA64_SGI_SN2 help Uses protocol mode instead of raw mode for the level 1 console on the - SGI SN (Scalable NUMA) platform for IA64. If you are compiling for + SGI SN (Scalable NUMA) platform for IA-64. If you are compiling for an SGI SN box then Y is the recommended value, otherwise say N. config PERCPU_IRQ @@ -336,8 +307,8 @@ depends on IA64_SGI_SN1 || IA64_SGI_SN2 help IRIX PCIBA-inspired user mode PCI interface for the SGI SN (Scalable - NUMA) platform for IA64. Unless you are compiling a kernel for an - SGI SN IA64 box, say N. + NUMA) platform for IA-64. Unless you are compiling a kernel for an + SGI SN IA-64 box, say N. # On IA-64, we always want an ELF /proc/kcore. config KCORE_ELF @@ -402,27 +373,17 @@ bool "SMP support" ---help--- This enables support for systems with more than one CPU. If you have - a system with only one CPU, like most personal computers, say N. If - you have a system with more than one CPU, say Y. + a system with only one CPU say N. If you have a system with more than + one CPU, say Y. If you say N here, the kernel will run on single and multiprocessor - machines, but will use only one CPU of a multiprocessor machine. If + systems, but will use only one CPU of a multiprocessor system. If you say Y here, the kernel will run on many, but not all, - singleprocessor machines. On a singleprocessor machine, the kernel + singleprocessor system. On a singleprocessor system, the kernel will run faster if you say N here. - Note that if you say Y here and choose architecture "586" or - "Pentium" under "Processor family", the kernel will not work on 486 - architectures. Similarly, multiprocessor kernels for the "PPro" - architecture may not work on all Pentium based boards. - - People using multiprocessor machines who say Y here should also say - Y to "Enhanced Real Time Clock Support", below. The "Advanced Power - Management" code will be disabled if you say Y here. - See also the , - , , - and the SMP-HOWTO available at + , and the SMP-HOWTO available at . If you don't know what to do here, say N. @@ -430,17 +391,19 @@ config IA32_SUPPORT bool "Support running of Linux/x86 binaries" help - IA64 processors can run IA32 (that is, x86) binaries by emulating - the IA32 instruction set. Say Y here to build in kernel support for - this. If in doubt, say Y. + IA-64 processors can execute IA-32 (X86) instructions. By + saying Y here, the kernel will include IA-32 system call + emulation support which makes it possible to transparently + run IA-32 Linux binaries on an IA-64 Linux system. + If in doubt, say Y. config PERFMON bool "Performance monitor support" help Selects whether support for the IA-64 performance monitor hardware is included in the kernel. This makes some kernel data-structures a - little bigger and slows down execution a bit, but it is still - usually a good idea to turn this on. If you're unsure, say N. + little bigger and slows down execution a bit, but it is generally + a good idea to turn this on. If you're unsure, say Y. config IA64_PALINFO tristate "/proc/pal support" @@ -450,7 +413,7 @@ about the processors in your systems, such as cache and TLB sizes and the PAL firmware version in use. - To use this option, you have to check that the "/proc file system + To use this option, you have to ensure that the "/proc file system support" (CONFIG_PROC_FS) is enabled, too. config EFI_VARS @@ -473,42 +436,21 @@ ---help--- ELF (Executable and Linkable Format) is a format for libraries and executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. + systems. Saying Y here will enable your kernel to run ELF binaries. Information about ELF is contained in the ELF HOWTO available from . - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf.o. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - config BINFMT_MISC tristate "Kernel support for MISC binaries" ---help--- If you say Y here, it will be possible to plug wrapper-driven binary formats into the kernel. You will like this especially when you use programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. + Emacs-Lisp. Once you have registered such a binary class with the + kernel, you can start one of those programs simply by typing in its + name at a shell prompt; Linux will automatically feed it to the + correct interpreter. You can do other nice things, too. Read the file to learn how to use this @@ -698,7 +640,7 @@ CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better and newer replacement for SLIP) or PLIP (Parallel Line Internet Protocol is mainly used to create a mini network by connecting the - parallel ports of two local machines) or AX.25/KISS (protocol for + parallel ports of two local systems) or AX.25/KISS (protocol for sending Internet traffic over amateur radio links). Make sure to read the NET-3-HOWTO. Eventually, you will have to read @@ -831,21 +773,6 @@ contains some slightly outdated but still useful information as well. - If you have a PnP sound card and you want to configure it at boot - time using the ISA PnP tools (read - ), then you need to - compile the sound card support as a module ( = code which can be - inserted in and removed from the running kernel whenever you want) - and load that module after the PnP configuration is finished. To do - this, say M here and read as well - as ; the module will be - called soundcore.o. - - I'm told that even without a sound card, you can make your computer - say more than an occasional beep, by programming the PC speaker. - Kernel patches and supporting utilities to do that are in the pcsp - package, available at . - source "sound/Kconfig" endmenu @@ -870,7 +797,7 @@ config IA64_GRANULE_16MB bool "16MB" help - IA64 identity-mapped regions use a large page size called "granules". + IA-64 identity-mapped regions use a large page size called "granules". Select "16MB" for a small granule size. Select "64MB" for a large granule size. This is the current default. @@ -895,14 +822,14 @@ somewhat, as all symbols have to be loaded into the kernel image. config IA64_PRINT_HAZARDS - bool "Print possible IA64 hazards to console" + bool "Print possible IA-64 dependency violations to console" depends on DEBUG_KERNEL help Selecting this option prints more information for Illegal Dependency - Faults, that is, for Read after Write, Write after Write or Write - after Read violations. This option is ignored if you are compiling - for an Itanium A step processor (CONFIG_ITANIUM_ASTEP_SPECIFIC). If - you're unsure, select Y. + Faults, that is, for Read-after-Write (RAW), Write-after-Write (WAW), + or Write-after-Read (WAR) violations. This option is ignored if you + are compiling for an Itanium A step processor + (CONFIG_ITANIUM_ASTEP_SPECIFIC). If you're unsure, select Y. config DISABLE_VHPT bool "Disable VHPT" @@ -931,10 +858,11 @@ bool "Early printk support" depends on DEBUG_KERNEL help - Selecting this option uses the VGA screen for printk() output before - the consoles are initialised. It is useful for debugging problems - early in the boot process, but only if you have a VGA screen - attached. If you're unsure, select N. + Selecting this option uses the VGA screen or serial console for + printk() output before the consoles are initialised. It is useful + for debugging problems early in the boot process, but only if you + have a suitable VGA/serial console attached. If you're unsure, + select N. config IA64_EARLY_PRINTK_UART bool "Early printk on MMIO serial port" @@ -970,7 +898,7 @@ bool "Turn on compare-and-exchange bug checking (slow!)" depends on DEBUG_KERNEL help - Selecting this option turns on bug checking for the IA64 + Selecting this option turns on bug checking for the IA-64 compare-and-exchange instructions. This is slow! Itaniums from step B3 or later don't have this problem. If you're unsure, select N. @@ -979,7 +907,7 @@ bool "Turn on irq debug checks (slow!)" depends on DEBUG_KERNEL help - Selecting this option turns on bug checking for the IA64 irq_save + Selecting this option turns on bug checking for the IA-64 irq_save and restore instructions. It's useful for tracking down spinlock problems, but slow! If you're unsure, select N. @@ -988,4 +916,3 @@ source "security/Kconfig" source "crypto/Kconfig" - diff -Nru a/arch/ia64/defconfig b/arch/ia64/defconfig --- a/arch/ia64/defconfig Mon Nov 4 14:31:00 2002 +++ b/arch/ia64/defconfig Mon Nov 4 14:31:00 2002 @@ -26,12 +26,7 @@ # Processor type and features # CONFIG_IA64=y -# CONFIG_ISA is not set -# CONFIG_EISA is not set -# CONFIG_MCA is not set -# CONFIG_SBUS is not set CONFIG_RWSEM_GENERIC_SPINLOCK=y -# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set CONFIG_ITANIUM=y # CONFIG_MCKINLEY is not set # CONFIG_IA64_GENERIC is not set @@ -43,6 +38,7 @@ # CONFIG_IA64_PAGE_SIZE_4KB is not set # CONFIG_IA64_PAGE_SIZE_8KB is not set CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set CONFIG_ACPI=y CONFIG_ACPI_EFI=y CONFIG_ACPI_INTERPRETER=y @@ -69,23 +65,19 @@ # # ACPI Support # +CONFIG_ACPI_BOOT=y CONFIG_ACPI_BUTTON=y CONFIG_ACPI_FAN=m CONFIG_ACPI_PROCESSOR=m CONFIG_ACPI_THERMAL=m # CONFIG_ACPI_DEBUG is not set -CONFIG_ACPI_PCI=y -CONFIG_ACPI=y -CONFIG_ACPI_EFI=y -CONFIG_ACPI_BOOT=y CONFIG_ACPI_BUS=y -CONFIG_ACPI_INTERPRETER=y CONFIG_ACPI_POWER=y +CONFIG_ACPI_PCI=y CONFIG_ACPI_SYSTEM=y CONFIG_PCI=y CONFIG_PCI_NAMES=y # CONFIG_HOTPLUG is not set -# CONFIG_PCMCIA is not set # # Parallel port support @@ -101,30 +93,18 @@ # Plug and Play configuration # # CONFIG_PNP is not set -# CONFIG_PNP_NAMES is not set -# CONFIG_PNP_DEBUG is not set - -# -# Protocols -# -# CONFIG_ISAPNP is not set -# CONFIG_PNPBIOS is not set # # Block devices # # CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_CISS_SCSI_TAPE is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_UMEM is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set # # IEEE 1394 (FireWire) support (EXPERIMENTAL) @@ -135,32 +115,16 @@ # I2O device support # # CONFIG_I2O is not set -# CONFIG_I2O_PCI is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set # # Multi-device support (RAID and LVM) # # CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set # # Fusion MPT device support # # CONFIG_FUSION is not set -# CONFIG_FUSION_BOOT is not set -# CONFIG_FUSION_ISENSE is not set -# CONFIG_FUSION_CTL is not set -# CONFIG_FUSION_LAN is not set # # ATA/ATAPI/MFM/RLL support @@ -175,12 +139,10 @@ # # Please see Documentation/ide.txt for help/info on IDE drives # -# CONFIG_BLK_DEV_HD_IDE is not set # CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y CONFIG_IDEDISK_MULTI_MODE=y # CONFIG_IDEDISK_STROKE is not set -# CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y CONFIG_BLK_DEV_IDEFLOPPY=y CONFIG_BLK_DEV_IDESCSI=y @@ -189,54 +151,37 @@ # # IDE chipset support/bugfixes # -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_CMD640_ENHANCED is not set -# CONFIG_BLK_DEV_ISAPNP is not set CONFIG_BLK_DEV_IDEPCI=y # CONFIG_BLK_DEV_GENERIC is not set CONFIG_IDEPCI_SHARE_IRQ=y CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_IDE_TCQ is not set -# CONFIG_BLK_DEV_IDE_TCQ_DEFAULT is not set # CONFIG_BLK_DEV_OFFBOARD is not set # CONFIG_BLK_DEV_IDEDMA_FORCED is not set # CONFIG_IDEDMA_PCI_AUTO is not set -# CONFIG_IDEDMA_ONLYDISK is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_PCI_WIP is not set -# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_BLK_DEV_ALI15X3 is not set -# CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD74XX is not set -# CONFIG_AMD74XX_OVERRIDE is not set # CONFIG_BLK_DEV_CMD64X is not set # CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set -# CONFIG_HPT34X_AUTODMA is not set # CONFIG_BLK_DEV_HPT366 is not set # CONFIG_BLK_DEV_PIIX is not set # CONFIG_BLK_DEV_NFORCE is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set # CONFIG_BLK_DEV_PDC202XX_OLD is not set -# CONFIG_PDC202XX_BURST is not set # CONFIG_BLK_DEV_PDC202XX_NEW is not set -# CONFIG_PDC202XX_FORCE is not set -# CONFIG_BLK_DEV_RZ1000 is not set # CONFIG_BLK_DEV_SVWKS is not set # CONFIG_BLK_DEV_SIIMAGE is not set -# CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set -# CONFIG_IDE_CHIPSETS is not set -# CONFIG_IDEDMA_AUTO is not set # CONFIG_IDEDMA_IVB is not set -# CONFIG_DMA_NONPCI is not set -CONFIG_BLK_DEV_IDE_MODES=y # # SCSI support @@ -247,7 +192,6 @@ # SCSI support type (disk, tape, CD-ROM) # CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 # CONFIG_CHR_DEV_ST is not set # CONFIG_CHR_DEV_OSST is not set # CONFIG_BLK_DEV_SR is not set @@ -265,7 +209,6 @@ # SCSI low-level drivers # # CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_7000FASST is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set @@ -278,31 +221,25 @@ # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_CPQFCTS is not set # CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_DTC3280 is not set # CONFIG_SCSI_EATA is not set # CONFIG_SCSI_EATA_DMA is not set # CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_NCR53C8XX is not set # CONFIG_SCSI_SYM53C8XX is not set -# CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set CONFIG_SCSI_QLOGIC_1280=y -# CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set @@ -328,16 +265,13 @@ # CONFIG_IPV6 is not set # -# SCTP Configuration (EXPERIMENTAL) +# SCTP Configuration (EXPERIMENTAL) # CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set # CONFIG_VLAN_8021Q is not set # CONFIG_LLC is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_DEV_APPLETALK is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set # CONFIG_X25 is not set @@ -372,13 +306,9 @@ # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y -# CONFIG_SUNLANCE is not set # CONFIG_HAPPYMEAL is not set -# CONFIG_SUNBMAC is not set -# CONFIG_SUNQE is not set # CONFIG_SUNGEM is not set # CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set @@ -387,34 +317,22 @@ # # CONFIG_NET_TULIP is not set # CONFIG_HP100 is not set -# CONFIG_NET_ISA is not set CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set # CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set # CONFIG_DGRS is not set CONFIG_EEPRO100=y # CONFIG_E100 is not set -# CONFIG_LNE390 is not set # CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set -# CONFIG_NE3210 is not set -# CONFIG_ES3210 is not set # CONFIG_8139CP is not set # CONFIG_8139TOO is not set -# CONFIG_8139TOO_PIO is not set -# CONFIG_8139TOO_TUNE_TWISTER is not set -# CONFIG_8139TOO_8129 is not set -# CONFIG_8139_OLD_RX_RESET is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set -# CONFIG_SUNDANCE_MMIO is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set -# CONFIG_VIA_RHINE_MMIO is not set # CONFIG_NET_POCKET is not set # @@ -423,8 +341,6 @@ # CONFIG_ACENIC is not set # CONFIG_DL2K is not set # CONFIG_E1000 is not set -# CONFIG_E1000_NAPI is not set -# CONFIG_MYRI_SBUS is not set # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set @@ -432,7 +348,6 @@ # CONFIG_TIGON3 is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set -# CONFIG_PLIP is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set @@ -491,17 +406,10 @@ # # CONFIG_GAMEPORT is not set CONFIG_SOUND_GAMEPORT=y -# CONFIG_GAMEPORT_NS558 is not set -# CONFIG_GAMEPORT_L4 is not set -# CONFIG_GAMEPORT_EMU10K1 is not set -# CONFIG_GAMEPORT_VORTEX is not set -# CONFIG_GAMEPORT_FM801 is not set -# CONFIG_GAMEPORT_CS461x is not set CONFIG_SERIO=y CONFIG_SERIO_I8042=y CONFIG_SERIO_SERPORT=y # CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_PARKBD is not set # # Input Device Drivers @@ -514,34 +422,8 @@ CONFIG_INPUT_MOUSE=y CONFIG_MOUSE_PS2=y # CONFIG_MOUSE_SERIAL is not set -# CONFIG_MOUSE_INPORT is not set -# CONFIG_MOUSE_LOGIBM is not set -# CONFIG_MOUSE_PC110PAD is not set # CONFIG_INPUT_JOYSTICK is not set -# CONFIG_JOYSTICK_ANALOG is not set -# CONFIG_JOYSTICK_A3D is not set -# CONFIG_JOYSTICK_ADI is not set -# CONFIG_JOYSTICK_COBRA is not set -# CONFIG_JOYSTICK_GF2K is not set -# CONFIG_JOYSTICK_GRIP is not set -# CONFIG_JOYSTICK_GRIP_MP is not set -# CONFIG_JOYSTICK_GUILLEMOT is not set -# CONFIG_JOYSTICK_INTERACT is not set -# CONFIG_JOYSTICK_SIDEWINDER is not set -# CONFIG_JOYSTICK_TMDC is not set -# CONFIG_JOYSTICK_IFORCE is not set -# CONFIG_JOYSTICK_WARRIOR is not set -# CONFIG_JOYSTICK_MAGELLAN is not set -# CONFIG_JOYSTICK_SPACEORB is not set -# CONFIG_JOYSTICK_SPACEBALL is not set -# CONFIG_JOYSTICK_STINGER is not set -# CONFIG_JOYSTICK_TWIDDLER is not set -# CONFIG_JOYSTICK_DB9 is not set -# CONFIG_JOYSTICK_GAMECON is not set -# CONFIG_JOYSTICK_TURBOGRAFX is not set -# CONFIG_INPUT_JOYDUMP is not set # CONFIG_INPUT_TOUCHSCREEN is not set -# CONFIG_TOUCHSCREEN_GUNZE is not set CONFIG_INPUT_MISC=y # CONFIG_INPUT_PCSPKR is not set # CONFIG_INPUT_UINPUT is not set @@ -559,9 +441,6 @@ # CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y -# CONFIG_SERIAL_8250_CS is not set -# CONFIG_SERIAL_8250_ACPI is not set -# CONFIG_SERIAL_8250_HCDP is not set CONFIG_SERIAL_8250_EXTENDED=y # CONFIG_SERIAL_8250_MANY_PORTS is not set CONFIG_SERIAL_8250_SHARE_IRQ=y @@ -582,10 +461,8 @@ # CONFIG_I2C=y CONFIG_I2C_ALGOBIT=y -# CONFIG_I2C_PHILIPSPAR is not set # CONFIG_I2C_ELV is not set # CONFIG_I2C_VELLEMAN is not set -# CONFIG_SCx200_I2C is not set # CONFIG_SCx200_ACB is not set # CONFIG_I2C_ALGOPCF is not set CONFIG_I2C_CHARDEV=y @@ -632,7 +509,6 @@ CONFIG_DRM_I810=y CONFIG_DRM_I830=y CONFIG_DRM_MGA=y -# CONFIG_SCx200_GPIO is not set # CONFIG_RAW_DRIVER is not set # @@ -644,28 +520,21 @@ # File systems # # CONFIG_QUOTA is not set -# CONFIG_QFMT_V1 is not set -# CONFIG_QFMT_V2 is not set CONFIG_AUTOFS_FS=y # CONFIG_AUTOFS4_FS is not set # CONFIG_REISERFS_FS is not set -# CONFIG_REISERFS_CHECK is not set -# CONFIG_REISERFS_PROC_INFO is not set # CONFIG_ADFS_FS is not set -# CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +# CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set CONFIG_EXT3_FS=y CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y -# CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=y # CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set # CONFIG_CRAMFS is not set # CONFIG_TMPFS is not set CONFIG_RAMFS=y @@ -673,31 +542,20 @@ # CONFIG_JOLIET is not set # CONFIG_ZISOFS is not set # CONFIG_JFS_FS is not set -# CONFIG_JFS_DEBUG is not set -# CONFIG_JFS_STATISTICS is not set # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set -# CONFIG_NTFS_DEBUG is not set -# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set # CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set # CONFIG_XFS_FS is not set -# CONFIG_XFS_RT is not set -# CONFIG_XFS_QUOTA is not set # # Network File Systems @@ -707,10 +565,9 @@ CONFIG_NFS_FS=y CONFIG_NFS_V3=y CONFIG_NFS_V4=y -# CONFIG_ROOT_NFS is not set CONFIG_NFSD=y CONFIG_NFSD_V3=y -CONFIG_NFSD_V4=y +# CONFIG_NFSD_V4 is not set # CONFIG_NFSD_TCP is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y @@ -719,16 +576,7 @@ # CONFIG_CIFS is not set # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set -# CONFIG_NCPFS_PACKET_SIGNING is not set -# CONFIG_NCPFS_IOCTL_LOCKING is not set -# CONFIG_NCPFS_STRONG is not set -# CONFIG_NCPFS_NFS_NS is not set -# CONFIG_NCPFS_OS2_NS is not set -# CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set # CONFIG_AFS_FS is not set -# CONFIG_ZISOFS_FS is not set # # Partition Types @@ -749,7 +597,6 @@ # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set CONFIG_EFI_PARTITION=y -# CONFIG_SMB_NLS is not set CONFIG_NLS=y # @@ -816,7 +663,6 @@ # CONFIG_SOUND_BT878 is not set # CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_EMU10K1 is not set -# CONFIG_MIDI_EMU10K1 is not set # CONFIG_SOUND_FUSION is not set CONFIG_SOUND_CS4281=y # CONFIG_SOUND_ES1370 is not set @@ -831,7 +677,6 @@ # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set # CONFIG_SOUND_VIA82CXXX is not set -# CONFIG_MIDI_VIA82CXXX is not set # CONFIG_SOUND_OSS is not set # CONFIG_SOUND_TVMIXER is not set @@ -870,15 +715,6 @@ # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set # CONFIG_USB_STORAGE is not set -# CONFIG_USB_STORAGE_DEBUG is not set -# CONFIG_USB_STORAGE_DATAFAB is not set -# CONFIG_USB_STORAGE_FREECOM is not set -# CONFIG_USB_STORAGE_ISD200 is not set -# CONFIG_USB_STORAGE_DPCM is not set -# CONFIG_USB_STORAGE_HP8200e is not set -# CONFIG_USB_STORAGE_SDDR09 is not set -# CONFIG_USB_STORAGE_SDDR55 is not set -# CONFIG_USB_STORAGE_JUMPSHOT is not set # # USB Human Interface Devices (HID) @@ -886,8 +722,6 @@ CONFIG_USB_HID=y CONFIG_USB_HIDINPUT=y # CONFIG_HID_FF is not set -# CONFIG_HID_PID is not set -# CONFIG_LOGITECH_FF is not set CONFIG_USB_HIDDEV=y # CONFIG_USB_AIPTEK is not set # CONFIG_USB_WACOM is not set @@ -908,16 +742,8 @@ # CONFIG_USB_DABUSB is not set # -# Video4Linux support is needed for USB Multimedia device support +# Video4Linux support is needed for USB Multimedia device support # -# CONFIG_USB_VICAM is not set -# CONFIG_USB_DSBR is not set -# CONFIG_USB_IBMCAM is not set -# CONFIG_USB_KONICAWC is not set -# CONFIG_USB_OV511 is not set -# CONFIG_USB_PWC is not set -# CONFIG_USB_SE401 is not set -# CONFIG_USB_STV680 is not set # # USB Network adaptors @@ -932,62 +758,26 @@ # # USB port drivers # -# CONFIG_USB_USS720 is not set # # USB Serial Converter support # # CONFIG_USB_SERIAL is not set -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -# CONFIG_USB_SERIAL_VISOR is not set -# CONFIG_USB_SERIAL_IPAQ is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_EDGEPORT_TI is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -# CONFIG_USB_SERIAL_KEYSPAN is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19QW is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set -# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set -# CONFIG_USB_SERIAL_KLSI is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_SAFE is not set -# CONFIG_USB_SERIAL_SAFE_PADDED is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OMNINET is not set # # USB Miscellaneous drivers # -# CONFIG_USB_EMI26 is not set # CONFIG_USB_TIGL is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set -# CONFIG_USB_SPEEDTOUCH is not set # CONFIG_USB_TEST is not set # # Library routines # # CONFIG_CRC32 is not set -# CONFIG_ZLIB_INFLATE is not set -# CONFIG_ZLIB_DEFLATE is not set # # Bluetooth support @@ -1016,3 +806,8 @@ # Security options # CONFIG_SECURITY_CAPABILITIES=y + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set diff -Nru a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c --- a/arch/ia64/hp/sim/simscsi.c Mon Nov 4 14:31:01 2002 +++ b/arch/ia64/hp/sim/simscsi.c Mon Nov 4 14:31:01 2002 @@ -131,20 +131,6 @@ } int -simscsi_abort (Scsi_Cmnd *cmd) -{ - printk ("simscsi_abort: unimplemented\n"); - return SCSI_ABORT_SUCCESS; -} - -int -simscsi_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) -{ - printk ("simscsi_reset: unimplemented\n"); - return SCSI_RESET_SUCCESS; -} - -int simscsi_biosparam (struct scsi_device *sdev, struct block_device *n, sector_t capacity, int ip[]) { diff -Nru a/arch/ia64/hp/sim/simscsi.h b/arch/ia64/hp/sim/simscsi.h --- a/arch/ia64/hp/sim/simscsi.h Mon Nov 4 14:31:00 2002 +++ b/arch/ia64/hp/sim/simscsi.h Mon Nov 4 14:31:00 2002 @@ -20,21 +20,19 @@ extern int simscsi_biosparam (struct scsi_device *, struct block_device *, sector_t, int[]); -#define SIMSCSI { \ - detect: simscsi_detect, \ - release: simscsi_release, \ - info: simscsi_info, \ - queuecommand: simscsi_queuecommand, \ - abort: simscsi_abort, \ - reset: simscsi_reset, \ - bios_param: simscsi_biosparam, \ - can_queue: SIMSCSI_REQ_QUEUE_LEN, \ - this_id: -1, \ - sg_tablesize: SG_ALL, \ - cmd_per_lun: SIMSCSI_REQ_QUEUE_LEN, \ - present: 0, \ - unchecked_isa_dma: 0, \ - use_clustering: DISABLE_CLUSTERING \ +#define SIMSCSI { \ + .detect = simscsi_detect, \ + .release = simscsi_release, \ + .info = simscsi_info, \ + .queuecommand = simscsi_queuecommand, \ + .bios_param = simscsi_biosparam, \ + .can_queue = SIMSCSI_REQ_QUEUE_LEN, \ + .this_id = -1, \ + .sg_tablesize = SG_ALL, \ + .cmd_per_lun = SIMSCSI_REQ_QUEUE_LEN, \ + .present = 0, \ + .unchecked_isa_dma = 0, \ + .use_clustering = DISABLE_CLUSTERING \ } #endif /* SIMSCSI_H */ diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c --- a/arch/ia64/ia32/sys_ia32.c Mon Nov 4 14:31:02 2002 +++ b/arch/ia64/ia32/sys_ia32.c Mon Nov 4 14:31:02 2002 @@ -3076,7 +3076,7 @@ break; default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); break; } diff -Nru a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S --- a/arch/ia64/kernel/entry.S Mon Nov 4 14:31:01 2002 +++ b/arch/ia64/kernel/entry.S Mon Nov 4 14:31:01 2002 @@ -1245,15 +1245,15 @@ data8 sys_alloc_hugepages data8 sys_free_hugepages // 1235 data8 sys_exit_group - data8 ia64_ni_syscall + data8 sys_lookup_dcookie data8 sys_io_setup data8 sys_io_destroy data8 sys_io_getevents // 1240 data8 sys_io_submit data8 sys_io_cancel - data8 ia64_ni_syscall - data8 ia64_ni_syscall - data8 ia64_ni_syscall // 1245 + data8 sys_epoll_create + data8 sys_epoll_ctl + data8 sys_epoll_wait // 1245 data8 ia64_ni_syscall data8 ia64_ni_syscall data8 ia64_ni_syscall diff -Nru a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c --- a/arch/ia64/kernel/irq.c Mon Nov 4 14:31:02 2002 +++ b/arch/ia64/kernel/irq.c Mon Nov 4 14:31:02 2002 @@ -172,7 +172,7 @@ #else for (j = 0; j < NR_CPUS; j++) if (cpu_online(j)) - seq_printf(p, "%10u ", kstat.irqs[j][i]); + seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); #endif seq_printf(p, " %14s", idesc->handler->typename); seq_printf(p, " %s", action->name); @@ -346,7 +346,7 @@ unsigned int status; irq_enter(); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; if (desc->status & IRQ_PER_CPU) { /* no locking required for CPU-local interrupts: */ diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c --- a/arch/ia64/kernel/process.c Mon Nov 4 14:31:01 2002 +++ b/arch/ia64/kernel/process.c Mon Nov 4 14:31:01 2002 @@ -516,7 +516,7 @@ struct task_struct *parent = current; int result, tid; - tid = clone(flags | CLONE_VM, 0); + tid = clone(flags | CLONE_VM | CLONE_UNTRACED, 0); if (parent != current) { result = (*fn)(arg); _exit(result); diff -Nru a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c --- a/arch/ia64/kernel/ptrace.c Mon Nov 4 14:31:03 2002 +++ b/arch/ia64/kernel/ptrace.c Mon Nov 4 14:31:03 2002 @@ -1268,16 +1268,8 @@ ret = ptrace_setregs(child, (struct pt_all_user_regs*) data); goto out_tsk; - case PTRACE_SETOPTIONS: - if (data & PTRACE_O_TRACESYSGOOD) - child->ptrace |= PT_TRACESYSGOOD; - else - child->ptrace &= ~PT_TRACESYSGOOD; - ret = 0; - break; - default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); goto out_tsk; } out_tsk: diff -Nru a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c --- a/arch/ia64/kernel/setup.c Mon Nov 4 14:31:01 2002 +++ b/arch/ia64/kernel/setup.c Mon Nov 4 14:31:01 2002 @@ -625,21 +625,18 @@ extern char __per_cpu_end[]; int cpu; - if (__per_cpu_end - __per_cpu_start > PAGE_SIZE) - panic("Per-cpu data area too big! (%Zu > %Zu)", - __per_cpu_end - __per_cpu_start, PAGE_SIZE); - - /* * get_free_pages() cannot be used before cpu_init() done. BSP allocates * "NR_CPUS" pages for all CPUs to avoid that AP calls get_zeroed_page(). */ if (smp_processor_id() == 0) { - cpu_data = (unsigned long)alloc_bootmem_pages(PAGE_SIZE * NR_CPUS); + cpu_data = (unsigned long) __alloc_bootmem(PERCPU_PAGE_SIZE * NR_CPUS, + PERCPU_PAGE_SIZE, + __pa(MAX_DMA_ADDRESS)); for (cpu = 0; cpu < NR_CPUS; cpu++) { memcpy(cpu_data, __phys_per_cpu_start, __per_cpu_end - __per_cpu_start); __per_cpu_offset[cpu] = (char *) cpu_data - __per_cpu_start; - cpu_data += PAGE_SIZE; + cpu_data += PERCPU_PAGE_SIZE; } } cpu_data = __per_cpu_start + __per_cpu_offset[smp_processor_id()]; @@ -650,7 +647,6 @@ cpu_info = cpu_data + ((char *) &__get_cpu_var(cpu_info) - __per_cpu_start); #ifdef CONFIG_NUMA cpu_info->node_data = get_node_data_ptr(); - cpu_info->nodeid = boot_get_local_nodeid(); #endif /* diff -Nru a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c --- a/arch/ia64/kernel/smpboot.c Mon Nov 4 14:31:01 2002 +++ b/arch/ia64/kernel/smpboot.c Mon Nov 4 14:31:01 2002 @@ -430,30 +430,39 @@ #ifdef CONFIG_NUMA -char cpu_to_node_map[NR_CPUS] __cacheline_aligned; +/* on which node is each logical CPU (one cacheline even for 64 CPUs) */ +volatile char cpu_to_node_map[NR_CPUS] __cacheline_aligned; +/* which logical CPUs are on which nodes */ +volatile unsigned long node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned; /* - * Build cpu to node mapping. + * Build cpu to node mapping and initialize the per node cpu masks. */ void __init build_cpu_to_node_map (void) { - int cpu, i; + int cpu, i, node; + for(node=0; node= 0) + node_to_cpu_mask[node] |= (1UL << cpu); } } diff -Nru a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c --- a/arch/ia64/kernel/sys_ia64.c Mon Nov 4 14:31:02 2002 +++ b/arch/ia64/kernel/sys_ia64.c Mon Nov 4 14:31:02 2002 @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include /* doh, must come after sched.h... */ diff -Nru a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c --- a/arch/ia64/mm/hugetlbpage.c Mon Nov 4 14:31:02 2002 +++ b/arch/ia64/mm/hugetlbpage.c Mon Nov 4 14:31:02 2002 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff -Nru a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c --- a/arch/ia64/mm/init.c Mon Nov 4 14:31:01 2002 +++ b/arch/ia64/mm/init.c Mon Nov 4 14:31:01 2002 @@ -287,7 +287,8 @@ ia64_srlz_d(); ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR, - pte_val(pfn_pte(__pa(my_cpu_data) >> PAGE_SHIFT, PAGE_KERNEL)), PAGE_SHIFT); + pte_val(pfn_pte(__pa(my_cpu_data) >> PAGE_SHIFT, PAGE_KERNEL)), + PERCPU_PAGE_SHIFT); ia64_set_psr(psr); ia64_srlz_i(); @@ -454,8 +455,6 @@ num_pgt_pages = nr_free_pages() / 10; if (num_pgt_pages > pgt_cache_water[1]) pgt_cache_water[1] = num_pgt_pages; - - show_mem(); /* install the gate page in the global page table: */ put_gate_page(virt_to_page(__start_gate_section), GATE_ADDR); diff -Nru a/arch/ia64/vmlinux.lds.S b/arch/ia64/vmlinux.lds.S --- a/arch/ia64/vmlinux.lds.S Mon Nov 4 14:31:02 2002 +++ b/arch/ia64/vmlinux.lds.S Mon Nov 4 14:31:02 2002 @@ -137,7 +137,7 @@ { *(.kstrtab) } /* Per-cpu data: */ - . = ALIGN(PAGE_SIZE); + . = ALIGN(PERCPU_PAGE_SIZE); __phys_per_cpu_start = .; .data.percpu PERCPU_ADDR : AT(__phys_per_cpu_start - PAGE_OFFSET) { @@ -145,7 +145,7 @@ *(.data.percpu) __per_cpu_end = .; } - . = __phys_per_cpu_start + 4096; /* ensure percpu fits into smallest page size (4KB) */ + . = __phys_per_cpu_start + PERCPU_PAGE_SIZE; /* ensure percpu data fits into percpu page size */ .data : AT(ADDR(.data) - PAGE_OFFSET) { *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS } diff -Nru a/arch/m68k/Kconfig b/arch/m68k/Kconfig --- a/arch/m68k/Kconfig Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/Kconfig Mon Nov 4 14:31:02 2002 @@ -6,21 +6,25 @@ bool default y -config UID16 +config MMU bool default y -config RWSEM_GENERIC_SPINLOCK +config SWAP bool default y -config RWSEM_XCHGADD_ALGORITHM +config UID16 bool + default y -config GENERIC_ISA_DMA +config RWSEM_GENERIC_SPINLOCK bool default y +config RWSEM_XCHGADD_ALGORITHM + bool + mainmenu "Linux/68k Kernel Configuration" @@ -193,7 +197,8 @@ help This option enables support for the Sun 3x series of workstations. Be warned that this support is very experimental. You will also want - to say Y to 68020 support and N to the other processors below. + to say Y to 68030 support and N to the other processors below. + Note that Sun 3x kernels are not compatible with Sun 3 hardware. General Linux information on the Sun 3x series (now discontinued) is at . @@ -202,13 +207,14 @@ config SUN3 bool "Sun3 support" help - This option enables support for the Sun 3 series of workstations. - Currently, only the Sun 3/80 is supported within the Sun 3x family. - You will also want to enable 68030 support. General Linux - information on the Sun 3x series (now discontinued) is at - . + This option enables support for the Sun 3 series of workstations + (3/50, 3/60, 3/1xx, 3/2xx systems). Enabling this option requires + that all other hardware types must be disabled, as Sun 3 kernels + are incompatible with all other m68k targets (including Sun 3x!). + Also, you will want to say Y to 68020 support and N to the other + processors below. - If you don't want to compile a kernel for a Sun 3, say N. + If you don't want to compile a kernel exclusively for a Sun 3, say N. config Q40 bool "Q40/Q60 support" @@ -630,6 +636,11 @@ (MCA) or VESA. ISA is an older system, now being displaced by PCI; newer boards don't support it. If you have ISA, say Y, otherwise N. +config GENERIC_ISA_DMA + bool + depends on Q40 || AMIGA_PCMCIA || GG2 + default y + source "drivers/pci/Kconfig" source "drivers/zorro/Kconfig" @@ -646,9 +657,7 @@ source "drivers/md/Kconfig" -if MAC source "drivers/input/Kconfig" -endif menu "ATA/ATAPI/MFM/RLL device support" @@ -1124,8 +1133,8 @@ depends on SUN3 && SCSI help This option will enable support for the OBIO (onboard io) NCR5380 - SCSI controller found in the Sun 3/50 and 3/60. Note that this - driver does not provide support for VME SCSI boards. + SCSI controller found in the Sun 3/50 and 3/60, as well as for + "Sun3" type VME scsi controllers also based on the NCR5380. General Linux information on the Sun 3 series (now discontinued) is at . @@ -1766,6 +1775,11 @@ If unsure, say Y. +config HW_CONSOLE + bool + depends on VT + default y + config NVRAM bool depends on ATARI @@ -1792,51 +1806,6 @@ This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module will be called nvram.o. If you want to compile it as a - module, say M here and read . - -config AMIGAMOUSE - tristate "Amiga mouse support" - depends on AMIGA - help - If you want to be able to use an Amiga mouse in Linux, say Y. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module is called amigamouse.o. If you want to compile it as a - module, say M here and read . - -config BUSMOUSE - bool - depends on SUN3X_ZS || ATARI && VT && ATARIMOUSE || AMIGA && AMIGAMOUSE - default y - ---help--- - Say Y here if your machine has a bus mouse as opposed to a serial - mouse. Most people have a regular serial MouseSystem or - Microsoft mouse (made by Logitech) that plugs into a COM port - (rectangular with 9 or 25 pins). These people say N here. - - If you have a laptop, you either have to check the documentation or - experiment a bit to find out whether the trackball is a serial mouse - or not; it's best to say Y here for you. - - This is the generic bus mouse driver code. If you have a bus mouse, - you will have to say Y here and also to the specific driver for your - mouse below. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called busmouse.o. If you want to compile it as a - module, say M here and read . - -config ATARIMOUSE - tristate "Atari mouse support" - depends on ATARI && VT - help - If you want to be able to use an Atari mouse in Linux, say Y. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module is called atarimouse.o. If you want to compile it as a module, say M here and read . config ATARI_MFPSER diff -Nru a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c --- a/arch/m68k/amiga/amiints.c Mon Nov 4 14:31:03 2002 +++ b/arch/m68k/amiga/amiints.c Mon Nov 4 14:31:03 2002 @@ -128,8 +128,7 @@ printk("%s: Warning: dev_id of %s is zero\n", __FUNCTION__, node->devname); - save_flags(flags); - cli(); + local_irq_save(flags); cur = *list; @@ -153,7 +152,7 @@ node->next = cur; *list = node; - restore_flags(flags); + local_irq_restore(flags); return 0; } @@ -162,19 +161,18 @@ unsigned long flags; irq_node_t *node; - save_flags(flags); - cli(); + local_irq_save(flags); for (node = *list; node; list = &node->next, node = *list) { if (node->dev_id == dev_id) { *list = node->next; /* Mark it as free. */ node->handler = NULL; - restore_flags(flags); + local_irq_restore(flags); return; } } - restore_flags(flags); + local_irq_restore(flags); printk ("%s: tried to remove invalid irq\n", __FUNCTION__); } @@ -350,7 +348,7 @@ inline void amiga_do_irq(int irq, struct pt_regs *fp) { - kstat.irqs[0][SYS_IRQS + irq]++; + kstat_cpu(0).irqs[SYS_IRQS + irq]++; ami_irq_list[irq]->handler(irq, ami_irq_list[irq]->dev_id, fp); } @@ -358,7 +356,7 @@ { irq_node_t *node; - kstat.irqs[0][SYS_IRQS + irq]++; + kstat_cpu(0).irqs[SYS_IRQS + irq]++; custom.intreq = amiga_intena_vals[irq]; @@ -479,7 +477,7 @@ if (!(node = ami_irq_list[i])) continue; seq_printf(p, "ami %2d: %10u ", i, - kstat.irqs[0][SYS_IRQS + i]); + kstat_cpu(0).irqs[SYS_IRQS + i]); do { if (node->flags & SA_INTERRUPT) seq_puts(p, "F "); diff -Nru a/arch/m68k/amiga/amisound.c b/arch/m68k/amiga/amisound.c --- a/arch/m68k/amiga/amisound.c Mon Nov 4 14:31:03 2002 +++ b/arch/m68k/amiga/amisound.c Mon Nov 4 14:31:03 2002 @@ -71,8 +71,7 @@ if (!snd_data) return; - save_flags(flags); - cli(); + local_irq_save(flags); del_timer( &sound_timer ); if (hz > 20 && hz < 32767) { @@ -100,7 +99,7 @@ } else nosound( 0 ); - restore_flags(flags); + local_irq_restore(flags); } diff -Nru a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c --- a/arch/m68k/amiga/cia.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/amiga/cia.c Mon Nov 4 14:31:02 2002 @@ -131,7 +131,7 @@ custom.intreq = base->int_mask; for (i = 0; i < CIA_IRQS; i++, irq++, mach_irq++) { if (ints & 1) { - kstat.irqs[0][irq]++; + kstat_cpu(0).irqs[irq]++; base->irq_list[i].handler(mach_irq, base->irq_list[i].dev_id, fp); } ints >>= 1; @@ -166,7 +166,7 @@ j = base->cia_irq; for (i = 0; i < CIA_IRQS; i++) { seq_printf(p, "cia %2d: %10d ", j + i, - kstat.irqs[0][SYS_IRQS + j + i]); + kstat_cpu(0).irqs[SYS_IRQS + j + i]); seq_puts(p, " "); seq_printf(p, "%s\n", base->irq_list[i].devname); } diff -Nru a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c --- a/arch/m68k/amiga/config.c Mon Nov 4 14:31:00 2002 +++ b/arch/m68k/amiga/config.c Mon Nov 4 14:31:00 2002 @@ -88,6 +88,7 @@ static int a3000_hwclk (int, struct rtc_time *); static int a2000_hwclk (int, struct rtc_time *); static int amiga_set_clock_mmss (unsigned long); +extern void amiga_mksound( unsigned int count, unsigned int ticks ); #ifdef CONFIG_AMIGA_FLOPPY extern void amiga_floppy_setup(char *, int *); #endif @@ -408,7 +409,7 @@ #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif -#ifdef CONFIG_INPUT_M68K_BEEP +#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) mach_beep = amiga_mksound; #endif diff -Nru a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c --- a/arch/m68k/apollo/config.c Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/apollo/config.c Mon Nov 4 14:31:01 2002 @@ -26,8 +26,6 @@ u_long apollo_model; extern void dn_sched_init(void (*handler)(int,void *,struct pt_regs *)); -extern int dn_keyb_init(void); -extern int dn_dummy_kbdrate(struct kbd_repeat *); extern void dn_init_IRQ(void); extern int dn_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id); extern void dn_free_irq(unsigned int irq, void *dev_id); @@ -37,7 +35,6 @@ extern unsigned long dn_gettimeoffset(void); extern int dn_dummy_hwclk(int, struct rtc_time *); extern int dn_dummy_set_clock_mmss(unsigned long); -extern void dn_mksound(unsigned int count, unsigned int ticks); extern void dn_dummy_reset(void); extern void dn_dummy_waitbut(void); extern struct fb_info *dn_fb_init(long *); @@ -165,10 +162,6 @@ dn_setup_model(); mach_sched_init=dn_sched_init; /* */ -#ifdef CONFIG_VT - mach_keyb_init=dn_keyb_init; - mach_kbdrate=dn_dummy_kbdrate; -#endif mach_init_IRQ=dn_init_IRQ; mach_default_handler=NULL; mach_request_irq = dn_request_irq; @@ -188,9 +181,6 @@ mach_reset = dn_dummy_reset; /* */ #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; -#endif -#ifdef CONFIG_VT - kd_mksound = dn_mksound; #endif #ifdef CONFIG_HEARTBEAT mach_heartbeat = dn_heartbeat; diff -Nru a/arch/m68k/apollo/dn_ints.c b/arch/m68k/apollo/dn_ints.c --- a/arch/m68k/apollo/dn_ints.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/apollo/dn_ints.c Mon Nov 4 14:31:02 2002 @@ -117,35 +117,6 @@ } -#ifdef CONFIG_VT -extern void write_keyb_cmd(u_short length, u_char *cmd); -static char BellOnCommand[] = { 0xFF, 0x21, 0x81 }, - BellOffCommand[] = { 0xFF, 0x21, 0x82 }; - -static void dn_nosound (unsigned long ignored) { - - write_keyb_cmd(sizeof(BellOffCommand),BellOffCommand); - -} - -void dn_mksound( unsigned int count, unsigned int ticks ) { - - static struct timer_list sound_timer = { function: dn_nosound }; - - del_timer( &sound_timer ); - if(count) { - write_keyb_cmd(sizeof(BellOnCommand),BellOnCommand); - if (ticks) { - sound_timer.expires = jiffies + ticks; - add_timer( &sound_timer ); - } - } - else - write_keyb_cmd(sizeof(BellOffCommand),BellOffCommand); -} -#endif /* CONFIG_VT */ - - void dn_dummy_video_setup(char *options,int *ints) { printk("no video yet\n"); diff -Nru a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile --- a/arch/m68k/atari/Makefile Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/atari/Makefile Mon Nov 4 14:31:02 2002 @@ -7,8 +7,6 @@ obj-y := config.o time.o debug.o ataints.o stdma.o \ atasound.o stram.o atari_ksyms.o -obj-$(CONFIG_VT) += atakeyb.o joystick.o - ifeq ($(CONFIG_PCI),y) obj-$(CONFIG_HADES) += hades-pci.o endif diff -Nru a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c --- a/arch/m68k/atari/ataints.c Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/atari/ataints.c Mon Nov 4 14:31:01 2002 @@ -37,7 +37,6 @@ #include #include -#include #include #include #include @@ -191,7 +190,7 @@ " andw #0xfeff,%%sr\n" /* set IPL = 6 again */ \ " orb #(1<<(%c3&7)),%a4:w\n" /* now unmask the int again */ \ " jbra ret_from_interrupt\n" \ - : : "i" (&kstat.irqs[0][n+8]), "i" (&irq_handler[n+8]), \ + : : "i" (&kstat_cpu(0).irqs[n+8]), "i" (&irq_handler[n+8]), \ "n" (PT_OFF_SR), "n" (n), \ "i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &mfp.int_mk_a) \ : (n & 16 ? &tt_mfp.int_mk_b : &mfp.int_mk_b)), \ @@ -297,7 +296,7 @@ addql #8,%%sp addql #4,%%sp jbra ret_from_interrupt" - : : "i" (&kstat.irqs[0]), "n" (PT_OFF_FORMATVEC), + : : "i" (&kstat_cpu(0).irqs), "n" (PT_OFF_FORMATVEC), "m" (local_irq_count(0)) ); for (;;); @@ -623,11 +622,11 @@ continue; if (i < STMFP_SOURCE_BASE) seq_printf(p, "auto %2d: %10u ", - i, kstat.irqs[0][i]); + i, kstat_cpu(0).irqs[i]); else seq_printf(p, "vec $%02x: %10u ", IRQ_SOURCE_TO_VECTOR(i), - kstat.irqs[0][i]); + kstat_cpu(0).irqs[i]); if (irq_handler[i].handler != atari_call_irq_list) { seq_printf(p, "%s\n", irq_param[i].devname); diff -Nru a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c --- a/arch/m68k/atari/config.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/atari/config.c Mon Nov 4 14:31:02 2002 @@ -66,6 +66,7 @@ extern void atari_enable_irq (unsigned int); extern void atari_disable_irq (unsigned int); extern int show_atari_interrupts (struct seq_file *, void *); +extern void atari_mksound( unsigned int count, unsigned int ticks ); #ifdef CONFIG_HEARTBEAT static void atari_heartbeat( int on ); #endif @@ -251,7 +252,7 @@ conswitchp = &dummy_con; #endif mach_max_dma_address = 0xffffff; -#ifdef CONFIG_INPUT_M68K_BEEP +#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) mach_beep = atari_mksound; #endif #ifdef CONFIG_HEARTBEAT diff -Nru a/arch/m68k/atari/hades-pci.c b/arch/m68k/atari/hades-pci.c --- a/arch/m68k/atari/hades-pci.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/atari/hades-pci.c Mon Nov 4 14:31:02 2002 @@ -311,26 +311,24 @@ slot = PCI_SLOT(dev->devfn); /* Determine slot number. */ dev->irq = irq_tab[slot]; if (pci_modify) - pcibios_write_config_byte(dev->bus->number, dev->devfn, - PCI_INTERRUPT_LINE, dev->irq); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); } } } /* - * static void hades_conf_device(unsigned char bus, unsigned char device_fn) + * static void hades_conf_device(struct pci_dev *dev) * * Machine dependent Configure the given device. * * Parameters: * - * bus - bus number of the device. - * device_fn - device and function number of the device. + * dev - the pci device. */ -static void __init hades_conf_device(unsigned char bus, unsigned char device_fn) +static void __init hades_conf_device(struct pci_dev *dev) { - pcibios_write_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE, 0); + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0); } static struct pci_ops hades_pci_ops = { diff -Nru a/arch/m68k/defconfig b/arch/m68k/defconfig --- a/arch/m68k/defconfig Mon Nov 4 14:31:00 2002 +++ b/arch/m68k/defconfig Mon Nov 4 14:31:00 2002 @@ -186,7 +186,6 @@ # CONFIG_VT=y CONFIG_VT_CONSOLE=y -CONFIG_AMIGAMOUSE=y CONFIG_BUSMOUSE=y CONFIG_AMIGA_BUILTIN_SERIAL=y # CONFIG_GVPIOEXT is not set diff -Nru a/arch/m68k/fpsp040/bindec.S b/arch/m68k/fpsp040/bindec.S --- a/arch/m68k/fpsp040/bindec.S Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/fpsp040/bindec.S Mon Nov 4 14:31:01 2002 @@ -137,7 +137,7 @@ |BINDEC idnt 2,1 | Motorola 040 Floating Point Software Package - .include "fpsp.h" +#include "fpsp.h" |section 8 diff -Nru a/arch/m68k/fpsp040/binstr.S b/arch/m68k/fpsp040/binstr.S --- a/arch/m68k/fpsp040/binstr.S Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/fpsp040/binstr.S Mon Nov 4 14:31:01 2002 @@ -68,7 +68,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" .global binstr binstr: diff -Nru a/arch/m68k/fpsp040/bugfix.S b/arch/m68k/fpsp040/bugfix.S --- a/arch/m68k/fpsp040/bugfix.S Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/fpsp040/bugfix.S Mon Nov 4 14:31:02 2002 @@ -160,7 +160,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" |xref fpsp_fmt_error diff -Nru a/arch/m68k/fpsp040/decbin.S b/arch/m68k/fpsp040/decbin.S --- a/arch/m68k/fpsp040/decbin.S Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/fpsp040/decbin.S Mon Nov 4 14:31:02 2002 @@ -77,7 +77,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" | | PTENRN, PTENRM, and PTENRP are arrays of powers of 10 rounded diff -Nru a/arch/m68k/fpsp040/do_func.S b/arch/m68k/fpsp040/do_func.S --- a/arch/m68k/fpsp040/do_func.S Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/fpsp040/do_func.S Mon Nov 4 14:31:02 2002 @@ -30,7 +30,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" |xref t_dz2 |xref t_operr diff -Nru a/arch/m68k/fpsp040/gen_except.S b/arch/m68k/fpsp040/gen_except.S --- a/arch/m68k/fpsp040/gen_except.S Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/fpsp040/gen_except.S Mon Nov 4 14:31:01 2002 @@ -37,7 +37,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" |xref real_trace |xref fpsp_done diff -Nru a/arch/m68k/fpsp040/get_op.S b/arch/m68k/fpsp040/get_op.S --- a/arch/m68k/fpsp040/get_op.S Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/fpsp040/get_op.S Mon Nov 4 14:31:01 2002 @@ -62,7 +62,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" .global PIRN,PIRZRM,PIRP .global SMALRN,SMALRZRM,SMALRP diff -Nru a/arch/m68k/fpsp040/kernel_ex.S b/arch/m68k/fpsp040/kernel_ex.S --- a/arch/m68k/fpsp040/kernel_ex.S Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/fpsp040/kernel_ex.S Mon Nov 4 14:31:02 2002 @@ -20,7 +20,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" mns_inf: .long 0xffff0000,0x00000000,0x00000000 pls_inf: .long 0x7fff0000,0x00000000,0x00000000 diff -Nru a/arch/m68k/fpsp040/res_func.S b/arch/m68k/fpsp040/res_func.S --- a/arch/m68k/fpsp040/res_func.S Mon Nov 4 14:31:00 2002 +++ b/arch/m68k/fpsp040/res_func.S Mon Nov 4 14:31:00 2002 @@ -24,7 +24,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" sp_bnds: .short 0x3f81,0x407e .short 0x3f6a,0x0000 diff -Nru a/arch/m68k/fpsp040/round.S b/arch/m68k/fpsp040/round.S --- a/arch/m68k/fpsp040/round.S Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/fpsp040/round.S Mon Nov 4 14:31:02 2002 @@ -16,7 +16,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" | | round --- round result according to precision/mode diff -Nru a/arch/m68k/fpsp040/satan.S b/arch/m68k/fpsp040/satan.S --- a/arch/m68k/fpsp040/satan.S Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/fpsp040/satan.S Mon Nov 4 14:31:02 2002 @@ -51,7 +51,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" BOUNDS1: .long 0x3FFB8000,0x4002FFFF diff -Nru a/arch/m68k/fpsp040/scale.S b/arch/m68k/fpsp040/scale.S --- a/arch/m68k/fpsp040/scale.S Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/fpsp040/scale.S Mon Nov 4 14:31:01 2002 @@ -29,7 +29,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" |xref t_ovfl2 |xref t_unfl diff -Nru a/arch/m68k/fpsp040/setox.S b/arch/m68k/fpsp040/setox.S --- a/arch/m68k/fpsp040/setox.S Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/fpsp040/setox.S Mon Nov 4 14:31:01 2002 @@ -339,7 +339,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" L2: .long 0x3FDC0000,0x82E30865,0x4361C4C6,0x00000000 diff -Nru a/arch/m68k/fpsp040/sgetem.S b/arch/m68k/fpsp040/sgetem.S --- a/arch/m68k/fpsp040/sgetem.S Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/fpsp040/sgetem.S Mon Nov 4 14:31:02 2002 @@ -32,7 +32,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" |xref nrm_set diff -Nru a/arch/m68k/fpsp040/sint.S b/arch/m68k/fpsp040/sint.S --- a/arch/m68k/fpsp040/sint.S Mon Nov 4 14:31:03 2002 +++ b/arch/m68k/fpsp040/sint.S Mon Nov 4 14:31:03 2002 @@ -59,7 +59,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" |xref dnrm_lp |xref nrm_set diff -Nru a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S --- a/arch/m68k/fpsp040/skeleton.S Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/fpsp040/skeleton.S Mon Nov 4 14:31:01 2002 @@ -51,7 +51,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" |xref b1238_fix diff -Nru a/arch/m68k/fpsp040/slogn.S b/arch/m68k/fpsp040/slogn.S --- a/arch/m68k/fpsp040/slogn.S Mon Nov 4 14:31:00 2002 +++ b/arch/m68k/fpsp040/slogn.S Mon Nov 4 14:31:00 2002 @@ -71,7 +71,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" BOUNDS1: .long 0x3FFEF07D,0x3FFF8841 BOUNDS2: .long 0x3FFE8000,0x3FFFC000 diff -Nru a/arch/m68k/fpsp040/smovecr.S b/arch/m68k/fpsp040/smovecr.S --- a/arch/m68k/fpsp040/smovecr.S Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/fpsp040/smovecr.S Mon Nov 4 14:31:02 2002 @@ -23,7 +23,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" |xref nrm_set |xref round diff -Nru a/arch/m68k/fpsp040/srem_mod.S b/arch/m68k/fpsp040/srem_mod.S --- a/arch/m68k/fpsp040/srem_mod.S Mon Nov 4 14:31:00 2002 +++ b/arch/m68k/fpsp040/srem_mod.S Mon Nov 4 14:31:00 2002 @@ -74,7 +74,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" .set Mod_Flag,L_SCR3 .set SignY,FP_SCR3+4 diff -Nru a/arch/m68k/fpsp040/ssin.S b/arch/m68k/fpsp040/ssin.S --- a/arch/m68k/fpsp040/ssin.S Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/fpsp040/ssin.S Mon Nov 4 14:31:01 2002 @@ -91,7 +91,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" BOUNDS1: .long 0x3FD78000,0x4004BC7E TWOBYPI: .long 0x3FE45F30,0x6DC9C883 diff -Nru a/arch/m68k/fpsp040/stan.S b/arch/m68k/fpsp040/stan.S --- a/arch/m68k/fpsp040/stan.S Mon Nov 4 14:31:00 2002 +++ b/arch/m68k/fpsp040/stan.S Mon Nov 4 14:31:00 2002 @@ -58,7 +58,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" BOUNDS1: .long 0x3FD78000,0x4004BC7E TWOBYPI: .long 0x3FE45F30,0x6DC9C883 diff -Nru a/arch/m68k/fpsp040/stanh.S b/arch/m68k/fpsp040/stanh.S --- a/arch/m68k/fpsp040/stanh.S Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/fpsp040/stanh.S Mon Nov 4 14:31:01 2002 @@ -57,7 +57,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" .set X,FP_SCR5 .set XDCARE,X+2 diff -Nru a/arch/m68k/fpsp040/sto_res.S b/arch/m68k/fpsp040/sto_res.S --- a/arch/m68k/fpsp040/sto_res.S Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/fpsp040/sto_res.S Mon Nov 4 14:31:02 2002 @@ -28,7 +28,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" .global sto_cos sto_cos: diff -Nru a/arch/m68k/fpsp040/stwotox.S b/arch/m68k/fpsp040/stwotox.S --- a/arch/m68k/fpsp040/stwotox.S Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/fpsp040/stwotox.S Mon Nov 4 14:31:01 2002 @@ -84,7 +84,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" BOUNDS1: .long 0x3FB98000,0x400D80C0 | ... 2^(-70),16480 BOUNDS2: .long 0x3FB98000,0x400B9B07 | ... 2^(-70),16480 LOG2/LOG10 diff -Nru a/arch/m68k/fpsp040/util.S b/arch/m68k/fpsp040/util.S --- a/arch/m68k/fpsp040/util.S Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/fpsp040/util.S Mon Nov 4 14:31:02 2002 @@ -24,7 +24,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" |xref mem_read diff -Nru a/arch/m68k/fpsp040/x_bsun.S b/arch/m68k/fpsp040/x_bsun.S --- a/arch/m68k/fpsp040/x_bsun.S Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/fpsp040/x_bsun.S Mon Nov 4 14:31:02 2002 @@ -21,7 +21,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" |xref real_bsun diff -Nru a/arch/m68k/fpsp040/x_fline.S b/arch/m68k/fpsp040/x_fline.S --- a/arch/m68k/fpsp040/x_fline.S Mon Nov 4 14:31:00 2002 +++ b/arch/m68k/fpsp040/x_fline.S Mon Nov 4 14:31:00 2002 @@ -21,7 +21,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" |xref real_fline |xref fpsp_unimp diff -Nru a/arch/m68k/fpsp040/x_operr.S b/arch/m68k/fpsp040/x_operr.S --- a/arch/m68k/fpsp040/x_operr.S Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/fpsp040/x_operr.S Mon Nov 4 14:31:02 2002 @@ -51,7 +51,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" |xref mem_write |xref real_operr diff -Nru a/arch/m68k/fpsp040/x_ovfl.S b/arch/m68k/fpsp040/x_ovfl.S --- a/arch/m68k/fpsp040/x_ovfl.S Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/fpsp040/x_ovfl.S Mon Nov 4 14:31:01 2002 @@ -43,7 +43,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" |xref ovf_r_x2 |xref ovf_r_x3 diff -Nru a/arch/m68k/fpsp040/x_snan.S b/arch/m68k/fpsp040/x_snan.S --- a/arch/m68k/fpsp040/x_snan.S Mon Nov 4 14:31:03 2002 +++ b/arch/m68k/fpsp040/x_snan.S Mon Nov 4 14:31:03 2002 @@ -30,7 +30,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" |xref get_fline |xref mem_write diff -Nru a/arch/m68k/fpsp040/x_store.S b/arch/m68k/fpsp040/x_store.S --- a/arch/m68k/fpsp040/x_store.S Mon Nov 4 14:31:03 2002 +++ b/arch/m68k/fpsp040/x_store.S Mon Nov 4 14:31:03 2002 @@ -22,7 +22,7 @@ fpreg_mask: .byte 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01 - .include "fpsp.h" +#include "fpsp.h" |xref mem_write |xref get_fline diff -Nru a/arch/m68k/fpsp040/x_unfl.S b/arch/m68k/fpsp040/x_unfl.S --- a/arch/m68k/fpsp040/x_unfl.S Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/fpsp040/x_unfl.S Mon Nov 4 14:31:01 2002 @@ -29,7 +29,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" |xref denorm |xref round diff -Nru a/arch/m68k/fpsp040/x_unimp.S b/arch/m68k/fpsp040/x_unimp.S --- a/arch/m68k/fpsp040/x_unimp.S Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/fpsp040/x_unimp.S Mon Nov 4 14:31:01 2002 @@ -30,7 +30,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" |xref get_op |xref do_func diff -Nru a/arch/m68k/fpsp040/x_unsupp.S b/arch/m68k/fpsp040/x_unsupp.S --- a/arch/m68k/fpsp040/x_unsupp.S Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/fpsp040/x_unsupp.S Mon Nov 4 14:31:02 2002 @@ -31,7 +31,7 @@ |section 8 - .include "fpsp.h" +#include "fpsp.h" |xref get_op |xref res_func diff -Nru a/arch/m68k/hp300/Makefile b/arch/m68k/hp300/Makefile --- a/arch/m68k/hp300/Makefile Mon Nov 4 14:31:00 2002 +++ b/arch/m68k/hp300/Makefile Mon Nov 4 14:31:00 2002 @@ -4,6 +4,4 @@ obj-y := ksyms.o config.o ints.o time.o reboot.o -obj-$(CONFIG_VT) += hil.o - include $(TOPDIR)/Rules.make diff -Nru a/arch/m68k/hp300/time.c b/arch/m68k/hp300/time.c --- a/arch/m68k/hp300/time.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/hp300/time.c Mon Nov 4 14:31:02 2002 @@ -40,7 +40,7 @@ { unsigned long tmp; void (*vector)(int, void *, struct pt_regs *) = dev_id; - readb(CLOCKBASE + CLKSR); + in_8(CLOCKBASE + CLKSR); asm volatile ("movpw %1@(5),%0" : "=d" (tmp) : "a" (CLOCKBASE)); vector(irq, NULL, regs); } @@ -51,25 +51,25 @@ unsigned char lsb, msb1, msb2; unsigned short ticks; - msb1 = readb(CLOCKBASE + 5); - lsb = readb(CLOCKBASE + 7); - msb2 = readb(CLOCKBASE + 5); + msb1 = in_8(CLOCKBASE + 5); + lsb = in_8(CLOCKBASE + 7); + msb2 = in_8(CLOCKBASE + 5); if (msb1 != msb2) /* A carry happened while we were reading. Read it again */ - lsb = readb(CLOCKBASE + 7); + lsb = in_8(CLOCKBASE + 7); ticks = INTVAL - ((msb2 << 8) | lsb); return (USECS_PER_JIFFY * ticks) / INTVAL; } void __init hp300_sched_init(void (*vector)(int, void *, struct pt_regs *)) { - writeb(0x1, CLOCKBASE + CLKCR2); /* select CR1 */ - writeb(0x1, CLOCKBASE + CLKCR1); /* reset */ + out_8(CLOCKBASE + CLKCR2, 0x1); /* select CR1 */ + out_8(CLOCKBASE + CLKCR1, 0x1); /* reset */ asm volatile(" movpw %0,%1@(5)" : : "d" (INTVAL), "a" (CLOCKBASE)); sys_request_irq(6, hp300_tick, IRQ_FLG_STD, "timer tick", vector); - writeb(0x1, CLOCKBASE + CLKCR2); /* select CR1 */ - writeb(0x40, CLOCKBASE + CLKCR1); /* enable irq */ + out_8(CLOCKBASE + CLKCR2, 0x1); /* select CR1 */ + out_8(CLOCKBASE + CLKCR1, 0x40); /* enable irq */ } diff -Nru a/arch/m68k/ifpsp060/fskeleton.S b/arch/m68k/ifpsp060/fskeleton.S --- a/arch/m68k/ifpsp060/fskeleton.S Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/ifpsp060/fskeleton.S Mon Nov 4 14:31:01 2002 @@ -340,4 +340,4 @@ | 060 FPSP KERNEL PACKAGE NEEDS TO GO HERE!!! - .include "fpsp.sa" +#include "fpsp.sa" diff -Nru a/arch/m68k/ifpsp060/iskeleton.S b/arch/m68k/ifpsp060/iskeleton.S --- a/arch/m68k/ifpsp060/iskeleton.S Mon Nov 4 14:31:00 2002 +++ b/arch/m68k/ifpsp060/iskeleton.S Mon Nov 4 14:31:00 2002 @@ -304,4 +304,4 @@ |########################################################################### | 060 INTEGER KERNEL PACKAGE MUST GO HERE!!! - .include "isp.sa" +#include "isp.sa" diff -Nru a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile --- a/arch/m68k/kernel/Makefile Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/kernel/Makefile Mon Nov 4 14:31:02 2002 @@ -19,18 +19,19 @@ include $(TOPDIR)/Rules.make -head.o: head.S m68k_defs.h +$(obj)/head.o: $(obj)/head.S $(obj)/m68k_defs.h -entry.o: entry.S m68k_defs.h +$(obj)/entry.o: $(obj)/entry.S $(obj)/m68k_defs.h -sun3-head.o: sun3-head.S m68k_defs.h +$(obj)/sun3-head.o: $(obj)/sun3-head.S $(obj)/m68k_defs.h -m68k_defs.h: m68k_defs.c m68k_defs.head - rm -f m68k_defs.d - SUNPRO_DEPENDENCIES="m68k_defs.d m68k_defs.h" \ - $(CC) $(filter-out -MD,$(CFLAGS)) -S m68k_defs.c - cp m68k_defs.head m68k_defs.h - grep '^#define' m68k_defs.s >> m68k_defs.h - rm m68k_defs.s --include m68k_defs.d +$(obj)/m68k_defs.h: $(src)/m68k_defs.c $(src)/m68k_defs.head + rm -f $(obj)/m68k_defs.d + SUNPRO_DEPENDENCIES="$(obj)/m68k_defs.d $(obj)/m68k_defs.h" \ + $(CC) $(filter-out -MD,$(CFLAGS)) -S $(src)/m68k_defs.c -o \ + $(obj)/m68k_defs.s + cp $(src)/m68k_defs.head $(obj)/m68k_defs.h + grep '^#define' $(obj)/m68k_defs.s >> $(obj)/m68k_defs.h + rm $(obj)/m68k_defs.s +-include $(obj)/m68k_defs.d diff -Nru a/arch/m68k/kernel/bios32.c b/arch/m68k/kernel/bios32.c --- a/arch/m68k/kernel/bios32.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/kernel/bios32.c Mon Nov 4 14:31:02 2002 @@ -95,7 +95,6 @@ static void __init disable_dev(struct pci_dev *dev) { - struct pci_bus *bus; unsigned short cmd; if (((dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA) || @@ -103,11 +102,10 @@ (dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)) && skip_vga) return; - bus = dev->bus; - pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); + pci_read_config_word(dev, PCI_COMMAND, &cmd); cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER); - pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); } /* @@ -122,7 +120,6 @@ static void __init layout_dev(struct pci_dev *dev) { - struct pci_bus *bus; unsigned short cmd; unsigned int base, mask, size, reg; unsigned int alignto; @@ -137,8 +134,7 @@ (dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)) && skip_vga) return; - bus = dev->bus; - pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); + pci_read_config_word(dev, PCI_COMMAND, &cmd); for (reg = PCI_BASE_ADDRESS_0, i = 0; reg <= PCI_BASE_ADDRESS_5; reg += 4, i++) { @@ -147,9 +143,8 @@ * device wants. */ - pcibios_write_config_dword(bus->number, dev->devfn, reg, - 0xffffffff); - pcibios_read_config_dword(bus->number, dev->devfn, reg, &base); + pci_write_config_dword(dev, reg, 0xffffffff); + pci_read_config_dword(dev, reg, &base); if (!base) { @@ -184,8 +179,7 @@ alignto = MAX(0x040, size) ; base = ALIGN(io_base, alignto); io_base = base + size; - pcibios_write_config_dword(bus->number, dev->devfn, - reg, base | PCI_BASE_ADDRESS_SPACE_IO); + pci_write_config_dword(dev, reg, base | PCI_BASE_ADDRESS_SPACE_IO); dev->resource[i].start = base; dev->resource[i].end = dev->resource[i].start + size - 1; @@ -228,8 +222,7 @@ alignto = MAX(0x1000, size) ; base = ALIGN(mem_base, alignto); mem_base = base + size; - pcibios_write_config_dword(bus->number, dev->devfn, - reg, base); + pci_write_config_dword(dev, reg, base); dev->resource[i].start = base; dev->resource[i].end = dev->resource[i].start + size - 1; @@ -243,8 +236,7 @@ */ reg += 4; - pcibios_write_config_dword(bus->number, dev->devfn, - reg, 0); + pci_write_config_dword(dev, reg, 0); i++; dev->resource[i].start = 0; @@ -272,17 +264,15 @@ cmd |= PCI_COMMAND_IO; } - pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND, - cmd | PCI_COMMAND_MASTER); + pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER); - pcibios_write_config_byte(bus->number, dev->devfn, PCI_LATENCY_TIMER, - (disable_pci_burst) ? 0 : 32); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, (disable_pci_burst) ? 0 : 32); if (bus_info != NULL) - bus_info->conf_device(bus->number, dev->devfn); /* Machine dependent configuration. */ + bus_info->conf_device(dev); /* Machine dependent configuration. */ DBG_DEVS(("layout_dev: bus %d slot 0x%x VID 0x%x DID 0x%x class 0x%x\n", - bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class)); + dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class)); } /* diff -Nru a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S --- a/arch/m68k/kernel/entry.S Mon Nov 4 14:31:00 2002 +++ b/arch/m68k/kernel/entry.S Mon Nov 4 14:31:00 2002 @@ -222,7 +222,7 @@ inthandler: SAVE_ALL_INT GET_CURRENT(%d0) - addql #1,irq_stat+CPUSTAT_LOCAL_IRQ_COUNT + addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+2) | put exception # in d0 bfextu %sp@(PT_VECTOR){#4,#10},%d0 @@ -241,18 +241,15 @@ 3: addql #8,%sp | pop parameters off stack ret_from_interrupt: - subql #1,irq_stat+CPUSTAT_LOCAL_IRQ_COUNT + subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+2) jeq 1f 2: RESTORE_ALL 1: -#if 1 - bfextu %sp@(PT_SR){#5,#3},%d0 | Check for nested interrupt. -#if MAX_NOINT_IPL > 0 - cmpiw #MAX_NOINT_IPL,%d0 -#endif - jhi 2b -#endif + moveq #(~ALLOWINT>>8)&0xff,%d0 + andb %sp@(PT_SR),%d0 + jne 2b + /* check if we need to do software interrupts */ tstl irq_stat+CPUSTAT_SOFTIRQ_PENDING jeq ret_from_exception diff -Nru a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c --- a/arch/m68k/kernel/ints.c Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/kernel/ints.c Mon Nov 4 14:31:01 2002 @@ -231,7 +231,7 @@ { if (vec >= VEC_INT1 && vec <= VEC_INT7 && !MACH_IS_BVME6000) { vec -= VEC_SPUR; - kstat.irqs[0][vec]++; + kstat_cpu(0).irqs[vec]++; irq_list[vec].handler(vec, irq_list[vec].dev_id, fp); } else { if (mach_process_int) @@ -250,7 +250,7 @@ if (mach_default_handler) { for (i = 0; i < SYS_IRQS; i++) { seq_printf(p, "auto %2d: %10u ", i, - i ? kstat.irqs[0][i] : num_spurious); + i ? kstat_cpu(0).irqs[i] : num_spurious); seq_puts(p, " "); seq_printf(p, "%s\n", irq_list[i].devname); } diff -Nru a/arch/m68k/kernel/m68k_defs.c b/arch/m68k/kernel/m68k_defs.c --- a/arch/m68k/kernel/m68k_defs.c Mon Nov 4 14:31:00 2002 +++ b/arch/m68k/kernel/m68k_defs.c Mon Nov 4 14:31:00 2002 @@ -71,8 +71,6 @@ /* offsets into the irq_cpustat_t struct */ DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); - DEFINE(CPUSTAT_LOCAL_IRQ_COUNT, offsetof(irq_cpustat_t, __local_irq_count)); - DEFINE(CPUSTAT_LOCAL_BH_COUNT, offsetof(irq_cpustat_t, __local_bh_count)); DEFINE(CPUSTAT_SYSCALL_COUNT, offsetof(irq_cpustat_t, __syscall_count)); /* offsets into the bi_record struct */ diff -Nru a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c --- a/arch/m68k/kernel/m68k_ksyms.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/kernel/m68k_ksyms.c Mon Nov 4 14:31:02 2002 @@ -42,13 +42,15 @@ EXPORT_SYMBOL(mm_vtop); EXPORT_SYMBOL(mm_ptov); EXPORT_SYMBOL(mm_end_of_chunk); +#else +EXPORT_SYMBOL(m68k_memoffset); #endif /* !CONFIG_SINGLE_MEMORY_CHUNK */ -EXPORT_SYMBOL(mm_vtop_fallback); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); EXPORT_SYMBOL(kernel_set_cachemode); #endif /* !CONFIG_SUN3 */ EXPORT_SYMBOL(m68k_debug_device); +EXPORT_SYMBOL(mach_hwclk); EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(strnlen); diff -Nru a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c --- a/arch/m68k/kernel/process.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/kernel/process.c Mon Nov 4 14:31:02 2002 @@ -41,7 +41,7 @@ */ static struct fs_struct init_fs = INIT_FS; static struct files_struct init_files = INIT_FILES; -static struct signal_struct init_signals = INIT_SIGNALS; +static struct signal_struct init_signals = INIT_SIGNALS(init_signals); struct mm_struct init_mm = INIT_MM(init_mm); union thread_union init_thread_union @@ -152,7 +152,7 @@ { register long retval __asm__ ("d0"); - register long clone_arg __asm__ ("d1") = flags | CLONE_VM; + register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED; retval = __NR_clone; __asm__ __volatile__ @@ -202,14 +202,14 @@ asmlinkage int m68k_fork(struct pt_regs *regs) { struct task_struct *p; - p = do_fork(SIGCHLD, rdusp(), regs, 0); + p = do_fork(SIGCHLD, rdusp(), regs, 0, NULL); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } asmlinkage int m68k_vfork(struct pt_regs *regs) { struct task_struct *p; - p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0); + p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } @@ -218,13 +218,15 @@ unsigned long clone_flags; unsigned long newsp; struct task_struct *p; + int *user_tid; /* syscall2 puts clone_flags in d1 and usp in d2 */ clone_flags = regs->d1; newsp = regs->d2; + user_tid = (int *)regs->d3; if (!newsp) newsp = rdusp(); - p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0); + p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, user_tid); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } diff -Nru a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c --- a/arch/m68k/kernel/ptrace.c Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/kernel/ptrace.c Mon Nov 4 14:31:01 2002 @@ -355,7 +355,7 @@ } default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); break; } out_tsk: @@ -370,7 +370,8 @@ if (!current->thread.work.delayed_trace && !current->thread.work.syscall_trace) return; - current->exit_code = SIGTRAP; + current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0); current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); diff -Nru a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c --- a/arch/m68k/kernel/setup.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/kernel/setup.c Mon Nov 4 14:31:02 2002 @@ -98,7 +98,7 @@ #ifdef CONFIG_M68K_L2_CACHE void (*mach_l2_flush) (int) = NULL; #endif -#ifdef CONFIG_INPUT_M68K_BEEP +#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) void (*mach_beep)(unsigned int, unsigned int) = NULL; #endif #if defined(CONFIG_ISA) && defined(MULTI_ISA) @@ -536,11 +536,6 @@ } #endif - -/* for "kbd-reset" cmdline param */ -void __init kbd_reset_setup(char *str, int *ints) -{ -} void check_bugs(void) { diff -Nru a/arch/m68k/kernel/sun3-head.S b/arch/m68k/kernel/sun3-head.S --- a/arch/m68k/kernel/sun3-head.S Mon Nov 4 14:31:00 2002 +++ b/arch/m68k/kernel/sun3-head.S Mon Nov 4 14:31:00 2002 @@ -16,9 +16,6 @@ .globl bootup_user_stack .globl bootup_kernel_stack .globl pg0 -.globl empty_bad_page -.globl empty_bad_page_table -.globl empty_zero_page .globl swapper_pg_dir .globl kernel_pmd_table .globl availmem @@ -27,10 +24,7 @@ | todo: all these should be in bss! swapper_pg_dir: .skip 0x2000 pg0: .skip 0x2000 -empty_bad_page: .skip 0x2000 -empty_bad_page_table: .skip 0x2000 kernel_pmd_table: .skip 0x2000 -empty_zero_page: .skip 0x2000 .globl kernel_pg_dir .equ kernel_pg_dir,kernel_pmd_table diff -Nru a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c --- a/arch/m68k/kernel/time.c Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/kernel/time.c Mon Nov 4 14:31:01 2002 @@ -23,6 +23,7 @@ #include #include +#include u64 jiffies_64; @@ -70,15 +71,22 @@ * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be * called as close as possible to 500 ms before the new second starts. */ + /* + * This code hopefully becomes obsolete in 2.5 or earlier + * Should it ever be reenabled it must be serialized with + * genrtc.c operation + */ +#if 0 if ((time_status & STA_UNSYNC) == 0 && xtime.tv_sec > last_rtc_update + 660 && - xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 && - xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) { + (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) tick) / 2 && + (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) tick) / 2) { if (set_rtc_mmss(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; else last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ } +#endif #ifdef CONFIG_HEARTBEAT /* use power LED as a heartbeat instead -- much more useful for debugging -- based on the version for PReP by Cort */ @@ -115,7 +123,7 @@ time.tm_year += 100; xtime.tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec); - xtime.tv_usec = 0; + xtime.tv_nsec = 0; } mach_sched_init(timer_interrupt); @@ -138,7 +146,7 @@ if (lost) usec += lost * (1000000/HZ); sec = xtime.tv_sec; - usec += xtime.tv_usec; + usec += xtime.tv_nsec/1000; read_unlock_irqrestore(&xtime_lock, flags); while (usec >= 1000000) { @@ -152,21 +160,25 @@ void do_settimeofday(struct timeval *tv) { + extern unsigned long wall_jiffies; + write_lock_irq(&xtime_lock); - /* This is revolting. We need to set the xtime.tv_usec + /* This is revolting. We need to set the xtime.tv_nsec * correctly. However, the value in this location is * is value at the last tick. * Discover what correction gettimeofday * would have done, and then undo it! */ tv->tv_usec -= mach_gettimeoffset(); + tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ); while (tv->tv_usec < 0) { tv->tv_usec += 1000000; tv->tv_sec--; } - xtime = *tv; + xtime.tv_sec = tv->tv_sec; + xtime.tv_nsec = tv->tv_usec * 1000; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; diff -Nru a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c --- a/arch/m68k/kernel/traps.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/kernel/traps.c Mon Nov 4 14:31:02 2002 @@ -881,9 +881,10 @@ show_trace((unsigned long *)tsk->thread.esp0); } -static void dump_stack(struct frame *fp) +void show_registers(struct pt_regs *regs) { - unsigned long *stack, *endstack, addr; + struct frame *fp = (struct frame *)regs; + unsigned long addr; int i; addr = (unsigned long)&fp->un; @@ -938,9 +939,22 @@ default: printk("\n"); } + show_stack((unsigned long *)addr); - stack = (unsigned long *)addr; - endstack = (unsigned long *)((addr + THREAD_SIZE - 1) & -THREAD_SIZE); + printk("Code: "); + for (i = 0; i < 10; i++) + printk("%04x ", 0xffff & ((short *) fp->ptregs.pc)[i]); + printk ("\n"); +} + +extern void show_stack(unsigned long *stack) +{ + unsigned long *endstack; + int i; + + if (!stack) + stack = (unsigned long *)&stack; + endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE); printk("Stack from %08lx:", (unsigned long)stack); for (i = 0; i < kstack_depth_to_print; i++) { @@ -951,12 +965,17 @@ printk(" %08lx", *stack++); } printk("\n"); - show_trace((unsigned long *)addr); + show_trace(stack); +} - printk("Code: "); - for (i = 0; i < 10; i++) - printk("%04x ", 0xffff & ((short *) fp->ptregs.pc)[i]); - printk ("\n"); +/* + * The architecture-independent backtrace generator + */ +void dump_stack(void) +{ + unsigned long stack; + + show_trace(&stack); } void bad_super_trap (struct frame *fp) @@ -1129,7 +1148,7 @@ printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, PAGE_SIZE+(unsigned long)current); - dump_stack((struct frame *)fp); + show_stack((unsigned long *)fp); do_exit(SIGSEGV); } diff -Nru a/arch/m68k/lib/checksum.c b/arch/m68k/lib/checksum.c --- a/arch/m68k/lib/checksum.c Mon Nov 4 14:31:03 2002 +++ b/arch/m68k/lib/checksum.c Mon Nov 4 14:31:03 2002 @@ -318,3 +318,103 @@ return(sum); } + +/* + * copy from kernel space while checksumming, otherwise like csum_partial + */ + +unsigned int +csum_partial_copy_nocheck(const char *src, char *dst, int len, int sum) +{ + unsigned long tmp1, tmp2; + __asm__("movel %2,%4\n\t" + "btst #1,%4\n\t" /* Check alignment */ + "jeq 2f\n\t" + "subql #2,%1\n\t" /* buff%4==2: treat first word */ + "jgt 1f\n\t" + "addql #2,%1\n\t" /* len was == 2, treat only rest */ + "jra 4f\n" + "1:\t" + "movew %2@+,%4\n\t" /* add first word to sum */ + "addw %4,%0\n\t" + "movew %4,%3@+\n\t" + "clrl %4\n\t" + "addxl %4,%0\n" /* add X bit */ + "2:\t" + /* unrolled loop for the main part: do 8 longs at once */ + "movel %1,%4\n\t" /* save len in tmp1 */ + "lsrl #5,%1\n\t" /* len/32 */ + "jeq 2f\n\t" /* not enough... */ + "subql #1,%1\n" + "1:\t" + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "dbra %1,1b\n\t" + "clrl %5\n\t" + "addxl %5,%0\n\t" /* add X bit */ + "clrw %1\n\t" + "subql #1,%1\n\t" + "jcc 1b\n" + "2:\t" + "movel %4,%1\n\t" /* restore len from tmp1 */ + "andw #0x1c,%4\n\t" /* number of rest longs */ + "jeq 4f\n\t" + "lsrw #2,%4\n\t" + "subqw #1,%4\n" + "3:\t" + /* loop for rest longs */ + "movel %2@+,%5\n\t" + "addxl %5,%0\n\t" + "movel %5,%3@+\n\t" + "dbra %4,3b\n\t" + "clrl %5\n\t" + "addxl %5,%0\n" /* add X bit */ + "4:\t" + /* now check for rest bytes that do not fit into longs */ + "andw #3,%1\n\t" + "jeq 7f\n\t" + "clrl %5\n\t" /* clear tmp2 for rest bytes */ + "subqw #2,%1\n\t" + "jlt 5f\n\t" + "movew %2@+,%5\n\t" /* have rest >= 2: get word */ + "movew %5,%3@+\n\t" + "swap %5\n\t" /* into bits 16..31 */ + "tstw %1\n\t" /* another byte? */ + "jeq 6f\n" + "5:\t" + "moveb %2@,%5\n\t" /* have odd rest: get byte */ + "moveb %5,%3@+\n\t" + "lslw #8,%5\n" /* into bits 8..15; 16..31 untouched */ + "6:\t" + "addl %5,%0\n\t" /* now add rest long to sum */ + "clrl %5\n\t" + "addxl %5,%0\n" /* add X bit */ + "7:\t" + : "=d" (sum), "=d" (len), "=a" (src), "=a" (dst), + "=&d" (tmp1), "=&d" (tmp2) + : "0" (sum), "1" (len), "2" (src), "3" (dst) + ); + return(sum); +} diff -Nru a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c --- a/arch/m68k/mac/config.c Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/mac/config.c Mon Nov 4 14:31:01 2002 @@ -78,6 +78,8 @@ extern void psc_init(void); extern void baboon_init(void); +extern void mac_mksound(unsigned int, unsigned int); + extern void nubus_sweep_video(void); /* Mac specific debug functions (in debug.c) */ @@ -217,7 +219,7 @@ #if 0 mach_debug_init = mac_debug_init; #endif -#ifdef CONFIG_INPUT_M68K_BEEP +#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) mach_beep = mac_mksound; #endif #ifdef CONFIG_HEARTBEAT diff -Nru a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c --- a/arch/m68k/mac/macints.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/mac/macints.c Mon Nov 4 14:31:02 2002 @@ -251,7 +251,7 @@ #endif /* SHUTUP_SONIC */ /* - * Now register the handlers for the the master IRQ handlers + * Now register the handlers for the master IRQ handlers * at levels 1-7. Most of the work is done elsewhere. */ @@ -345,7 +345,7 @@ irq_node_t *node, *slow_nodes; unsigned long cpu_flags; - kstat.irqs[0][irq]++; + kstat_cpu(0).irqs[irq]++; #ifdef DEBUG_SPURIOUS if (!mac_irq_list[irq] && (console_loglevel > 7)) { @@ -620,7 +620,7 @@ case 8: base = "bbn"; break; } - seq_printf(p, "%4s %2d: %10u ", base, i, kstat.irqs[0][i]); + seq_printf(p, "%4s %2d: %10u ", base, i, kstat_cpu(0).irqs[i]); do { if (node->flags & IRQ_FLG_FAST) { diff -Nru a/arch/m68k/mm/Makefile b/arch/m68k/mm/Makefile --- a/arch/m68k/mm/Makefile Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/mm/Makefile Mon Nov 4 14:31:01 2002 @@ -7,7 +7,7 @@ ifndef CONFIG_SUN3 obj-y += kmap.o memory.o motorola.o else -obj-y += sun3mmu.o +obj-y += sun3kmap.o sun3mmu.o endif diff -Nru a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c --- a/arch/m68k/mm/memory.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/mm/memory.c Mon Nov 4 14:31:02 2002 @@ -133,34 +133,6 @@ return 0; } -static unsigned long transp_transl_matches( unsigned long regval, - unsigned long vaddr ) -{ - unsigned long base, mask; - - /* enabled? */ - if (!(regval & 0x8000)) - return( 0 ); - - if (CPU_IS_030) { - /* function code match? */ - base = (regval >> 4) & 7; - mask = ~(regval & 7); - if (((SUPER_DATA ^ base) & mask) != 0) - return 0; - } - else { - /* must not be user-only */ - if ((regval & 0x6000) == 0) - return( 0 ); - } - - /* address match? */ - base = regval & 0xff000000; - mask = ~(regval << 8) & 0xff000000; - return (((unsigned long)vaddr ^ base) & mask) == 0; -} - #if DEBUG_INVALID_PTOV int mm_inv_cnt = 5; #endif @@ -190,134 +162,9 @@ if (voff == 0) return m68k_memory[i-1].addr + m68k_memory[i-1].size; - return mm_vtop_fallback(vaddr); -} -#endif - -/* Separate function to make the common case faster (needs to save less - registers) */ -unsigned long mm_vtop_fallback(unsigned long vaddr) -{ - /* not in one of the memory chunks; test for applying transparent - * translation */ - - if (CPU_IS_030) { - unsigned long ttreg; - - asm volatile( ".chip 68030\n\t" - "pmove %/tt0,%0@\n\t" - ".chip 68k" - : : "a" (&ttreg) ); - if (transp_transl_matches( ttreg, vaddr )) - return (unsigned long)vaddr; - asm volatile( ".chip 68030\n\t" - "pmove %/tt1,%0@\n\t" - ".chip 68k" - : : "a" (&ttreg) ); - if (transp_transl_matches( ttreg, vaddr )) - return (unsigned long)vaddr; - } - else if (CPU_IS_040_OR_060) { - unsigned long ttreg; - - asm volatile( ".chip 68040\n\t" - "movec %%dtt0,%0\n\t" - ".chip 68k" - : "=d" (ttreg) ); - if (transp_transl_matches( ttreg, vaddr )) - return (unsigned long)vaddr; - asm volatile( ".chip 68040\n\t" - "movec %%dtt1,%0\n\t" - ".chip 68k" - : "=d" (ttreg) ); - if (transp_transl_matches( ttreg, vaddr )) - return (unsigned long)vaddr; - } - - /* no match, too, so get the actual physical address from the MMU. */ - - if (CPU_IS_060) { - mm_segment_t fs = get_fs(); - unsigned long paddr; - - set_fs (MAKE_MM_SEG(SUPER_DATA)); - - /* The PLPAR instruction causes an access error if the translation - * is not possible. To catch this we use the same exception mechanism - * as for user space accesses in . */ - asm volatile (".chip 68060\n" - "1: plpar (%0)\n" - ".chip 68k\n" - "2:\n" - ".section .fixup,\"ax\"\n" - " .even\n" - "3: lea -1,%0\n" - " jra 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 1b,3b\n" - ".previous" - : "=a" (paddr) - : "0" (vaddr)); - set_fs (fs); - - return paddr; - - } else if (CPU_IS_040) { - unsigned long mmusr; - mm_segment_t fs = get_fs(); - - set_fs (MAKE_MM_SEG(SUPER_DATA)); - - asm volatile (".chip 68040\n\t" - "ptestr (%1)\n\t" - "movec %%mmusr, %0\n\t" - ".chip 68k" - : "=r" (mmusr) - : "a" (vaddr)); - set_fs (fs); - - if (mmusr & MMU_T_040) { - return (unsigned long)vaddr; /* Transparent translation */ - } - if (mmusr & MMU_R_040) - return (mmusr & PAGE_MASK) | ((unsigned long)vaddr & (PAGE_SIZE-1)); - - printk("VTOP040: bad virtual address %lx (%lx)", vaddr, mmusr); - return -1; - } else { - volatile unsigned short temp; - unsigned short mmusr; - unsigned long *descaddr; - - asm volatile ("ptestr #5,%2@,#7,%0\n\t" - "pmove %/psr,%1@" - : "=a&" (descaddr) - : "a" (&temp), "a" (vaddr)); - mmusr = temp; - - if (mmusr & (MMU_I|MMU_B|MMU_L)) - printk("VTOP030: bad virtual address %lx (%x)\n", vaddr, mmusr); - - descaddr = phys_to_virt((unsigned long)descaddr); - - switch (mmusr & MMU_NUM) { - case 1: - return (*descaddr & 0xfe000000) | ((unsigned long)vaddr & 0x01ffffff); - case 2: - return (*descaddr & 0xfffc0000) | ((unsigned long)vaddr & 0x0003ffff); - case 3: - return (*descaddr & PAGE_MASK) | ((unsigned long)vaddr & (PAGE_SIZE-1)); - default: - printk("VTOP: bad levels (%u) for virtual address %lx\n", - mmusr & MMU_NUM, vaddr); - } - } - - printk("VTOP: bad virtual address %lx\n", vaddr); return -1; } +#endif #ifndef CONFIG_SINGLE_MEMORY_CHUNK unsigned long mm_ptov (unsigned long paddr) @@ -343,74 +190,56 @@ paddr, __builtin_return_address(0)); } #endif - /* - * assume that the kernel virtual address is the same as the - * physical address. - * - * This should be reasonable in most situations: - * 1) They shouldn't be dereferencing the virtual address - * unless they are sure that it is valid from kernel space. - * 2) The only usage I see so far is converting a page table - * reference to some non-FASTMEM address space when freeing - * mmaped "/dev/mem" pages. These addresses are just passed - * to "free_page", which ignores addresses that aren't in - * the memory list anyway. - * - */ - -#ifdef CONFIG_AMIGA - /* - * if on an amiga and address is in first 16M, move it - * to the ZTWO_VADDR range - */ - if (MACH_IS_AMIGA && paddr < 16*1024*1024) - return ZTWO_VADDR(paddr); -#endif return -1; } #endif /* invalidate page in both caches */ -#define clear040(paddr) \ - __asm__ __volatile__ ("nop\n\t" \ - ".chip 68040\n\t" \ - "cinvp %%bc,(%0)\n\t" \ - ".chip 68k" \ - : : "a" (paddr)) +static inline void clear040(unsigned long paddr) +{ + asm volatile ( + "nop\n\t" + ".chip 68040\n\t" + "cinvp %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (paddr)); +} /* invalidate page in i-cache */ -#define cleari040(paddr) \ - __asm__ __volatile__ ("nop\n\t" \ - ".chip 68040\n\t" \ - "cinvp %%ic,(%0)\n\t" \ - ".chip 68k" \ - : : "a" (paddr)) +static inline void cleari040(unsigned long paddr) +{ + asm volatile ( + "nop\n\t" + ".chip 68040\n\t" + "cinvp %%ic,(%0)\n\t" + ".chip 68k" + : : "a" (paddr)); +} /* push page in both caches */ -#define push040(paddr) \ - __asm__ __volatile__ ("nop\n\t" \ - ".chip 68040\n\t" \ - "cpushp %%bc,(%0)\n\t" \ - ".chip 68k" \ - : : "a" (paddr)) +/* RZ: cpush %bc DOES invalidate %ic, regardless of DPI */ +static inline void push040(unsigned long paddr) +{ + asm volatile ( + "nop\n\t" + ".chip 68040\n\t" + "cpushp %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (paddr)); +} /* push and invalidate page in both caches, must disable ints * to avoid invalidating valid data */ -#define pushcl040(paddr) \ - do { unsigned long flags; \ - save_flags(flags); \ - cli(); \ - push040(paddr); \ - if (CPU_IS_060) clear040(paddr); \ - restore_flags(flags); \ - } while(0) - -/* push page in both caches, invalidate in i-cache */ -/* RZ: cpush %bc DOES invalidate %ic, regardless of DPI */ -#define pushcli040(paddr) \ - do { push040(paddr); \ - } while(0) +static inline void pushcl040(unsigned long paddr) +{ + unsigned long flags; + local_irq_save(flags); + push040(paddr); + if (CPU_IS_060) + clear040(paddr); + local_irq_restore(flags); +} /* * 040: Hit every page containing an address in the range paddr..paddr+len-1. @@ -504,7 +333,7 @@ paddr &= PAGE_MASK; do { - pushcli040(paddr); + push040(paddr); paddr += tmp; } while ((len -= tmp) > 0); } @@ -529,12 +358,6 @@ #endif } - -#undef clear040 -#undef cleari040 -#undef push040 -#undef pushcl040 -#undef pushcli040 #ifndef CONFIG_SINGLE_MEMORY_CHUNK int mm_end_of_chunk (unsigned long addr, int len) diff -Nru a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c --- a/arch/m68k/mm/motorola.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/mm/motorola.c Mon Nov 4 14:31:02 2002 @@ -196,9 +196,6 @@ return virtaddr; } -extern unsigned long empty_bad_page_table; -extern unsigned long empty_bad_page; - /* * paging_init() continues the virtual memory environment setup which * was begun by the code in arch/head.S. diff -Nru a/arch/m68k/mm/sun3kmap.c b/arch/m68k/mm/sun3kmap.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68k/mm/sun3kmap.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,156 @@ +/* + * linux/arch/m68k/mm/sun3kmap.c + * + * Copyright (C) 2002 Sam Creasey + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#undef SUN3_KMAP_DEBUG + +#ifdef SUN3_KMAP_DEBUG +extern void print_pte_vaddr(unsigned long vaddr); +#endif + +extern void mmu_emu_map_pmeg (int context, int vaddr); + +static inline void do_page_mapin(unsigned long phys, unsigned long virt, + unsigned long type) +{ + unsigned long pte; + pte_t ptep; + + ptep = pfn_pte(phys >> PAGE_SHIFT, PAGE_KERNEL); + pte = pte_val(ptep); + pte |= type; + + sun3_put_pte(virt, pte); + +#ifdef SUN3_KMAP_DEBUG + print_pte_vaddr(virt); +#endif + +} + +static inline void do_pmeg_mapin(unsigned long phys, unsigned long virt, + unsigned long type, int pages) +{ + + if(sun3_get_segmap(virt & ~SUN3_PMEG_MASK) == SUN3_INVALID_PMEG) + mmu_emu_map_pmeg(sun3_get_context(), virt); + + while(pages) { + do_page_mapin(phys, virt, type); + phys += PAGE_SIZE; + virt += PAGE_SIZE; + pages--; + } +} + +void *sun3_ioremap(unsigned long phys, unsigned long size, + unsigned long type) +{ + struct vm_struct *area; + unsigned long offset, virt, ret; + int pages; + + if(!size) + return NULL; + + /* page align */ + offset = phys & (PAGE_SIZE-1); + phys &= ~(PAGE_SIZE-1); + + size += offset; + size = PAGE_ALIGN(size); + if((area = get_vm_area(size, VM_IOREMAP)) == NULL) + return NULL; + +#ifdef SUN3_KMAP_DEBUG + printk("ioremap: got virt %p size %lx(%lx)\n", + area->addr, size, area->size); +#endif + + pages = size / PAGE_SIZE; + virt = (unsigned long)area->addr; + ret = virt + offset; + + while(pages) { + int seg_pages; + + seg_pages = (SUN3_PMEG_SIZE - (virt & SUN3_PMEG_MASK)) / PAGE_SIZE; + if(seg_pages > pages) + seg_pages = pages; + + do_pmeg_mapin(phys, virt, type, seg_pages); + + pages -= seg_pages; + phys += seg_pages * PAGE_SIZE; + virt += seg_pages * PAGE_SIZE; + } + + return (void *)ret; + +} + + +void *__ioremap(unsigned long phys, unsigned long size, int cache) +{ + + return sun3_ioremap(phys, size, SUN3_PAGE_TYPE_IO); + +} + +void iounmap(void *addr) +{ + vfree((void *)(PAGE_MASK & (unsigned long)addr)); +} + +/* sun3_map_test(addr, val) -- Reads a byte from addr, storing to val, + * trapping the potential read fault. Returns 0 if the access faulted, + * 1 on success. + * + * This function is primarily used to check addresses on the VME bus. + * + * Mucking with the page fault handler seems a little hackish to me, but + * SunOS, NetBSD, and Mach all implemented this check in such a manner, + * so I figure we're allowed. + */ +int sun3_map_test(unsigned long addr, char *val) +{ + int ret = 0; + + __asm__ __volatile__ + (".globl _sun3_map_test_start\n" + "_sun3_map_test_start:\n" + "1: moveb (%2), (%0)\n" + " moveq #1, %1\n" + "2:\n" + ".section .fixup,\"ax\"\n" + ".even\n" + "3: moveq #0, %1\n" + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + ".align 4\n" + ".long 1b,3b\n" + ".previous\n" + ".globl _sun3_map_test_end\n" + "_sun3_map_test_end:\n" + : "=a"(val), "=r"(ret) + : "a"(addr)); + + return ret; +} diff -Nru a/arch/m68k/mm/sun3mmu.c b/arch/m68k/mm/sun3mmu.c --- a/arch/m68k/mm/sun3mmu.c Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/mm/sun3mmu.c Mon Nov 4 14:31:01 2002 @@ -33,8 +33,6 @@ const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; -extern unsigned long empty_bad_page_table; -extern unsigned long empty_bad_page; extern unsigned long num_pages; void free_initmem(void) @@ -59,8 +57,8 @@ #ifdef TEST_VERIFY_AREA wp_works_ok = 0; #endif - empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); - memset((void *)empty_zero_page, 0, PAGE_SIZE); + empty_zero_page = alloc_bootmem_pages(PAGE_SIZE); + memset(empty_zero_page, 0, PAGE_SIZE); address = PAGE_OFFSET; pg_dir = swapper_pg_dir; diff -Nru a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c --- a/arch/m68k/mvme147/config.c Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/mvme147/config.c Mon Nov 4 14:31:01 2002 @@ -181,11 +181,6 @@ return 0; } -int mvme147_keyb_init (void) -{ - return 0; -} - /*------------------- Serial console stuff ------------------------*/ static void scc_delay (void) diff -Nru a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c --- a/arch/m68k/q40/config.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/q40/config.c Mon Nov 4 14:31:02 2002 @@ -59,6 +59,8 @@ extern void q40_waitbut(void); void q40_set_vectors (void); +extern void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ ); + extern char *saved_command_line; extern char m68k_debug_device[]; static void q40_mem_console_write(struct console *co, const char *b, @@ -181,7 +183,7 @@ mach_get_model = q40_get_model; mach_get_hardware_list = q40_get_hardware_list; -#ifdef CONFIG_INPUT_M68K_BEEP +#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) mach_beep = q40_mksound; #endif #ifdef CONFIG_HEARTBEAT diff -Nru a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c --- a/arch/m68k/q40/q40ints.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/q40/q40ints.c Mon Nov 4 14:31:02 2002 @@ -204,8 +204,9 @@ * this stuff doesn't really belong here.. */ -int ql_ticks=0; /* 200Hz ticks since last jiffie */ -static int sound_ticks=0; +int ql_ticks; /* 200Hz ticks since last jiffie */ +static int sound_ticks; +short q40rtc_oldsecs; #define SVOL 45 @@ -242,9 +243,9 @@ *DAC_RIGHT=sval; } #if defined(CONFIG_Q40RTC) || defined(CONFIG_GEN_RTC) - if (gen_rtc_irq_ctrl && (q40rtc_oldsecs != RTC_SECS)) + if (gen_rtc_irq_ctrl && (q40rtc_oldsecs != Q40_RTC_SECS)) { - q40rtc_oldsecs = RTC_SECS; + q40rtc_oldsecs = Q40_RTC_SECS; gen_rtc_irq_flags = RTC_UIE; gen_rtc_interrupt(0); } diff -Nru a/arch/m68k/sun3/Makefile b/arch/m68k/sun3/Makefile --- a/arch/m68k/sun3/Makefile Mon Nov 4 14:31:00 2002 +++ b/arch/m68k/sun3/Makefile Mon Nov 4 14:31:00 2002 @@ -4,9 +4,9 @@ export-objs := sun3_ksyms.o -obj-y := sun3_ksyms.o sun3ints.o sun3dvma.o sbus.o +obj-y := sun3_ksyms.o sun3ints.o sun3dvma.o sbus.o idprom.o -obj-$(CONFIG_SUN3) += config.o idprom.o mmu_emu.o leds.o dvma.o \ +obj-$(CONFIG_SUN3) += config.o mmu_emu.o leds.o dvma.o \ intersil.o include $(TOPDIR)/Rules.make diff -Nru a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c --- a/arch/m68k/sun3/config.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/sun3/config.c Mon Nov 4 14:31:02 2002 @@ -151,9 +151,6 @@ mach_default_handler = &sun3_default_handler; mach_request_irq = sun3_request_irq; mach_free_irq = sun3_free_irq; -#ifdef CONFIG_VT -// mach_keyb_init = sun3_keyb_init; -#endif enable_irq = sun3_enable_irq; disable_irq = sun3_disable_irq; mach_process_int = sun3_process_int; diff -Nru a/arch/m68k/sun3/idprom.c b/arch/m68k/sun3/idprom.c --- a/arch/m68k/sun3/idprom.c Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/sun3/idprom.c Mon Nov 4 14:31:01 2002 @@ -31,8 +31,8 @@ { "Sun 3/60", (SM_SUN3 | SM_3_60) }, { "Sun 3/E", (SM_SUN3 | SM_3_E) }, /* Now, Sun3x's */ -{ "Sun 3/460 Series", (SM_SUN3 | SM_3_460) }, -{ "Sun 3/80", (SM_SUN3 | SM_3_80) }, +{ "Sun 3/460 Series", (SM_SUN3X | SM_3_460) }, +{ "Sun 3/80", (SM_SUN3X | SM_3_80) }, /* Then, Sun4's */ //{ "Sun 4/100 Series", (SM_SUN4 | SM_4_110) }, //{ "Sun 4/200 Series", (SM_SUN4 | SM_4_260) }, diff -Nru a/arch/m68k/sun3/intersil.c b/arch/m68k/sun3/intersil.c --- a/arch/m68k/sun3/intersil.c Mon Nov 4 14:31:00 2002 +++ b/arch/m68k/sun3/intersil.c Mon Nov 4 14:31:00 2002 @@ -13,6 +13,7 @@ #include #include +#include #include #include #include diff -Nru a/arch/m68k/sun3/mmu_emu.c b/arch/m68k/sun3/mmu_emu.c --- a/arch/m68k/sun3/mmu_emu.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/sun3/mmu_emu.c Mon Nov 4 14:31:02 2002 @@ -52,7 +52,8 @@ /* pointers to the mm structs for each task in each context. 0xffffffff is a marker for kernel context */ -struct mm_struct *ctx_alloc[CONTEXTS_NUM] = {0xffffffff, 0, 0, 0, 0, 0, 0, 0}; +struct mm_struct *ctx_alloc[CONTEXTS_NUM] = {(struct mm_struct *)0xffffffff, + 0, 0, 0, 0, 0, 0, 0}; /* has this context been mmdrop'd? */ static unsigned char ctx_avail = CONTEXTS_NUM-1; @@ -176,7 +177,6 @@ pmeg_alloc[sun3_get_segmap(seg)] = 2; } } - dvma_init(); @@ -275,7 +275,7 @@ //todo: better allocation scheme? but is extra complexity worthwhile? //todo: only clear old entries if necessary? how to tell? -static inline void mmu_emu_map_pmeg (int context, int vaddr) +inline void mmu_emu_map_pmeg (int context, int vaddr) { static unsigned char curr_pmeg = 128; int i; diff -Nru a/arch/m68k/sun3/sun3dvma.c b/arch/m68k/sun3/sun3dvma.c --- a/arch/m68k/sun3/sun3dvma.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/sun3/sun3dvma.c Mon Nov 4 14:31:02 2002 @@ -14,6 +14,8 @@ #include #include +#undef DVMA_DEBUG + #ifdef CONFIG_SUN3X extern void dvma_unmap_iommu(unsigned long baddr, int len); #else @@ -22,6 +24,10 @@ } #endif +#ifdef CONFIG_SUN3 +extern void sun3_dvma_init(void); +#endif + unsigned long iommu_use[IOMMU_TOTAL_ENTRIES]; #define dvma_index(baddr) ((baddr - DVMA_START) >> DVMA_PAGE_SHIFT) @@ -39,6 +45,60 @@ static struct list_head hole_cache; static struct hole initholes[64]; +#ifdef DVMA_DEBUG + +static unsigned long dvma_allocs = 0; +static unsigned long dvma_frees = 0; +static unsigned long long dvma_alloc_bytes = 0; +static unsigned long long dvma_free_bytes = 0; + +static void print_use(void) +{ + + int i; + int j = 0; + + printk("dvma entry usage:\n"); + + for(i = 0; i < IOMMU_TOTAL_ENTRIES; i++) { + if(!iommu_use[i]) + continue; + + j++; + + printk("dvma entry: %08lx len %08lx\n", + ( i << DVMA_PAGE_SHIFT) + DVMA_START, + iommu_use[i]); + } + + printk("%d entries in use total\n", j); + + printk("allocation/free calls: %lu/%lu\n", dvma_allocs, dvma_frees); + printk("allocation/free bytes: %Lx/%Lx\n", dvma_alloc_bytes, + dvma_free_bytes); +} + +static void print_holes(struct list_head *holes) +{ + + struct list_head *cur; + struct hole *hole; + + printk("listing dvma holes\n"); + list_for_each(cur, holes) { + hole = list_entry(cur, struct hole, list); + + if((hole->start == 0) && (hole->end == 0) && (hole->size == 0)) + continue; + + printk("hole: start %08lx end %08lx size %08lx\n", hole->start, hole->end, hole->size); + } + + printk("end of hole listing...\n"); + +} +#endif DVMA_DEBUG + static inline int refill(void) { @@ -93,7 +153,11 @@ struct hole *hole; if(list_empty(&hole_list)) { - printk("out of dvma holes!\n"); +#ifdef DVMA_DEBUG + printk("out of dvma holes! (printing hole cache)\n"); + print_holes(&hole_cache); + print_use(); +#endif BUG(); } @@ -111,11 +175,19 @@ hole->end -= newlen; hole->size -= newlen; dvma_entry_use(hole->end) = newlen; +#ifdef DVMA_DEBUG + dvma_allocs++; + dvma_alloc_bytes += newlen; +#endif return hole->end; } else if(hole->size == newlen) { list_del(&(hole->list)); list_add(&(hole->list), &hole_cache); dvma_entry_use(hole->start) = newlen; +#ifdef DVMA_DEBUG + dvma_allocs++; + dvma_alloc_bytes += newlen; +#endif return hole->start; } @@ -140,6 +212,11 @@ baddr &= DVMA_PAGE_MASK; dvma_unmap_iommu(baddr, len); +#ifdef DVMA_DEBUG + dvma_frees++; + dvma_free_bytes += len; +#endif + list_for_each(cur, &hole_list) { hole = list_entry(cur, struct hole, list); @@ -240,8 +317,14 @@ void dvma_unmap(void *baddr) { - - free_baddr((unsigned long)baddr); + unsigned long addr; + + addr = (unsigned long)baddr; + /* check if this is a vme mapping */ + if(!(addr & 0x00f00000)) + addr |= 0xf00000; + + free_baddr(addr); return; diff -Nru a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c --- a/arch/m68k/sun3/sun3ints.c Mon Nov 4 14:31:03 2002 +++ b/arch/m68k/sun3/sun3ints.c Mon Nov 4 14:31:03 2002 @@ -18,6 +18,7 @@ #include extern void sun3_leds (unsigned char); +static void sun3_inthandle(int irq, void *dev_id, struct pt_regs *fp); void sun3_disable_interrupts(void) { @@ -58,26 +59,22 @@ inline void sun3_do_irq(int irq, struct pt_regs *fp) { - kstat.irqs[0][SYS_IRQS + irq]++; + kstat_cpu(0).irqs[SYS_IRQS + irq]++; *sun3_intreg &= ~(1< #include #include +#include #include "time.h" volatile char *clock_va; extern volatile unsigned char *sun3_intreg; +extern void sun3_get_model(char *model); -int __init sun3x_keyb_init(void) -{ - return 0; -} - -int sun3x_kbdrate(struct kbd_repeat *r) -{ - return 0; -} - -void sun3x_kbd_leds(unsigned int i) +void sun3_leds(unsigned int i) { } -void sun3_leds(unsigned int i) +static int sun3x_get_hardware_list(char *buffer) { + + int len = 0; -} + len += sprintf(buffer + len, "PROM Revision:\t%s\n", + romvec->pv_monid); + + return len; -/* should probably detect types of these eventually. */ -static void sun3x_get_model(char *model) -{ - sprintf(model, "Sun3x"); } /* @@ -60,12 +53,6 @@ mach_get_irq_list = show_sun3_interrupts; mach_max_dma_address = 0xffffffff; /* we can DMA anywhere, whee */ - -#ifdef CONFIG_VT - mach_keyb_init = sun3x_keyb_init; - mach_kbdrate = sun3x_kbdrate; - mach_kbd_leds = sun3x_kbd_leds; -#endif mach_default_handler = &sun3_default_handler; mach_sched_init = sun3x_sched_init; diff -Nru a/arch/m68k/sun3x/prom.c b/arch/m68k/sun3x/prom.c --- a/arch/m68k/sun3x/prom.c Mon Nov 4 14:31:01 2002 +++ b/arch/m68k/sun3x/prom.c Mon Nov 4 14:31:01 2002 @@ -26,8 +26,6 @@ int (*sun3x_mayput)(int); void (*sun3x_prom_reboot)(void); e_vector sun3x_prom_abort; -struct idprom *idprom; -static struct idprom idprom_buffer; struct linux_romvec *romvec; /* prom vector table */ @@ -107,8 +105,6 @@ void sun3x_prom_init(void) { /* Read the vector table */ - int i; - sun3x_putchar = *(void (**)(int)) (SUN3X_P_PUTCHAR); sun3x_getchar = *(int (**)(void)) (SUN3X_P_GETCHAR); @@ -118,13 +114,11 @@ sun3x_prom_abort = *(e_vector *) (SUN3X_P_ABORT); romvec = (struct linux_romvec *)SUN3X_PROM_BASE; - /* make a copy of the idprom structure */ - for(i = 0; i < sizeof(struct idprom); i++) - ((unsigned char *)(&idprom_buffer))[i] = ((unsigned char *)SUN3X_IDPROM)[i]; - idprom = &idprom_buffer; + idprom_init(); - if((idprom->id_machtype & SM_ARCH_MASK) != SM_SUN3X) { - printk("Warning: machine reports strange type %02x\n"); + if(!((idprom->id_machtype & SM_ARCH_MASK) == SM_SUN3X)) { + printk("Warning: machine reports strange type %02x\n", + idprom->id_machtype); printk("Pretending it's a 3/80, but very afraid...\n"); idprom->id_machtype = SM_SUN3X | SM_3_80; } @@ -161,4 +155,20 @@ void prom_halt (void) { sun3x_halt(); +} + +/* Get the idprom and stuff it into buffer 'idbuf'. Returns the + * format type. 'num_bytes' is the number of bytes that your idbuf + * has space for. Returns 0xff on error. + */ +unsigned char +prom_get_idprom(char *idbuf, int num_bytes) +{ + int i; + + /* make a copy of the idprom structure */ + for(i = 0; i < num_bytes; i++) + idbuf[i] = ((char *)SUN3X_IDPROM)[i]; + + return idbuf[0]; } diff -Nru a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c --- a/arch/m68k/sun3x/time.c Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/sun3x/time.c Mon Nov 4 14:31:02 2002 @@ -79,6 +79,7 @@ return 0L; } +#if 0 static void sun3x_timer_tick(int irq, void *dev_id, struct pt_regs *regs) { void (*vector)(int, void *, struct pt_regs *) = dev_id; @@ -89,6 +90,7 @@ vector(irq, NULL, regs); } +#endif void __init sun3x_sched_init(void (*vector)(int, void *, struct pt_regs *)) { diff -Nru a/arch/m68k/vmlinux-std.lds b/arch/m68k/vmlinux-std.lds --- a/arch/m68k/vmlinux-std.lds Mon Nov 4 14:31:02 2002 +++ b/arch/m68k/vmlinux-std.lds Mon Nov 4 14:31:02 2002 @@ -38,13 +38,14 @@ _edata = .; /* End of data section */ + /* will be freed after init */ . = ALIGN(4096); /* Init code and data */ __init_begin = .; - .text.init : { *(.text.init) } - .data.init : { *(.data.init) } + .init.text : { *(.init.text) } + .init.data : { *(.init.data) } . = ALIGN(16); __setup_start = .; - .setup.init : { *(.setup.init) } + .init.setup : { *(.init.setup) } __setup_end = .; __initcall_start = .; .initcall.init : { @@ -60,9 +61,16 @@ . = ALIGN(8192); __init_end = .; - init_task : { *(init_task) } /* The initial task and kernel stack */ + .data.init_task : { *(.data.init_task) } /* The initial task and kernel stack */ _end = . ; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.exit.text) + *(.exit.data) + *(.exitcall.exit) + } /* Stabs debugging sections. */ .stab 0 : { *(.stab) } diff -Nru a/arch/m68k/vmlinux-sun3.lds b/arch/m68k/vmlinux-sun3.lds --- a/arch/m68k/vmlinux-sun3.lds Mon Nov 4 14:31:00 2002 +++ b/arch/m68k/vmlinux-sun3.lds Mon Nov 4 14:31:00 2002 @@ -34,13 +34,14 @@ /* End of data goes *here* so that freeing init code works properly. */ _edata = .; + /* will be freed after init */ . = ALIGN(8192); /* Init code and data */ __init_begin = .; - .text.init : { *(.text.init) } - .data.init : { *(.data.init) } + .init.text : { *(.init.text) } + .init.data : { *(.init.data) } . = ALIGN(16); __setup_start = .; - .setup.init : { *(.setup.init) } + .init.setup : { *(.init.setup) } __setup_end = .; __initcall_start = .; .initcall.init : { @@ -61,6 +62,13 @@ .bss : { *(.bss) } /* BSS */ _end = . ; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.exit.text) + *(.exit.data) + *(.exitcall.exit) + } .crap : { /* Stabs debugging sections. */ diff -Nru a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/Kconfig Mon Nov 4 14:31:04 2002 @@ -0,0 +1,796 @@ +# +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/config-language.txt. +# + +mainmenu "uClinux/68k (w/o MMU) Kernel Configuration" + +config MMU + bool + default n + +config SWAP + bool + default n + +config FPU + bool + default n + +config UID16 + bool + default y + +config RWSEM_GENERIC_SPINLOCK + bool + default y + +config RWSEM_XCHGADD_ALGORITHM + bool + default n + + +source "init/Kconfig" + +menu "Processor type and features" + +choice + prompt "CPU" + default M68EZ328 + +config M68328 + bool "MC68328" + help + Motorola 68328 processor support. + +config M68EZ328 + bool "MC68EZ328" + help + Motorola 68EX328 processor support. + +config M68VZ328 + bool "MC68VZ328" + help + Motorola 68VZ328 processor support. + +config M68360 + bool "MC68360" + help + Motorola 68360 processor support. + +config M5206 + bool "MCF5206" + help + Motorola ColdFire 5206 processor support. + +config M5206e + bool "MCF5206e" + help + Motorola ColdFire 5206e processor support. + +config M5249 + bool "MCF5249" + help + Motorola ColdFire 5249 processor support. + +config M5272 + bool "MCF5272" + help + Motorola ColdFire 5272 processor support. + +config M5307 + bool "MCF5307" + help + Motorola ColdFire 5307 processor support. + +config M5407 + bool "MCF5407" + help + Motorola ColdFire 5407 processor support. + +endchoice + +config COLDFIRE + bool + depends on (M5206 || M5206e || M5249 || M5272 || M5307 || M5407) + default y + +choice + prompt "CPU CLOCK Frequency" + default AUTO + +config CLOCK_AUTO + bool "AUTO" + ---help--- + Define the CPU clock frequency in use. On many boards you don't + really need to know, so you can select the AUTO option. On some + boards you need to know the real clock frequency to determine other + system timing (for example baud rate dividors, etc). Some processors + have an internal PLL and you can seletc a frequency to set that too. + You need to know a little about the internals of your processor to + set this. If in doubt choose the AUTO option. + +config CLOCK_11MHz + bool "11MHz" + help + Select an 11MHz CPU clock frequency. + +config CLOCK_16MHz + bool "16MHz" + help + Select an 16MHz CPU clock frequency. + +config CLOCK_20MHz + bool "20MHz" + help + Select an 20MHz CPU clock frequency. + +config CLOCK_24MHz + bool "24MHz" + help + Select an 24MHz CPU clock frequency. + +config CLOCK_25MHz + bool "25MHz" + help + Select an 25MHz CPU clock frequency. + +config CLOCK_33MHz + bool "33MHz" + help + Select an 33MHz CPU clock frequency. + +config CLOCK_40MHz + bool "40MHz" + help + Select an 40MHz CPU clock frequency. + +config CLOCK_45MHz + bool "45MHz" + help + Select an 45MHz CPU clock frequency. + +config CLOCK_48MHz + bool "48MHz" + help + Select an 48MHz CPU clock frequency. + +config CLOCK_50MHz + bool "50MHz" + help + Select an 50MHz CPU clock frequency. + +config CLOCK_54MHz + bool "54MHz" + help + Select an 54MHz CPU clock frequency. + +config CLOCK_60MHz + bool "60MHz" + help + Select an 60MHz CPU clock frequency. + +config CLOCK_66MHz + bool "66MHz" + help + Select an 66MHz CPU clock frequency. + +config CLOCK_70MHz + bool "70MHz" + help + Select an 70MHz CPU clock frequency. + +config CLOCK_140MHz + bool "140MHz" + help + Select an 140MHz CPU clock frequency. + +endchoice + +config OLDMASK + bool "Old mask 5307 (1H55J) silicon" + depends on M5307 + help + Build support for the older revision ColdFire 5307 silicon. + Specifically this is the 1H55J mask revision. + +comment "Platform" + +config PILOT3 + bool "Pilot 1000/5000, PalmPilot Personal/Pro, or PalmIII support" + depends on M68328 + help + Support for the Palm Pilot 1000/5000, Personal/Pro and PalmIII. + +config XCOPILOT_BUGS + bool " (X)Copilot support" + depends on PILOT3 + help + Support the bugs of Xcopilot. + +config UCSIMM + bool "uCsimm module support" + depends on M68EZ328 + help + Support for the Arcturus Networks uCsimm module. + +config UCDIMM + bool "uDsimm module support" + depends on M68VZ328 + help + Support for the Arcturus Networks uDsimm module. + +config DRAGEN2 + bool "Dragen Engine II board support" + depends on M68VZ328 + help + Support for the Dragen Engine II board. + +config HWADDR_FROMEEPROM + bool " Read ETH address from EEPROM" + depends on DRAGEN2 + help + Use MAC address from EEPROM. + +config HWADDR_OFFSET + int " Offset from start of EEPROM" + default "2" + depends on HWADDR_FROMEEPROM + +config INIT_LCD + bool " Initialize LCD" + depends on (UCSIMM || UCDIMM || DRAGEN2) + help + Initialize the LCD controller of the 68x328 processor. + +config MEMORY_RESERVE + int " Memory reservation (MiB)" + depends on (UCSIMM || UCDIMM || DRAGEN2) + help + Reserve certain memory regions on 68x328 based boards. + +config UCQUICC + bool "Lineo uCquicc board support" + depends on M68360 + help + Support for the Lineo uCquicc board. + +config ARN5206 + bool "Arnewsh 5206 board support" + depends on M5206 + help + Support for the Arnewsh 5206 board. + +config M5206eC3 + bool "Motorola M5206eC3 board support" + depends on M5206e + help + Support for the Motorola M5206eC3 board. + +config ELITE + bool "Motorola M5206eLITE board support" + depends on M5206e + help + Support for the Motorola M5206eLITE board. + +config M5249C3 + bool "Motorola M5249C3 board support" + depends on M5249 + help + Support for the Motorola M5249C3 board. + +config M5272C3 + bool "Motorola M5272C3 board support" + depends on M5272 + help + Support for the Motorola M5272C3 board. + +config ARN5307 + bool "Arnewsh 5307 board support" + depends on M5307 + help + Support for the Arnewsh 5307 board. + +config M5307C3 + bool "Motorola M5307C3 board support" + depends on M5307 + help + Support for the Motorola M5307C3 board. + +config eLIA + bool "Moreton Bay eLIA board support" + depends on M5307 + help + Support for the Moreton Bay eLIA board. + +config SECUREEDGEMP3 + bool "SnapGear SecureEdge/MP3 platform support" + depends on M5307 + help + Support for the SnapGear SecureEdge/MP3 platform. + +config M5407C3 + bool "Motorola M5407C3 board support" + depends on M5407 + help + Support for the Motorola M5407C3 board. + +config CLEOPATRA + bool "Feith CLEOPATRA board support" + depends on (M5307 || M5407) + help + Support for the Feith Cleopatra boards. + +config NETtel + bool "SecureEdge/NETtel board support" + depends on (M5206e || M5272 || M5307) + help + Support for the SnapGear NETtel/SecureEdge/SnapGear boards. + +config SNAPGEAR + bool "SnapGear router board support" + depends on NETtel + help + Special additional support for SnapGear router boards. + +config ROMFS_FROM_ROM + bool " ROMFS image not RAM resident" + depends on (NETtel || SNAPGEAR) + help + The ROMfs filesystem will stay resident in the FLASH/ROM, not be + moved into RAM. + +config PILOT + bool + default y + depends on (PILOT3 || PILOT5) + +config ARNEWSH + bool + default y + depends on (ARN5206 || ARN5307) + +config MOTOROLA + bool + default y + depends on (M5206eC3 || M5249C3 || M5272C3 || M5307C3 || M5407C3) + +config LARGE_ALLOCS + bool "Allow allocating large blocks (> 1MB) of memory" + help + Allow the slab memory allocator to keep chains for very large + memory sizes - upto 32MB. You may need this if your system has + a lot of RAM, and you need to able to allocate very large + contiguous chunks. If unsure, say N. + +choice + prompt "RAM size" + default AUTO + +config RAMAUTO + bool "AUTO" + ---help--- + Configure the RAM size on your platform. Many platforms can auto + detect this, on those choose the AUTO option. Otherwise set the + RAM size you intend using. + +config RAM4MB + bool "4MiB" + help + Set RAM size to be 4MiB. + +config RAM4MB + bool "4MiB" + help + Set RAM size to be 4MiB. + +config RAM8MB + bool "8MiB" + help + Set RAM size to be 8MiB. + +config RAM16MB + bool "16MiB" + help + Set RAM size to be 16MiB. + +config RAM32MB + bool "32MiB" + help + Set RAM size to be 32MiB. + +endchoice + +choice + prompt "RAM bus width" + default RAMAUTOBIT + +config RAMAUTOBIT + bool "AUTO" + ---help--- + Select the physical RAM data bus size. Not needed on most platforms, + so you can generally choose AUTO. + +config RAM8BIT + bool "8bit" + help + Configure RAM bus to be 8 bits wide. + +config RAM16BIT + bool "16bit" + help + Configure RAM bus to be 16 bits wide. + +config RAM32BIT + bool "32bit" + help + Configure RAM bus to be 32 bits wide. + +endchoice + +choice + prompt "Kernel executes from" + ---help--- + Choose the memory type that the kernel will be running in. + +config RAMKERNEL + bool "RAM" + help + The kernel will be resident in RAM when running. + +config ROMKERNEL + bool "ROM" + help + The kernel will be resident in FLASH/ROM when running. + +config HIMEMKERNEL + bool "HIMEM" + help + The kernel will be resident in high memory when running. + +endchoice + +endmenu + + +menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)" + +config PCI + bool "PCI support" + help + Support for PCI bus. + +config COMEMPCI + bool "CO-MEM lite PCI controller support" + depends on (M5307 || M5407) + +source "drivers/pci/Kconfig" + +config HOTPLUG + bool "Support for hot-pluggable device" + ---help--- + Say Y here if you want to plug devices into your computer while + the system is running, and be able to use them quickly. In many + cases, the devices can likewise be unplugged at any time too. + + One well known example of this is PCMCIA- or PC-cards, credit-card + size devices such as network cards, modems or hard drives which are + plugged into slots found on all modern laptop computers. Another + example, used on modern desktops as well as laptops, is USB. + + Enable HOTPLUG and KMOD, and build a modular kernel. Get agent + software (at ) and install it. + Then your kernel will automatically call out to a user mode "policy + agent" (/sbin/hotplug) to load modules and set up software needed + to use devices as you hotplug them. + +source "drivers/pcmcia/Kconfig" + +source "drivers/hotplug/Kconfig" + +endmenu + +menu "Executable file formats" + +config KCORE_AOUT + bool + default y + +config KCORE_ELF + default y + +config BINFMT_FLAT + tristate "Kernel support for flat binaries" + help + Support uClinux FLAT format binaries. + +config BINFMT_ZFLAT + bool " Enable ZFLAT support" + depends on BINFMT_FLAT + help + Supoprt FLAT format compressed binaries + +endmenu + +menu "Power management options" + +config PM + bool "Power Management support" + help + Support processor power management modes + +endmenu + + +source "drivers/mtd/Kconfig" + +source "drivers/parport/Kconfig" + +source "drivers/pnp/Kconfig" + +source "drivers/block/Kconfig" + + +menu "ATA/IDE/MFM/RLL support" + +config IDE + tristate "ATA/ATAPI/MFM/RLL device support" + ---help--- + If you say Y here, your kernel will be able to manage low cost mass + storage units such as ATA/(E)IDE and ATAPI units. The most common + cases are IDE hard drives and ATAPI CD-ROM drives. + + It only makes sense to choose this option if your board actually + has an IDE interface. If unsure, say N. + +source "drivers/ide/Kconfig" + +endmenu + + +menu "SCSI device support" + +config SCSI + tristate "SCSI device support" + help + If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or + any other SCSI device under Linux, say Y and make sure that you know + the name of your SCSI host adapter (the card inside your computer + that "speaks" the SCSI protocol, also called SCSI controller), + because you will be asked for it. + +source "drivers/scsi/Kconfig" + +endmenu + + +menu "Old CD-ROM drivers (not SCSI, not IDE)" + depends on ISA + +config CD_NO_IDESCSI + bool "Support non-SCSI/IDE/ATAPI CDROM drives" + ---help--- + If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y + here, otherwise N. Read the CD-ROM-HOWTO, available from + . + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about these CD-ROM drives. If you are unsure what you + have, say Y and find out whether you have one of the following + drives. + + For each of these drivers, a file Documentation/cdrom/{driver_name} + exists. Especially in cases where you do not know exactly which kind + of drive you have you should read there. Most of these drivers use a + file drivers/cdrom/{driver_name}.h where you can define your + interface parameters and switch some internal goodies. + + All these CD-ROM drivers are also usable as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want). If you want to compile them as module, say M instead of Y and + read . + + If you want to use any of these CD-ROM drivers, you also have to + answer Y or M to "ISO 9660 CD-ROM file system support" below (this + answer will get "defaulted" for you if you enable any of the Linux + CD-ROM drivers). + +source "drivers/cdrom/Kconfig" + +endmenu + + +source "drivers/md/Kconfig" + +source "drivers/message/fusion/Kconfig" + +source "drivers/ieee1394/Kconfig" + +source "drivers/message/i2o/Kconfig" + +source "net/Kconfig" + + +menu "Network device support" + depends on NET + +config NETDEVICES + bool "Network device support" + ---help--- + You can say N here if you don't intend to connect your Linux box to + any other computer at all or if all your connections will be over a + telephone line with a modem either via UUCP (UUCP is a protocol to + forward mail and news between unix hosts over telephone lines; read + the UUCP-HOWTO, available from + ) or dialing up a shell + account or a BBS, even using term (term is a program which gives you + almost full Internet connectivity if you have a regular dial up + shell account on some Internet connected Unix computer. Read + ). + + You'll have to say Y if your computer contains a network card that + you want to use under Linux (make sure you know its name because you + will be asked for it and read the Ethernet-HOWTO (especially if you + plan to use more than one network card under Linux)) or if you want + to use SLIP (Serial Line Internet Protocol is the protocol used to + send Internet traffic over telephone lines or null modem cables) or + CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better + and newer replacement for SLIP) or PLIP (Parallel Line Internet + Protocol is mainly used to create a mini network by connecting the + parallel ports of two local machines) or AX.25/KISS (protocol for + sending Internet traffic over amateur radio links). + + Make sure to read the NET-3-HOWTO. Eventually, you will have to read + Olaf Kirch's excellent and free book "Network Administrator's + Guide", to be found in . If + unsure, say Y. + +source "drivers/net/Kconfig" + +source "drivers/atm/Kconfig" + +endmenu + +source "net/ax25/Kconfig" + +source "net/irda/Kconfig" + +source "drivers/isdn/Kconfig" + +source "drivers/telephony/Kconfig" + +# +# input before char - char/joystick depends on it. As does USB. +# +source "drivers/input/Kconfig" + +source "drivers/char/Kconfig" + +#source drivers/misc/Config.in +source "drivers/media/Kconfig" + +source "fs/Kconfig" + + +menu "Console drivers" + depends on VT + +config VGA_CONSOLE + bool "VGA text console" + help + Saying Y here will allow you to use Linux in text mode through a + display that complies with the generic VGA standard. Virtually + everyone wants that. + + The program SVGATextMode can be used to utilize SVGA video cards to + their full potential in text mode. Download it from + . + + If unsure, say N. + +config VIDEO_SELECT + bool "Video mode selection support" + ---help--- + This enables support for text mode selection on kernel startup. If + you want to take advantage of some high-resolution text mode your + card's BIOS offers, but the traditional Linux utilities like + SVGATextMode don't, you can say Y here and set the mode using the + "vga=" option from your boot loader (lilo or loadlin) or set + "vga=ask" which brings up a video mode menu on kernel startup. (Try + "man bootparam" or see the documentation of your boot loader about + how to pass options to the kernel.) + + Read the file for more information + about the Video mode selection support. If unsure, say N. + +source "drivers/video/Kconfig" + +endmenu + + +menu "Sound" + +config SOUND + tristate "Sound card support" + ---help--- + If you have a sound card in your computer, i.e. if it can say more + than an occasional beep, say Y. Be sure to have all the information + about your sound card and its configuration down (I/O port, + interrupt and DMA channel), because you will be asked for it. + + You want to read the Sound-HOWTO, available from + . General information about + the modular sound system is contained in the files + . The file + contains some slightly + outdated but still useful information as well. + + If you have a PnP sound card and you want to configure it at boot + time using the ISA PnP tools (read + ), then you need to + compile the sound card support as a module ( = code which can be + inserted in and removed from the running kernel whenever you want) + and load that module after the PnP configuration is finished. To do + this, say M here and read as well + as ; the module will be + called soundcore.o. + + I'm told that even without a sound card, you can make your computer + say more than an occasional beep, by programming the PC speaker. + Kernel patches and supporting utilities to do that are in the pcsp + package, available at . + +source "sound/Kconfig" + +endmenu + +source "drivers/usb/Kconfig" + +source "net/bluetooth/Kconfig" + + +menu "Kernel hacking" + +config FULLDEBUG + bool "Full Symbolic/Source Debugging support" + help + Enable debuging symbols on kernel build. + +config MAGIC_SYSRQ + bool "Magic SysRq key" + help + Enables console device to interprent special characters as + commands to dump state information. + +config HIGHPROFILE + bool "Use fast second timer for profiling" + help + Use a fast secondary clock to produce profiling information. + +config DUMPTOFLASH + bool "Panic/Dump to FLASH" + depends on COLDFIRE + help + Dump any panic of trap output into a flash memory segment + for later analysis. + +config NO_KERNEL_MSG + bool "Suppress Kernel BUG Messages" + help + Do not output any debug BUG messages within the kernel. + +config BDM_DISABLE + bool "Disable BDM signals" + depends on (EXPERIMENTAL && COLDFIRE) + help + Disable the CPU's BDM signals. + +endmenu + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" + diff -Nru a/arch/m68knommu/Makefile b/arch/m68knommu/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/Makefile Mon Nov 4 14:31:04 2002 @@ -0,0 +1,108 @@ +# +# arch/m68knommu/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# (C) Copyright 2002, Greg Ungerer +# + +platform-$(CONFIG_M68328) := 68328 +platform-$(CONFIG_M68EZ328) := 68EZ328 +platform-$(CONFIG_M68VZ328) := 68VZ328 +platform-$(CONFIG_M68360) := 68360 +platform-$(CONFIG_M5206) := 5206 +platform-$(CONFIG_M5206e) := 5206e +platform-$(CONFIG_M5249) := 5249 +platform-$(CONFIG_M5272) := 5272 +platform-$(CONFIG_M5307) := 5307 +platform-$(CONFIG_M5407) := 5407 +PLATFORM := $(platform-y) + +board-$(CONFIG_PILOT) := pilot +board-$(CONFIG_UCSIMM) := ucsimm +board-$(CONFIG_UCDIMM) := ucdimm +board-$(CONFIG_UCQUICC) := uCquicc +board-$(CONFIG_DRAGEN2) := de2 +board-$(CONFIG_ARNEWSH) := ARNEWSH +board-$(CONFIG_MOTOROLA) := MOTOROLA +board-$(CONFIG_ELITE) := eLITE +board-$(CONFIG_eLIA) := eLIA +board-$(CONFIG_NETtel) := NETtel +board-$(CONFIG_SECUREEDGEMP3) := MP3 +board-$(CONFIG_CLEOPATRA) := CLEOPATRA +BOARD := $(board-y) + +model-$(CONFIG_RAMKERNEL) := ram +model-$(CONFIG_ROMKERNEL) := rom +model-$(CONFIG_HIMEMKERNEL) := himem +MODEL := $(model-y) + +# +# Some code support is grouped together for a common cpu-subclass (for +# example all ColdFire cpu's are very similar). Determine the sub-class +# for the selected cpu. ONLY need to define this for the non-core member +# of the family. +# +cpuclass-$(CONFIG_M5206) := 5307 +cpuclass-$(CONFIG_M5206e) := 5307 +cpuclass-$(CONFIG_M5249) := 5307 +cpuclass-$(CONFIG_M5272) := 5307 +cpuclass-$(CONFIG_M5407) := 5307 +cpuclass-$(CONFIG_M68EZ328) := 68328 +cpuclass-$(CONFIG_M68VZ328) := 68328 +CPUCLASS := $(cpuclass-y) +CLASSDIR := arch/m68knommu/platform/$(cpuclass-y)/ + +export PLATFORM BOARD MODEL CPUCLASS + +# +# Some CFLAG additions based on specific CPU type. +# +cflags-$(CONFIG_M5206) := -m5200 -Wa,-S -Wa,-m5200 +cflags-$(CONFIG_M5206e) := -m5200 -Wa,-S -Wa,-m5200 +cflags-$(CONFIG_M5249) := -m5200 -Wa,-S -Wa,-m5200 +cflags-$(CONFIG_M5272) := -m5307 -Wa,-S -Wa,-m5307 +cflags-$(CONFIG_M5307) := -m5307 -Wa,-S -Wa,-m5307 +cflags-$(CONFIG_M5407) := -m5200 -Wa,-S -Wa,-m5200 +cflags-$(CONFIG_M68328) := -m68000 +cflags-$(CONFIG_M68EZ328) := -m68000 +cflags-$(CONFIG_M68VZ328) := -m68000 +cflags-$(CONFIG_M68360) := -m68332 + +AFLAGS += $(cflags-y) + +CFLAGS += $(cflags-y) +CFLAGS += -fno-builtin +CFLAGS += -O2 -g +CFLAGS += -D__linux__ +CFLAGS += -DUTS_SYSNAME=\"uClinux\" + +HEAD := arch/m68knommu/platform/$(platform-y)/$(board-y)/crt0_$(model-y).o + +clean-files := include/asm-$(ARCH)/asm-offsets.h.tmp \ + include/asm-$(ARCH)/asm-offsets.h \ + arch/$(ARCH)/kernel/asm-offsets.s + +core-y += arch/m68knommu/kernel/ \ + arch/m68knommu/mm/ \ + $(CLASSDIR) \ + arch/m68knommu/platform/$(PLATFORM)/ +libs-y += arch/m68knommu/lib/ + +include $(TOPDIR)/Rules.make + +prepare: include/asm-$(ARCH)/asm-offsets.h + +archmrproper: + +archclean: + $(call descend arch/$(ARCH)/boot, subdirclean) + +include/asm-$(ARCH)/asm-offsets.h: arch/$(ARCH)/kernel/asm-offsets.s \ + include/asm include/linux/version.h \ + include/config/MARKER + @echo -n ' Generating $@' + @$(generate-asm-offsets.h) < $< > $@.tmp + @$(update-if-changed) diff -Nru a/arch/m68knommu/defconfig b/arch/m68knommu/defconfig --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/defconfig Mon Nov 4 14:31:04 2002 @@ -0,0 +1,538 @@ +# +# Automatically generated by make menuconfig: don't edit +# +# CONFIG_MMU is not set +# CONFIG_SWAP is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Processor type and features +# +# CONFIG_M68000 is not set +# CONFIG_M68EN302 is not set +# CONFIG_M68328 is not set +# CONFIG_M68EZ328 is not set +# CONFIG_M68VZ328 is not set +# CONFIG_M68332 is not set +# CONFIG_M68360 is not set +# CONFIG_M5204 is not set +# CONFIG_M5206 is not set +# CONFIG_M5206e is not set +# CONFIG_M5249 is not set +CONFIG_M5272=y +# CONFIG_M5307 is not set +# CONFIG_M5407 is not set +CONFIG_COLDFIRE=y +# CONFIG_CLOCK_AUTO is not set +# CONFIG_CLOCK_11MHz is not set +# CONFIG_CLOCK_16MHz is not set +# CONFIG_CLOCK_20MHz is not set +# CONFIG_CLOCK_24MHz is not set +# CONFIG_CLOCK_25MHz is not set +# CONFIG_CLOCK_33MHz is not set +# CONFIG_CLOCK_40MHz is not set +# CONFIG_CLOCK_45MHz is not set +# CONFIG_CLOCK_48MHz is not set +# CONFIG_CLOCK_50MHz is not set +# CONFIG_CLOCK_54MHz is not set +# CONFIG_CLOCK_60MHz is not set +CONFIG_CLOCK_66MHz=y +# CONFIG_CLOCK_70MHz is not set +# CONFIG_CLOCK_140MHz is not set +CONFIG_M5272C3=y +# CONFIG_GILBARCONAP is not set +# CONFIG_NETtel is not set +# CONFIG_SNAPGEAR is not set +# CONFIG_ROMFS_FROM_ROM is not set +CONFIG_MOTOROLA=y +# CONFIG_LARGE_ALLOCS is not set +# CONFIG_RAMAUTO is not set +# CONFIG_RAM4MB is not set +# CONFIG_RAM8MB is not set +CONFIG_RAM16MB=y +# CONFIG_RAM32MB is not set +CONFIG_AUTOBIT=y +# CONFIG_RAM8BIT is not set +# CONFIG_RAM16BIT is not set +# CONFIG_RAM32bit is not set +CONFIG_RAMKERNEL=y +# CONFIG_ROMKERNEL is not set +# CONFIG_HIMEMKERNEL is not set + +# +# General setup +# +CONFIG_NET=y +# CONFIG_PCI is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +# CONFIG_SYSVIPC is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +# CONFIG_KCORE_ELF is not set +CONFIG_KCORE_AOUT=y +CONFIG_BINFMT_FLAT=y +# CONFIG_BINFMT_ZFLAT is not set +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_ELF is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +# CONFIG_MTD_GEN_PROBE is not set +# CONFIG_MTD_CFI_INTELEXT is not set +# CONFIG_MTD_CFI_AMDSTD is not set +CONFIG_MTD_RAM=y +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set +CONFIG_MTD_UCLINUX=y +# CONFIG_MTD_SNAPGEARuC is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_PNP_NAMES is not set +# CONFIG_PNP_DEBUG is not set +# CONFIG_ISAPNP is not set +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_DEV_BLKMEM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IPV6_SCTP__=y +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_LLC is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set +CONFIG_FEC=y + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_E1000_NAPI is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN_BOOL is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_RESETSWITCH is not set +# CONFIG_LEDMAN is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_CS is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_RSA is not set +CONFIG_SERIAL_COLDFIRE=y +# CONFIG_UNIX98_PTYS is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_RAW_DRIVER is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_QFMT_V1 is not set +# CONFIG_QFMT_V2 is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=y +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_QUOTA is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +# CONFIG_NFS_FS is not set +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_V4 is not set +# CONFIG_NFSD_TCP is not set +# CONFIG_SUNRPC is not set +# CONFIG_LOCKD is not set +# CONFIG_EXPORTFS is not set +# CONFIG_CIFS is not set +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_AFS_FS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +# CONFIG_FULLDEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_PROFILE is not set +# CONFIG_DUMPTOFLASH is not set +# CONFIG_NO_KERNEL_MSG is not set +# CONFIG_SMALL_TASKS is not set +# CONFIG_BDM_DISABLE is not set + +# +# Security options +# +CONFIG_SECURITY_CAPABILITIES=y + +# +# Library routines +# +# CONFIG_CRC32 is not set +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZLIB_DEFLATE is not set diff -Nru a/arch/m68knommu/kernel/Makefile b/arch/m68knommu/kernel/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/kernel/Makefile Mon Nov 4 14:31:04 2002 @@ -0,0 +1,13 @@ +# +# Makefile for arch/m68knommu/kernel. +# + +export-objs := m68k_ksyms.o + +obj-y += init_task.o ints.o m68k_ksyms.o process.o ptrace.o semaphore.o \ + setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o + +obj-$(CONFIG_COMEMPCI) += comempci.o + +include $(TOPDIR)/Rules.make + diff -Nru a/arch/m68knommu/kernel/asm-offsets.c b/arch/m68knommu/kernel/asm-offsets.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/kernel/asm-offsets.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,85 @@ +/* + * This program is used to generate definitions needed by + * assembly language modules. + * + * We use the technique used in the OSF Mach kernel code: + * generate asm statements containing #defines, + * compile this file to assembler, and then extract the + * #defines from the assembly-language output. + */ + +#include +#include +#include +#include +#include +#include + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +int main(void) +{ + /* offsets into the task struct */ + DEFINE(TASK_STATE, offsetof(struct task_struct, state)); + DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); + DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); + DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked)); + DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); + DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info)); + DEFINE(TASK_MM, offsetof(struct task_struct, mm)); + DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); + + /* offsets into the irq_cpustat_t struct */ + DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); + + /* offsets into the thread struct */ + DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp)); + DEFINE(THREAD_USP, offsetof(struct thread_struct, usp)); + DEFINE(THREAD_SR, offsetof(struct thread_struct, sr)); + DEFINE(THREAD_FS, offsetof(struct thread_struct, fs)); + DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp)); + DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0)); + DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp)); + DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl)); + DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate)); + + /* offsets into the pt_regs */ + DEFINE(PT_D0, offsetof(struct pt_regs, d0)); + DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0)); + DEFINE(PT_D1, offsetof(struct pt_regs, d1)); + DEFINE(PT_D2, offsetof(struct pt_regs, d2)); + DEFINE(PT_D3, offsetof(struct pt_regs, d3)); + DEFINE(PT_D4, offsetof(struct pt_regs, d4)); + DEFINE(PT_D5, offsetof(struct pt_regs, d5)); + DEFINE(PT_A0, offsetof(struct pt_regs, a0)); + DEFINE(PT_A1, offsetof(struct pt_regs, a1)); + DEFINE(PT_A2, offsetof(struct pt_regs, a2)); + DEFINE(PT_PC, offsetof(struct pt_regs, pc)); + DEFINE(PT_SR, offsetof(struct pt_regs, sr)); + /* bitfields are a bit difficult */ + DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4); + +#ifndef CONFIG_COLDFIRE + /* offsets into the irq_handler struct */ + DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler)); + DEFINE(IRQ_DEVID, offsetof(struct irq_node, dev_id)); + DEFINE(IRQ_NEXT, offsetof(struct irq_node, next)); +#endif + + /* offsets into the kernel_stat struct */ + DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs)); + + /* signal defines */ + DEFINE(SIGSEGV, SIGSEGV); + DEFINE(SEGV_MAPERR, SEGV_MAPERR); + DEFINE(SIGTRAP, SIGTRAP); + DEFINE(TRAP_TRACE, TRAP_TRACE); + + DEFINE(PT_PTRACED, PT_PTRACED); + DEFINE(PT_DTRACE, PT_DTRACE); + + return 0; +} diff -Nru a/arch/m68knommu/kernel/comempci.c b/arch/m68knommu/kernel/comempci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/kernel/comempci.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,1171 @@ +/*****************************************************************************/ + +/* + * comemlite.c -- PCI access code for embedded CO-MEM Lite PCI controller. + * + * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com). + * (C) Copyright 2000, Lineo (www.lineo.com) + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_eLIA +#include +#endif + +/*****************************************************************************/ + +/* + * Debug configuration defines. DEBUGRES sets debugging output for + * the resource allocation phase. DEBUGPCI traces on pcibios_ function + * calls, and DEBUGIO traces all accesses to devices on the PCI bus. + */ +/*#define DEBUGRES 1*/ +/*#define DEBUGPCI 1*/ +/*#define DEBUGIO 1*/ + +/*****************************************************************************/ + +/* + * PCI markers for bus present and active slots. + */ +int pci_bus_is_present = 0; +unsigned long pci_slotmask = 0; + +/* + * We may or may not need to swap the bytes of PCI bus tranfers. + * The endianess is re-roder automatically by the CO-MEM, but it + * will get the wrong byte order for a pure data stream. + */ +#define pci_byteswap 0 + + +/* + * Resource tracking. The CO-MEM part creates a virtual address + * space that all the PCI devices live in - it is not in any way + * directly mapped into the ColdFire address space. So we can + * really assign any resources we like to devices, as long as + * they do not clash with other PCI devices. + */ +unsigned int pci_iobase = 0x100; /* Arbitary start address */ +unsigned int pci_membase = 0x00010000; /* Arbitary start address */ + +#define PCI_MINIO 0x100 /* 256 byte minimum I/O */ +#define PCI_MINMEM 0x00010000 /* 64k minimum chunk */ + +/* + * The CO-MEM's shared memory segment is visible inside the PCI + * memory address space. We need to keep track of the address that + * this is mapped at, to setup the bus masters pointers. + */ +unsigned int pci_shmemaddr; + +/*****************************************************************************/ + +void pci_interrupt(int irq, void *id, struct pt_regs *fp); + +/*****************************************************************************/ + +/* + * Some platforms have custom ways of reseting the PCI bus. + */ + +void pci_resetbus(void) +{ +#ifdef CONFIG_eLIA + int i; + +#ifdef DEBUGPCI + printk("pci_resetbus()\n"); +#endif + + *((volatile unsigned short *) (MCF_MBAR+MCFSIM_PADDR)) |= eLIA_PCIRESET; + for (i = 0; (i < 1000); i++) { + *((volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT)) = + (ppdata | eLIA_PCIRESET); + } + + + *((volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT)) = ppdata; +#endif +} + +/*****************************************************************************/ + +int pcibios_assignres(int slot) +{ + volatile unsigned long *rp; + volatile unsigned char *ip; + unsigned int idsel, addr, val, align, i; + int bar; + +#ifdef DEBUGPCI + printk("pcibios_assignres(slot=%x)\n", slot); +#endif + + rp = (volatile unsigned long *) COMEM_BASE; + idsel = COMEM_DA_ADDR(0x1 << (slot + 16)); + + /* Try to assign resource to each BAR */ + for (bar = 0; (bar < 6); bar++) { + addr = COMEM_PCIBUS + PCI_BASE_ADDRESS_0 + (bar * 4); + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel; + val = rp[LREG(addr)]; +#ifdef DEBUGRES + printk("-----------------------------------" + "-------------------------------------\n"); + printk("BAR[%d]: read=%08x ", bar, val); +#endif + + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel; + rp[LREG(addr)] = 0xffffffff; + + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel; + val = rp[LREG(addr)]; +#ifdef DEBUGRES + printk("write=%08x ", val); +#endif + if (val == 0) { +#ifdef DEBUGRES + printk("\n"); +#endif + continue; + } + + /* Determine space required by BAR */ + /* FIXME: this should go backwords from 0x80000000... */ + for (i = 0; (i < 32); i++) { + if ((0x1 << i) & (val & 0xfffffffc)) + break; + } + +#ifdef DEBUGRES + printk("size=%08x(%d)\n", (0x1 << i), i); +#endif + i = 0x1 << i; + + /* Assign a resource */ + if (val & PCI_BASE_ADDRESS_SPACE_IO) { + if (i < PCI_MINIO) + i = PCI_MINIO; +#ifdef DEBUGRES + printk("BAR[%d]: IO size=%08x iobase=%08x\n", + bar, i, pci_iobase); +#endif + if (i > 0xffff) { + /* Invalid size?? */ + val = 0 | PCI_BASE_ADDRESS_SPACE_IO; +#ifdef DEBUGRES + printk("BAR[%d]: too big for IO??\n", bar); +#endif + } else { + /* Check for un-alignment */ + if ((align = pci_iobase % i)) + pci_iobase += (i - align); + val = pci_iobase | PCI_BASE_ADDRESS_SPACE_IO; + pci_iobase += i; + } + } else { + if (i < PCI_MINMEM) + i = PCI_MINMEM; +#ifdef DEBUGRES + printk("BAR[%d]: MEMORY size=%08x membase=%08x\n", + bar, i, pci_membase); +#endif + /* Check for un-alignment */ + if ((align = pci_membase % i)) + pci_membase += (i - align); + val = pci_membase | PCI_BASE_ADDRESS_SPACE_MEMORY; + pci_membase += i; + } + + /* Write resource back into BAR register */ + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel; + rp[LREG(addr)] = val; +#ifdef DEBUGRES + printk("BAR[%d]: assigned bar=%08x\n", bar, val); +#endif + } + +#ifdef DEBUGRES + printk("-----------------------------------" + "-------------------------------------\n"); +#endif + + /* Assign IRQ if one is wanted... */ + ip = (volatile unsigned char *) (COMEM_BASE + COMEM_PCIBUS); + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel; + + addr = (PCI_INTERRUPT_PIN & 0xfc) + (~PCI_INTERRUPT_PIN & 0x03); + if (ip[addr]) { + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel; + addr = (PCI_INTERRUPT_LINE & 0xfc)+(~PCI_INTERRUPT_LINE & 0x03); + ip[addr] = 25; +#ifdef DEBUGRES + printk("IRQ LINE=25\n"); +#endif + } + + return(0); +} + +/*****************************************************************************/ + +int pcibios_enable(int slot) +{ + volatile unsigned long *rp; + volatile unsigned short *wp; + unsigned int idsel, addr; + unsigned short cmd; + +#ifdef DEBUGPCI + printk("pcibios_enbale(slot=%x)\n", slot); +#endif + + rp = (volatile unsigned long *) COMEM_BASE; + wp = (volatile unsigned short *) COMEM_BASE; + idsel = COMEM_DA_ADDR(0x1 << (slot + 16)); + + /* Get current command settings */ + addr = COMEM_PCIBUS + PCI_COMMAND; + addr = (addr & ~0x3) + (~addr & 0x02); + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel; + cmd = wp[WREG(addr)]; + /*val = ((val & 0xff) << 8) | ((val >> 8) & 0xff);*/ + + /* Enable I/O and memory accesses to this device */ + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel; + cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + wp[WREG(addr)] = cmd; + + return(0); +} + +/*****************************************************************************/ + +unsigned long pcibios_init(unsigned long mem_start, unsigned long mem_end) +{ + volatile unsigned long *rp; + unsigned long sel, id; + int slot; + +#ifdef DEBUGPCI + printk("pcibios_init()\n"); +#endif + + pci_resetbus(); + + /* + * Do some sort of basic check to see if the CO-MEM part + * is present... This works ok, but I think we really need + * something better... + */ + rp = (volatile unsigned long *) COMEM_BASE; + if ((rp[LREG(COMEM_LBUSCFG)] & 0xff) != 0x50) { + printk("PCI: no PCI bus present\n"); + return(mem_start); + } + +#ifdef COMEM_BRIDGEDEV + /* + * Setup the PCI bridge device first. It needs resources too, + * so that bus masters can get to its shared memory. + */ + slot = COMEM_BRIDGEDEV; + sel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << (slot + 16)); + rp[LREG(COMEM_DAHBASE)] = sel; + rp[LREG(COMEM_PCIBUS)] = 0; /* Clear bus */ + id = rp[LREG(COMEM_PCIBUS)]; + if ((id == 0) || ((id & 0xffff0000) == (sel & 0xffff0000))) { + printk("PCI: no PCI bus bridge present\n"); + return(mem_start); + } + + printk("PCI: bridge device at slot=%d id=%08x\n", slot, (int) id); + pci_slotmask |= 0x1 << slot; + pci_shmemaddr = pci_membase; + pcibios_assignres(slot); + pcibios_enable(slot); +#endif + + pci_bus_is_present = 1; + + /* + * Do a quick scan of the PCI bus and see what is here. + */ + for (slot = COMEM_MINDEV; (slot <= COMEM_MAXDEV); slot++) { + sel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << (slot + 16)); + rp[LREG(COMEM_DAHBASE)] = sel; + rp[LREG(COMEM_PCIBUS)] = 0; /* Clear bus */ + id = rp[LREG(COMEM_PCIBUS)]; + if ((id != 0) && ((id & 0xffff0000) != (sel & 0xffff0000))) { + printk("PCI: slot=%d id=%08x\n", slot, (int) id); + pci_slotmask |= 0x1 << slot; + pcibios_assignres(slot); + pcibios_enable(slot); + } + } + + /* Get PCI irq for local vectoring */ + if (request_irq(COMEM_IRQ, pci_interrupt, 0, "PCI bridge", NULL)) { + printk("PCI: failed to acquire interrupt %d\n", COMEM_IRQ); + } else { + mcf_autovector(COMEM_IRQ); + } + + return(mem_start); +} + +/*****************************************************************************/ + +unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end) +{ + return(mem_start); +} + +/*****************************************************************************/ + +int pcibios_present(void) +{ + return(pci_bus_is_present); +} + +/*****************************************************************************/ + +int pcibios_read_config_dword(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned int *val) +{ + volatile unsigned long *rp; + unsigned long idsel, fnsel; + +#ifdef DEBUGPCI + printk("pcibios_read_config_dword(bus=%x,dev=%x,offset=%x,val=%x)\n", + bus, dev, offset, val); +#endif + + if (bus || ((pci_slotmask & (0x1 << PCI_SLOT(dev))) == 0)) { + *val = 0xffffffff; + return(PCIBIOS_SUCCESSFUL); + } + + rp = (volatile unsigned long *) COMEM_BASE; + idsel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << ((dev >> 3) + 16)); + fnsel = (dev & 0x7) << 8; + + rp[LREG(COMEM_DAHBASE)] = idsel; + *val = rp[LREG(COMEM_PCIBUS + (offset & 0xfc) + fnsel)]; + +#if 1 + /* If we get back what we wrote, then nothing there */ + /* This is pretty dodgy, but, hey, what else do we do?? */ + if (!offset && (*val == ((idsel & 0xfffff000) | (offset & 0x00000fff)))) + *val = 0xffffffff; +#endif + + return(PCIBIOS_SUCCESSFUL); +} + +/*****************************************************************************/ + +int pcibios_read_config_word(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned short *val) +{ + volatile unsigned long *rp; + volatile unsigned short *bp; + unsigned long idsel, fnsel; + unsigned char swapoffset; + +#ifdef DEBUGPCI + printk("pcibios_read_config_word(bus=%x,dev=%x,offset=%x)\n", + bus, dev, offset); +#endif + + if (bus || ((pci_slotmask & (0x1 << PCI_SLOT(dev))) == 0)) { + *val = 0xffff; + return(PCIBIOS_SUCCESSFUL); + } + + rp = (volatile unsigned long *) COMEM_BASE; + bp = (volatile unsigned short *) COMEM_BASE; + idsel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << ((dev >> 3) + 16)); + fnsel = (dev & 0x7) << 8; + swapoffset = (offset & 0xfc) + (~offset & 0x02); + + rp[LREG(COMEM_DAHBASE)] = idsel; + *val = bp[WREG(COMEM_PCIBUS + swapoffset + fnsel)]; + + return(PCIBIOS_SUCCESSFUL); +} + +/*****************************************************************************/ + +int pcibios_read_config_byte(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned char *val) +{ + volatile unsigned long *rp; + volatile unsigned char *bp; + unsigned long idsel, fnsel; + unsigned char swapoffset; + +#ifdef DEBUGPCI + printk("pcibios_read_config_byte(bus=%x,dev=%x,offset=%x)\n", + bus, dev, offset); +#endif + + if (bus || ((pci_slotmask & (0x1 << PCI_SLOT(dev))) == 0)) { + *val = 0xff; + return(PCIBIOS_SUCCESSFUL); + } + + rp = (volatile unsigned long *) COMEM_BASE; + bp = (volatile unsigned char *) COMEM_BASE; + idsel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << ((dev >> 3) + 16)); + fnsel = (dev & 0x7) << 8; + swapoffset = (offset & 0xfc) + (~offset & 0x03); + + rp[LREG(COMEM_DAHBASE)] = idsel; + *val = bp[(COMEM_PCIBUS + swapoffset + fnsel)]; + + return(PCIBIOS_SUCCESSFUL); +} + +/*****************************************************************************/ + +int pcibios_write_config_dword(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned int val) +{ + volatile unsigned long *rp; + unsigned long idsel, fnsel; + +#ifdef DEBUGPCI + printk("pcibios_write_config_dword(bus=%x,dev=%x,offset=%x,val=%x)\n", + bus, dev, offset, val); +#endif + + if (bus || ((pci_slotmask & (0x1 << PCI_SLOT(dev))) == 0)) + return(PCIBIOS_SUCCESSFUL); + + rp = (volatile unsigned long *) COMEM_BASE; + idsel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << ((dev >> 3) + 16)); + fnsel = (dev & 0x7) << 8; + + rp[LREG(COMEM_DAHBASE)] = idsel; + rp[LREG(COMEM_PCIBUS + (offset & 0xfc) + fnsel)] = val; + return(PCIBIOS_SUCCESSFUL); +} + +/*****************************************************************************/ + +int pcibios_write_config_word(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned short val) +{ + + volatile unsigned long *rp; + volatile unsigned short *bp; + unsigned long idsel, fnsel; + unsigned char swapoffset; + +#ifdef DEBUGPCI + printk("pcibios_write_config_word(bus=%x,dev=%x,offset=%x,val=%x)\n", + bus, dev, offset, val); +#endif + + if (bus || ((pci_slotmask & (0x1 << PCI_SLOT(dev))) == 0)) + return(PCIBIOS_SUCCESSFUL); + + rp = (volatile unsigned long *) COMEM_BASE; + bp = (volatile unsigned short *) COMEM_BASE; + idsel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << ((dev >> 3) + 16)); + fnsel = (dev & 0x7) << 8; + swapoffset = (offset & 0xfc) + (~offset & 0x02); + + rp[LREG(COMEM_DAHBASE)] = idsel; + bp[WREG(COMEM_PCIBUS + swapoffset + fnsel)] = val; + return(PCIBIOS_SUCCESSFUL); +} + +/*****************************************************************************/ + +int pcibios_write_config_byte(unsigned char bus, unsigned char dev, + unsigned char offset, unsigned char val) +{ + volatile unsigned long *rp; + volatile unsigned char *bp; + unsigned long idsel, fnsel; + unsigned char swapoffset; + +#ifdef DEBUGPCI + printk("pcibios_write_config_byte(bus=%x,dev=%x,offset=%x,val=%x)\n", + bus, dev, offset, val); +#endif + + if (bus || ((pci_slotmask & (0x1 << PCI_SLOT(dev))) == 0)) + return(PCIBIOS_SUCCESSFUL); + + rp = (volatile unsigned long *) COMEM_BASE; + bp = (volatile unsigned char *) COMEM_BASE; + idsel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << ((dev >> 3) + 16)); + fnsel = (dev & 0x7) << 8; + swapoffset = (offset & 0xfc) + (~offset & 0x03); + + rp[LREG(COMEM_DAHBASE)] = idsel; + bp[(COMEM_PCIBUS + swapoffset + fnsel)] = val; + return(PCIBIOS_SUCCESSFUL); +} + +/*****************************************************************************/ + +int pcibios_find_device(unsigned short vendor, unsigned short devid, + unsigned short index, unsigned char *bus, unsigned char *dev) +{ + unsigned int vendev, val; + unsigned char devnr; + +#ifdef DEBUGPCI + printk("pcibios_find_device(vendor=%04x,devid=%04x,index=%d)\n", + vendor, devid, index); +#endif + + if (vendor == 0xffff) + return(PCIBIOS_BAD_VENDOR_ID); + + vendev = (devid << 16) | vendor; + for (devnr = 0; (devnr < 32); devnr++) { + pcibios_read_config_dword(0, devnr, PCI_VENDOR_ID, &val); + if (vendev == val) { + if (index-- == 0) { + *bus = 0; + *dev = devnr; + return(PCIBIOS_SUCCESSFUL); + } + } + } + + return(PCIBIOS_DEVICE_NOT_FOUND); +} + +/*****************************************************************************/ + +int pcibios_find_class(unsigned int class, unsigned short index, + unsigned char *bus, unsigned char *dev) +{ + unsigned int val; + unsigned char devnr; + +#ifdef DEBUGPCI + printk("pcibios_find_class(class=%04x,index=%d)\n", class, index); +#endif + + /* FIXME: this ignores multi-function devices... */ + for (devnr = 0; (devnr < 128); devnr += 8) { + pcibios_read_config_dword(0, devnr, PCI_CLASS_REVISION, &val); + if ((val >> 8) == class) { + if (index-- == 0) { + *bus = 0; + *dev = devnr; + return(PCIBIOS_SUCCESSFUL); + } + } + } + + return(PCIBIOS_DEVICE_NOT_FOUND); +} + +/*****************************************************************************/ + +/* + * Local routines to interrcept the standard I/O and vector handling + * code. Don't include this 'till now - initialization code above needs + * access to the real code too. + */ +#include + +/*****************************************************************************/ + +void pci_outb(unsigned char val, unsigned int addr) +{ + volatile unsigned long *rp; + volatile unsigned char *bp; + +#ifdef DEBUGIO + printk("pci_outb(val=%02x,addr=%x)\n", val, addr); +#endif + + rp = (volatile unsigned long *) COMEM_BASE; + bp = (volatile unsigned char *) COMEM_BASE; + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr); + addr = (addr & ~0x3) + (~addr & 0x03); + bp[(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val; +} + +/*****************************************************************************/ + +void pci_outw(unsigned short val, unsigned int addr) +{ + volatile unsigned long *rp; + volatile unsigned short *sp; + +#ifdef DEBUGIO + printk("pci_outw(val=%04x,addr=%x)", val, addr); +#endif + + rp = (volatile unsigned long *) COMEM_BASE; + sp = (volatile unsigned short *) COMEM_BASE; + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr); + addr = (addr & ~0x3) + (~addr & 0x02); + if (pci_byteswap) + val = ((val & 0xff) << 8) | ((val >> 8) & 0xff); + sp[WREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val; +} + +/*****************************************************************************/ + +void pci_outl(unsigned int val, unsigned int addr) +{ + volatile unsigned long *rp; + volatile unsigned int *lp; + +#ifdef DEBUGIO + printk("pci_outl(val=%08x,addr=%x)\n", val, addr); +#endif + + rp = (volatile unsigned long *) COMEM_BASE; + lp = (volatile unsigned int *) COMEM_BASE; + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr); + + if (pci_byteswap) + val = (val << 24) | ((val & 0x0000ff00) << 8) | + ((val & 0x00ff0000) >> 8) | (val >> 24); + + lp[LREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val; +} + +/*****************************************************************************/ + +unsigned long pci_blmask[] = { + 0x000000e0, + 0x000000d0, + 0x000000b0, + 0x00000070 +}; + +unsigned char pci_inb(unsigned int addr) +{ + volatile unsigned long *rp; + volatile unsigned char *bp; + unsigned long r; + unsigned char val; + +#ifdef DEBUGIO + printk("pci_inb(addr=%x)", addr); +#endif + + rp = (volatile unsigned long *) COMEM_BASE; + bp = (volatile unsigned char *) COMEM_BASE; + + r = COMEM_DA_IORD | COMEM_DA_ADDR(addr) | pci_blmask[(addr & 0x3)]; + rp[LREG(COMEM_DAHBASE)] = r; + + addr = (addr & ~0x3) + (~addr & 0x3); + val = bp[(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))]; + return(val); +} + +/*****************************************************************************/ + +unsigned long pci_bwmask[] = { + 0x000000c0, + 0x000000c0, + 0x00000030, + 0x00000030 +}; + +unsigned short pci_inw(unsigned int addr) +{ + volatile unsigned long *rp; + volatile unsigned short *sp; + unsigned long r; + unsigned short val; + +#ifdef DEBUGIO + printk("pci_inw(addr=%x)", addr); +#endif + + rp = (volatile unsigned long *) COMEM_BASE; + r = COMEM_DA_IORD | COMEM_DA_ADDR(addr) | pci_bwmask[(addr & 0x3)]; + rp[LREG(COMEM_DAHBASE)] = r; + + sp = (volatile unsigned short *) COMEM_BASE; + addr = (addr & ~0x3) + (~addr & 0x02); + val = sp[WREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))]; + if (pci_byteswap) + val = ((val & 0xff) << 8) | ((val >> 8) & 0xff); +#ifdef DEBUGIO + printk("=%04x\n", val); +#endif + return(val); +} + +/*****************************************************************************/ + +unsigned int pci_inl(unsigned int addr) +{ + volatile unsigned long *rp; + volatile unsigned int *lp; + unsigned int val; + +#ifdef DEBUGIO + printk("pci_inl(addr=%x)", addr); +#endif + + rp = (volatile unsigned long *) COMEM_BASE; + lp = (volatile unsigned int *) COMEM_BASE; + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(addr); + val = lp[LREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))]; + + if (pci_byteswap) + val = (val << 24) | ((val & 0x0000ff00) << 8) | + ((val & 0x00ff0000) >> 8) | (val >> 24); + +#ifdef DEBUGIO + printk("=%08x\n", val); +#endif + return(val); +} + +/*****************************************************************************/ + +void pci_outsb(void *addr, void *buf, int len) +{ + volatile unsigned long *rp; + volatile unsigned char *bp; + unsigned char *dp = (unsigned char *) buf; + unsigned int a = (unsigned int) addr; + +#ifdef DEBUGIO + printk("pci_outsb(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); +#endif + + rp = (volatile unsigned long *) COMEM_BASE; + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(a); + + a = (a & ~0x3) + (~a & 0x03); + bp = (volatile unsigned char *) + (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); + + while (len--) + *bp = *dp++; +} + +/*****************************************************************************/ + +void pci_outsw(void *addr, void *buf, int len) +{ + volatile unsigned long *rp; + volatile unsigned short *wp; + unsigned short w, *dp = (unsigned short *) buf; + unsigned int a = (unsigned int) addr; + +#ifdef DEBUGIO + printk("pci_outsw(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); +#endif + + rp = (volatile unsigned long *) COMEM_BASE; + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(a); + + a = (a & ~0x3) + (~a & 0x2); + wp = (volatile unsigned short *) + (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); + + while (len--) { + w = *dp++; + if (pci_byteswap) + w = ((w & 0xff) << 8) | ((w >> 8) & 0xff); + *wp = w; + } +} + +/*****************************************************************************/ + +void pci_outsl(void *addr, void *buf, int len) +{ + volatile unsigned long *rp; + volatile unsigned long *lp; + unsigned long l, *dp = (unsigned long *) buf; + unsigned int a = (unsigned int) addr; + +#ifdef DEBUGIO + printk("pci_outsl(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); +#endif + + rp = (volatile unsigned long *) COMEM_BASE; + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(a); + + lp = (volatile unsigned long *) + (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); + + while (len--) { + l = *dp++; + if (pci_byteswap) + l = (l << 24) | ((l & 0x0000ff00) << 8) | + ((l & 0x00ff0000) >> 8) | (l >> 24); + *lp = l; + } +} + +/*****************************************************************************/ + +void pci_insb(void *addr, void *buf, int len) +{ + volatile unsigned long *rp; + volatile unsigned char *bp; + unsigned char *dp = (unsigned char *) buf; + unsigned int a = (unsigned int) addr; + +#ifdef DEBUGIO + printk("pci_insb(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); +#endif + + rp = (volatile unsigned long *) COMEM_BASE; + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(a); + + a = (a & ~0x3) + (~a & 0x03); + bp = (volatile unsigned char *) + (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); + + while (len--) + *dp++ = *bp; +} + +/*****************************************************************************/ + +void pci_insw(void *addr, void *buf, int len) +{ + volatile unsigned long *rp; + volatile unsigned short *wp; + unsigned short w, *dp = (unsigned short *) buf; + unsigned int a = (unsigned int) addr; + +#ifdef DEBUGIO + printk("pci_insw(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); +#endif + + rp = (volatile unsigned long *) COMEM_BASE; + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(a); + + a = (a & ~0x3) + (~a & 0x2); + wp = (volatile unsigned short *) + (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); + + while (len--) { + w = *wp; + if (pci_byteswap) + w = ((w & 0xff) << 8) | ((w >> 8) & 0xff); + *dp++ = w; + } +} + +/*****************************************************************************/ + +void pci_insl(void *addr, void *buf, int len) +{ + volatile unsigned long *rp; + volatile unsigned long *lp; + unsigned long l, *dp = (unsigned long *) buf; + unsigned int a = (unsigned int) addr; + +#ifdef DEBUGIO + printk("pci_insl(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); +#endif + + rp = (volatile unsigned long *) COMEM_BASE; + rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(a); + + lp = (volatile unsigned long *) + (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); + + while (len--) { + l = *lp; + if (pci_byteswap) + l = (l << 24) | ((l & 0x0000ff00) << 8) | + ((l & 0x00ff0000) >> 8) | (l >> 24); + *dp++ = l; + } +} + +/*****************************************************************************/ + +struct pci_localirqlist { + void (*handler)(int, void *, struct pt_regs *); + const char *device; + void *dev_id; +}; + +struct pci_localirqlist pci_irqlist[COMEM_MAXPCI]; + +/*****************************************************************************/ + +int pci_request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *device, void *dev_id) +{ + int i; + +#ifdef DEBUGIO + printk("pci_request_irq(irq=%d,handler=%x,flags=%x,device=%s," + "dev_id=%x)\n", irq, (int) handler, (int) flags, device, + (int) dev_id); +#endif + + /* Check if this interrupt handler is already lodged */ + for (i = 0; (i < COMEM_MAXPCI); i++) { + if (pci_irqlist[i].handler == handler) + return(0); + } + + /* Find a free spot to put this handler */ + for (i = 0; (i < COMEM_MAXPCI); i++) { + if (pci_irqlist[i].handler == 0) { + pci_irqlist[i].handler = handler; + pci_irqlist[i].device = device; + pci_irqlist[i].dev_id = dev_id; + return(0); + } + } + + /* Couldn't fit?? */ + return(1); +} + +/*****************************************************************************/ + +void pci_free_irq(unsigned int irq, void *dev_id) +{ + int i; + +#ifdef DEBUGIO + printk("pci_free_irq(irq=%d,dev_id=%x)\n", irq, (int) dev_id); +#endif + + if (dev_id == (void *) NULL) + return; + + /* Check if this interrupt handler is lodged */ + for (i = 0; (i < COMEM_MAXPCI); i++) { + if (pci_irqlist[i].dev_id == dev_id) { + pci_irqlist[i].handler = NULL; + pci_irqlist[i].device = NULL; + pci_irqlist[i].dev_id = NULL; + break; + } + } +} + +/*****************************************************************************/ + +void pci_interrupt(int irq, void *id, struct pt_regs *fp) +{ + int i; + +#ifdef DEBUGIO + printk("pci_interrupt(irq=%d,id=%x,fp=%x)\n", irq, (int) id, (int) fp); +#endif + + for (i = 0; (i < COMEM_MAXPCI); i++) { + if (pci_irqlist[i].handler) + (*pci_irqlist[i].handler)(irq,pci_irqlist[i].dev_id,fp); + } +} + +/*****************************************************************************/ + +/* + * The shared memory region is broken up into contiguous 512 byte + * regions for easy allocation... This is not an optimal solution + * but it makes allocation and freeing regions really easy. + */ + +#define PCI_MEMSLOTSIZE 512 +#define PCI_MEMSLOTS (COMEM_SHMEMSIZE / PCI_MEMSLOTSIZE) + +char pci_shmemmap[PCI_MEMSLOTS]; + + +void *pci_bmalloc(int size) +{ + int i, j, nrslots; + +#ifdef DEBUGIO + printk("pci_bmalloc(size=%d)\n", size); +#endif + + if (size <= 0) + return((void *) NULL); + + nrslots = (size - 1) / PCI_MEMSLOTSIZE; + + for (i = 0; (i < (PCI_MEMSLOTS-nrslots)); i++) { + if (pci_shmemmap[i] == 0) { + for (j = i+1; (j < (i+nrslots)); j++) { + if (pci_shmemmap[j]) + goto restart; + } + + for (j = i; (j <= i+nrslots); j++) + pci_shmemmap[j] = 1; + break; + } +restart: + } + + return((void *) (COMEM_BASE + COMEM_SHMEM + (i * PCI_MEMSLOTSIZE))); +} + +/*****************************************************************************/ + +void pci_bmfree(void *mp, int size) +{ + int i, j, nrslots; + +#ifdef DEBUGIO + printk("pci_bmfree(mp=%x,size=%d)\n", (int) mp, size); +#endif + + nrslots = size / PCI_MEMSLOTSIZE; + i = (((unsigned long) mp) - (COMEM_BASE + COMEM_SHMEM)) / + PCI_MEMSLOTSIZE; + + for (j = i; (j < (i+nrslots)); j++) + pci_shmemmap[j] = 0; +} + +/*****************************************************************************/ + +unsigned long pci_virt_to_bus(volatile void *address) +{ + unsigned long l; + +#ifdef DEBUGIO + printk("pci_virt_to_bus(address=%x)", (int) address); +#endif + + l = ((unsigned long) address) - COMEM_BASE; +#ifdef DEBUGIO + printk("=%x\n", (int) (l+pci_shmemaddr)); +#endif + return(l + pci_shmemaddr); +} + +/*****************************************************************************/ + +void *pci_bus_to_virt(unsigned long address) +{ + unsigned long l; + +#ifdef DEBUGIO + printk("pci_bus_to_virt(address=%x)", (int) address); +#endif + + l = address - pci_shmemaddr; +#ifdef DEBUGIO + printk("=%x\n", (int) (address + COMEM_BASE)); +#endif + return((void *) (address + COMEM_BASE)); +} + +/*****************************************************************************/ + +void pci_bmcpyto(void *dst, void *src, int len) +{ + unsigned long *dp, *sp, val; + unsigned char *dcp, *scp; + int i, j; + +#ifdef DEBUGIO + printk("pci_bmcpyto(dst=%x,src=%x,len=%d)\n", (int)dst, (int)src, len); +#endif + + dp = (unsigned long *) dst; + sp = (unsigned long *) src; + i = len >> 2; + +#if 0 + printk("DATA:"); + scp = (unsigned char *) sp; + for (i = 0; (i < len); i++) { + if ((i % 16) == 0) printk("\n%04x: ", i); + printk("%02x ", *scp++); + } + printk("\n"); +#endif + + for (j = 0; (i >= 0); i--, j++) { + val = *sp++; + val = (val << 24) | ((val & 0x0000ff00) << 8) | + ((val & 0x00ff0000) >> 8) | (val >> 24); + *dp++ = val; + } + + if (len & 0x3) { + dcp = (unsigned char *) dp; + scp = ((unsigned char *) sp) + 3; + for (i = 0; (i < (len & 0x3)); i++) + *dcp++ = *scp--; + } +} + +/*****************************************************************************/ + +void pci_bmcpyfrom(void *dst, void *src, int len) +{ + unsigned long *dp, *sp, val; + unsigned char *dcp, *scp; + int i; + +#ifdef DEBUGIO + printk("pci_bmcpyfrom(dst=%x,src=%x,len=%d)\n",(int)dst,(int)src,len); +#endif + + dp = (unsigned long *) dst; + sp = (unsigned long *) src; + i = len >> 2; + + for (; (i >= 0); i--) { + val = *sp++; + val = (val << 24) | ((val & 0x0000ff00) << 8) | + ((val & 0x00ff0000) >> 8) | (val >> 24); + *dp++ = val; + } + + if (len & 0x3) { + dcp = ((unsigned char *) dp) + 3; + scp = (unsigned char *) sp; + for (i = 0; (i < (len & 0x3)); i++) + *dcp++ = *scp--; + } + +#if 0 + printk("DATA:"); + dcp = (unsigned char *) dst; + for (i = 0; (i < len); i++) { + if ((i % 16) == 0) printk("\n%04x: ", i); + printk("%02x ", *dcp++); + } + printk("\n"); +#endif +} + +/*****************************************************************************/ diff -Nru a/arch/m68knommu/kernel/init_task.c b/arch/m68knommu/kernel/init_task.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/kernel/init_task.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,37 @@ +/* + * linux/arch/m68knommu/kernel/init_task.c + */ +#include +#include +#include +#include +#include + +#include +#include + +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS(init_signals); +struct mm_struct init_mm = INIT_MM(init_mm); + +/* + * Initial task structure. + * + * All other task structs will be allocated on slabs in fork.c + */ +__asm__(".align 4"); +struct task_struct init_task = INIT_TASK(init_task); + + +/* + * Initial thread structure. + * + * We need to make sure that this is 8192-byte aligned due to the + * way process stacks are handled. This is done by having a special + * "init_task" linker map entry.. + */ +union thread_union init_thread_union + __attribute__((__section__(".data.init_task"))) = + { INIT_THREAD_INFO(init_task) }; + diff -Nru a/arch/m68knommu/kernel/ints.c b/arch/m68knommu/kernel/ints.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/kernel/ints.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,274 @@ +/* + * linux/arch/m68knommu/kernel/ints.c -- General interrupt handling code + * + * Copyright (C) 1999-2002 Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 1998 D. Jeff Dionne , + * Kenneth Albanowski , + * Copyright (C) 2000 Lineo Inc. (www.lineo.com) + * + * Based on: + * + * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * This table stores the address info for each vector handler. + */ +irq_handler_t irq_list[SYS_IRQS]; +unsigned int *mach_kstat_irqs; + +#define NUM_IRQ_NODES 16 +static irq_node_t nodes[NUM_IRQ_NODES]; + +/* The number of spurious interrupts */ +volatile unsigned int num_spurious; + +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; + +static void default_irq_handler(int irq, void *ptr, struct pt_regs *regs) +{ +#if 1 + printk("%s(%d): default irq handler vec=%d [0x%x]\n", + __FILE__, __LINE__, irq, irq); +#endif +} + +/* + * void init_IRQ(void) + * + * Parameters: None + * + * Returns: Nothing + * + * This function should be called during kernel startup to initialize + * the IRQ handling routines. + */ + +void __init init_IRQ(void) +{ + int i; + + for (i = 0; i < SYS_IRQS; i++) { + if (mach_default_handler) + irq_list[i].handler = (*mach_default_handler)[i]; + else + irq_list[i].handler = default_irq_handler; + irq_list[i].flags = IRQ_FLG_STD; + irq_list[i].dev_id = NULL; + irq_list[i].devname = NULL; + } + + for (i = 0; i < NUM_IRQ_NODES; i++) + nodes[i].handler = NULL; + + if (mach_init_IRQ) + mach_init_IRQ(); + + mach_kstat_irqs = &kstat.irqs[0][0]; +} + +irq_node_t *new_irq_node(void) +{ + irq_node_t *node; + short i; + + for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) + if (!node->handler) + return node; + + printk("new_irq_node: out of nodes\n"); + return NULL; +} + +int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) +{ + if (irq < 0 || irq >= NR_IRQS) { + printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, + irq, devname); + return -ENXIO; + } + + if (!(irq_list[irq].flags & IRQ_FLG_STD)) { + if (irq_list[irq].flags & IRQ_FLG_LOCK) { + printk("%s: IRQ %d from %s is not replaceable\n", + __FUNCTION__, irq, irq_list[irq].devname); + return -EBUSY; + } + if (flags & IRQ_FLG_REPLACE) { + printk("%s: %s can't replace IRQ %d from %s\n", + __FUNCTION__, devname, irq, irq_list[irq].devname); + return -EBUSY; + } + } + +#ifdef CONFIG_COLDFIRE + if (flags & IRQ_FLG_FAST) { + extern asmlinkage void fasthandler(void); + extern void set_evector(int vecnum, void (*handler)(void)); + set_evector(irq, fasthandler); + } +#endif + + irq_list[irq].handler = handler; + irq_list[irq].flags = flags; + irq_list[irq].dev_id = dev_id; + irq_list[irq].devname = devname; + return 0; +} + +void free_irq(unsigned int irq, void *dev_id) +{ + if (irq >= NR_IRQS) { + printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); + return; + } + + if (irq_list[irq].dev_id != dev_id) + printk("%s: Removing probably wrong IRQ %d from %s\n", + __FUNCTION__, irq, irq_list[irq].devname); + +#ifdef CONFIG_COLDFIRE + if (irq_list[irq].flags & IRQ_FLG_FAST) { + extern asmlinkage void inthandler(void); + extern void set_evector(int vecnum, void (*handler)(void)); + set_evector(irq, inthandler); + } +#endif + + if (mach_default_handler) + irq_list[irq].handler = (*mach_default_handler)[irq]; + else + irq_list[irq].handler = default_irq_handler; + irq_list[irq].flags = IRQ_FLG_STD; + irq_list[irq].dev_id = NULL; + irq_list[irq].devname = NULL; +} + + +int sys_request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) +{ + if (irq > IRQ7) { + printk("%s: Incorrect IRQ %d from %s\n", + __FUNCTION__, irq, devname); + return -ENXIO; + } + +#if 0 + if (!(irq_list[irq].flags & IRQ_FLG_STD)) { + if (irq_list[irq].flags & IRQ_FLG_LOCK) { + printk("%s: IRQ %d from %s is not replaceable\n", + __FUNCTION__, irq, irq_list[irq].devname); + return -EBUSY; + } + if (!(flags & IRQ_FLG_REPLACE)) { + printk("%s: %s can't replace IRQ %d from %s\n", + __FUNCTION__, devname, irq, irq_list[irq].devname); + return -EBUSY; + } + } +#endif + + irq_list[irq].handler = handler; + irq_list[irq].flags = flags; + irq_list[irq].dev_id = dev_id; + irq_list[irq].devname = devname; + return 0; +} + +void sys_free_irq(unsigned int irq, void *dev_id) +{ + if (irq > IRQ7) { + printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); + return; + } + + if (irq_list[irq].dev_id != dev_id) + printk("%s: Removing probably wrong IRQ %d from %s\n", + __FUNCTION__, irq, irq_list[irq].devname); + + irq_list[irq].handler = (*mach_default_handler)[irq]; + irq_list[irq].flags = 0; + irq_list[irq].dev_id = NULL; + irq_list[irq].devname = NULL; +} + +/* + * Do we need these probe functions on the m68k? + * + * ... may be usefull with ISA devices + */ +unsigned long probe_irq_on (void) +{ + return 0; +} + +int probe_irq_off (unsigned long irqs) +{ + return 0; +} + +asmlinkage void process_int(unsigned long vec, struct pt_regs *fp) +{ + if (vec >= VEC_INT1 && vec <= VEC_INT7) { + vec -= VEC_SPUR; + kstat.irqs[0][vec]++; + irq_list[vec].handler(vec, irq_list[vec].dev_id, fp); + } else { + if (mach_process_int) + mach_process_int(vec, fp); + else + panic("Can't process interrupt vector %ld\n", vec); + return; + } +} + + +int show_interrupts(struct seq_file *p, void *v) +{ + int i; + + for (i = 0; i < NR_IRQS; i++) { + if (irq_list[i].flags & IRQ_FLG_STD) + continue; + + seq_printf(p, "%3d: %10u ", i, + (i ? kstat.irqs[0][i] : num_spurious)); + if (irq_list[i].flags & IRQ_FLG_LOCK) + seq_printf(p, "L "); + else + seq_printf(p, " "); + seq_printf(p, "%s\n", irq_list[i].devname); + } + + if (mach_get_irq_list) + mach_get_irq_list(p, v); + return(0); +} + +void init_irq_proc(void) +{ + /* Insert /proc/irq driver here */ +} + diff -Nru a/arch/m68knommu/kernel/m68k_ksyms.c b/arch/m68knommu/kernel/m68k_ksyms.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/kernel/m68k_ksyms.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void dump_thread(struct pt_regs *, struct user *); +extern int dump_fpu(elf_fpregset_t *); + +/* platform dependent support */ + +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(iounmap); +EXPORT_SYMBOL(dump_fpu); +EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(strrchr); +EXPORT_SYMBOL(strstr); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strncmp); + +EXPORT_SYMBOL(ip_fast_csum); + +EXPORT_SYMBOL(mach_enable_irq); +EXPORT_SYMBOL(mach_disable_irq); +EXPORT_SYMBOL(kernel_thread); + +/* Networking helper routines. */ +EXPORT_SYMBOL(csum_partial_copy); + +/* The following are special because they're not called + explicitly (the C compiler generates them). Fortunately, + their interface isn't gonna change any time soon now, so + it's OK to leave it out of version control. */ +EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL_NOVERS(memcmp); +EXPORT_SYMBOL_NOVERS(memscan); +EXPORT_SYMBOL_NOVERS(memmove); + +EXPORT_SYMBOL_NOVERS(__down_failed); +EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); +EXPORT_SYMBOL_NOVERS(__down_failed_trylock); +EXPORT_SYMBOL_NOVERS(__up_wakeup); + +EXPORT_SYMBOL(get_wchan); + +/* + * libgcc functions - functions that are used internally by the + * compiler... (prototypes are not correct though, but that + * doesn't really matter since they're not versioned). + */ +extern void __gcc_bcmp(void); +extern void __ashldi3(void); +extern void __ashrdi3(void); +extern void __cmpdi2(void); +extern void __divdi3(void); +extern void __divsi3(void); +extern void __lshrdi3(void); +extern void __moddi3(void); +extern void __modsi3(void); +extern void __muldi3(void); +extern void __mulsi3(void); +extern void __negdi2(void); +extern void __ucmpdi2(void); +extern void __udivdi3(void); +extern void __udivmoddi4(void); +extern void __udivsi3(void); +extern void __umoddi3(void); +extern void __umodsi3(void); + + /* gcc lib functions */ +EXPORT_SYMBOL_NOVERS(__gcc_bcmp); +EXPORT_SYMBOL_NOVERS(__ashldi3); +EXPORT_SYMBOL_NOVERS(__ashrdi3); +EXPORT_SYMBOL_NOVERS(__cmpdi2); +EXPORT_SYMBOL_NOVERS(__divdi3); +EXPORT_SYMBOL_NOVERS(__divsi3); +EXPORT_SYMBOL_NOVERS(__lshrdi3); +EXPORT_SYMBOL_NOVERS(__moddi3); +EXPORT_SYMBOL_NOVERS(__modsi3); +EXPORT_SYMBOL_NOVERS(__muldi3); +EXPORT_SYMBOL_NOVERS(__mulsi3); +EXPORT_SYMBOL_NOVERS(__negdi2); +EXPORT_SYMBOL_NOVERS(__ucmpdi2); +EXPORT_SYMBOL_NOVERS(__udivdi3); +EXPORT_SYMBOL_NOVERS(__udivmoddi4); +EXPORT_SYMBOL_NOVERS(__udivsi3); +EXPORT_SYMBOL_NOVERS(__umoddi3); +EXPORT_SYMBOL_NOVERS(__umodsi3); + +EXPORT_SYMBOL_NOVERS(is_in_rom); + +#ifdef CONFIG_COLDFIRE +extern unsigned int *dma_device_address; +extern unsigned long dma_base_addr, _ramend; +EXPORT_SYMBOL_NOVERS(dma_base_addr); +EXPORT_SYMBOL_NOVERS(dma_device_address); +EXPORT_SYMBOL_NOVERS(_ramend); + +extern asmlinkage void trap(void); +extern void *_ramvec; +EXPORT_SYMBOL_NOVERS(trap); +EXPORT_SYMBOL_NOVERS(_ramvec); +#endif /* CONFIG_COLDFIRE */ diff -Nru a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/kernel/process.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,450 @@ +/* + * linux/arch/m68knommu/kernel/process.c + * + * Copyright (C) 1995 Hamish Macdonald + * + * 68060 fixes by Jesper Skov + * + * uClinux changes + * Copyright (C) 2000-2002, David McCullough + */ + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +asmlinkage void ret_from_fork(void); + + +/* + * The idle loop on an m68knommu.. + */ +void default_idle(void) +{ + while(1) { + if (need_resched()) + __asm__("stop #0x2000" : : : "cc"); + schedule(); + } +} + +void (*idle)(void) = default_idle; + +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle(void) +{ + /* endless idle loop with no priority at all */ + idle(); +} + +void machine_restart(char * __unused) +{ + if (mach_reset) + mach_reset(); + for (;;); +} + +void machine_halt(void) +{ + if (mach_halt) + mach_halt(); + for (;;); +} + +void machine_power_off(void) +{ + if (mach_power_off) + mach_power_off(); + for (;;); +} + +void show_regs(struct pt_regs * regs) +{ + printk("\n"); + printk("Format %02x Vector: %04x PC: %08lx Status: %04x %s\n", + regs->format, regs->vector, regs->pc, regs->sr, print_tainted()); + printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n", + regs->orig_d0, regs->d0, regs->a2, regs->a1); + printk("A0: %08lx D5: %08lx D4: %08lx\n", + regs->a0, regs->d5, regs->d4); + printk("D3: %08lx D2: %08lx D1: %08lx\n", + regs->d3, regs->d2, regs->d1); + if (!(regs->sr & PS_S)) + printk("USP: %08lx\n", rdusp()); +} + +/* + * Create a kernel thread + */ +int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + long retval; + long clone_arg = flags | CLONE_VM; + mm_segment_t fs; + + fs = get_fs(); + set_fs(KERNEL_DS); + + __asm__ __volatile__ ( + "movel %%sp, %%d2\n\t" + "movel %5, %%d1\n\t" + "movel %1, %%d0\n\t" + "trap #0\n\t" + "cmpl %%sp, %%d2\n\t" + "jeq 1f\n\t" + "movel %3, %%sp@-\n\t" + "jsr %4@\n\t" + "movel %2, %%d0\n\t" + "trap #0\n" + "1:" + : "=d" (retval) + : "i" (__NR_clone), + "i" (__NR_exit), + "a" (arg), + "a" (fn), + "a" (clone_arg) + : "cc", "%d0", "%d1", "%d2"); + + set_fs(fs); + return retval; +} + +void flush_thread(void) +{ +#ifdef CONFIG_FPU + unsigned long zero = 0; +#endif + set_fs(USER_DS); + current->thread.fs = __USER_DS; +#ifdef CONFIG_FPU + if (!FPU_IS_EMU) + asm volatile (".chip 68k/68881\n\t" + "frestore %0@\n\t" + ".chip 68k" : : "a" (&zero)); +#endif +} + +/* + * "m68k_fork()".. By the time we get here, the + * non-volatile registers have also been saved on the + * stack. We do some ugly pointer stuff here.. (see + * also copy_thread) + */ + +asmlinkage int m68k_fork(struct pt_regs *regs) +{ + /* fork almost works, enough to trick you into looking elsewhere :-( */ + return(-EINVAL); +} + +asmlinkage int m68k_vfork(struct pt_regs *regs) +{ + struct task_struct *p; + p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL); + return IS_ERR(p) ? PTR_ERR(p) : p->pid; +} + +asmlinkage int m68k_clone(struct pt_regs *regs) +{ + unsigned long clone_flags; + unsigned long newsp; + struct task_struct *p; + + /* syscall2 puts clone_flags in d1 and usp in d2 */ + clone_flags = regs->d1; + newsp = regs->d2; + if (!newsp) + newsp = rdusp(); + p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, NULL); + return IS_ERR(p) ? PTR_ERR(p) : p->pid; +} + +int copy_thread(int nr, unsigned long clone_flags, + unsigned long usp, unsigned long topstk, + struct task_struct * p, struct pt_regs * regs) +{ + struct pt_regs * childregs; + struct switch_stack * childstack, *stack; + unsigned long stack_offset, *retp; + + stack_offset = KTHREAD_SIZE - sizeof(struct pt_regs); + childregs = (struct pt_regs *) ((unsigned long) p->thread_info + stack_offset); + + *childregs = *regs; + childregs->d0 = 0; + + retp = ((unsigned long *) regs); + stack = ((struct switch_stack *) retp) - 1; + + childstack = ((struct switch_stack *) childregs) - 1; + *childstack = *stack; + childstack->retpc = (unsigned long)ret_from_fork; + + p->thread.usp = usp; + p->thread.ksp = (unsigned long)childstack; + /* + * Must save the current SFC/DFC value, NOT the value when + * the parent was last descheduled - RGH 10-08-96 + */ + p->thread.fs = get_fs().seg; + +#ifdef CONFIG_FPU + if (!FPU_IS_EMU) { + /* Copy the current fpu state */ + asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); + + if (p->thread.fpstate[0]) + asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" + "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" + : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0]) + : "memory"); + /* Restore the state in case the fpu was busy */ + asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); + } +#endif + + return 0; +} + +/* Fill in the fpu structure for a core dump. */ + +int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu) +{ +#ifdef CONFIG_FPU + char fpustate[216]; + + if (FPU_IS_EMU) { + int i; + + memcpy(fpu->fpcntl, current->thread.fpcntl, 12); + memcpy(fpu->fpregs, current->thread.fp, 96); + /* Convert internal fpu reg representation + * into long double format + */ + for (i = 0; i < 24; i += 3) + fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | + ((fpu->fpregs[i] & 0x0000ffff) << 16); + return 1; + } + + /* First dump the fpu context to avoid protocol violation. */ + asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); + if (!fpustate[0]) + return 0; + + asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" + :: "m" (fpu->fpcntl[0]) + : "memory"); + asm volatile ("fmovemx %/fp0-%/fp7,%0" + :: "m" (fpu->fpregs[0]) + : "memory"); +#endif + return 1; +} + +/* + * fill in the user structure for a core dump.. + */ +void dump_thread(struct pt_regs * regs, struct user * dump) +{ + struct switch_stack *sw; + + /* changed the size calculations - should hopefully work better. lbt */ + dump->magic = CMAGIC; + dump->start_code = 0; + dump->start_stack = rdusp() & ~(PAGE_SIZE - 1); + dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; + dump->u_dsize = ((unsigned long) (current->mm->brk + + (PAGE_SIZE-1))) >> PAGE_SHIFT; + dump->u_dsize -= dump->u_tsize; + dump->u_ssize = 0; + + if (dump->start_stack < TASK_SIZE) + dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; + + dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump); + sw = ((struct switch_stack *)regs) - 1; + dump->regs.d1 = regs->d1; + dump->regs.d2 = regs->d2; + dump->regs.d3 = regs->d3; + dump->regs.d4 = regs->d4; + dump->regs.d5 = regs->d5; + dump->regs.d6 = sw->d6; + dump->regs.d7 = sw->d7; + dump->regs.a0 = regs->a0; + dump->regs.a1 = regs->a1; + dump->regs.a2 = regs->a2; + dump->regs.a3 = sw->a3; + dump->regs.a4 = sw->a4; + dump->regs.a5 = sw->a5; + dump->regs.a6 = sw->a6; + dump->regs.d0 = regs->d0; + dump->regs.orig_d0 = regs->orig_d0; + dump->regs.stkadj = regs->stkadj; + dump->regs.sr = regs->sr; + dump->regs.pc = regs->pc; + dump->regs.fmtvec = (regs->format << 12) | regs->vector; + /* dump floating point stuff */ + dump->u_fpvalid = dump_fpu (regs, &dump->m68kfp); +} + +/* + * Generic dumping code. Used for panic and debug. + */ +void dump(struct pt_regs *fp) +{ + unsigned long *sp; + unsigned char *tp; + int i; + + printk("\nCURRENT PROCESS:\n\n"); + printk("COMM=%s PID=%d\n", current->comm, current->pid); + + if (current->mm) { + printk("TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n", + (int) current->mm->start_code, + (int) current->mm->end_code, + (int) current->mm->start_data, + (int) current->mm->end_data, + (int) current->mm->end_data, + (int) current->mm->brk); + printk("USER-STACK=%08x KERNEL-STACK=%08x\n\n", + (int) current->mm->start_stack, + (int)(((unsigned long) current) + KTHREAD_SIZE)); + } + + printk("PC: %08lx\n", fp->pc); + printk("SR: %08lx SP: %08lx\n", (long) fp->sr, (long) fp); + printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", + fp->d0, fp->d1, fp->d2, fp->d3); + printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", + fp->d4, fp->d5, fp->a0, fp->a1); + printk("\nUSP: %08x TRAPFRAME: %08x\n", (unsigned int) rdusp(), + (unsigned int) fp); + + printk("\nCODE:"); + tp = ((unsigned char *) fp->pc) - 0x20; + for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { + if ((i % 0x10) == 0) + printk("\n%08x: ", (int) (tp + i)); + printk("%08x ", (int) *sp++); + } + printk("\n"); + + printk("\nKERNEL STACK:"); + tp = ((unsigned char *) fp) - 0x40; + for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { + if ((i % 0x10) == 0) + printk("\n%08x: ", (int) (tp + i)); + printk("%08x ", (int) *sp++); + } + printk("\n"); + printk("\n"); + + printk("\nUSER STACK:"); + tp = (unsigned char *) (rdusp() - 0x10); + for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) { + if ((i % 0x10) == 0) + printk("\n%08x: ", (int) (tp + i)); + printk("%08x ", (int) *sp++); + } + printk("\n\n"); +} + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(char *name, char **argv, char **envp) +{ + int error; + char * filename; + struct pt_regs *regs = (struct pt_regs *) &name; + + lock_kernel(); + filename = getname(name); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, argv, envp, regs); + putname(filename); +out: + unlock_kernel(); + return error; +} + +/* + * These bracket the sleeping functions.. + */ +extern void scheduling_functions_start_here(void); +extern void scheduling_functions_end_here(void); +#define first_sched ((unsigned long) scheduling_functions_start_here) +#define last_sched ((unsigned long) scheduling_functions_end_here) + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long fp, pc; + unsigned long stack_page; + int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + stack_page = (unsigned long)p; + fp = ((struct switch_stack *)p->thread.ksp)->a6; + do { + if (fp < stack_page+sizeof(struct task_struct) || + fp >= 8184+stack_page) + return 0; + pc = ((unsigned long *)fp)[1]; + /* FIXME: This depends on the order of these functions. */ + if (pc < first_sched || pc >= last_sched) + return pc; + fp = *(unsigned long *) fp; + } while (count++ < 16); + return 0; +} + +/* + * Return saved PC of a blocked thread. + */ +unsigned long thread_saved_pc(struct task_struct *tsk) +{ + extern void scheduling_functions_start_here(void); + extern void scheduling_functions_end_here(void); + struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp; + + /* Check whether the thread is blocked in resume() */ + if (sw->retpc > (unsigned long)scheduling_functions_start_here && + sw->retpc < (unsigned long)scheduling_functions_end_here) + return ((unsigned long *)sw->a6)[1]; + else + return sw->retpc; +} + diff -Nru a/arch/m68knommu/kernel/ptrace.c b/arch/m68knommu/kernel/ptrace.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/kernel/ptrace.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,392 @@ +/* + * linux/arch/m68knommu/kernel/ptrace.c + * + * Copyright (C) 1994 by Hamish Macdonald + * Taken from linux/kernel/ptrace.c and modified for M680x0. + * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of + * this archive for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +/* determines which bits in the SR the user has access to. */ +/* 1 = access 0 = no access */ +#define SR_MASK 0x001f + +/* sets the trace bits. */ +#define TRACE_BITS 0x8000 + +/* Find the stack offset for a register, relative to thread.esp0. */ +#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) +#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \ + - sizeof(struct switch_stack)) +/* Mapping from PT_xxx to the stack offset at which the register is + saved. Notice that usp has no stack-slot and needs to be treated + specially (see get_reg/put_reg below). */ +static int regoff[] = { + PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4), + PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0), + PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4), + SW_REG(a5), SW_REG(a6), PT_REG(d0), -1, + PT_REG(orig_d0), PT_REG(sr), PT_REG(pc), +}; + +/* + * Get contents of register REGNO in task TASK. + */ +static inline long get_reg(struct task_struct *task, int regno) +{ + unsigned long *addr; + + if (regno == PT_USP) + addr = &task->thread.usp; + else if (regno < sizeof(regoff)/sizeof(regoff[0])) + addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); + else + return 0; + return *addr; +} + +/* + * Write contents of register REGNO in task TASK. + */ +static inline int put_reg(struct task_struct *task, int regno, + unsigned long data) +{ + unsigned long *addr; + + if (regno == PT_USP) + addr = &task->thread.usp; + else if (regno < sizeof(regoff)/sizeof(regoff[0])) + addr = (unsigned long *) (task->thread.esp0 + regoff[regno]); + else + return -1; + *addr = data; + return 0; +} + +/* + * Called by kernel/ptrace.c when detaching.. + * + * Make sure the single step bit is not set. + */ +void ptrace_disable(struct task_struct *child) +{ + unsigned long tmp; + /* make sure the single step bit is not set. */ + tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); + put_reg(child, PT_SR, tmp); +} + +asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +{ + struct task_struct *child; + int ret; + + lock_kernel(); + ret = -EPERM; + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->ptrace & PT_PTRACED) + goto out; + /* set the ptrace bit in the process flags. */ + current->ptrace |= PT_PTRACED; + ret = 0; + goto out; + } + ret = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + goto out; + + ret = -EPERM; + if (pid == 1) /* you may not mess with init */ + goto out_tsk; + + if (request == PTRACE_ATTACH) { + ret = ptrace_attach(child); + goto out_tsk; + } + ret = -ESRCH; + if (!(child->ptrace & PT_PTRACED)) + goto out_tsk; + if (child->state != TASK_STOPPED) { + if (request != PTRACE_KILL) + goto out_tsk; + } + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) + goto out_tsk; + + switch (request) { + /* when I and D space are separate, these will need to be fixed. */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int copied; + + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + ret = -EIO; + if (copied != sizeof(tmp)) + break; + ret = put_user(tmp,(unsigned long *) data); + break; + } + + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: { + unsigned long tmp; + + ret = -EIO; + if ((addr & 3) || addr < 0 || + addr > sizeof(struct user) - 3) + break; + + tmp = 0; /* Default return condition */ + addr = addr >> 2; /* temporary hack. */ + ret = -EIO; + if (addr < 19) { + tmp = get_reg(child, addr); + if (addr == PT_SR) + tmp >>= 16; + } else if (addr >= 21 && addr < 49) { + tmp = child->thread.fp[addr - 21]; +#ifdef CONFIG_M68KFPU_EMU + /* Convert internal fpu reg representation + * into long double format + */ + if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) + tmp = ((tmp & 0xffff0000) << 15) | + ((tmp & 0x0000ffff) << 16); +#endif + } else if (addr == 49) { + tmp = child->mm->start_code; + } else if (addr == 50) { + tmp = child->mm->start_data; + } else if (addr == 51) { + tmp = child->mm->end_code; + } else + break; + ret = put_user(tmp,(unsigned long *) data); + break; + } + + /* when I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + ret = 0; + if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + break; + ret = -EIO; + break; + + case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + ret = -EIO; + if ((addr & 3) || addr < 0 || + addr > sizeof(struct user) - 3) + break; + + addr = addr >> 2; /* temporary hack. */ + + if (addr == PT_SR) { + data &= SR_MASK; + data <<= 16; + data |= get_reg(child, PT_SR) & ~(SR_MASK << 16); + } + if (addr < 19) { + if (put_reg(child, addr, data)) + break; + ret = 0; + break; + } + if (addr >= 21 && addr < 48) + { +#ifdef CONFIG_M68KFPU_EMU + /* Convert long double format + * into internal fpu reg representation + */ + if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) { + data = (unsigned long)data << 15; + data = (data & 0xffff0000) | + ((data & 0x0000ffff) >> 1); + } +#endif + child->thread.fp[addr - 21] = data; + ret = 0; + } + break; + + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: { /* restart after signal. */ + long tmp; + + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + if (request == PTRACE_SYSCALL) + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + else + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + child->exit_code = data; + /* make sure the single step bit is not set. */ + tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); + put_reg(child, PT_SR, tmp); + wake_up_process(child); + ret = 0; + break; + } + + /* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: { + long tmp; + + ret = 0; + if (child->state == TASK_ZOMBIE) /* already dead */ + break; + child->exit_code = SIGKILL; + /* make sure the single step bit is not set. */ + tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); + put_reg(child, PT_SR, tmp); + wake_up_process(child); + break; + } + + case PTRACE_SINGLESTEP: { /* set the trap flag. */ + long tmp; + + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16); + put_reg(child, PT_SR, tmp); + + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + } + + case PTRACE_DETACH: /* detach a process that was attached. */ + ret = ptrace_detach(child, data); + break; + + case PTRACE_GETREGS: { /* Get all gp regs from the child. */ + int i; + unsigned long tmp; + for (i = 0; i < 19; i++) { + tmp = get_reg(child, i); + if (i == PT_SR) + tmp >>= 16; + if (put_user(tmp, (unsigned long *) data)) { + ret = -EFAULT; + break; + } + data += sizeof(long); + } + ret = 0; + break; + } + + case PTRACE_SETREGS: { /* Set all gp regs in the child. */ + int i; + unsigned long tmp; + for (i = 0; i < 19; i++) { + if (get_user(tmp, (unsigned long *) data)) { + ret = -EFAULT; + break; + } + if (i == PT_SR) { + tmp &= SR_MASK; + tmp <<= 16; + tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16); + } + put_reg(child, i, tmp); + data += sizeof(long); + } + ret = 0; + break; + } + +#ifdef PTRACE_GETFPREGS + case PTRACE_GETFPREGS: { /* Get the child FPU state. */ + ret = 0; + if (copy_to_user((void *)data, &child->thread.fp, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + break; + } +#endif + +#ifdef PTRACE_SETFPREGS + case PTRACE_SETFPREGS: { /* Set the child FPU state. */ + ret = 0; + if (copy_from_user(&child->thread.fp, (void *)data, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + break; + } +#endif + + default: + ret = -EIO; + break; + } +out_tsk: + put_task_struct(child); +out: + unlock_kernel(); + return ret; +} + +asmlinkage void syscall_trace(void) +{ + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + if (!(current->ptrace & PT_PTRACED)) + return; + current->exit_code = SIGTRAP; + current->state = TASK_STOPPED; + notify_parent(current, SIGCHLD); + schedule(); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} diff -Nru a/arch/m68knommu/kernel/semaphore.c b/arch/m68knommu/kernel/semaphore.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/kernel/semaphore.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,133 @@ +/* + * Generic semaphore code. Buyer beware. Do your own + * specific changes in + */ + +#include +#include +#include +#include + +#ifndef CONFIG_RMW_INSNS +spinlock_t semaphore_wake_lock; +#endif + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to sleep, while the "waking" variable is + * incremented when the "up()" code goes to wake up waiting + * processes. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * + * When __up() is called, the count was negative before + * incrementing it, and we need to wake up somebody. + * + * This routine adds one to the count of processes that need to + * wake up and exit. ALL waiting processes actually wake up but + * only the one that gets to the "waking" field first will gate + * through and acquire the semaphore. The others will go back + * to sleep. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ +void __up(struct semaphore *sem) +{ + wake_one_more(sem); + wake_up(&sem->wait); +} + +/* + * Perform the "down" function. Return zero for semaphore acquired, + * return negative for signalled out of the function. + * + * If called from __down, the return is ignored and the wait loop is + * not interruptible. This means that a task waiting on a semaphore + * using "down()" cannot be killed until someone does an "up()" on + * the semaphore. + * + * If called from __down_interruptible, the return value gets checked + * upon return. If the return value is negative then the task continues + * with the negative value in the return register (it can be tested by + * the caller). + * + * Either form may be used in conjunction with "up()". + * + */ + + +#define DOWN_HEAD(task_state) \ + \ + \ + current->state = (task_state); \ + add_wait_queue(&sem->wait, &wait); \ + \ + /* \ + * Ok, we're set up. sem->count is known to be less than zero \ + * so we must wait. \ + * \ + * We can let go the lock for purposes of waiting. \ + * We re-acquire it after awaking so as to protect \ + * all semaphore operations. \ + * \ + * If "up()" is called before we call waking_non_zero() then \ + * we will catch it right away. If it is called later then \ + * we will have to go through a wakeup cycle to catch it. \ + * \ + * Multiple waiters contend for the semaphore lock to see \ + * who gets to gate through and who has to wait some more. \ + */ \ + for (;;) { + +#define DOWN_TAIL(task_state) \ + current->state = (task_state); \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __down(struct semaphore * sem) +{ + DECLARE_WAITQUEUE(wait, current); + + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __down_interruptible(struct semaphore * sem) +{ + DECLARE_WAITQUEUE(wait, current); + int ret = 0; + + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, current); + if (ret) + { + if (ret == 1) + /* ret != 0 only if we get interrupted -arca */ + ret = 0; + break; + } + schedule(); + DOWN_TAIL(TASK_INTERRUPTIBLE) + return ret; +} + +int __down_trylock(struct semaphore * sem) +{ + return waking_non_zero_trylock(sem); +} diff -Nru a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/kernel/setup.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,360 @@ +/* + * linux/arch/m68knommu/kernel/setup.c + * + * Copyright (C) 1999-2002 Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 1998,1999 D. Jeff Dionne + * Copyleft ()) 2000 James D. Schettine {james@telos-systems.com} + * Copyright (C) 1998 Kenneth Albanowski + * Copyright (C) 1995 Hamish Macdonald + * Copyright (C) 2000 Lineo Inc. (www.lineo.com) + * Copyright (C) 2001 Lineo, Inc. + * + * 68VZ328 Fixes/support Evan Stawnyczy + */ + +/* + * This file handles the architecture-dependent parts of system setup + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_BLK_DEV_INITRD +#include +#include +#endif + +#ifdef CONFIG_CONSOLE +extern struct consw *conswitchp; +#ifdef CONFIG_FRAMEBUFFER +extern struct consw fb_con; +#endif +#endif + +unsigned long rom_length; +unsigned long memory_start; +unsigned long memory_end; + +char command_line[512]; +char saved_command_line[512]; + +/* setup some dummy routines */ +static void dummy_waitbut(void) +{ +} + +void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) = NULL; +void (*mach_tick)( void ) = NULL; +/* machine dependent keyboard functions */ +int (*mach_keyb_init) (void) = NULL; +int (*mach_kbdrate) (struct kbd_repeat *) = NULL; +void (*mach_kbd_leds) (unsigned int) = NULL; +/* machine dependent irq functions */ +void (*mach_init_IRQ) (void) = NULL; +void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL; +int (*mach_request_irq) (unsigned int, void (*)(int, void *, struct pt_regs *), + unsigned long, const char *, void *); +void (*mach_free_irq) (unsigned int irq, void *dev_id) = NULL; +void (*mach_enable_irq) (unsigned int) = NULL; +void (*mach_disable_irq) (unsigned int) = NULL; +int (*mach_get_irq_list) (struct seq_file *, void *) = NULL; +void (*mach_process_int) (int irq, struct pt_regs *fp) = NULL; +void (*mach_trap_init) (void); +/* machine dependent timer functions */ +unsigned long (*mach_gettimeoffset) (void) = NULL; +void (*mach_gettod) (int*, int*, int*, int*, int*, int*) = NULL; +int (*mach_hwclk) (int, struct hwclk_time*) = NULL; +int (*mach_set_clock_mmss) (unsigned long) = NULL; +void (*mach_mksound)( unsigned int count, unsigned int ticks ) = NULL; +void (*mach_reset)( void ) = NULL; +void (*waitbut)(void) = dummy_waitbut; +void (*mach_debug_init)(void) = NULL; +void (*mach_halt)( void ) = NULL; +void (*mach_power_off)( void ) = NULL; + + +#ifdef CONFIG_M68000 + #define CPU "MC68000" +#endif +#ifdef CONFIG_M68328 + #define CPU "MC68328" +#endif +#ifdef CONFIG_M68EZ328 + #define CPU "MC68EZ328" +#endif +#ifdef CONFIG_M68VZ328 + #define CPU "MC68VZ328" +#endif +#ifdef CONFIG_M68332 + #define CPU "MC68332" +#endif +#ifdef CONFIG_M68360 + #define CPU "MC68360" +#endif +#if defined(CONFIG_M5206) + #define CPU "COLDFIRE(m5206)" +#endif +#if defined(CONFIG_M5206e) + #define CPU "COLDFIRE(m5206e)" +#endif +#if defined(CONFIG_M5249) + #define CPU "COLDFIRE(m5249)" +#endif +#if defined(CONFIG_M5272) + #define CPU "COLDFIRE(m5272)" +#endif +#if defined(CONFIG_M5307) + #define CPU "COLDFIRE(m5307)" +#endif +#if defined(CONFIG_M5407) + #define CPU "COLDFIRE(m5407)" +#endif +#ifndef CPU + #define CPU "UNKOWN" +#endif + +/* (es) */ +/* note: why is this defined here? the must be a better place to put this */ +#if defined( CONFIG_TELOS) || defined( CONFIG_UCDIMM ) || defined( CONFIG_UCSIMM ) || defined(CONFIG_DRAGEN2) || (defined( CONFIG_PILOT ) && defined( CONFIG_M68328 )) +#define CAT_ROMARRAY +#endif +/* (/es) */ + +extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end; +extern int _ramstart, _ramend; + +void setup_arch(char **cmdline_p) +{ + int bootmap_size; + +#if defined(CAT_ROMARRAY) && defined(DEBUG) + extern int __data_rom_start; + extern int __data_start; + int *romarray = (int *)((int) &__data_rom_start + + (int)&_edata - (int)&__data_start); +#endif + + memory_start = PAGE_ALIGN(_ramstart); + memory_end = _ramend; /* by now the stack is part of the init task */ + + init_mm.start_code = (unsigned long) &_stext; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) 0; + + config_BSP(&command_line[0], sizeof(command_line)); + + printk("\x0F\r\n\nuClinux/" CPU "\n"); + +#ifdef CONFIG_UCDIMM + printk("uCdimm by Lineo, Inc. \n"); +#endif +#ifdef CONFIG_M68VZ328 + printk("M68VZ328 support by Evan Stawnyczy \n"); +#endif +#ifdef CONFIG_COLDFIRE + printk("COLDFIRE port done by Greg Ungerer, gerg@snapgear.com\n"); +#ifdef CONFIG_M5307 + printk("Modified for M5307 by Dave Miller, dmiller@intellistor.com\n"); +#endif +#ifdef CONFIG_ELITE + printk("Modified for M5206eLITE by Rob Scott, rscott@mtrob.fdns.net\n"); +#endif +#ifdef CONFIG_TELOS + printk("Modified for Omnia ToolVox by James D. Schettine, james@telos-systems.com\n"); +#endif +#endif + printk("Flat model support (C) 1998,1999 Kenneth Albanowski, D. Jeff Dionne\n"); + +#if defined( CONFIG_PILOT ) && defined( CONFIG_M68328 ) + printk("TRG SuperPilot FLASH card support \n"); +#endif + +#if defined( CONFIG_PILOT ) && defined( CONFIG_M68EZ328 ) + printk("PalmV support by Lineo Inc. \n"); +#endif + +#ifdef CONFIG_M68EZ328ADS + printk("M68EZ328ADS board support (C) 1999 Vladimir Gurevich \n"); +#endif + +#ifdef CONFIG_ALMA_ANS + printk("Alma Electronics board support (C) 1999 Vladimir Gurevich \n"); +#endif +#if defined (CONFIG_M68360) + printk("QUICC port done by SED Systems ,\n"); + printk("based on 2.0.38 port by Lineo Inc. .\n"); +#endif +#ifdef CONFIG_DRAGEN2 + printk("Dragon Engine II board support by Georges Menie\n"); +#endif + +#ifdef DEBUG + printk("KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x " + "BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext, + (int) &_sdata, (int) &_edata, + (int) &_sbss, (int) &_ebss); + printk("KERNEL -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x " + "STACK=0x%06x-0x%06x\n", +#ifdef CAT_ROMARRAY + (int) romarray, ((int) romarray) + romarray[2], +#else + (int) &_ebss, (int) memory_start, +#endif + (int) memory_start, (int) memory_end, + (int) memory_end, (int) _ramend); +#endif + +#ifdef CONFIG_BLK_DEV_BLKMEM + ROOT_DEV = MKDEV(BLKMEM_MAJOR, 0); +#endif + + /* Keep a copy of command line */ + *cmdline_p = &command_line[0]; + memcpy(saved_command_line, command_line, sizeof(saved_command_line)); + saved_command_line[sizeof(saved_command_line)-1] = 0; + +#ifdef DEBUG + if (strlen(*cmdline_p)) + printk("Command line: '%s'\n", *cmdline_p); +#endif + +#ifdef CONFIG_CONSOLE +#ifdef CONFIG_FRAMEBUFFER + conswitchp = &fb_con; +#else + conswitchp = 0; +#endif +#endif + + /* + * Give all the memory to the bootmap allocator, tell it to put the + * boot mem_map at the start of memory. + */ + bootmap_size = init_bootmem_node( + NODE_DATA(0), + memory_start >> PAGE_SHIFT, /* map goes here */ + PAGE_OFFSET >> PAGE_SHIFT, /* 0 on coldfire */ + memory_end >> PAGE_SHIFT); + /* + * Free the usable memory, we have to make sure we do not free + * the bootmem bitmap so we then reserve it after freeing it :-) + */ + free_bootmem(memory_start, memory_end - memory_start); + reserve_bootmem(memory_start, bootmap_size); + + /* + * Get kmalloc into gear. + */ + paging_init(); +} + +int get_cpuinfo(char * buffer) +{ + char *cpu, *mmu, *fpu; + u_long clockfreq; + + cpu = CPU; + mmu = "none"; + fpu = "none"; + +#ifdef CONFIG_COLDFIRE + clockfreq = (loops_per_jiffy*HZ)*3; +#else + clockfreq = (loops_per_jiffy*HZ)*16; +#endif + + return(sprintf(buffer, "CPU:\t\t%s\n" + "MMU:\t\t%s\n" + "FPU:\t\t%s\n" + "Clocking:\t%lu.%1luMHz\n" + "BogoMips:\t%lu.%02lu\n" + "Calibration:\t%lu loops\n", + cpu, mmu, fpu, + clockfreq/1000000,(clockfreq/100000)%10, + (loops_per_jiffy*HZ)/500000,((loops_per_jiffy*HZ)/5000)%100, + (loops_per_jiffy*HZ))); + +} + +/* + * Get CPU information for use by the procfs. + */ + +static int show_cpuinfo(struct seq_file *m, void *v) +{ + char *cpu, *mmu, *fpu; + u_long clockfreq; + + cpu = CPU; + mmu = "none"; + fpu = "none"; + +#ifdef CONFIG_COLDFIRE + clockfreq = (loops_per_jiffy*HZ)*3; +#else + clockfreq = (loops_per_jiffy*HZ)*16; +#endif + + seq_printf(m, "CPU:\t\t%s\n" + "MMU:\t\t%s\n" + "FPU:\t\t%s\n" + "Clocking:\t%lu.%1luMHz\n" + "BogoMips:\t%lu.%02lu\n" + "Calibration:\t%lu loops\n", + cpu, mmu, fpu, + clockfreq/1000000,(clockfreq/100000)%10, + (loops_per_jiffy*HZ)/500000,((loops_per_jiffy*HZ)/5000)%100, + (loops_per_jiffy*HZ)); + + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return *pos < NR_CPUS ? ((void *) 0x12345678) : NULL; +} + +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return c_start(m, pos); +} + +static void c_stop(struct seq_file *m, void *v) +{ +} + +struct seq_operations cpuinfo_op = { + start: c_start, + next: c_next, + stop: c_stop, + show: show_cpuinfo, +}; + +void arch_gettod(int *year, int *mon, int *day, int *hour, + int *min, int *sec) +{ + if (mach_gettod) + mach_gettod(year, mon, day, hour, min, sec); + else + *year = *mon = *day = *hour = *min = *sec = 0; +} + diff -Nru a/arch/m68knommu/kernel/signal.c b/arch/m68knommu/kernel/signal.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/kernel/signal.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,886 @@ +/* + * linux/arch/m68knommu/kernel/signal.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +/* + * Linux/m68k support by Hamish Macdonald + * + * 68060 fixes by Jesper Skov + * + * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab + * + * mathemu support by Roman Zippel + * (Note: fpstate in the signal context is completly ignored for the emulator + * and the internal floating point format is put on stack) + */ + +/* + * ++roman (07/09/96): implemented signal stacks (specially for tosemu on + * Atari :-) Current limitation: Only one sigstack can be active at one time. + * If a second signal with SA_ONSTACK set arrives while working on a sigstack, + * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested + * signal handlers! + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +asmlinkage long sys_wait4(pid_t pid, unsigned int * stat_addr, int options, + struct rusage * ru); +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +asmlinkage int do_sigsuspend(struct pt_regs *regs) +{ + old_sigset_t mask = regs->d3; + sigset_t saveset; + + mask &= _BLOCKABLE; + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + + regs->d0 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + return -EINTR; + } +} + +asmlinkage int +do_rt_sigsuspend(struct pt_regs *regs) +{ + sigset_t *unewset = (sigset_t *)regs->d1; + size_t sigsetsize = (size_t)regs->d2; + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(); + + regs->d0 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + return -EINTR; + } +} + +asmlinkage int +sys_sigaction(int sig, const struct old_sigaction *act, + struct old_sigaction *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +asmlinkage int +sys_sigaltstack(const stack_t *uss, stack_t *uoss) +{ + return do_sigaltstack(uss, uoss, rdusp()); +} + + +/* + * Do a signal return; undo the signal stack. + * + * Keep the return code on the stack quadword aligned! + * That makes the cache flush below easier. + */ + +struct sigframe +{ + char *pretcode; + int sig; + int code; + struct sigcontext *psc; + char retcode[8]; + unsigned long extramask[_NSIG_WORDS-1]; + struct sigcontext sc; +}; + +struct rt_sigframe +{ + char *pretcode; + int sig; + struct siginfo *pinfo; + void *puc; + char retcode[8]; + struct siginfo info; + struct ucontext uc; +}; + +#ifdef CONFIG_FPU + +static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */ + +static inline int restore_fpu_state(struct sigcontext *sc) +{ + int err = 1; + + if (FPU_IS_EMU) { + /* restore registers */ + memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12); + memcpy(current->thread.fp, sc->sc_fpregs, 24); + return 0; + } + + if (sc->sc_fpstate[0]) { + /* Verify the frame format. */ + if (sc->sc_fpstate[0] != fpu_version) + goto out; + + __asm__ volatile (".chip 68k/68881\n\t" + "fmovemx %0,%/fp0-%/fp1\n\t" + "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t" + ".chip 68k" + : /* no outputs */ + : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl)); + } + __asm__ volatile (".chip 68k/68881\n\t" + "frestore %0\n\t" + ".chip 68k" : : "m" (*sc->sc_fpstate)); + err = 0; + +out: + return err; +} + +#define FPCONTEXT_SIZE 216 +#define uc_fpstate uc_filler[0] +#define uc_formatvec uc_filler[FPCONTEXT_SIZE/4] +#define uc_extra uc_filler[FPCONTEXT_SIZE/4+1] + +static inline int rt_restore_fpu_state(struct ucontext *uc) +{ + unsigned char fpstate[FPCONTEXT_SIZE]; + int context_size = 0; + fpregset_t fpregs; + int err = 1; + + if (FPU_IS_EMU) { + /* restore fpu control register */ + if (__copy_from_user(current->thread.fpcntl, + &uc->uc_mcontext.fpregs.f_pcr, 12)) + goto out; + /* restore all other fpu register */ + if (__copy_from_user(current->thread.fp, + uc->uc_mcontext.fpregs.f_fpregs, 96)) + goto out; + return 0; + } + + if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate)) + goto out; + if (fpstate[0]) { + context_size = fpstate[1]; + + /* Verify the frame format. */ + if (fpstate[0] != fpu_version) + goto out; + if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs, + sizeof(fpregs))) + goto out; + __asm__ volatile (".chip 68k/68881\n\t" + "fmovemx %0,%/fp0-%/fp7\n\t" + "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t" + ".chip 68k" + : /* no outputs */ + : "m" (*fpregs.f_fpregs), + "m" (fpregs.f_pcr)); + } + if (context_size && + __copy_from_user(fpstate + 4, (long *)&uc->uc_fpstate + 1, + context_size)) + goto out; + __asm__ volatile (".chip 68k/68881\n\t" + "frestore %0\n\t" + ".chip 68k" : : "m" (*fpstate)); + err = 0; + +out: + return err; +} + +#endif + +static inline int +restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp, + int *pd0) +{ + int formatvec; + struct sigcontext context; + int err = 0; + + /* get previous context */ + if (copy_from_user(&context, usc, sizeof(context))) + goto badframe; + + /* restore passed registers */ + regs->d1 = context.sc_d1; + regs->a0 = context.sc_a0; + regs->a1 = context.sc_a1; + regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff); + regs->pc = context.sc_pc; + regs->orig_d0 = -1; /* disable syscall checks */ + wrusp(context.sc_usp); + formatvec = context.sc_formatvec; + regs->format = formatvec >> 12; + regs->vector = formatvec & 0xfff; + +#ifdef CONFIG_FPU + err = restore_fpu_state(&context); +#endif + + *pd0 = context.sc_d0; + return err; + +badframe: + return 1; +} + +static inline int +rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, + struct ucontext *uc, int *pd0) +{ + int temp; + greg_t *gregs = uc->uc_mcontext.gregs; + unsigned long usp; + int err; + + err = __get_user(temp, &uc->uc_mcontext.version); + if (temp != MCONTEXT_VERSION) + goto badframe; + /* restore passed registers */ + err |= __get_user(regs->d0, &gregs[0]); + err |= __get_user(regs->d1, &gregs[1]); + err |= __get_user(regs->d2, &gregs[2]); + err |= __get_user(regs->d3, &gregs[3]); + err |= __get_user(regs->d4, &gregs[4]); + err |= __get_user(regs->d5, &gregs[5]); + err |= __get_user(sw->d6, &gregs[6]); + err |= __get_user(sw->d7, &gregs[7]); + err |= __get_user(regs->a0, &gregs[8]); + err |= __get_user(regs->a1, &gregs[9]); + err |= __get_user(regs->a2, &gregs[10]); + err |= __get_user(sw->a3, &gregs[11]); + err |= __get_user(sw->a4, &gregs[12]); + err |= __get_user(sw->a5, &gregs[13]); + err |= __get_user(sw->a6, &gregs[14]); + err |= __get_user(usp, &gregs[15]); + wrusp(usp); + err |= __get_user(regs->pc, &gregs[16]); + err |= __get_user(temp, &gregs[17]); + regs->sr = (regs->sr & 0xff00) | (temp & 0xff); + regs->orig_d0 = -1; /* disable syscall checks */ + regs->format = temp >> 12; + regs->vector = temp & 0xfff; + + if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) + goto badframe; + + *pd0 = regs->d0; + return err; + +badframe: + return 1; +} + +asmlinkage int do_sigreturn(unsigned long __unused) +{ + struct switch_stack *sw = (struct switch_stack *) &__unused; + struct pt_regs *regs = (struct pt_regs *) (sw + 1); + unsigned long usp = rdusp(); + struct sigframe *frame = (struct sigframe *)(usp - 4); + sigset_t set; + int d0; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__get_user(set.sig[0], &frame->sc.sc_mask) || + (_NSIG_WORDS > 1 && + __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + current->blocked = set; + recalc_sigpending(); + + if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0)) + goto badframe; + return d0; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +asmlinkage int do_rt_sigreturn(unsigned long __unused) +{ + struct switch_stack *sw = (struct switch_stack *) &__unused; + struct pt_regs *regs = (struct pt_regs *) (sw + 1); + unsigned long usp = rdusp(); + struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4); + sigset_t set; + int d0; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + current->blocked = set; + recalc_sigpending(); + + if (rt_restore_ucontext(regs, sw, &frame->uc, &d0)) + goto badframe; + return d0; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +#ifdef CONFIG_FPU +/* + * Set up a signal frame. + */ + +static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) +{ + if (FPU_IS_EMU) { + /* save registers */ + memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12); + memcpy(sc->sc_fpregs, current->thread.fp, 24); + return; + } + + __asm__ volatile (".chip 68k/68881\n\t" + "fsave %0\n\t" + ".chip 68k" + : : "m" (*sc->sc_fpstate) : "memory"); + + if (sc->sc_fpstate[0]) { + fpu_version = sc->sc_fpstate[0]; + __asm__ volatile (".chip 68k/68881\n\t" + "fmovemx %/fp0-%/fp1,%0\n\t" + "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t" + ".chip 68k" + : /* no outputs */ + : "m" (*sc->sc_fpregs), + "m" (*sc->sc_fpcntl) + : "memory"); + } +} + +static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs) +{ + unsigned char fpstate[FPCONTEXT_SIZE]; + int context_size = 0; + int err = 0; + + if (FPU_IS_EMU) { + /* save fpu control register */ + err |= copy_to_user(&uc->uc_mcontext.fpregs.f_pcr, + current->thread.fpcntl, 12); + /* save all other fpu register */ + err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs, + current->thread.fp, 96); + return err; + } + + __asm__ volatile (".chip 68k/68881\n\t" + "fsave %0\n\t" + ".chip 68k" + : : "m" (*fpstate) : "memory"); + + err |= __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate); + if (fpstate[0]) { + fpregset_t fpregs; + context_size = fpstate[1]; + fpu_version = fpstate[0]; + __asm__ volatile (".chip 68k/68881\n\t" + "fmovemx %/fp0-%/fp7,%0\n\t" + "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t" + ".chip 68k" + : /* no outputs */ + : "m" (*fpregs.f_fpregs), + "m" (fpregs.f_pcr) + : "memory"); + err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, + sizeof(fpregs)); + } + if (context_size) + err |= copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4, + context_size); + return err; +} + +#endif + +static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, + unsigned long mask) +{ + sc->sc_mask = mask; + sc->sc_usp = rdusp(); + sc->sc_d0 = regs->d0; + sc->sc_d1 = regs->d1; + sc->sc_a0 = regs->a0; + sc->sc_a1 = regs->a1; + sc->sc_sr = regs->sr; + sc->sc_pc = regs->pc; + sc->sc_formatvec = regs->format << 12 | regs->vector; +#ifdef CONFIG_FPU + save_fpu_state(sc, regs); +#endif +} + +static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs) +{ + struct switch_stack *sw = (struct switch_stack *)regs - 1; + greg_t *gregs = uc->uc_mcontext.gregs; + int err = 0; + + err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); + err |= __put_user(regs->d0, &gregs[0]); + err |= __put_user(regs->d1, &gregs[1]); + err |= __put_user(regs->d2, &gregs[2]); + err |= __put_user(regs->d3, &gregs[3]); + err |= __put_user(regs->d4, &gregs[4]); + err |= __put_user(regs->d5, &gregs[5]); + err |= __put_user(sw->d6, &gregs[6]); + err |= __put_user(sw->d7, &gregs[7]); + err |= __put_user(regs->a0, &gregs[8]); + err |= __put_user(regs->a1, &gregs[9]); + err |= __put_user(regs->a2, &gregs[10]); + err |= __put_user(sw->a3, &gregs[11]); + err |= __put_user(sw->a4, &gregs[12]); + err |= __put_user(sw->a5, &gregs[13]); + err |= __put_user(sw->a6, &gregs[14]); + err |= __put_user(rdusp(), &gregs[15]); + err |= __put_user(regs->pc, &gregs[16]); + err |= __put_user(regs->sr, &gregs[17]); +#ifdef CONFIG_FPU + err |= rt_save_fpu_state(uc, regs); +#endif + return err; +} + +static inline void push_cache (unsigned long vaddr) +{ +} + +static inline void * +get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) +{ + unsigned long usp; + + /* Default to using normal stack. */ + usp = rdusp(); + + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + if (!on_sig_stack(usp)) + usp = current->sas_ss_sp + current->sas_ss_size; + } + return (void *)((usp - frame_size) & -8UL); +} + +static void setup_frame (int sig, struct k_sigaction *ka, + sigset_t *set, struct pt_regs *regs) +{ + struct sigframe *frame; + struct sigcontext context; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + err |= __put_user((current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig), + &frame->sig); + + err |= __put_user(regs->vector, &frame->code); + err |= __put_user(&frame->sc, &frame->psc); + + if (_NSIG_WORDS > 1) + err |= copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + + setup_sigcontext(&context, regs, set->sig[0]); + err |= copy_to_user (&frame->sc, &context, sizeof(context)); + + /* Set up to return from userspace. */ + err |= __put_user(frame->retcode, &frame->pretcode); + /* moveq #,d0; trap #0 */ + err |= __put_user(0x70004e40 + (__NR_sigreturn << 16), + (long *)(frame->retcode)); + + if (err) + goto give_sigsegv; + + push_cache ((unsigned long) &frame->retcode); + + /* Set up registers for signal handler */ + wrusp ((unsigned long) frame); + regs->pc = (unsigned long) ka->sa.sa_handler; + +adjust_stack: + /* Prepare to skip over the extra stuff in the exception frame. */ + if (regs->stkadj) { + struct pt_regs *tregs = + (struct pt_regs *)((ulong)regs + regs->stkadj); +#if DEBUG + printk("Performing stackadjust=%04x\n", regs->stkadj); +#endif + /* This must be copied with decreasing addresses to + handle overlaps. */ + tregs->vector = 0; + tregs->format = 0; + tregs->pc = regs->pc; + tregs->sr = regs->sr; + } + return; + +give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); + goto adjust_stack; +} + +static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + struct rt_sigframe *frame; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + err |= __put_user((current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig), + &frame->sig); + err |= __put_user(&frame->info, &frame->pinfo); + err |= __put_user(&frame->uc, &frame->puc); + err |= copy_siginfo_to_user(&frame->info, info); + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user((void *)current->sas_ss_sp, + &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(rdusp()), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= rt_setup_ucontext(&frame->uc, regs); + err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); + + /* Set up to return from userspace. */ + err |= __put_user(frame->retcode, &frame->pretcode); + /* moveq #,d0; notb d0; trap #0 */ + err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16), + (long *)(frame->retcode + 0)); + err |= __put_user(0x4e40, (short *)(frame->retcode + 4)); + + if (err) + goto give_sigsegv; + + push_cache ((unsigned long) &frame->retcode); + + /* Set up registers for signal handler */ + wrusp ((unsigned long) frame); + regs->pc = (unsigned long) ka->sa.sa_handler; + +adjust_stack: + /* Prepare to skip over the extra stuff in the exception frame. */ + if (regs->stkadj) { + struct pt_regs *tregs = + (struct pt_regs *)((ulong)regs + regs->stkadj); +#if DEBUG + printk("Performing stackadjust=%04x\n", regs->stkadj); +#endif + /* This must be copied with decreasing addresses to + handle overlaps. */ + tregs->vector = 0; + tregs->format = 0; + tregs->pc = regs->pc; + tregs->sr = regs->sr; + } + return; + +give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); + goto adjust_stack; +} + +static inline void +handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) +{ + switch (regs->d0) { + case -ERESTARTNOHAND: + if (!has_handler) + goto do_restart; + regs->d0 = -EINTR; + break; + + case -ERESTARTSYS: + if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { + regs->d0 = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + do_restart: + regs->d0 = regs->orig_d0; + regs->pc -= 2; + break; + } +} + +/* + * OK, we're invoking a handler + */ +static void +handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *oldset, struct pt_regs *regs) +{ + /* are we from a system call? */ + if (regs->orig_d0 >= 0) + /* If so, check system call restarting.. */ + handle_restart(regs, ka, 1); + + /* set up the stack frame */ + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(sig, ka, info, oldset, regs); + else + setup_frame(sig, ka, oldset, regs); + + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked,sig); + recalc_sigpending(); +} + +/* + * Note that 'init' is a special process: it doesn't get signals it doesn't + * want to handle. Thus you cannot kill init even with a SIGKILL even by + * mistake. + * + * Note that we go through the signals twice: once to check the signals + * that the kernel can handle, and then we build all the user-level signal + * handling stack-frames in one go after that. + */ +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) +{ + siginfo_t info; + struct k_sigaction *ka; + + current->thread.esp0 = (unsigned long) regs; + + if (!oldset) + oldset = ¤t->blocked; + + for (;;) { + int signr; + + signr = get_signal_to_deliver(&info, regs); + + if (!signr) + break; + + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { + current->exit_code = signr; + current->state = TASK_STOPPED; + regs->sr &= ~PS_T; + + /* Did we come from a system call? */ + if (regs->orig_d0 >= 0) { + /* Restart the system call the same way as + if the process were not traced. */ + struct k_sigaction *ka = + ¤t->sig->action[signr-1]; + int has_handler = + (ka->sa.sa_handler != SIG_IGN && + ka->sa.sa_handler != SIG_DFL); + handle_restart(regs, ka, has_handler); + } + notify_parent(current, SIGCHLD); + schedule(); + + /* We're back. Did the debugger cancel the sig? */ + if (!(signr = current->exit_code)) { + discard_frame: + continue; + } + current->exit_code = 0; + + /* The debugger continued. Ignore SIGSTOP. */ + if (signr == SIGSTOP) + goto discard_frame; + + /* Update the siginfo structure. Is this good? */ + if (signr != info.si_signo) { + info.si_signo = signr; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->parent->pid; + info.si_uid = current->parent->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); + continue; + } + } + + ka = ¤t->sig->action[signr-1]; + if (ka->sa.sa_handler == SIG_IGN) { + if (signr != SIGCHLD) + continue; + /* Check for SIGCHLD: it's special. */ + while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) + /* nothing */; + continue; + } + + if (ka->sa.sa_handler == SIG_DFL) { + int exit_code = signr; + + if (current->pid == 1) + continue; + + switch (signr) { + case SIGCONT: case SIGCHLD: + case SIGWINCH: case SIGURG: + continue; + + case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (is_orphaned_pgrp(current->pgrp)) + continue; + /* FALLTHRU */ + + case SIGSTOP: + current->state = TASK_STOPPED; + current->exit_code = signr; + if (!(current->parent->sig->action[SIGCHLD-1] + .sa.sa_flags & SA_NOCLDSTOP)) + notify_parent(current, SIGCHLD); + schedule(); + continue; + + case SIGQUIT: case SIGILL: case SIGTRAP: + case SIGIOT: case SIGFPE: case SIGSEGV: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: + if (do_coredump(signr, regs)) + exit_code |= 0x80; + /* FALLTHRU */ + + default: + sigaddset(¤t->pending.signal, signr); + recalc_sigpending(); + current->flags |= PF_SIGNALED; + do_exit(exit_code); + /* NOTREACHED */ + } + } + + /* Whee! Actually deliver the signal. */ + handle_signal(signr, ka, &info, oldset, regs); + return 1; + } + + /* Did we come from a system call? */ + if (regs->orig_d0 >= 0) + /* Restart the system call - no handlers present */ + handle_restart(regs, NULL, 0); + + /* If we are about to discard some frame stuff we must copy + over the remaining frame. */ + if (regs->stkadj) { + struct pt_regs *tregs = + (struct pt_regs *) ((ulong) regs + regs->stkadj); + + /* This must be copied with decreasing addresses to + handle overlaps. */ + tregs->vector = 0; + tregs->format = 0; + tregs->pc = regs->pc; + tregs->sr = regs->sr; + } + return 0; +} diff -Nru a/arch/m68knommu/kernel/sys_m68k.c b/arch/m68knommu/kernel/sys_m68k.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/kernel/sys_m68k.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,215 @@ +/* + * linux/arch/m68knommu/kernel/sys_m68k.c + * + * This file contains various random system calls that + * have a non-standard calling sequence on the Linux/m68k + * platform. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way unix traditionally does this, though. + */ +asmlinkage int sys_pipe(unsigned long * fildes) +{ + int fd[2]; + int error; + + error = do_pipe(fd); + if (!error) { + if (copy_to_user(fildes, fd, 2*sizeof(int))) + error = -EFAULT; + } + return error; +} + +/* common code for old and new mmaps */ +static inline long do_mmap2( + unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + int error = -EBADF; + struct file * file = NULL; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + goto out; + } + + down_write(¤t->mm->mmap_sem); + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + up_write(¤t->mm->mmap_sem); + + if (file) + fput(file); +out: + return error; +} + +asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + return do_mmap2(addr, len, prot, flags, fd, pgoff); +} + +/* + * Perform the select(nd, in, out, ex, tv) and mmap() system + * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to + * handle more than 4 system call parameters, so these system calls + * used a memory block for parameter passing.. + */ + +struct mmap_arg_struct { + unsigned long addr; + unsigned long len; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; +}; + +asmlinkage int old_mmap(struct mmap_arg_struct *arg) +{ + struct mmap_arg_struct a; + int error = -EFAULT; + + if (copy_from_user(&a, arg, sizeof(a))) + goto out; + + error = -EINVAL; + if (a.offset & ~PAGE_MASK) + goto out; + + a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + + error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); +out: + return error; +} + +extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); + +struct sel_arg_struct { + unsigned long n; + fd_set *inp, *outp, *exp; + struct timeval *tvp; +}; + +asmlinkage int old_select(struct sel_arg_struct *arg) +{ + struct sel_arg_struct a; + + if (copy_from_user(&a, arg, sizeof(a))) + return -EFAULT; + /* sys_select() does the appropriate kernel locking */ + return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); +} + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. + */ +asmlinkage int sys_ipc (uint call, int first, int second, + int third, void *ptr, long fifth) +{ + int version; + + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + if (call <= SEMCTL) + switch (call) { + case SEMOP: + return sys_semop (first, (struct sembuf *)ptr, second); + case SEMGET: + return sys_semget (first, second, third); + case SEMCTL: { + union semun fourth; + if (!ptr) + return -EINVAL; + if (get_user(fourth.__pad, (void **) ptr)) + return -EFAULT; + return sys_semctl (first, second, third, fourth); + } + default: + return -EINVAL; + } + if (call <= MSGCTL) + switch (call) { + case MSGSND: + return sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; + if (!ptr) + return -EINVAL; + if (copy_from_user (&tmp, + (struct ipc_kludge *)ptr, + sizeof (tmp))) + return -EFAULT; + return sys_msgrcv (first, tmp.msgp, second, + tmp.msgtyp, third); + } + default: + return sys_msgrcv (first, + (struct msgbuf *) ptr, + second, fifth, third); + } + case MSGGET: + return sys_msgget ((key_t) first, second); + case MSGCTL: + return sys_msgctl (first, second, + (struct msqid_ds *) ptr); + default: + return -EINVAL; + } + + return -EINVAL; +} + +asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) +{ + return -ENOSYS; +} + + +/* sys_cacheflush -- flush (part of) the processor cache. */ +asmlinkage int +sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len) +{ + flush_cache_all(); + return(0); +} + +asmlinkage int sys_getpagesize(void) +{ + return PAGE_SIZE; +} + diff -Nru a/arch/m68knommu/kernel/syscalltable.S b/arch/m68knommu/kernel/syscalltable.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/kernel/syscalltable.S Mon Nov 4 14:31:03 2002 @@ -0,0 +1,279 @@ +/* + * linux/arch/m68knommu/kernel/syscalltable.S + * + * Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com) + * + * Based on older entry.S files, the following copyrights apply: + * + * Copyright (C) 1998 D. Jeff Dionne , + * Kenneth Albanowski , + * Copyright (C) 2000 Lineo Inc. (www.lineo.com) + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include + +.text +ALIGN +ENTRY(sys_call_table) + .long sys_ni_syscall /* 0 - old "setup()" system call*/ + .long sys_exit + .long sys_fork + .long sys_read + .long sys_write + .long sys_open /* 5 */ + .long sys_close + .long sys_waitpid + .long sys_creat + .long sys_link + .long sys_unlink /* 10 */ + .long sys_execve + .long sys_chdir + .long sys_time + .long sys_mknod + .long sys_chmod /* 15 */ + .long sys_chown16 + .long sys_ni_syscall /* old break syscall holder */ + .long sys_stat + .long sys_lseek + .long sys_getpid /* 20 */ + .long sys_mount + .long sys_oldumount + .long sys_setuid16 + .long sys_getuid16 + .long sys_stime /* 25 */ + .long sys_ptrace + .long sys_alarm + .long sys_fstat + .long sys_pause + .long sys_utime /* 30 */ + .long sys_ni_syscall /* old stty syscall holder */ + .long sys_ni_syscall /* old gtty syscall holder */ + .long sys_access + .long sys_nice + .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ + .long sys_sync + .long sys_kill + .long sys_rename + .long sys_mkdir + .long sys_rmdir /* 40 */ + .long sys_dup + .long sys_pipe + .long sys_times + .long sys_ni_syscall /* old prof syscall holder */ + .long sys_brk /* 45 */ + .long sys_setgid16 + .long sys_getgid16 + .long sys_signal + .long sys_geteuid16 + .long sys_getegid16 /* 50 */ + .long sys_acct + .long sys_umount /* recycled never used phys() */ + .long sys_ni_syscall /* old lock syscall holder */ + .long sys_ioctl + .long sys_fcntl /* 55 */ + .long sys_ni_syscall /* old mpx syscall holder */ + .long sys_setpgid + .long sys_ni_syscall /* old ulimit syscall holder */ + .long sys_ni_syscall + .long sys_umask /* 60 */ + .long sys_chroot + .long sys_ustat + .long sys_dup2 + .long sys_getppid + .long sys_getpgrp /* 65 */ + .long sys_setsid + .long sys_sigaction + .long sys_sgetmask + .long sys_ssetmask + .long sys_setreuid16 /* 70 */ + .long sys_setregid16 + .long sys_sigsuspend + .long sys_sigpending + .long sys_sethostname + .long sys_setrlimit /* 75 */ + .long sys_old_getrlimit + .long sys_getrusage + .long sys_gettimeofday + .long sys_settimeofday + .long sys_getgroups16 /* 80 */ + .long sys_setgroups16 + .long old_select + .long sys_symlink + .long sys_lstat + .long sys_readlink /* 85 */ + .long sys_uselib + .long sys_ni_syscall /* sys_swapon */ + .long sys_reboot + .long old_readdir + .long old_mmap /* 90 */ + .long sys_munmap + .long sys_truncate + .long sys_ftruncate + .long sys_fchmod + .long sys_fchown16 /* 95 */ + .long sys_getpriority + .long sys_setpriority + .long sys_ni_syscall /* old profil syscall holder */ + .long sys_statfs + .long sys_fstatfs /* 100 */ + .long sys_ioperm + .long sys_socketcall + .long sys_syslog + .long sys_setitimer + .long sys_getitimer /* 105 */ + .long sys_newstat + .long sys_newlstat + .long sys_newfstat + .long sys_ni_syscall + .long sys_ni_syscall /* iopl for i386 */ /* 110 */ + .long sys_vhangup + .long sys_ni_syscall /* obsolete idle() syscall */ + .long sys_ni_syscall /* vm86old for i386 */ + .long sys_wait4 + .long sys_ni_syscall /* 115 */ /* sys_swapoff */ + .long sys_sysinfo + .long sys_ipc + .long sys_fsync + .long sys_sigreturn + .long sys_clone /* 120 */ + .long sys_setdomainname + .long sys_newuname + .long sys_cacheflush /* modify_ldt for i386 */ + .long sys_adjtimex + .long sys_ni_syscall /* 125 */ /* sys_mprotect */ + .long sys_sigprocmask + .long sys_create_module + .long sys_init_module + .long sys_delete_module + .long sys_get_kernel_syms /* 130 */ + .long sys_quotactl + .long sys_getpgid + .long sys_fchdir + .long sys_bdflush + .long sys_sysfs /* 135 */ + .long sys_personality + .long sys_ni_syscall /* for afs_syscall */ + .long sys_setfsuid16 + .long sys_setfsgid16 + .long sys_llseek /* 140 */ + .long sys_getdents + .long sys_select + .long sys_flock + .long sys_ni_syscall /* sys_msync */ + .long sys_readv /* 145 */ + .long sys_writev + .long sys_getsid + .long sys_fdatasync + .long sys_sysctl + .long sys_ni_syscall /* 150 */ /* sys_mlock */ + .long sys_ni_syscall /* sys_munlock */ + .long sys_ni_syscall /* sys_mlockall */ + .long sys_ni_syscall /* sys_munlockall */ + .long sys_sched_setparam + .long sys_sched_getparam /* 155 */ + .long sys_sched_setscheduler + .long sys_sched_getscheduler + .long sys_sched_yield + .long sys_sched_get_priority_max + .long sys_sched_get_priority_min /* 160 */ + .long sys_sched_rr_get_interval + .long sys_nanosleep + .long sys_ni_syscall /* sys_mremap */ + .long sys_setresuid16 + .long sys_getresuid16 /* 165 */ + .long sys_ni_syscall /* for vm86 */ + .long sys_query_module + .long sys_poll + .long sys_ni_syscall /*sys_nfsservctl*/ + .long sys_setresgid16 /* 170 */ + .long sys_getresgid16 + .long sys_prctl + .long sys_rt_sigreturn + .long sys_rt_sigaction + .long sys_rt_sigprocmask /* 175 */ + .long sys_rt_sigpending + .long sys_rt_sigtimedwait + .long sys_rt_sigqueueinfo + .long sys_rt_sigsuspend + .long sys_pread64 /* 180 */ + .long sys_pwrite64 + .long sys_lchown16 + .long sys_getcwd + .long sys_capget + .long sys_capset /* 185 */ + .long sys_sigaltstack + .long sys_sendfile + .long sys_ni_syscall /* streams1 */ + .long sys_ni_syscall /* streams2 */ + .long sys_vfork /* 190 */ + .long sys_getrlimit + .long sys_mmap2 + .long sys_truncate64 + .long sys_ftruncate64 + .long sys_stat64 /* 195 */ + .long sys_lstat64 + .long sys_fstat64 + .long sys_chown + .long sys_getuid + .long sys_getgid /* 200 */ + .long sys_geteuid + .long sys_getegid + .long sys_setreuid + .long sys_setregid + .long sys_getgroups /* 205 */ + .long sys_setgroups + .long sys_fchown + .long sys_setresuid + .long sys_getresuid + .long sys_setresgid /* 210 */ + .long sys_getresgid + .long sys_lchown + .long sys_setuid + .long sys_setgid + .long sys_setfsuid /* 215 */ + .long sys_setfsgid + .long sys_pivot_root + .long sys_mincore + .long sys_ni_syscall /* sys_madvise */ + .long sys_getdents64 /* 220 */ + .long sys_fcntl64 + .long sys_ni_syscall /* reserved for TUX */ + .long sys_security /* reserved for Security */ + .long sys_gettid + .long sys_ni_syscall /* 225 */ /* sys_readahead */ + .long sys_setxattr + .long sys_lsetxattr + .long sys_fsetxattr + .long sys_getxattr + .long sys_lgetxattr /* 230 */ + .long sys_fgetxattr + .long sys_listxattr + .long sys_llistxattr + .long sys_flistxattr + .long sys_removexattr /* 235 */ + .long sys_lremovexattr + .long sys_fremovexattr + .long sys_tkill + .long sys_sendfile64 + .long sys_futex /* 240 */ + .long sys_sched_setaffinity + .long sys_sched_getaffinity + .long sys_ni_syscall /* sys_set_thread_area */ + .long sys_ni_syscall /* sys_get_thread_area */ + .long sys_io_setup /* 245 */ + .long sys_io_destroy + .long sys_io_getevents + .long sys_io_submit + .long sys_io_cancel + .long sys_ni_syscall /* 250 */ /* sys_alloc_hugepages */ + .long sys_ni_syscall /* sys_freec_hugepages */ + .long sys_exit_group + .long sys_lookup_dcookie + + .rept NR_syscalls-(.-sys_call_table)/4 + .long sys_ni_syscall + .endr + diff -Nru a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/kernel/time.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,178 @@ +/* + * linux/arch/m68knommu/kernel/time.c + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * + * This file contains the m68k-specific time handling details. + * Most of the stuff is located in the machine specific files. + * + * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 + * "A Kernel Model for Precision Timekeeping" by Dave Mills + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TICK_SIZE (tick_nsec / 1000) + +u64 jiffies_64; + +static inline int set_rtc_mmss(unsigned long nowtime) +{ + if (mach_set_clock_mmss) + return mach_set_clock_mmss (nowtime); + return -1; +} + +static inline void do_profile (unsigned long pc) +{ + if (prof_buffer && current->pid) { + extern int _stext; + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + if (pc < prof_len) + ++prof_buffer[pc]; + else + /* + * Don't ignore out-of-bounds PC values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + ++prof_buffer[prof_len-1]; + } +} + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + */ +static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs) +{ + /* last time the cmos clock got updated */ + static long last_rtc_update=0; + + /* may need to kick the hardware timer */ + if (mach_tick) + mach_tick(); + + do_timer(regs); + + if (!user_mode(regs)) + do_profile(regs->pc); + + /* + * If we have an externally synchronized Linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + */ + if ((time_status & STA_UNSYNC) == 0 && + xtime.tv_sec > last_rtc_update + 660 && + (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && + (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + } +#ifdef CONFIG_HEARTBEAT + /* use power LED as a heartbeat instead -- much more useful + for debugging -- based on the version for PReP by Cort */ + /* acts like an actual heart beat -- ie thump-thump-pause... */ + if (mach_heartbeat) { + static unsigned cnt = 0, period = 0, dist = 0; + + if (cnt == 0 || cnt == dist) + mach_heartbeat( 1 ); + else if (cnt == 7 || cnt == dist+7) + mach_heartbeat( 0 ); + + if (++cnt > period) { + cnt = 0; + /* The hyperbolic function below modifies the heartbeat period + * length in dependency of the current (5min) load. It goes + * through the points f(0)=126, f(1)=86, f(5)=51, + * f(inf)->30. */ + period = ((672<= 1000000) { + usec -= 1000000; + sec++; + } + + tv->tv_sec = sec; + tv->tv_usec = usec; +} + +void do_settimeofday(struct timeval *tv) +{ + write_lock_irq(&xtime_lock); + /* This is revolting. We need to set the xtime.tv_usec + * correctly. However, the value in this location is + * is value at the last tick. + * Discover what correction gettimeofday + * would have done, and then undo it! + */ + if (mach_gettimeoffset) + tv->tv_usec -= mach_gettimeoffset(); + + while (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + + xtime.tv_sec = tv->tv_sec; + xtime.tv_nsec = (tv->tv_usec * 1000); + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + write_unlock_irq(&xtime_lock); +} diff -Nru a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/kernel/traps.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,313 @@ +/* + * linux/arch/m68knommu/kernel/traps.c + * + * Copyright (C) 1993, 1994 by Hamish Macdonald + * + * 68040 fixes by Michael Rausch + * 68040 fixes by Martin Apel + * 68060 fixes by Roman Hodek + * 68060 fixes by Jesper Skov + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +/* + * Sets up all exception vectors + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static char *vec_names[] = { + "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR", + "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc", + "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111", + "UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION", + "FORMAT ERROR", "UNINITIALIZED INTERRUPT", + "UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17", + "UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19", + "UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21", + "UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23", + "SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT", + "LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT", + "SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3", + "TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7", + "TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11", + "TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15", + "FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW", + "FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN", + "FPCP UNSUPPORTED OPERATION", + "MMU CONFIGURATION ERROR" +}; + +void __init trap_init(void) +{ + if (mach_trap_init) + mach_trap_init(); +} + +void die_if_kernel(char *str, struct pt_regs *fp, int nr) +{ + if (!(fp->sr & PS_S)) + return; + + console_verbose(); + printk("%s: %08x\n",str,nr); + printk("PC: [<%08lx>]\nSR: %04x SP: %p a2: %08lx\n", + fp->pc, fp->sr, fp, fp->a2); + printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", + fp->d0, fp->d1, fp->d2, fp->d3); + printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", + fp->d4, fp->d5, fp->a0, fp->a1); + + printk("Process %s (pid: %d, stackpage=%08lx)\n", + current->comm, current->pid, PAGE_SIZE+(unsigned long)current); + show_stack((unsigned long *)fp); + do_exit(SIGSEGV); +} + +asmlinkage void buserr_c(struct frame *fp) +{ + /* Only set esp0 if coming from user mode */ + if (user_mode(&fp->ptregs)) + current->thread.esp0 = (unsigned long) fp; + +#if DEBUG + printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format); +#endif + + die_if_kernel("bad frame format",&fp->ptregs,0); +#if DEBUG + printk("Unknown SIGSEGV - 4\n"); +#endif + force_sig(SIGSEGV, current); +} + + +int kstack_depth_to_print = 48; + +void show_stack(unsigned long *esp) +{ + unsigned long *stack, *endstack, addr; + extern char _start, _etext; + int i; + + if (esp == NULL) + esp = (unsigned long *) &esp; + + stack = esp; + addr = (unsigned long) esp; + endstack = (unsigned long *) PAGE_ALIGN(addr); + + printk("Stack from %08lx:", (unsigned long)stack); + for (i = 0; i < kstack_depth_to_print; i++) { + if (stack + 1 > endstack) + break; + if (i % 8 == 0) + printk("\n "); + printk(" %08lx", *stack++); + } + + printk("\nCall Trace:"); + i = 0; + while (stack + 1 <= endstack) { + addr = *stack++; + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (((addr >= (unsigned long) &_start) && + (addr <= (unsigned long) &_etext))) { + if (i % 4 == 0) + printk("\n "); + printk(" [<%08lx>]", addr); + i++; + } + } + printk("\n"); +} + +void bad_super_trap(struct frame *fp) +{ + console_verbose(); + if (fp->ptregs.vector < 4*sizeof(vec_names)/sizeof(vec_names[0])) + printk ("*** %s *** FORMAT=%X\n", + vec_names[(fp->ptregs.vector) >> 2], + fp->ptregs.format); + else + printk ("*** Exception %d *** FORMAT=%X\n", + (fp->ptregs.vector) >> 2, + fp->ptregs.format); + printk ("Current process id is %d\n", current->pid); + die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); +} + +asmlinkage void trap_c(struct frame *fp) +{ + int sig; + siginfo_t info; + + if (fp->ptregs.sr & PS_S) { + if ((fp->ptregs.vector >> 2) == VEC_TRACE) { + /* traced a trapping instruction */ + current->ptrace |= PT_DTRACE; + } else + bad_super_trap(fp); + return; + } + + /* send the appropriate signal to the user program */ + switch ((fp->ptregs.vector) >> 2) { + case VEC_ADDRERR: + info.si_code = BUS_ADRALN; + sig = SIGBUS; + break; + case VEC_ILLEGAL: + case VEC_LINE10: + case VEC_LINE11: + info.si_code = ILL_ILLOPC; + sig = SIGILL; + break; + case VEC_PRIV: + info.si_code = ILL_PRVOPC; + sig = SIGILL; + break; + case VEC_COPROC: + info.si_code = ILL_COPROC; + sig = SIGILL; + break; + case VEC_TRAP1: /* gdbserver breakpoint */ + fp->ptregs.pc -= 2; + info.si_code = TRAP_TRACE; + sig = SIGTRAP; + break; + case VEC_TRAP2: + case VEC_TRAP3: + case VEC_TRAP4: + case VEC_TRAP5: + case VEC_TRAP6: + case VEC_TRAP7: + case VEC_TRAP8: + case VEC_TRAP9: + case VEC_TRAP10: + case VEC_TRAP11: + case VEC_TRAP12: + case VEC_TRAP13: + case VEC_TRAP14: + info.si_code = ILL_ILLTRP; + sig = SIGILL; + break; + case VEC_FPBRUC: + case VEC_FPOE: + case VEC_FPNAN: + info.si_code = FPE_FLTINV; + sig = SIGFPE; + break; + case VEC_FPIR: + info.si_code = FPE_FLTRES; + sig = SIGFPE; + break; + case VEC_FPDIVZ: + info.si_code = FPE_FLTDIV; + sig = SIGFPE; + break; + case VEC_FPUNDER: + info.si_code = FPE_FLTUND; + sig = SIGFPE; + break; + case VEC_FPOVER: + info.si_code = FPE_FLTOVF; + sig = SIGFPE; + break; + case VEC_ZERODIV: + info.si_code = FPE_INTDIV; + sig = SIGFPE; + break; + case VEC_CHK: + case VEC_TRAP: + info.si_code = FPE_INTOVF; + sig = SIGFPE; + break; + case VEC_TRACE: /* ptrace single step */ + info.si_code = TRAP_TRACE; + sig = SIGTRAP; + break; + case VEC_TRAP15: /* breakpoint */ + info.si_code = TRAP_BRKPT; + sig = SIGTRAP; + break; + default: + info.si_code = ILL_ILLOPC; + sig = SIGILL; + break; + } + info.si_signo = sig; + info.si_errno = 0; + switch (fp->ptregs.format) { + default: + info.si_addr = (void *) fp->ptregs.pc; + break; + case 2: + info.si_addr = (void *) fp->un.fmt2.iaddr; + break; + case 7: + info.si_addr = (void *) fp->un.fmt7.effaddr; + break; + case 9: + info.si_addr = (void *) fp->un.fmt9.iaddr; + break; + case 10: + info.si_addr = (void *) fp->un.fmta.daddr; + break; + case 11: + info.si_addr = (void *) fp->un.fmtb.daddr; + break; + } + force_sig_info (sig, &info, current); +} + +asmlinkage void set_esp0(unsigned long ssp) +{ + current->thread.esp0 = ssp; +} + +void show_trace_task(struct task_struct *tsk) +{ + printk("STACK ksp=0x%lx, usp=0x%lx\n", tsk->thread.ksp, tsk->thread.usp); +} + +#ifdef CONFIG_M68KFPU_EMU +asmlinkage void fpemu_signal(int signal, int code, void *addr) +{ + siginfo_t info; + + info.si_signo = signal; + info.si_errno = 0; + info.si_code = code; + info.si_addr = addr; + force_sig_info(signal, &info, current); +} +#endif diff -Nru a/arch/m68knommu/lib/Makefile b/arch/m68knommu/lib/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/lib/Makefile Mon Nov 4 14:31:04 2002 @@ -0,0 +1,10 @@ +# +# Makefile for m68knommu specific library files.. +# + +L_TARGET = lib.a +obj-y := ashldi3.o ashrdi3.o lshrdi3.o \ + muldi3.o mulsi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \ + checksum.o semaphore.o memcpy.o memset.o + +include $(TOPDIR)/Rules.make diff -Nru a/arch/m68knommu/lib/ashldi3.c b/arch/m68knommu/lib/ashldi3.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/lib/ashldi3.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,62 @@ +/* ashrdi3.c extracted from gcc-2.95.2/libgcc2.c which is: */ +/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC 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 GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define BITS_PER_UNIT 8 + +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef int word_type __attribute__ ((mode (__word__))); + +struct DIstruct {SItype high, low;}; + +typedef union +{ + struct DIstruct s; + DItype ll; +} DIunion; + +DItype +__ashldi3 (DItype u, word_type b) +{ + DIunion w; + word_type bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof (SItype) * BITS_PER_UNIT) - b; + if (bm <= 0) + { + w.s.low = 0; + w.s.high = (USItype)uu.s.low << -bm; + } + else + { + USItype carries = (USItype)uu.s.low >> bm; + w.s.low = (USItype)uu.s.low << b; + w.s.high = ((USItype)uu.s.high << b) | carries; + } + + return w.ll; +} diff -Nru a/arch/m68knommu/lib/ashrdi3.c b/arch/m68knommu/lib/ashrdi3.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/lib/ashrdi3.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,63 @@ +/* ashrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */ +/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC 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 GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define BITS_PER_UNIT 8 + +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef int word_type __attribute__ ((mode (__word__))); + +struct DIstruct {SItype high, low;}; + +typedef union +{ + struct DIstruct s; + DItype ll; +} DIunion; + +DItype +__ashrdi3 (DItype u, word_type b) +{ + DIunion w; + word_type bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof (SItype) * BITS_PER_UNIT) - b; + if (bm <= 0) + { + /* w.s.high = 1..1 or 0..0 */ + w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1); + w.s.low = uu.s.high >> -bm; + } + else + { + USItype carries = (USItype)uu.s.high << bm; + w.s.high = uu.s.high >> b; + w.s.low = ((USItype)uu.s.low >> b) | carries; + } + + return w.ll; +} diff -Nru a/arch/m68knommu/lib/checksum.c b/arch/m68knommu/lib/checksum.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/lib/checksum.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,156 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * IP/TCP/UDP checksumming routines + * + * Authors: Jorge Cwik, + * Arnt Gulbrandsen, + * Tom May, + * Andreas Schwab, + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek: + * Fixed some nasty bugs, causing some horrible crashes. + * A: At some points, the sum (%0) was used as + * length-counter instead of the length counter + * (%1). Thanks to Roman Hodek for pointing this out. + * B: GCC seems to mess up if one uses too many + * data-registers to hold input values and one tries to + * specify d0 and d1 as scratch registers. Letting gcc choose these + * registers itself solves the problem. + * + * 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. + */ + +/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access kills, so most + of the assembly has to go. */ + +#include + +static inline unsigned short from32to16(unsigned long x) +{ + /* add up 16-bit and 16-bit for 16+c bit */ + x = (x & 0xffff) + (x >> 16); + /* add up carry.. */ + x = (x & 0xffff) + (x >> 16); + return x; +} + +static unsigned long do_csum(const unsigned char * buff, int len) +{ + int odd, count; + unsigned long result = 0; + + if (len <= 0) + goto out; + odd = 1 & (unsigned long) buff; + if (odd) { + result = *buff; + len--; + buff++; + } + count = len >> 1; /* nr of 16-bit words.. */ + if (count) { + if (2 & (unsigned long) buff) { + result += *(unsigned short *) buff; + count--; + len -= 2; + buff += 2; + } + count >>= 1; /* nr of 32-bit words.. */ + if (count) { + unsigned long carry = 0; + do { + unsigned long w = *(unsigned long *) buff; + count--; + buff += 4; + result += carry; + result += w; + carry = (w > result); + } while (count); + result += carry; + result = (result & 0xffff) + (result >> 16); + } + if (len & 2) { + result += *(unsigned short *) buff; + buff += 2; + } + } + if (len & 1) + result += (*buff << 8); + result = from32to16(result); + if (odd) + result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); +out: + return result; +} + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + */ +unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl) +{ + return ~do_csum(iph,ihl*4); +} + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) +{ + unsigned int result = do_csum(buff, len); + + /* add in old sum, and carry.. */ + result += sum; + if (sum > result) + result += 1; + return result; +} + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ +unsigned short ip_compute_csum(const unsigned char * buff, int len) +{ + return ~do_csum(buff,len); +} + +/* + * copy from fs while checksumming, otherwise like csum_partial + */ + +unsigned int +csum_partial_copy_from_user(const char *src, char *dst, int len, int sum, int *csum_err) +{ + if (csum_err) *csum_err = 0; + memcpy(dst, src, len); + return csum_partial(dst, len, sum); +} + +/* + * copy from ds while checksumming, otherwise like csum_partial + */ + +unsigned int +csum_partial_copy(const char *src, char *dst, int len, int sum) +{ + memcpy(dst, src, len); + return csum_partial(dst, len, sum); +} diff -Nru a/arch/m68knommu/lib/divsi3.S b/arch/m68knommu/lib/divsi3.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/lib/divsi3.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,125 @@ +/* libgcc1 routines for 68000 w/o floating-point hardware. + Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +/* Use this one for any 680x0; assumes no floating point hardware. + The trailing " '" appearing on some lines is for ANSI preprocessors. Yuk. + Some of this code comes from MINIX, via the folks at ericsson. + D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992 +*/ + +/* These are predefined by new versions of GNU cpp. */ + +#ifndef __USER_LABEL_PREFIX__ +#define __USER_LABEL_PREFIX__ _ +#endif + +#ifndef __REGISTER_PREFIX__ +#define __REGISTER_PREFIX__ +#endif + +#ifndef __IMMEDIATE_PREFIX__ +#define __IMMEDIATE_PREFIX__ # +#endif + +/* ANSI concatenation macros. */ + +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +/* Use the right prefix for global labels. */ + +#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) + +/* Use the right prefix for registers. */ + +#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x) + +/* Use the right prefix for immediate values. */ + +#define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x) + +#define d0 REG (d0) +#define d1 REG (d1) +#define d2 REG (d2) +#define d3 REG (d3) +#define d4 REG (d4) +#define d5 REG (d5) +#define d6 REG (d6) +#define d7 REG (d7) +#define a0 REG (a0) +#define a1 REG (a1) +#define a2 REG (a2) +#define a3 REG (a3) +#define a4 REG (a4) +#define a5 REG (a5) +#define a6 REG (a6) +#define fp REG (fp) +#define sp REG (sp) + + .text + .proc + .globl SYM (__divsi3) +SYM (__divsi3): + movel d2, sp@- + + moveq IMM (1), d2 /* sign of result stored in d2 (=1 or =-1) */ + movel sp@(12), d1 /* d1 = divisor */ + jpl L1 + negl d1 +#ifndef __mcf5200__ + negb d2 /* change sign because divisor <0 */ +#else + negl d2 /* change sign because divisor <0 */ +#endif +L1: movel sp@(8), d0 /* d0 = dividend */ + jpl L2 + negl d0 +#ifndef __mcf5200__ + negb d2 +#else + negl d2 +#endif + +L2: movel d1, sp@- + movel d0, sp@- + jbsr SYM (__udivsi3) /* divide abs(dividend) by abs(divisor) */ + addql IMM (8), sp + + tstb d2 + jpl L3 + negl d0 + +L3: movel sp@+, d2 + rts + diff -Nru a/arch/m68knommu/lib/lshrdi3.c b/arch/m68knommu/lib/lshrdi3.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/lib/lshrdi3.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,62 @@ +/* lshrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */ +/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC 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 GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define BITS_PER_UNIT 8 + +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef int word_type __attribute__ ((mode (__word__))); + +struct DIstruct {SItype high, low;}; + +typedef union +{ + struct DIstruct s; + DItype ll; +} DIunion; + +DItype +__lshrdi3 (DItype u, word_type b) +{ + DIunion w; + word_type bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof (SItype) * BITS_PER_UNIT) - b; + if (bm <= 0) + { + w.s.high = 0; + w.s.low = (USItype)uu.s.high >> -bm; + } + else + { + USItype carries = (USItype)uu.s.high << bm; + w.s.high = (USItype)uu.s.high >> b; + w.s.low = ((USItype)uu.s.low >> b) | carries; + } + + return w.ll; +} diff -Nru a/arch/m68knommu/lib/memcpy.c b/arch/m68knommu/lib/memcpy.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/lib/memcpy.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,63 @@ + +#include +#include + +void * memcpy(void * to, const void * from, size_t n) +{ +#ifdef CONFIG_COLDFIRE + void *xto = to; + size_t temp; + + if (!n) + return xto; + if ((long) to & 1) + { + char *cto = to; + const char *cfrom = from; + *cto++ = *cfrom++; + to = cto; + from = cfrom; + n--; + } + if (n > 2 && (long) to & 2) + { + short *sto = to; + const short *sfrom = from; + *sto++ = *sfrom++; + to = sto; + from = sfrom; + n -= 2; + } + temp = n >> 2; + if (temp) + { + long *lto = to; + const long *lfrom = from; + for (; temp; temp--) + *lto++ = *lfrom++; + to = lto; + from = lfrom; + } + if (n & 2) + { + short *sto = to; + const short *sfrom = from; + *sto++ = *sfrom++; + to = sto; + from = sfrom; + } + if (n & 1) + { + char *cto = to; + const char *cfrom = from; + *cto = *cfrom; + } + return xto; +#else + const char *c_from = from; + char *c_to = to; + while (n-- > 0) + *c_to++ = *c_from++; + return((void *) to); +#endif +} diff -Nru a/arch/m68knommu/lib/memset.c b/arch/m68knommu/lib/memset.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/lib/memset.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,47 @@ +#include + +void * memset(void * s, int c, size_t count) +{ + void *xs = s; + size_t temp; + + if (!count) + return xs; + c &= 0xff; + c |= c << 8; + c |= c << 16; + if ((long) s & 1) + { + char *cs = s; + *cs++ = c; + s = cs; + count--; + } + if (count > 2 && (long) s & 2) + { + short *ss = s; + *ss++ = c; + s = ss; + count -= 2; + } + temp = count >> 2; + if (temp) + { + long *ls = s; + for (; temp; temp--) + *ls++ = c; + s = ls; + } + if (count & 2) + { + short *ss = s; + *ss++ = c; + s = ss; + } + if (count & 1) + { + char *cs = s; + *cs = c; + } + return xs; +} diff -Nru a/arch/m68knommu/lib/modsi3.S b/arch/m68knommu/lib/modsi3.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/lib/modsi3.S Mon Nov 4 14:31:03 2002 @@ -0,0 +1,113 @@ +/* libgcc1 routines for 68000 w/o floating-point hardware. + Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +/* Use this one for any 680x0; assumes no floating point hardware. + The trailing " '" appearing on some lines is for ANSI preprocessors. Yuk. + Some of this code comes from MINIX, via the folks at ericsson. + D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992 +*/ + +/* These are predefined by new versions of GNU cpp. */ + +#ifndef __USER_LABEL_PREFIX__ +#define __USER_LABEL_PREFIX__ _ +#endif + +#ifndef __REGISTER_PREFIX__ +#define __REGISTER_PREFIX__ +#endif + +#ifndef __IMMEDIATE_PREFIX__ +#define __IMMEDIATE_PREFIX__ # +#endif + +/* ANSI concatenation macros. */ + +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +/* Use the right prefix for global labels. */ + +#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) + +/* Use the right prefix for registers. */ + +#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x) + +/* Use the right prefix for immediate values. */ + +#define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x) + +#define d0 REG (d0) +#define d1 REG (d1) +#define d2 REG (d2) +#define d3 REG (d3) +#define d4 REG (d4) +#define d5 REG (d5) +#define d6 REG (d6) +#define d7 REG (d7) +#define a0 REG (a0) +#define a1 REG (a1) +#define a2 REG (a2) +#define a3 REG (a3) +#define a4 REG (a4) +#define a5 REG (a5) +#define a6 REG (a6) +#define fp REG (fp) +#define sp REG (sp) + + .text + .proc + .globl SYM (__modsi3) +SYM (__modsi3): + movel sp@(8), d1 /* d1 = divisor */ + movel sp@(4), d0 /* d0 = dividend */ + movel d1, sp@- + movel d0, sp@- + jbsr SYM (__divsi3) + addql IMM (8), sp + movel sp@(8), d1 /* d1 = divisor */ +#ifndef __mcf5200__ + movel d1, sp@- + movel d0, sp@- + jbsr SYM (__mulsi3) /* d0 = (a/b)*b */ + addql IMM (8), sp +#else + mulsl d1,d0 +#endif + movel sp@(4), d1 /* d1 = dividend */ + subl d0, d1 /* d1 = a - (a/b)*b */ + movel d1, d0 + rts + diff -Nru a/arch/m68knommu/lib/muldi3.c b/arch/m68knommu/lib/muldi3.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/lib/muldi3.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,86 @@ +/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and + gcc-2.7.2.3/longlong.h which is: */ +/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC 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 GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define BITS_PER_UNIT 8 +#define SI_TYPE_SIZE 32 + +#define __BITS4 (SI_TYPE_SIZE / 4) +#define __ll_B (1L << (SI_TYPE_SIZE / 2)) +#define __ll_lowpart(t) ((USItype) (t) % __ll_B) +#define __ll_highpart(t) ((USItype) (t) / __ll_B) + +#define umul_ppmm(w1, w0, u, v) \ + do { \ + USItype __x0, __x1, __x2, __x3; \ + USItype __ul, __vl, __uh, __vh; \ + \ + __ul = __ll_lowpart (u); \ + __uh = __ll_highpart (u); \ + __vl = __ll_lowpart (v); \ + __vh = __ll_highpart (v); \ + \ + __x0 = (USItype) __ul * __vl; \ + __x1 = (USItype) __ul * __vh; \ + __x2 = (USItype) __uh * __vl; \ + __x3 = (USItype) __uh * __vh; \ + \ + __x1 += __ll_highpart (__x0);/* this can't give carry */ \ + __x1 += __x2; /* but this indeed can */ \ + if (__x1 < __x2) /* did we get it? */ \ + __x3 += __ll_B; /* yes, add it in the proper pos. */ \ + \ + (w1) = __x3 + __ll_highpart (__x1); \ + (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \ + } while (0) + +#define __umulsidi3(u, v) \ + ({DIunion __w; \ + umul_ppmm (__w.s.high, __w.s.low, u, v); \ + __w.ll; }) + +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef int word_type __attribute__ ((mode (__word__))); + +struct DIstruct {SItype high, low;}; + +typedef union +{ + struct DIstruct s; + DItype ll; +} DIunion; + +DItype +__muldi3 (DItype u, DItype v) +{ + DIunion w; + DIunion uu, vv; + + uu.ll = u, + vv.ll = v; + + w.ll = __umulsidi3 (uu.s.low, vv.s.low); + w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high + + (USItype) uu.s.high * (USItype) vv.s.low); + + return w.ll; +} diff -Nru a/arch/m68knommu/lib/mulsi3.S b/arch/m68knommu/lib/mulsi3.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/lib/mulsi3.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,110 @@ +/* libgcc1 routines for 68000 w/o floating-point hardware. + Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +/* Use this one for any 680x0; assumes no floating point hardware. + The trailing " '" appearing on some lines is for ANSI preprocessors. Yuk. + Some of this code comes from MINIX, via the folks at ericsson. + D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992 +*/ + +/* These are predefined by new versions of GNU cpp. */ + +#ifndef __USER_LABEL_PREFIX__ +#define __USER_LABEL_PREFIX__ _ +#endif + +#ifndef __REGISTER_PREFIX__ +#define __REGISTER_PREFIX__ +#endif + +#ifndef __IMMEDIATE_PREFIX__ +#define __IMMEDIATE_PREFIX__ # +#endif + +/* ANSI concatenation macros. */ + +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +/* Use the right prefix for global labels. */ + +#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) + +/* Use the right prefix for registers. */ + +#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x) + +/* Use the right prefix for immediate values. */ + +#define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x) + +#define d0 REG (d0) +#define d1 REG (d1) +#define d2 REG (d2) +#define d3 REG (d3) +#define d4 REG (d4) +#define d5 REG (d5) +#define d6 REG (d6) +#define d7 REG (d7) +#define a0 REG (a0) +#define a1 REG (a1) +#define a2 REG (a2) +#define a3 REG (a3) +#define a4 REG (a4) +#define a5 REG (a5) +#define a6 REG (a6) +#define fp REG (fp) +#define sp REG (sp) + + .text + .proc + .globl SYM (__mulsi3) +SYM (__mulsi3): + movew sp@(4), d0 /* x0 -> d0 */ + muluw sp@(10), d0 /* x0*y1 */ + movew sp@(6), d1 /* x1 -> d1 */ + muluw sp@(8), d1 /* x1*y0 */ +#ifndef __mcf5200__ + addw d1, d0 +#else + addl d1, d0 +#endif + swap d0 + clrw d0 + movew sp@(6), d1 /* x1 -> d1 */ + muluw sp@(10), d1 /* x1*y1 */ + addl d1, d0 + + rts + diff -Nru a/arch/m68knommu/lib/semaphore.S b/arch/m68knommu/lib/semaphore.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/lib/semaphore.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,67 @@ +/* + * linux/arch/m68k/lib/semaphore.S + * + * Copyright (C) 1996 Linus Torvalds + * + * m68k version by Andreas Schwab + * + * MAR/1999 -- modified to support ColdFire (gerg@snapgear.com) + */ + +#include +#include +#include + +/* + * "down_failed" is called with the eventual return address + * in %a0, and the address of the semaphore in %a1. We need + * to increment the number of waiters on the semaphore, + * call "__down()", and then eventually return to try again. + */ +ENTRY(__down_failed) +#ifdef CONFIG_COLDFIRE + subl #12,%sp + moveml %a0/%d0/%d1,(%sp) +#else + moveml %a0/%d0/%d1,-(%sp) +#endif + movel %a1,-(%sp) + jbsr __down + movel (%sp)+,%a1 + movel (%sp)+,%d0 + movel (%sp)+,%d1 + rts + +ENTRY(__down_failed_interruptible) + movel %a0,-(%sp) + movel %d1,-(%sp) + movel %a1,-(%sp) + jbsr __down_interruptible + movel (%sp)+,%a1 + movel (%sp)+,%d1 + rts + +ENTRY(__up_wakeup) +#ifdef CONFIG_COLDFIRE + subl #12,%sp + moveml %a0/%d0/%d1,(%sp) +#else + moveml %a0/%d0/%d1,-(%sp) +#endif + movel %a1,-(%sp) + jbsr __up + movel (%sp)+,%a1 + movel (%sp)+,%d0 + movel (%sp)+,%d1 + rts + +ENTRY(__down_failed_trylock) + movel %a0,-(%sp) + movel %d1,-(%sp) + movel %a1,-(%sp) + jbsr __down_trylock + movel (%sp)+,%a1 + movel (%sp)+,%d1 + movel (%sp)+,%a0 + rts + diff -Nru a/arch/m68knommu/lib/udivsi3.S b/arch/m68knommu/lib/udivsi3.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/lib/udivsi3.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,162 @@ +/* libgcc1 routines for 68000 w/o floating-point hardware. + Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +/* Use this one for any 680x0; assumes no floating point hardware. + The trailing " '" appearing on some lines is for ANSI preprocessors. Yuk. + Some of this code comes from MINIX, via the folks at ericsson. + D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992 +*/ + +/* These are predefined by new versions of GNU cpp. */ + +#ifndef __USER_LABEL_PREFIX__ +#define __USER_LABEL_PREFIX__ _ +#endif + +#ifndef __REGISTER_PREFIX__ +#define __REGISTER_PREFIX__ +#endif + +#ifndef __IMMEDIATE_PREFIX__ +#define __IMMEDIATE_PREFIX__ # +#endif + +/* ANSI concatenation macros. */ + +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +/* Use the right prefix for global labels. */ + +#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) + +/* Use the right prefix for registers. */ + +#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x) + +/* Use the right prefix for immediate values. */ + +#define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x) + +#define d0 REG (d0) +#define d1 REG (d1) +#define d2 REG (d2) +#define d3 REG (d3) +#define d4 REG (d4) +#define d5 REG (d5) +#define d6 REG (d6) +#define d7 REG (d7) +#define a0 REG (a0) +#define a1 REG (a1) +#define a2 REG (a2) +#define a3 REG (a3) +#define a4 REG (a4) +#define a5 REG (a5) +#define a6 REG (a6) +#define fp REG (fp) +#define sp REG (sp) + + .text + .proc + .globl SYM (__udivsi3) +SYM (__udivsi3): +#ifndef __mcf5200__ + movel d2, sp@- + movel sp@(12), d1 /* d1 = divisor */ + movel sp@(8), d0 /* d0 = dividend */ + + cmpl IMM (0x10000), d1 /* divisor >= 2 ^ 16 ? */ + jcc L3 /* then try next algorithm */ + movel d0, d2 + clrw d2 + swap d2 + divu d1, d2 /* high quotient in lower word */ + movew d2, d0 /* save high quotient */ + swap d0 + movew sp@(10), d2 /* get low dividend + high rest */ + divu d1, d2 /* low quotient */ + movew d2, d0 + jra L6 + +L3: movel d1, d2 /* use d2 as divisor backup */ +L4: lsrl IMM (1), d1 /* shift divisor */ + lsrl IMM (1), d0 /* shift dividend */ + cmpl IMM (0x10000), d1 /* still divisor >= 2 ^ 16 ? */ + jcc L4 + divu d1, d0 /* now we have 16 bit divisor */ + andl IMM (0xffff), d0 /* mask out divisor, ignore remainder */ + +/* Multiply the 16 bit tentative quotient with the 32 bit divisor. Because of + the operand ranges, this might give a 33 bit product. If this product is + greater than the dividend, the tentative quotient was too large. */ + movel d2, d1 + mulu d0, d1 /* low part, 32 bits */ + swap d2 + mulu d0, d2 /* high part, at most 17 bits */ + swap d2 /* align high part with low part */ + tstw d2 /* high part 17 bits? */ + jne L5 /* if 17 bits, quotient was too large */ + addl d2, d1 /* add parts */ + jcs L5 /* if sum is 33 bits, quotient was too large */ + cmpl sp@(8), d1 /* compare the sum with the dividend */ + jls L6 /* if sum > dividend, quotient was too large */ +L5: subql IMM (1), d0 /* adjust quotient */ + +L6: movel sp@+, d2 + rts + +#else /* __mcf5200__ */ + +/* Coldfire implementation of non-restoring division algorithm from + Hennessy & Patterson, Appendix A. */ + link a6,IMM (-12) + moveml d2-d4,sp@ + movel a6@(8),d0 + movel a6@(12),d1 + clrl d2 | clear p + moveq IMM (31),d4 +L1: addl d0,d0 | shift reg pair (p,a) one bit left + addxl d2,d2 + movl d2,d3 | subtract b from p, store in tmp. + subl d1,d3 + jcs L2 | if no carry, + bset IMM (0),d0 | set the low order bit of a to 1, + movl d3,d2 | and store tmp in p. +L2: subql IMM (1),d4 + jcc L1 + moveml sp@,d2-d4 | restore data registers + unlk a6 | and return + rts +#endif /* __mcf5200__ */ + diff -Nru a/arch/m68knommu/lib/umodsi3.S b/arch/m68knommu/lib/umodsi3.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/lib/umodsi3.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,113 @@ +/* libgcc1 routines for 68000 w/o floating-point hardware. + Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +/* Use this one for any 680x0; assumes no floating point hardware. + The trailing " '" appearing on some lines is for ANSI preprocessors. Yuk. + Some of this code comes from MINIX, via the folks at ericsson. + D. V. Henkel-Wallace (gumby@cygnus.com) Fete Bastille, 1992 +*/ + +/* These are predefined by new versions of GNU cpp. */ + +#ifndef __USER_LABEL_PREFIX__ +#define __USER_LABEL_PREFIX__ _ +#endif + +#ifndef __REGISTER_PREFIX__ +#define __REGISTER_PREFIX__ +#endif + +#ifndef __IMMEDIATE_PREFIX__ +#define __IMMEDIATE_PREFIX__ # +#endif + +/* ANSI concatenation macros. */ + +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +/* Use the right prefix for global labels. */ + +#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) + +/* Use the right prefix for registers. */ + +#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x) + +/* Use the right prefix for immediate values. */ + +#define IMM(x) CONCAT1 (__IMMEDIATE_PREFIX__, x) + +#define d0 REG (d0) +#define d1 REG (d1) +#define d2 REG (d2) +#define d3 REG (d3) +#define d4 REG (d4) +#define d5 REG (d5) +#define d6 REG (d6) +#define d7 REG (d7) +#define a0 REG (a0) +#define a1 REG (a1) +#define a2 REG (a2) +#define a3 REG (a3) +#define a4 REG (a4) +#define a5 REG (a5) +#define a6 REG (a6) +#define fp REG (fp) +#define sp REG (sp) + + .text + .proc + .globl SYM (__umodsi3) +SYM (__umodsi3): + movel sp@(8), d1 /* d1 = divisor */ + movel sp@(4), d0 /* d0 = dividend */ + movel d1, sp@- + movel d0, sp@- + jbsr SYM (__udivsi3) + addql IMM (8), sp + movel sp@(8), d1 /* d1 = divisor */ +#ifndef __mcf5200__ + movel d1, sp@- + movel d0, sp@- + jbsr SYM (__mulsi3) /* d0 = (a/b)*b */ + addql IMM (8), sp +#else + mulsl d1,d0 +#endif + movel sp@(4), d1 /* d1 = dividend */ + subl d0, d1 /* d1 = a - (a/b)*b */ + movel d1, d0 + rts + diff -Nru a/arch/m68knommu/mm/Makefile b/arch/m68knommu/mm/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/mm/Makefile Mon Nov 4 14:31:04 2002 @@ -0,0 +1,7 @@ +# +# Makefile for the linux m68knommu specific parts of the memory manager. +# + +obj-y += init.o fault.o memory.o kmap.o + +include $(TOPDIR)/Rules.make diff -Nru a/arch/m68knommu/mm/fault.c b/arch/m68knommu/mm/fault.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/mm/fault.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,57 @@ +/* + * linux/arch/m68knommu/mm/fault.c + * + * Copyright (C) 1998 D. Jeff Dionne , + * Copyright (C) 2000 Lineo, Inc. (www.lineo.com) + * + * Based on: + * + * linux/arch/m68k/mm/fault.c + * + * Copyright (C) 1995 Hamish Macdonald + */ + +#include +#include +#include +#include + +#include +#include + +extern void die_if_kernel(char *, struct pt_regs *, long); + +/* + * This routine handles page faults. It determines the problem, and + * then passes it off to one of the appropriate routines. + * + * error_code: + * bit 0 == 0 means no page found, 1 means protection fault + * bit 1 == 0 means read, 1 means write + * + * If this routine detects a bad access, it returns 1, otherwise it + * returns 0. + */ +asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, + unsigned long error_code) +{ +#ifdef DEBUG + printk ("regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld\n", + regs->sr, regs->pc, address, error_code); +#endif + + /* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + if ((unsigned long) address < PAGE_SIZE) { + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + } else + printk(KERN_ALERT "Unable to handle kernel access"); + printk(" at virtual address %08lx\n",address); + die_if_kernel("Oops", regs, error_code); + do_exit(SIGKILL); + + return 1; +} + diff -Nru a/arch/m68knommu/mm/init.c b/arch/m68knommu/mm/init.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/mm/init.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,235 @@ +/* + * linux/arch/m68knommu/mm/init.c + * + * Copyright (C) 1998 D. Jeff Dionne , + * Kenneth Albanowski , + * Copyright (C) 2000 Lineo, Inc. (www.lineo.com) + * + * Based on: + * + * linux/arch/m68k/mm/init.c + * + * Copyright (C) 1995 Hamish Macdonald + * + * JAN/1999 -- hacked to support ColdFire (gerg@snapgear.com) + * DEC/2000 -- linux 2.4 support + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_RAM +#include +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG + +extern void die_if_kernel(char *,struct pt_regs *,long); +extern void free_initmem(void); + +/* + * BAD_PAGE is the page that is used for page faults when linux + * is out-of-memory. Older versions of linux just did a + * do_exit(), but using this instead means there is less risk + * for a process dying in kernel mode, possibly leaving a inode + * unused etc.. + * + * BAD_PAGETABLE is the accompanying page-table: it is initialized + * to point to BAD_PAGE entries. + * + * ZERO_PAGE is a special page that is used for zero-initialized + * data and COW. + */ +static unsigned long empty_bad_page_table; + +static unsigned long empty_bad_page; + +unsigned long empty_zero_page; + +extern unsigned long rom_length; + +void show_mem(void) +{ + unsigned long i; + int free = 0, total = 0, reserved = 0, shared = 0; + int cached = 0; + + printk("\nMem-info:\n"); + show_free_areas(); + i = max_mapnr; + while (i-- > 0) { + total++; + if (PageReserved(mem_map+i)) + reserved++; + else if (PageSwapCache(mem_map+i)) + cached++; + else if (!page_count(mem_map+i)) + free++; + else + shared += page_count(mem_map+i) - 1; + } + printk("%d pages of RAM\n",total); + printk("%d free pages\n",free); + printk("%d reserved pages\n",reserved); + printk("%d pages shared\n",shared); + printk("%d pages swap cached\n",cached); +} + +extern unsigned long memory_start; +extern unsigned long memory_end; + +/* + * paging_init() continues the virtual memory environment setup which + * was begun by the code in arch/head.S. + * The parameters are pointers to where to stick the starting and ending + * addresses of available kernel virtual memory. + */ +void paging_init(void) +{ + /* + * Make sure start_mem is page aligned, otherwise bootmem and + * page_alloc get different views of the world. + */ +#ifdef DEBUG + unsigned long start_mem = PAGE_ALIGN(memory_start); +#endif + unsigned long end_mem = memory_end & PAGE_MASK; + +#ifdef DEBUG + printk ("start_mem is %#lx\nvirtual_end is %#lx\n", + start_mem, end_mem); +#endif + + /* + * Initialize the bad page table and bad page to point + * to a couple of allocated pages. + */ + empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); + empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); + empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); + memset((void *)empty_zero_page, 0, PAGE_SIZE); + + /* + * Set up SFC/DFC registers (user data space). + */ + set_fs (USER_DS); + +#ifdef DEBUG + printk ("before free_area_init\n"); + + printk ("free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n", + start_mem, end_mem); +#endif + + { + unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; + + zones_size[ZONE_DMA] = 0 >> PAGE_SHIFT; + zones_size[ZONE_NORMAL] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT; +#ifdef CONFIG_HIGHMEM + zones_size[ZONE_HIGHMEM] = 0; +#endif + free_area_init(zones_size); + } +} + +void mem_init(void) +{ + int codek = 0, datak = 0, initk = 0; + unsigned long tmp; + extern char _etext, _stext, _sdata, _ebss, __init_begin, __init_end; + extern unsigned int _ramend, _rambase; + unsigned long len = _ramend - _rambase; + unsigned long start_mem = memory_start; /* DAVIDM - these must start at end of kernel */ + unsigned long end_mem = memory_end; /* DAVIDM - this must not include kernel stack at top */ + +#ifdef DEBUG + printk("Mem_init: start=%lx, end=%lx\n", start_mem, end_mem); +#endif + + end_mem &= PAGE_MASK; + high_memory = (void *) end_mem; + + start_mem = PAGE_ALIGN(start_mem); + max_mapnr = num_physpages = MAP_NR(high_memory); + + /* this will put all memory onto the freelists */ + totalram_pages = free_all_bootmem(); + + codek = (&_etext - &_stext) >> 10; + datak = (&_ebss - &_sdata) >> 10; + initk = (&__init_begin - &__init_end) >> 10; + + tmp = nr_free_pages() << PAGE_SHIFT; + printk("Memory available: %luk/%luk RAM, %luk/%luk ROM (%dk kernel code, %dk data)\n", + tmp >> 10, + len >> 10, + (rom_length > 0) ? ((rom_length >> 10) - codek) : 0, + rom_length >> 10, + codek, + datak + ); +} + + +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ + int pages = 0; + for (; start < end; start += PAGE_SIZE) { + ClearPageReserved(virt_to_page(start)); + set_page_count(virt_to_page(start), 1); + free_page(start); + totalram_pages++; + pages++; + } + printk ("Freeing initrd memory: %dk freed\n", pages); +} +#endif + +void +free_initmem() +{ +#ifdef CONFIG_RAMKERNEL + unsigned long addr; + extern char __init_begin, __init_end; + /* + * The following code should be cool even if these sections + * are not page aligned. + */ + addr = PAGE_ALIGN((unsigned long)(&__init_begin)); + /* next to check that the page we free is not a partial page */ + for (; addr + PAGE_SIZE < (unsigned long)(&__init_end); addr +=PAGE_SIZE) { + ClearPageReserved(virt_to_page(addr)); + set_page_count(virt_to_page(addr), 1); + free_page(addr); + totalram_pages++; + } + printk("Freeing unused kernel memory: %ldk freed (0x%x - 0x%x)\n", + (addr - PAGE_ALIGN((long) &__init_begin)) >> 10, + (int)(PAGE_ALIGN((unsigned long)(&__init_begin))), + (int)(addr - PAGE_SIZE)); +#endif +} + diff -Nru a/arch/m68knommu/mm/kmap.c b/arch/m68knommu/mm/kmap.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/mm/kmap.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,56 @@ +/* + * linux/arch/m68knommu/mm/kmap.c + * + * Copyright (C) 2000 Lineo, + * Copyright (C) 2000-2002 David McCullough + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#undef DEBUG + +/* + * Map some physical address range into the kernel address space. + */ +void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag) +{ + return (void *)physaddr; +} + +/* + * Unmap a ioremap()ed region again. + */ +void iounmap(void *addr) +{ +} + +/* + * __iounmap unmaps nearly everything, so be careful + * it doesn't free currently pointer/page tables anymore but it + * wans't used anyway and might be added later. + */ +void __iounmap(void *addr, unsigned long size) +{ +} + +/* + * Set new cache mode for some kernel address space. + * The caller must push data for that range itself, if such data may already + * be in the cache. + */ +void kernel_set_cachemode(void *addr, unsigned long size, int cmode) +{ +} diff -Nru a/arch/m68knommu/mm/memory.c b/arch/m68knommu/mm/memory.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/mm/memory.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,166 @@ +/* + * linux/arch/m68knommu/mm/memory.c + * + * Copyright (C) 1998 Kenneth Albanowski , + * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com) + * + * Based on: + * + * linux/arch/m68k/mm/memory.c + * + * Copyright (C) 1995 Hamish Macdonald + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * cache_clear() semantics: Clear any cache entries for the area in question, + * without writing back dirty entries first. This is useful if the data will + * be overwritten anyway, e.g. by DMA to memory. The range is defined by a + * _physical_ address. + */ + +void cache_clear (unsigned long paddr, int len) +{ +} + + +/* + * Define cache invalidate functions. The ColdFire 5407 is really + * the only processor that needs to do some work here. Anything + * that has separate data and instruction caches will be a problem. + */ +#ifdef CONFIG_M5407 + +static __inline__ void cache_invalidate_lines(unsigned long paddr, int len) +{ + unsigned long sset, eset; + + sset = (paddr & 0x00000ff0); + eset = ((paddr + len) & 0x0000ff0) + 0x10; + + __asm__ __volatile__ ( + "nop\n\t" + "clrl %%d0\n\t" + "1:\n\t" + "movel %0,%%a0\n\t" + "addl %%d0,%%a0\n\t" + "2:\n\t" + ".word 0xf4e8\n\t" + "addl #0x10,%%a0\n\t" + "cmpl %1,%%a0\n\t" + "blt 2b\n\t" + "addql #1,%%d0\n\t" + "cmpil #4,%%d0\n\t" + "bne 1b" + : : "a" (sset), "a" (eset) : "d0", "a0" ); +} + +#else +#define cache_invalidate_lines(a,b) +#endif + + +/* + * cache_push() semantics: Write back any dirty cache data in the given area, + * and invalidate the range in the instruction cache. It needs not (but may) + * invalidate those entries also in the data cache. The range is defined by a + * _physical_ address. + */ + +void cache_push (unsigned long paddr, int len) +{ + cache_invalidate_lines(paddr, len); +} + + +/* + * cache_push_v() semantics: Write back any dirty cache data in the given + * area, and invalidate those entries at least in the instruction cache. This + * is intended to be used after data has been written that can be executed as + * code later. The range is defined by a _user_mode_ _virtual_ address (or, + * more exactly, the space is defined by the %sfc/%dfc register.) + */ + +void cache_push_v (unsigned long vaddr, int len) +{ + cache_invalidate_lines(vaddr, len); +} + +/* Map some physical address range into the kernel address space. The + * code is copied and adapted from map_chunk(). + */ + +unsigned long kernel_map(unsigned long paddr, unsigned long size, + int nocacheflag, unsigned long *memavailp ) +{ + return paddr; +} + + +int is_in_rom(unsigned long addr) +{ + +#ifdef CONFIG_COLDFIRE + { + extern unsigned long _ramstart, _ramend; + + /* Anything not in operational RAM is returned as in rom! */ + if (addr < _ramstart || addr >= _ramend) + return(1); + } +#endif + +#if defined(CONFIG_PILOT) || defined(CONFIG_UCSIMM) + if (addr >= 0x10c00000) + return 1; +#endif + +#ifdef CONFIG_M68EZ328ADS + if ( 0x00200000 <= addr && addr < 0x00400000) + return 1; +#endif + +#ifdef CONFIG_M68332 + extern char _etext; + + #ifdef SHGLCORE_ROM_BANK_0_ADDR + if ((addr >= SHGLCORE_ROM_BANK_0_ADDR) && + (addr < (SHGLCORE_ROM_BANK_0_ADDR+SHGLCORE_ROM_BANK_0_LENGTH))) + return 1; + #endif + #ifdef SHGLCORE_ROM_BANK_1_ADDR + else if ((addr >= SHGLCORE_ROM_BANK_1_ADDR) && + (addr < (SHGLCORE_ROM_BANK_1_ADDR+SHGLCORE_ROM_BANK_1_LENGTH))) + return 1; + #endif + #ifdef SHGLCORE_FLASH_BANK_0_ADDR + else if ((addr >= SHGLCORE_FLASH_BANK_0_ADDR) && + (addr < (SHGLCORE_FLASH_BANK_0_ADDR+SHGLCORE_FLASH_BANK_0_LENGTH))) + return 1; + #endif + #ifdef SHGLCORE_FLASH_BANK_1_ADDR + else if ((addr >= SHGLCORE_FLASH_BANK_1_ADDR) && + (addr < (SHGLCORE_FLASH_BANK_1_ADDR+SHGLCORE_FLASH_BANK_1_LENGTH))) + return 1; + #endif +#endif + + /* Default case, not in ROM */ + return(0); +} + diff -Nru a/arch/m68knommu/platform/5206/ARNEWSH/crt0_ram.S b/arch/m68knommu/platform/5206/ARNEWSH/crt0_ram.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5206/ARNEWSH/crt0_ram.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,206 @@ +/*****************************************************************************/ + +/* + * crt0_ram.S -- startup code for MCF5206 ColdFire Arnewsh board. + * + * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com). + * + * 1999/02/24 Modified for the 5307 processor David W. Miller + */ + +/*****************************************************************************/ + +#include "linux/autoconf.h" +#include "asm/coldfire.h" +#include "asm/mcfsim.h" + +/*****************************************************************************/ + +/* + * Arnewsh m5206 ColdFire eval board, chip select and memory setup. + */ + +#define MEM_BASE 0x00000000 /* Memory base at address 0 */ +#define VBR_BASE MEM_BASE /* Vector address */ + +/* + * The following define the limits within which to search for + * available RAM. + */ +#define MEM_MIN 0x00100000 /* Search from 1Mb */ +#define MEM_MAX 0x02000000 /* Max DRAM 32Mb! */ +#define MEM_LUMP 0x00010000 /* 64 Kb chunks */ + +#define MEM_TMPSTACK 0x00010000 /* At 64k - for exceptions */ + +/* + * Chip Select setup. + */ +#define CS0_ADDR 0x0000f000 /* CS0 connected to Flash ROM */ +#define CS0_MASK 0xf0000000 /* is 1Mbyte */ +#define CS0_CTRL 0x00000000 /* read-only */ +#define CS1_ADDR 0x00000000 /* CS1 not connected */ +#define CS1_MASK 0x00000000 +#define CS1_CTRL 0x00000000 +#define CS2_ADDR 0x00003000 /* CS2 connected to SRAM */ +#define CS2_MASK 0x0000f000 /* is 1Mbyte */ +#define CS2_CTRL 0x00001903 /* read-write */ +#define CS3_ADDR 0x00004000 /* CS3 connected to LED, par port */ +#define CS3_MASK 0x0000f000 /* is 1Mbyte */ +#define CS3_CTRL 0x00000083 /* read-write */ +#define CS4_ADDR 0x00000000 /* CS4 not connected */ +#define CS4_MASK 0x00000000 +#define CS4_CTRL 0x00000123 +#define CS5_ADDR 0x00000000 /* CS5 not connected */ +#define CS5_MASK 0x00000000 +#define CS5_CTRL 0x00000000 +#define CS6_ADDR 0x00000000 /* CS6 not connected */ +#define CS6_MASK 0x00000000 +#define CS6_CTRL 0x00000000 +#define CS7_ADDR 0x00000000 /* CS7 not connected */ +#define CS7_MASK 0x00000000 +#define CS7_CTRL 0x00000000 +#define DMC_CTRL 0x00000000 /* default memory control */ + +/*****************************************************************************/ + +.global _start +.global _rambase +.global _ramvec +.global _ramstart +.global _ramend + +/*****************************************************************************/ + +.data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +_rambase: +.long 0 +_ramvec: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +/*****************************************************************************/ + +.text + +/* + * This is the codes first entry point. This is where it all + * begins... + */ + +_start: + nop /* Filler */ + move.w #0x2700, %sr /* No interrupts */ + + + /* + * Setup VBR here, otherwise buserror remap will not work. + * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996) + * + * bkr@cut.de 19990306 + * + * Note: this is because dBUG points VBR to ROM, making vectors read + * only, so the bus trap can't be changed. (RS) + */ + move.l #VBR_BASE, %a7 /* Note VBR can't be read */ + movec %a7, %VBR + move.l %a7, _ramvec /* Set up vector addr */ + move.l %a7, _rambase /* Set up base RAM addr */ + + + /* + * Determine size of RAM, then set up initial stack. + * + * On the Arnewsh 5206 board we can probe for the amount + * of DRAM present... + */ + move.l #MEM_MIN, %a0 /* Start at bottom */ + move.l #MEM_MAX, %a1 /* Set stop point */ + lea.l MEM_TMPSTACK, %sp /* Set up tmp stack ptr */ + + move.l #VBR_BASE+8, %a2 /* Address of bus trap */ + lea.l _ram_buserr, %a3 /* Get RAM trap address */ + move.l %a3, (%a2) /* Set trap to local ptr */ + +_find_ram: + move.l (%a0), %d0 /* Attempt read */ + add.l #MEM_LUMP, %a0 /* Try next bank */ + cmp.l %a1, %a0 /* Check more? */ + bne _find_ram + + /* + * BUS error trap handler - used for RAM probing. + */ +_ram_buserr: + bra _found_ram + +_found_ram: /* Vectored here on bus err */ + move.l %a0, %d0 /* Mem end addr is in a0 */ + move.l %d0, %sp /* Set up initial stack ptr */ + move.l %d0, _ramend /* Set end ram addr */ + + + /* + * Enable CPU internal cache. + */ + move.l #0x01000000, %d0 /* Invalidate cache cmd */ + movec %d0, %CACR /* Invalidate cache */ + move.l #0x80000100, %d0 /* Setup cache mask */ + movec %d0, %CACR /* Enable cache */ + + + /* + * Move ROM filesystem above bss :-) + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Set up destination */ + move.l %a0, %a2 /* Copy of bss start */ + + move.l 8(%a0), %d0 /* Get size of ROMFS */ + addq.l #8, %d0 /* Allow for rounding */ + and.l #0xfffffffc, %d0 /* Whole words */ + + add.l %d0, %a0 /* Copy from end */ + add.l %d0, %a1 /* Copy from end */ + move.l %a1, _ramstart /* Set start of ram */ + +_copy_romfs: + move.l -(%a0), %d0 /* Copy dword */ + move.l %d0, -(%a1) + cmp.l %a0, %a2 /* Check if at end */ + bne _copy_romfs + + /* + * Zero out the bss region. + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Get end of bss */ + clr.l %d0 /* Set value */ +_clear_bss: + move.l %d0, (%a0)+ /* Clear each word */ + cmp.l %a0, %a1 /* Check if at end */ + bne _clear_bss + + /* + * Load the current task pointer and stack. + */ + lea init_thread_union, %a0 + lea 0x2000(%a0), %sp + + /* + * Assember start up done, start code proper. + */ + jsr start_kernel /* Start Linux kernel */ + +_exit: + jmp _exit /* Should never get here */ + +/*****************************************************************************/ diff -Nru a/arch/m68knommu/platform/5206/ARNEWSH/ram.ld b/arch/m68knommu/platform/5206/ARNEWSH/ram.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5206/ARNEWSH/ram.ld Mon Nov 4 14:31:03 2002 @@ -0,0 +1,72 @@ + +MEMORY { + ram : ORIGIN = 0x10000, LENGTH = 0x200000 +} + +jiffies = jiffies_64 + 4; + +SECTIONS { + + .text : { + _stext = . ; + *(.text) + *(.exit.text) + *(.text.lock) + *(.exitcall.exit) + *(.rodata) + . = ALIGN(0x4) ; + *(.kstrtab) + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + *(__ksymtab) + __stop___ksymtab = .; + . = ALIGN(4) ; + _etext = . ; + } > ram + + .data BLOCK(0x4) : { + _sdata = . ; + __data_start = . ; + *(.data) + *(.data.exit) + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + _edata = . ; + } > ram + + .init BLOCK(4096) : { + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(4) ; + __init_end = .; + } > ram + + .bss BLOCK(0x4) : { + _sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN(4) ; + _ebss = . ; + _end = . ; + } > ram +} + diff -Nru a/arch/m68knommu/platform/5206/Makefile b/arch/m68knommu/platform/5206/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5206/Makefile Mon Nov 4 14:31:04 2002 @@ -0,0 +1,24 @@ +# +# Makefile for the m68knommu linux kernel. +# + +# +# If you want to play with the HW breakpoints then you will +# need to add define this, which will give you a stack backtrace +# on the console port whenever a DBG interrupt occurs. You have to +# set up you HW breakpoints to trigger a DBG interrupt: +# +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT +# + +ifdef CONFIG_FULLDEBUG +AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 +endif + +obj-y := config.o + +EXTRA_TARGETS := $(BOARD)/crt0_$(MODEL).o + +include $(TOPDIR)/Rules.make + diff -Nru a/arch/m68knommu/platform/5206/config.c b/arch/m68knommu/platform/5206/config.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5206/config.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,155 @@ +/***************************************************************************/ + +/* + * linux/arch/m68knommu/platform/5206/config.c + * + * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 2000-2001, Lineo Inc. (www.lineo.com) + */ + +/***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/***************************************************************************/ + +/* + * DMA channel base address table. + */ +unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { + MCF_MBAR + MCFDMA_BASE0, + MCF_MBAR + MCFDMA_BASE1, +}; + +unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; + +/***************************************************************************/ + +void coldfire_tick(void) +{ + volatile unsigned char *timerp; + + /* Reset the ColdFire timer */ + timerp = (volatile unsigned char *) (MCF_MBAR + MCFTIMER_BASE1); + timerp[MCFTIMER_TER] = MCFTIMER_TER_CAP | MCFTIMER_TER_REF; +} + +/***************************************************************************/ + +void coldfire_timer_init(void (*handler)(int, void *, struct pt_regs *)) +{ + volatile unsigned short *timerp; + volatile unsigned char *icrp; + + /* Set up TIMER 1 as poll clock */ + timerp = (volatile unsigned short *) (MCF_MBAR + MCFTIMER_BASE1); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_DISABLE; + + timerp[MCFTIMER_TRR] = (unsigned short) ((MCF_CLK / 16) / HZ); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | + MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE; + + icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_TIMER1ICR); + + *icrp = MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL5 | MCFSIM_ICR_PRI3; + request_irq(29, handler, SA_INTERRUPT, "ColdFire Timer", NULL); + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_TIMER1); +} + +/***************************************************************************/ + +/* + * Program the vector to be an auto-vectored. + */ + +void mcf_autovector(unsigned int vec) +{ + volatile unsigned char *mbar; + unsigned char icr; + + if ((vec >= 25) && (vec <= 31)) { + vec -= 25; + mbar = (volatile unsigned char *) MCF_MBAR; + icr = MCFSIM_ICR_AUTOVEC | (vec << 3); + *(mbar + MCFSIM_ICR1 + vec) = icr; + vec = 0x1 << (vec + 1); + mcf_setimr(mcf_getimr() & ~vec); + } +} + +/***************************************************************************/ + +extern e_vector *_ramvec; + +void set_evector(int vecnum, void (*handler)(void)) +{ + if (vecnum >= 0 && vecnum <= 255) + _ramvec[vecnum] = handler; +} + +/***************************************************************************/ + +/* assembler routines */ +asmlinkage void buserr(void); +asmlinkage void trap(void); +asmlinkage void system_call(void); +asmlinkage void inthandler(void); + +void coldfire_trap_init(void) +{ + int i; + +#ifndef ENABLE_dBUG + mcf_setimr(MCFSIM_IMR_MASKALL); +#endif + + /* + * There is a common trap handler and common interrupt + * handler that handle almost every vector. We treat + * the system call and bus error special, they get their + * own first level handlers. + */ +#ifndef ENABLE_dBUG + for (i = 3; (i <= 23); i++) + _ramvec[i] = trap; + for (i = 33; (i <= 63); i++) + _ramvec[i] = trap; +#endif + + for (i = 24; (i <= 30); i++) + _ramvec[i] = inthandler; +#ifndef ENABLE_dBUG + _ramvec[31] = inthandler; // Disables the IRQ7 button +#endif + + for (i = 64; (i < 255); i++) + _ramvec[i] = inthandler; + _ramvec[255] = 0; + + _ramvec[2] = buserr; + _ramvec[32] = system_call; +} + +/***************************************************************************/ + +void config_BSP(char *commandp, int size) +{ + memset(commandp, 0, size); + mach_sched_init = coldfire_timer_init; + mach_tick = coldfire_tick; + mach_trap_init = coldfire_trap_init; +} + +/***************************************************************************/ diff -Nru a/arch/m68knommu/platform/5206e/MOTOROLA/crt0_ram.S b/arch/m68knommu/platform/5206e/MOTOROLA/crt0_ram.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5206e/MOTOROLA/crt0_ram.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,145 @@ +/*****************************************************************************/ + +/* + * crt0_ram.S -- startup code for MCF5206e ColdFire based CADRE3 boards. + * + * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com) + * + * 1999/02/24 Modified for the 5307 processor David W. Miller + */ + +/*****************************************************************************/ + +#include "linux/autoconf.h" +#include "asm/coldfire.h" +#include "asm/mcfsim.h" + +/*****************************************************************************/ + +/* + * Cadre-III M5206e ColdFire eval board, chip select and memory setup. + */ + +#define MEM_BASE 0x00000000 /* Memory base at address 0 */ +#define MEM_SIZE 0x00400000 /* Memory size 4Mb */ +#define VBR_BASE MEM_BASE /* Vector address */ + +/*****************************************************************************/ + +.global _start +.global _rambase +.global _ramvec +.global _ramstart +.global _ramend + +/*****************************************************************************/ + +.data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +_rambase: +.long 0 +_ramvec: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +/*****************************************************************************/ + +.text + +/* + * This is the codes first entry point. This is where it all + * begins... + */ + +_start: + nop /* Filler */ + move.w #0x2700, %sr /* No interrupts */ + + /* + * Setup VBR here, otherwise buserror remap will not work. + * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996) + * + * bkr@cut.de 19990306 + * + * Note: this is because dBUG points VBR to ROM, making vectors read + * only, so the bus trap can't be changed. (RS) + */ + move.l #VBR_BASE, %a7 /* Note VBR can't be read */ + movec %a7, %VBR + move.l %a7, _ramvec /* Set up vector addr */ + move.l %a7, _rambase /* Set up base RAM addr */ + + + /* + * Set to 4 meg for the Cadre III board (m5206e). + */ + move.l #MEM_SIZE, %a0 + + move.l %a0, %d0 /* Mem end addr is in a0 */ + move.l %d0, %sp /* Set up initial stack ptr */ + move.l %d0, _ramend /* Set end ram addr */ + + + /* + * Enable CPU internal cache. + */ + move.l #0x01000000, %d0 /* Invalidate cache cmd */ + movec %d0, %CACR /* Invalidate cache */ + move.l #0x80000100, %d0 /* Setup cache mask */ + movec %d0, %CACR /* Enable cache */ + + + /* + * Move ROM filesystem above bss :-) + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Set up destination */ + move.l %a0, %a2 /* Copy of bss start */ + + move.l 8(%a0), %d0 /* Get size of ROMFS */ + addq.l #8, %d0 /* Allow for rounding */ + and.l #0xfffffffc, %d0 /* Whole words */ + + add.l %d0, %a0 /* Copy from end */ + add.l %d0, %a1 /* Copy from end */ + move.l %a1, _ramstart /* Set start of ram */ + +_copy_romfs: + move.l -(%a0), %d0 /* Copy dword */ + move.l %d0, -(%a1) + cmp.l %a0, %a2 /* Check if at end */ + bne _copy_romfs + + /* + * Zero out the bss region. + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Get end of bss */ + clr.l %d0 /* Set value */ +_clear_bss: + move.l %d0, (%a0)+ /* Clear each word */ + cmp.l %a0, %a1 /* Check if at end */ + bne _clear_bss + + /* + * Load the current task pointer and stack. + */ + lea init_thread_union, %a0 + lea 0x2000(%a0), %sp + + /* + * Assember start up done, start code proper. + */ + jsr start_kernel /* Start Linux kernel */ + +_exit: + jmp _exit /* Should never get here */ + +/*****************************************************************************/ diff -Nru a/arch/m68knommu/platform/5206e/MOTOROLA/ram.ld b/arch/m68knommu/platform/5206e/MOTOROLA/ram.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5206e/MOTOROLA/ram.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,72 @@ + +MEMORY { + ram : ORIGIN = 0x20000, LENGTH = 0x007E0000 +} + +jiffies = jiffies_64 + 4; + +SECTIONS { + + .text : { + _stext = . ; + *(.text) + *(.exit/text) + *(.text.lock) + *(.exitcall.exit) + *(.rodata) + . = ALIGN(0x4) ; + *(.kstrtab) + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + *(__ksymtab) + __stop___ksymtab = .; + . = ALIGN(4) ; + _etext = . ; + } > ram + + .data BLOCK(0x4) : { + _sdata = . ; + __data_start = . ; + *(.data) + *(.data.exit) + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + _edata = . ; + } > ram + + .init BLOCK(4096) : { + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(4) ; + __init_end = .; + } > ram + + .bss BLOCK(0x4) : { + _sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN(4) ; + _ebss = . ; + _end = . ; + } > ram +} + diff -Nru a/arch/m68knommu/platform/5206e/Makefile b/arch/m68knommu/platform/5206e/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5206e/Makefile Mon Nov 4 14:31:04 2002 @@ -0,0 +1,24 @@ +# +# Makefile for the m68knommu linux kernel. +# + +# +# If you want to play with the HW breakpoints then you will +# need to add define this, which will give you a stack backtrace +# on the console port whenever a DBG interrupt occurs. You have to +# set up you HW breakpoints to trigger a DBG interrupt: +# +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT +# + +ifdef CONFIG_FULLDEBUG +AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 +endif + +obj-y := config.o + +EXTRA_TARGETS := $(BOARD)/crt0_$(MODEL).o + +include $(TOPDIR)/Rules.make + diff -Nru a/arch/m68knommu/platform/5206e/config.c b/arch/m68knommu/platform/5206e/config.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5206e/config.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,233 @@ +/***************************************************************************/ + +/* + * linux/arch/m68knommu/platform/5206e/config.c + * + * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com) + */ + +/***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_NETtel +#include +#include +#endif + +/***************************************************************************/ + +#ifdef CONFIG_NETtel +void reset_setupbutton(void); +#endif + +/***************************************************************************/ + +/* + * DMA channel base address table. + */ +unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { + MCF_MBAR + MCFDMA_BASE0, + MCF_MBAR + MCFDMA_BASE1, +}; + +unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; + +/***************************************************************************/ + +void coldfire_tick(void) +{ + volatile unsigned char *timerp; + + /* Reset the ColdFire timer */ + timerp = (volatile unsigned char *) (MCF_MBAR + MCFTIMER_BASE1); + timerp[MCFTIMER_TER] = MCFTIMER_TER_CAP | MCFTIMER_TER_REF; +} + +/***************************************************************************/ + +void coldfire_timer_init(void (*handler)(int, void *, struct pt_regs *)) +{ + volatile unsigned short *timerp; + volatile unsigned char *icrp; + + /* Set up TIMER 1 as poll clock */ + timerp = (volatile unsigned short *) (MCF_MBAR + MCFTIMER_BASE1); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_DISABLE; + + timerp[MCFTIMER_TRR] = (unsigned short) ((MCF_CLK / 16) / HZ); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | + MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE; + + icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_TIMER1ICR); + +#ifdef CONFIG_NETtel + *icrp = MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3; + request_irq(30, handler, SA_INTERRUPT, "ColdFire Timer", NULL); + reset_setupbutton(); +#else + *icrp = MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL5 | MCFSIM_ICR_PRI3; + request_irq(29, handler, SA_INTERRUPT, "ColdFire Timer", NULL); +#endif + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_TIMER1); +} + +/***************************************************************************/ + +/* + * Program the vector to be an auto-vectored. + */ + +void mcf_autovector(unsigned int vec) +{ + volatile unsigned char *mbar; + unsigned char icr; + + if ((vec >= 25) && (vec <= 31)) { + vec -= 25; + mbar = (volatile unsigned char *) MCF_MBAR; + icr = MCFSIM_ICR_AUTOVEC | (vec << 3); + *(mbar + MCFSIM_ICR1 + vec) = icr; + vec = 0x1 << (vec + 1); + mcf_setimr(mcf_getimr() & ~vec); + } +} + +/***************************************************************************/ + +extern e_vector *_ramvec; + +void set_evector(int vecnum, void (*handler)(void)) +{ + if (vecnum >= 0 && vecnum <= 255) + _ramvec[vecnum] = handler; +} + +/***************************************************************************/ + +/* assembler routines */ +asmlinkage void buserr(void); +asmlinkage void trap(void); +asmlinkage void system_call(void); +asmlinkage void inthandler(void); + +void coldfire_trap_init(void) +{ + int i; +#ifdef MCF_MEMORY_PROTECT + extern unsigned long _end; + extern unsigned long memory_end; +#endif + +#ifndef ENABLE_dBUG + mcf_setimr(MCFSIM_IMR_MASKALL); +#endif + + /* + * There is a common trap handler and common interrupt + * handler that handle almost every vector. We treat + * the system call and bus error special, they get their + * own first level handlers. + */ +#ifndef ENABLE_dBUG + for (i = 3; (i <= 23); i++) + _ramvec[i] = trap; + for (i = 33; (i <= 63); i++) + _ramvec[i] = trap; +#endif + + for (i = 24; (i <= 30); i++) + _ramvec[i] = inthandler; +#ifndef ENABLE_dBUG + _ramvec[31] = inthandler; // Disables the IRQ7 button +#endif + + for (i = 64; (i < 255); i++) + _ramvec[i] = inthandler; + _ramvec[255] = 0; + + _ramvec[2] = buserr; + _ramvec[32] = system_call; +} + +/***************************************************************************/ + +#ifdef CONFIG_NETtel + +/* + * Routines to support the NETtel software reset button. + */ +void reset_button(int irq, void *dev_id, struct pt_regs *regs) +{ + extern void flash_eraseconfig(void); + static int inbutton = 0; + + /* + * IRQ7 is not maskable by the CPU core. It is possible + * that switch bounce may get us back here before we have + * really serviced the interrupt. + */ + if (inbutton) + return; + inbutton = 1; + /* Disable interrupt at SIM - best we can do... */ + mcf_setimr(mcf_getimr() | MCFSIM_IMR_EINT7); + /* Try and de-bounce the switch a little... */ + udelay(10000); + + flash_eraseconfig(); + + /* Don't leave here 'till button is no longer pushed! */ + for (;;) { + if ((mcf_getipr() & MCFSIM_IMR_EINT7) == 0) + break; + } + + HARD_RESET_NOW(); + /* Should never get here... */ + + inbutton = 0; + /* Interrupt service done, enable it again */ + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_EINT7); +} + +/***************************************************************************/ + +void reset_setupbutton(void) +{ + mcf_autovector(31); + request_irq(31, reset_button, (SA_INTERRUPT | IRQ_FLG_FAST), + "Reset Button", NULL); +} + +#endif /* CONFIG_NETtel */ + +/***************************************************************************/ + +void config_BSP(char *commandp, int size) +{ +#ifdef CONFIG_NETtel + /* Copy command line from FLASH to local buffer... */ + memcpy(commandp, (char *) 0xf0004000, size); + commandp[size-1] = 0; +#else + memset(commandp, 0, size); +#endif /* CONFIG_NETtel */ + + mach_sched_init = coldfire_timer_init; + mach_tick = coldfire_tick; + mach_trap_init = coldfire_trap_init; +} + +/***************************************************************************/ diff -Nru a/arch/m68knommu/platform/5206e/eLITE/crt0_ram.S b/arch/m68knommu/platform/5206e/eLITE/crt0_ram.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5206e/eLITE/crt0_ram.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,339 @@ +/*****************************************************************************/ + +/* + * crt0_ram.S -- startup code for MCF5206e ColdFire based eLITE boards. + * + * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com). + * Copyright (C) 1999 Rob Scott (rscott@mtrob.fdns.net) + * + * 1999/02/24 Modified for the 5307 processor David W. Miller + */ + +/*****************************************************************************/ + +#include "linux/autoconf.h" +#include "asm/coldfire.h" +#include "asm/mcfsim.h" + +/*****************************************************************************/ + +/* + * M5206eLITE ColdFire eval board, chip select and memory setup. + */ + +#ifdef CONFIG_SMALL +#define MEM_BASE 0x30000000 /* Base memory for M5206eLITE */ +#define MEM_RESERVED 0x00020000 /* Don't use memory reserved by dBUG */ +#define MEM_SIZE 0x00100000 /* 1 MB of SRAM on M5206eLITE */ +#else +#define MEM_BASE 0x00000000 /* Base memory for M5206eLITE */ +#define MEM_RESERVED 0x00010000 /* Skip first MEM_LUMP for colilo */ +#define MEM_SIZE 0x02000000 /* Max DRAM 32Mb */ +#endif +#define MEM_MIN MEM_BASE+MEM_RESERVED +/* Define end of probeable memory space */ +#define MEM_MAX MEM_BASE+MEM_SIZE +#define MEM_BUILTIN 0x20000000 /* Put built in SRAM at dBUG loc */ +#define MEM_TMPSTACK MEM_BUILTIN+0x800 /* Use built in SRAM for tmp stack */ +#define MEM_LUMP 0x00010000 /* 64 Kb chunks */ +#define VBR_BASE MEM_BUILTIN /* Use built in SRAM for vectors */ + +#define CS0_ADDR 0x0000ffe0 /* CS0 connected to Flash ROM */ +#define CS0_MASK 0x000f0000 /* is 1Mbyte */ +#define CS0_CTRL 0x00001da3 /* read-write (for flash) */ +#define CS1_ADDR 0x00000000 /* CS1 not connected */ +#define CS1_MASK 0x00000000 +#define CS1_CTRL 0x00000000 +#define CS2_ADDR 0x00003000 /* CS2 connected to SRAM */ +#define CS2_MASK 0x000f0000 /* is 1Mbyte */ +#define CS2_CTRL 0x00001903 /* read-write */ +#define CS3_ADDR 0x00004000 /* CS3 connected to LED, par port */ +#define CS3_MASK 0x000f0000 /* is 1Mbyte */ +#define CS3_CTRL 0x00000183 /* read-write */ +#define CS4_ADDR 0x00000000 /* CS4 not connected */ +#define CS4_MASK 0x00000000 +#define CS4_CTRL 0x00000000 +#define CS5_ADDR 0x00000000 /* CS5 not connected */ +#define CS5_MASK 0x00000000 +#define CS5_CTRL 0x00000000 +#define CS6_ADDR 0x00000000 /* CS6 not connected */ +#define CS6_MASK 0x00000000 +#define CS6_CTRL 0x00000000 +#define CS7_ADDR 0x00000000 /* CS7 not connected */ +#define CS7_MASK 0x00000000 +#define CS7_CTRL 0x00000000 +#define DMC_CTRL 0x00000000 /* default memory control */ + +#define DCRR 0x00000034 /* Refresh period */ +/* DCTR definition: + <15>: DAEM, 1 = Drive Multiplexed Address During External Master DRAM xfer + <14>: EDO, 1 = EDO, 0 = Normal + <12>: RCD, 1 = 2 clk RAS-to-CAS, 0 = 1.0 clk RAS-to-CAS + <10:09>: RSH, 10 = 3.5 clk RAS low, 01 = 2.5 clk, 00 = 1.5 clk + <06:05>: RP, 10 = 3.5 clk RAS Precharge, 01 = 2.5 clk, 00 = 1.5 clk + <03>: CAS, 1 = 2.5 clk CAS assertion, 0 = 1.5 clk + <01>: CP, 1 = 1.5 CAS clk precharge, 0 = .5 clk + <00>: CSR, 1 = 2.0 clk CAS before RAS setup, 0 = 1.0 clk +*/ +#define DCTR 0x0000144B /* Slow DRAM */ +#define DCAR0 0x00000000 /* DRAM0 address, 0 base addr */ +#define DCMR0 0x003e0000 /* DRAM0 mask, 4Mb DRAM */ +#define DCCR0 0x00000007 /* DRAM0 control, R/W, burst pg mde */ +#define DCAR1 0x00000000 /* DRAM1 address, 0 base addr */ +#define DCMR1 0x00000000 /* DRAM1 mask, no DRAM */ +#define DCCR1 0x00000000 /* DRAM1 control, off */ + +/*****************************************************************************/ + +.global _start +.global _rambase +.global _ramvec +.global _ramstart +.global _ramend + +/*****************************************************************************/ + +.data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +_rambase: +.long 0 +_ramvec: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +/*****************************************************************************/ + +.text + +/* + * This is the codes first entry point. This is where it all + * begins... + */ + +_start: + nop /* Filler */ + move.w #0x2700, %sr /* No interrupts */ + + move.l #MCF_MBAR+1, %a0 /* Set I/O base addr */ + movec %a0, %MBAR /* Note: bit 0 is Validate */ + move.l #MEM_BUILTIN+1,%a0 /* Set SRAM base addr */ + movec %a0, %RAMBAR0 /* Note: bit 0 is Validate */ + + move.l #MCF_MBAR, %a0 /* Get I/O base addr */ + + /* ----------------------- CS1 ----------------------- */ + move.w #CS1_ADDR, %d0 /* CS1 address */ + move.w %d0, MCFSIM_CSAR1(%a0) /* CS1 address */ + move.l #CS1_MASK, %d0 /* CS1 mask */ + move.l %d0, MCFSIM_CSMR1(%a0) /* CS1 mask */ + move.w #CS1_CTRL, %d0 /* CS1 control */ + move.w %d0, MCFSIM_CSCR1(%a0) /* CS1 control */ + + /* ----------------------- CS2 ----------------------- */ + move.w #CS2_ADDR, %d0 /* CS2 address */ + move.w %d0, MCFSIM_CSAR2(%a0) /* CS2 address */ + move.l #CS2_MASK, %d0 /* CS2 mask */ + move.l %d0, MCFSIM_CSMR2(%a0) /* CS2 mask */ + move.w #CS2_CTRL, %d0 /* CS2 control */ + move.w %d0, MCFSIM_CSCR2(%a0) /* CS2 control */ + + /* ----------------------- CS3 ----------------------- */ + move.w #CS3_ADDR, %d0 /* CS3 address */ + move.w %d0, MCFSIM_CSAR3(%a0) /* CS3 address */ + move.l #CS3_MASK, %d0 /* CS3 mask */ + move.l %d0, MCFSIM_CSMR3(%a0) /* CS3 mask */ + move.w #CS3_CTRL, %d0 /* CS3 control */ + move.w %d0, MCFSIM_CSCR3(%a0) /* CS3 control */ + + /* ----------------------- CS4 ----------------------- */ + move.w #CS4_ADDR, %d0 /* CS4 address */ + move.w %d0, MCFSIM_CSAR4(%a0) /* CS4 address */ + move.l #CS4_MASK, %d0 /* CS4 mask */ + move.l %d0, MCFSIM_CSMR4(%a0) /* CS4 mask */ + move.w #CS4_CTRL, %d0 /* CS4 control */ + move.w %d0, MCFSIM_CSCR4(%a0) /* CS4 control */ + + /* ----------------------- CS5 ----------------------- */ + move.w #CS5_ADDR, %d0 /* CS5 address */ + move.w %d0, MCFSIM_CSAR5(%a0) /* CS5 address */ + move.l #CS5_MASK, %d0 /* CS5 mask */ + move.l %d0, MCFSIM_CSMR5(%a0) /* CS5 mask */ + move.w #CS5_CTRL, %d0 /* CS5 control */ + move.w %d0, MCFSIM_CSCR5(%a0) /* CS5 control */ + + /* ----------------------- CS6 ----------------------- */ + move.w #CS6_ADDR, %d0 /* CS6 address */ + move.w %d0, MCFSIM_CSAR6(%a0) /* CS6 address */ + move.l #CS6_MASK, %d0 /* CS6 mask */ + move.l %d0, MCFSIM_CSMR6(%a0) /* CS6 mask */ + move.w #CS6_CTRL, %d0 /* CS6 control */ + move.w %d0, MCFSIM_CSCR6(%a0) /* CS6 control */ + + /* ----------------------- CS7 ----------------------- */ + move.w #CS7_ADDR, %d0 /* CS7 address */ + move.w %d0, MCFSIM_CSAR7(%a0) /* CS7 address */ + move.l #CS7_MASK, %d0 /* CS7 mask */ + move.l %d0, MCFSIM_CSMR7(%a0) /* CS7 mask */ + move.w #CS7_CTRL, %d0 /* CS7 control */ + move.w %d0, MCFSIM_CSCR7(%a0) /* CS7 control */ + + /* --------------------- Default --------------------- */ + move.w #DMC_CTRL, %d0 /* Default control */ + move.w %d0, MCFSIM_DMCR(%a0) /* Default control */ + + /* ----------------------- DRAM ------------------------ */ + move.w #DCRR, %d0 /* Refresh period */ + move.w %d0, MCFSIM_DCRR(%a0) /* Refresh period */ + move.w #DCTR, %d0 /* Timing address */ + move.w %d0, MCFSIM_DCTR(%a0) /* Timing address */ + move.w #DCAR0, %d0 /* DRAM0 base address */ + move.w %d0, MCFSIM_DCAR0(%a0) /* DRAM0 base address */ + move.l #DCMR0, %d0 /* DRAM0 mask */ + move.l %d0, MCFSIM_DCMR0(%a0) /* DRAM0 mask */ + move.b #DCCR0, %d0 /* DRAM0 control */ + move.b %d0, MCFSIM_DCCR0(%a0) /* DRAM0 control */ + move.w #DCAR1, %d0 /* DRAM1 base address */ + move.w %d0, MCFSIM_DCAR1(%a0) /* DRAM1 base address */ + move.l #DCMR1, %d0 /* DRAM1 mask */ + move.l %d0, MCFSIM_DCMR1(%a0) /* DRAM1 mask */ + move.b #DCCR1, %d0 /* DRAM1 control */ + move.b %d0, MCFSIM_DCCR1(%a0) /* DRAM1 control */ + + /* + * ChipSelect 0 - ROM cs + * + * ChipSelect 0 is the global chip select coming out of system reset. + * CS0 is asserted for every access until CSMR0 is written. Therefore, + * the entire ChipSelect must be properly set prior to asserting + * CSCR0_V. + */ + move.w #CS0_ADDR, %d0 /* CS0 address */ + move.w %d0, MCFSIM_CSAR0(%a0) /* CS0 address */ + move.l #CS0_MASK, %d0 /* CS0 mask */ + move.l %d0, MCFSIM_CSMR0(%a0) /* CS0 mask */ + move.w #CS0_CTRL, %d0 /* CS0 control */ + move.w %d0, MCFSIM_CSCR0(%a0) /* CS0 control */ + + + /* + * Setup VBR here, otherwise buserror remap will not work. + * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996) + * + * bkr@cut.de 19990306 + * + * Note: this is because dBUG points VBR to ROM, making vectors read + * only, so the bus trap can't be changed. (RS) + */ + move.l #VBR_BASE, %a7 /* Note VBR can't be read */ + movec %a7, %VBR + move.l %a7, _ramvec /* Set up vector addr */ + move.l %a7, _rambase /* Set up base RAM addr */ + + + /* + * Determine size of RAM, then set up initial stack + * Done differently for different eval boards and cpus. + */ + +#if defined(CONFIG_SMALL) + /* + * Set to SRAM size when configuring a minimal system + */ + move.l #MEM_MAX, %a0 + +#else + /* + * On the Arnewsh 5206 board and the Motorola m5206eLITE board + * we can probe for the amount of DRAM present... + */ + move.l #MEM_MIN, %a0 /* Start at bottom */ + move.l #MEM_MAX, %a1 /* Set stop point */ + lea.l MEM_TMPSTACK, %sp /* Set up tmp stack ptr */ + + move.l #VBR_BASE+8, %a2 /* Address of bus trap */ + lea.l _ram_buserr, %a3 /* Get RAM trap address */ + move.l %a3, (%a2) /* Set trap to local ptr */ + +_find_ram: + move.l (%a0), %d0 /* Attempt read */ + add.l #MEM_LUMP, %a0 /* Try next bank */ + cmp.l %a1, %a0 /* Check more? */ + bne _find_ram + + /* + * BUS error trap handler - used for RAM probing. + */ +_ram_buserr: + bra _found_ram + +_found_ram: /* Vectored here on bus err */ +#endif + + move.l %a0, %d0 /* Mem end addr is in a0 */ + move.l %d0, %sp /* Set up initial stack ptr */ + move.l %d0, _ramend /* Set end ram addr */ + + + /* + * Enable CPU internal cache. + */ + move.l #0x01000000, %d0 /* Invalidate cache cmd */ + movec %d0, %CACR /* Invalidate cache */ + move.l #0x80000100, %d0 /* Setup cache mask */ + movec %d0, %CACR /* Enable cache */ + + + /* + * Move ROM filesystem above bss :-) + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Set up destination */ + move.l %a0, %a2 /* Copy of bss start */ + + move.l 8(%a0), %d0 /* Get size of ROMFS */ + addq.l #8, %d0 /* Allow for rounding */ + and.l #0xfffffffc, %d0 /* Whole words */ + + add.l %d0, %a0 /* Copy from end */ + add.l %d0, %a1 /* Copy from end */ + move.l %a1, _ramstart /* Set start of ram */ + +_copy_romfs: + move.l -(%a0), %d0 /* Copy dword */ + move.l %d0, -(%a1) + cmp.l %a0, %a2 /* Check if at end */ + bne _copy_romfs + + /* + * Zero out the bss region. + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Get end of bss */ + clr.l %d0 /* Set value */ +_clear_bss: + move.l %d0, (%a0)+ /* Clear each word */ + cmp.l %a0, %a1 /* Check if at end */ + bne _clear_bss + + /* + * Load the current task pointer and stack. + */ + lea init_thread_union, %a0 + lea 0x2000(%a0), %sp + + /* + * Assember start up done, start code proper. + */ + jsr start_kernel /* Start Linux kernel */ + +_exit: + jmp _exit /* Should never get here */ + +/*****************************************************************************/ diff -Nru a/arch/m68knommu/platform/5206e/eLITE/ram.ld b/arch/m68knommu/platform/5206e/eLITE/ram.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5206e/eLITE/ram.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,72 @@ + +MEMORY { + ram : ORIGIN = 0x30020000, LENGTH = 0xe0000 +} + +jiffies = jiffies_64 + 4; + +SECTIONS { + + .text 0x30020000 : { + _stext = . ; + *(.text) + *(.exit.text) + *(.text.lock) + *(.exitcall.exit) + *(.rodata) + . = ALIGN(0x4) ; + *(.kstrtab) + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + *(__ksymtab) + __stop___ksymtab = .; + . = ALIGN(4) ; + _etext = . ; + } > ram + + .data BLOCK(0x4) : { + _sdata = . ; + __data_start = . ; + *(.data) + *(.data.exit) + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + _edata = . ; + } > ram + + .init BLOCK(4096) : { + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(4) ; + __init_end = .; + } > ram + + .bss BLOCK(0x4) : { + _sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN(4) ; + _ebss = . ; + _end = . ; + } > ram +} + diff -Nru a/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S b/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,223 @@ +/*****************************************************************************/ + +/* + * crt0_ram.S -- startup code for Motorola M5249C3 eval board. + * + * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com). + */ + +/*****************************************************************************/ + +#include "linux/autoconf.h" +#include "asm/coldfire.h" +#include "asm/mcfsim.h" + +/*****************************************************************************/ + +/* + * Motorola M5249C3 ColdFire eval board, chip select and memory setup. + */ +#define MEM_BASE 0x00000000 /* Memory base at address 0 */ +#define MEM_SIZE 0x00800000 /* Memory size 8MB */ +#define VBR_BASE MEM_BASE /* Vector address */ + +/*****************************************************************************/ + +.global _start +.global _rambase +.global _ramvec +.global _ramstart +.global _ramend + +/*****************************************************************************/ + +.data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +_rambase: +.long 0 +_ramvec: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +/*****************************************************************************/ + +.text + +/* + * This is the codes first entry point. This is where it all + * begins... + */ + +_start: + nop /* Filler */ + move.w #0x2700, %sr /* No interrupts */ + + /* + * Set MBAR1 and MBAR2, just incase they are not set. + */ + move.l #0x10000001, %a0 + movec %a0, %MBAR /* Map MBAR region */ + subq.l #1, %a0 /* Get MBAR address in a0 */ + + move.l #0x80000001, %a1 + movec %a1, #3086 /* Map MBAR2 region */ + subq.l #1, %a1 /* Get MBAR2 address in a1 */ + + /* + * Move secondary interrupts to base at 128. + */ + move.b #0x80, %d0 + move.b %d0, 0x16b(%a1) /* Interrupt base register */ + +#if 1 + /* + * Work around broken CSMR0/DRAM vector problem. + */ + move.l #0x001F0021, %d0 /* Disable C/I bit */ + move.l %d0, 0x84(%a0) /* Set CSMR0 */ +#endif + + /* + * Disable the PLL firstly. (Who knows what state it is + * in here!). + */ + move.l 0x180(%a1), %d0 /* Get current PLL value */ + and.l #0xfffffffe, %d0 /* PLL bypass first */ + move.l %d0, 0x180(%a1) /* Set PLL register */ + nop + +#if CONFIG_CLOCK_140MHz + /* + * Set initial clock frequency. This assumes M5249C3 board + * is fitted with 11.2896MHz crystal. It will program the + * PLL for 140MHz. Lets go fast :-) + */ + move.l #0x125a40f0, %d0 /* Set for 140MHz */ + move.l %d0, 0x180(%a1) /* Set PLL register */ + or.l #0x1, %d0 + move.l %d0, 0x180(%a1) /* Set PLL register */ +#endif + + /* + * Setup CS1 for ethernet controller. + * (Setup as per M5249C3 doco). + */ + move.l #0xe0000000, %d0 /* CS1 mapped at 0xe0000000 */ + move.l %d0, 0x8c(%a0) + move.l #0x001f0021, %d0 /* CS1 size of 1Mb */ + move.l %d0, 0x90(%a0) + move.w #0x0080, %d0 /* CS1 = 16bit port, AA */ + move.w %d0, 0x96(%a0) + + /* + * Setup CS2 for IDE interface. + */ + move.l #0x50000000, %d0 /* CS2 mapped at 0x50000000 */ + move.l %d0, 0x98(%a0) + move.l #0x001f0001, %d0 /* CS2 size of 1MB */ + move.l %d0, 0x9c(%a0) + move.w #0x0080, %d0 /* CS2 = 16bit, TA */ + move.w %d0, 0xa2(%a0) + + move.l #0x00107000, %d0 /* IDEconfig1 */ + move.l %d0, 0x18c(%a1) + move.l #0x000c0400, %d0 /* IDEconfig2 */ + move.l %d0, 0x190(%a1) + + move.l #0x00080000, %d0 /* GPIO19, IDE reset bit */ + or.l %d0, 0xc(%a1) /* Function GPIO19 */ + or.l %d0, 0x8(%a1) /* Enable GPIO19 as output */ + or.l %d0, 0x4(%a1) /* De-assert IDE reset */ + + + /* + * Setup VBR as per eval board (really dBUG does this). + * These settings must match it. + */ + move.l #VBR_BASE, %a0 /* Note VBR can't be read */ + movec %a0, %VBR + move.l %a0, _ramvec /* Set up vector addr */ + move.l %a0, _rambase /* Set up base RAM addr */ + + + /* + * Set the memory size, and then set a temporary stack. + */ + move.l #MEM_SIZE, %a0 + + move.l %a0, %d0 /* Mem end addr is in a0 */ + move.l %d0, %sp /* Set up initial stack ptr */ + move.l %d0, _ramend /* Set end ram addr */ + + + /* + * Enable CPU internal cache. + */ + move.l #0x01000000, %d0 /* Invalidate whole cache */ + movec %d0, %CACR + nop + + move.l #0x0000c000, %d0 /* Set SDRAM cached only */ + movec %d0, %ACR0 + move.l #0x00000000, %d0 /* No other regions cached */ + movec %d0, %ACR1 + + move.l #0xa0000200, %d0 /* Enable cache... */ + movec %d0, %CACR + nop + + + /* + * Move ROM filesystem above bss :-) + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Set up destination */ + move.l %a0, %a2 /* Copy of bss start */ + + move.l 8(%a0), %d0 /* Get size of ROMFS */ + addq.l #8, %d0 /* Allow for rounding */ + and.l #0xfffffffc, %d0 /* Whole words */ + + add.l %d0, %a0 /* Copy from end */ + add.l %d0, %a1 /* Copy from end */ + move.l %a1, _ramstart /* Set start of ram */ + +_copy_romfs: + move.l -(%a0), %d0 /* Copy dword */ + move.l %d0, -(%a1) + cmp.l %a0, %a2 /* Check if at end */ + bne _copy_romfs + + /* + * Zero out the bss region. + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Get end of bss */ + clr.l %d0 /* Set value */ +_clear_bss: + move.l %d0, (%a0)+ /* Clear each word */ + cmp.l %a0, %a1 /* Check if at end */ + bne _clear_bss + + /* + * Load the current thread pointer and stack. + */ + lea init_thread_union, %a0 + lea 0x2000(%a0), %sp + + /* + * Assember start up done, start code proper. + */ + jsr start_kernel /* Start Linux kernel */ + +_exit: + jmp _exit /* Should never get here */ + +/*****************************************************************************/ diff -Nru a/arch/m68knommu/platform/5249/MOTOROLA/ram.ld b/arch/m68knommu/platform/5249/MOTOROLA/ram.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5249/MOTOROLA/ram.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,76 @@ + +MEMORY { + ram : ORIGIN = 0x20000, LENGTH = 0x3e0000 +} + +jiffies = jiffies_64 + 4; + +SECTIONS { + + .text : { + _stext = . ; + *(.text) + *(.exit.text) + *(.text.lock) + *(.exitcall.exit) + *(.rodata) + *(.modinfo) + . = ALIGN(0x4) ; + *(.kstrtab) + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + *(__ksymtab) + __stop___ksymtab = .; + . = ALIGN(4) ; + _etext = . ; + } > ram + + .data BLOCK(0x4) : { + . = ALIGN(4); + _sdata = . ; + __data_start = . ; + *(.data) + *(.data.exit) + . = ALIGN(8192) ; + *(.data.init_task) + . = ALIGN(8192) ; + _edata = . ; + } > ram + + .init BLOCK(4096) : { + . = ALIGN(4096); + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(4); + __init_end = .; + } > ram + + .bss BLOCK(0x4) : { + . = ALIGN(4); + _sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN(4) ; + _ebss = . ; + _end = . ; + } > ram +} + diff -Nru a/arch/m68knommu/platform/5249/Makefile b/arch/m68knommu/platform/5249/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5249/Makefile Mon Nov 4 14:31:04 2002 @@ -0,0 +1,24 @@ +# +# Makefile for the m68knommu linux kernel. +# + +# +# If you want to play with the HW breakpoints then you will +# need to add define this, which will give you a stack backtrace +# on the console port whenever a DBG interrupt occurs. You have to +# set up you HW breakpoints to trigger a DBG interrupt: +# +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT +# + +ifdef CONFIG_FULLDEBUG +AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 +endif + +obj-y := config.o + +EXTRA_TARGETS := $(BOARD)/crt0_$(MODEL).o + +include $(TOPDIR)/Rules.make + diff -Nru a/arch/m68knommu/platform/5249/config.c b/arch/m68knommu/platform/5249/config.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5249/config.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,229 @@ +/***************************************************************************/ + +/* + * linux/arch/m68knommu/platform/5249/config.c + * + * Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com) + */ + +/***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/***************************************************************************/ + +void coldfire_profile_init(void); + +/***************************************************************************/ + +/* + * DMA channel base address table. + */ +unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { + MCF_MBAR + MCFDMA_BASE0, + MCF_MBAR + MCFDMA_BASE1, + MCF_MBAR + MCFDMA_BASE2, + MCF_MBAR + MCFDMA_BASE3, +}; + +unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; + +/***************************************************************************/ + +void coldfire_tick(void) +{ + volatile unsigned char *timerp; + + /* Reset the ColdFire timer */ + timerp = (volatile unsigned char *) (MCF_MBAR + MCFTIMER_BASE1); + timerp[MCFTIMER_TER] = MCFTIMER_TER_CAP | MCFTIMER_TER_REF; +} + +/***************************************************************************/ + +void coldfire_timer_init(void (*handler)(int, void *, struct pt_regs *)) +{ + volatile unsigned short *timerp; + volatile unsigned char *icrp; + + /* Set up TIMER 1 as poll clock */ + timerp = (volatile unsigned short *) (MCF_MBAR + MCFTIMER_BASE1); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_DISABLE; + + timerp[MCFTIMER_TRR] = (unsigned short) ((MCF_CLK / 16) / HZ); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | + MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE; + + icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_TIMER1ICR); + *icrp = MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL5 | MCFSIM_ICR_PRI3; + request_irq(29, handler, SA_INTERRUPT, "ColdFire Timer", NULL); + +#ifdef CONFIG_HIGHPROFILE + coldfire_profile_init(); +#endif + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_TIMER1); +} + +/***************************************************************************/ +#ifdef CONFIG_HIGHPROFILE +/***************************************************************************/ + +#define PROFILEHZ 1013 + +/* + * Use the other timer to provide high accuracy profiling info. + */ + +void coldfire_profile_tick(int irq, void *dummy, struct pt_regs *regs) +{ + volatile unsigned char *timerp; + + /* Reset the ColdFire timer2 */ + timerp = (volatile unsigned char *) (MCF_MBAR + MCFTIMER_BASE2); + timerp[MCFTIMER_TER] = MCFTIMER_TER_CAP | MCFTIMER_TER_REF; + + if (!user_mode(regs)) { + if (prof_buffer && current->pid) { + extern int _stext; + unsigned long ip = instruction_pointer(regs); + ip -= (unsigned long) &_stext; + ip >>= prof_shift; + if (ip < prof_len) + prof_buffer[ip]++; + } + } +} + +void coldfire_profile_init(void) +{ + volatile unsigned short *timerp; + volatile unsigned char *icrp; + + printk("PROFILE: lodging timer2=%d as profile timer\n", PROFILEHZ); + + /* Set up TIMER 2 as poll clock */ + timerp = (volatile unsigned short *) (MCF_MBAR + MCFTIMER_BASE2); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_DISABLE; + + timerp[MCFTIMER_TRR] = (unsigned short) ((MCF_CLK / 16) / PROFILEHZ); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | + MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE; + + icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_TIMER2ICR); + + *icrp = MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3; + request_irq(31, coldfire_profile_tick, (SA_INTERRUPT | IRQ_FLG_FAST), + "Profile Timer", NULL); + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_TIMER2); +} + +/***************************************************************************/ +#endif /* CONFIG_HIGHPROFILE */ +/***************************************************************************/ + +/* + * Program the vector to be an auto-vectored. + */ + +void mcf_autovector(unsigned int vec) +{ + volatile unsigned char *mbar; + + if ((vec >= 25) && (vec <= 31)) { + mbar = (volatile unsigned char *) MCF_MBAR; + vec = 0x1 << (vec - 24); + *(mbar + MCFSIM_AVR) |= vec; + mcf_setimr(mcf_getimr() & ~vec); + } +} + +/***************************************************************************/ + +extern e_vector *_ramvec; + +void set_evector(int vecnum, void (*handler)(void)) +{ + if (vecnum >= 0 && vecnum <= 255) + _ramvec[vecnum] = handler; +} + +/***************************************************************************/ + +/* assembler routines */ +asmlinkage void buserr(void); +asmlinkage void trap(void); +asmlinkage void system_call(void); +asmlinkage void inthandler(void); + +void __init coldfire_trap_init(void) +{ + int i; + +#ifndef ENABLE_dBUG + mcf_setimr(MCFSIM_IMR_MASKALL); +#endif + + /* + * There is a common trap handler and common interrupt + * handler that handle almost every vector. We treat + * the system call and bus error special, they get their + * own first level handlers. + */ +#ifndef ENABLE_dBUG + for (i = 3; (i <= 23); i++) + _ramvec[i] = trap; + for (i = 33; (i <= 63); i++) + _ramvec[i] = trap; +#endif + + for (i = 24; (i <= 30); i++) + _ramvec[i] = inthandler; +#ifndef ENABLE_dBUG + _ramvec[31] = inthandler; // Disables the IRQ7 button +#endif + + for (i = 64; (i < 255); i++) + _ramvec[i] = inthandler; + _ramvec[255] = 0; + + _ramvec[2] = buserr; + _ramvec[32] = system_call; +} + +/***************************************************************************/ + +void config_BSP(char *commandp, int size) +{ + memset(commandp, 0, size); + + mach_sched_init = coldfire_timer_init; + mach_tick = coldfire_tick; + mach_trap_init = coldfire_trap_init; +} + +/***************************************************************************/ +#ifdef TRAP_DBG_INTERRUPT + +asmlinkage void dbginterrupt_c(struct frame *fp) +{ + extern void dump(struct pt_regs *fp); + printk("%s(%d): BUS ERROR TRAP\n", __FILE__, __LINE__); + dump((struct pt_regs *) fp); + asm("halt"); +} + +#endif +/***************************************************************************/ diff -Nru a/arch/m68knommu/platform/5272/MOTOROLA/crt0_ram.S b/arch/m68knommu/platform/5272/MOTOROLA/crt0_ram.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5272/MOTOROLA/crt0_ram.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,152 @@ +/*****************************************************************************/ + +/* + * crt0_ram.S -- startup code for MCF5272 ColdFire based MOTOROLA boards. + * + * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com). + * (C) Copyright 2000, Lineo (www.lineo.com). + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +/*****************************************************************************/ + +/* + * Motorola M5272C3 ColdFire eval board, chip select and memory setup. + */ + +#define MEM_BASE 0x00000000 /* Memory base at address 0 */ +#define VBR_BASE MEM_BASE /* Vector address */ + +#if defined(CONFIG_RAM16MB) +#define MEM_SIZE 0x01000000 /* Memory size 16Mb */ +#elif defined(CONFIG_RAM8MB) +#define MEM_SIZE 0x00800000 /* Memory size 8Mb */ +#else +#define MEM_SIZE 0x00400000 /* Memory size 4Mb */ +#endif + +/*****************************************************************************/ + +.global _start +.global _rambase +.global _ramvec +.global _ramstart +.global _ramend + +/*****************************************************************************/ + +.data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +_rambase: +.long 0 +_ramvec: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +/*****************************************************************************/ + +.text + +/* + * This is the codes first entry point. This is where it all + * begins... + */ + +_start: + nop /* Filler */ + move.w #0x2700, %sr /* No interrupts */ + + /* + * Setup VBR here, otherwise buserror remap will not work. + * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996) + * + * bkr@cut.de 19990306 + * + * Note: this is because dBUG points VBR to ROM, making vectors read + * only, so the bus trap can't be changed. (RS) + */ + move.l #VBR_BASE, %a7 /* Note VBR can't be read */ + movec %a7, %VBR + move.l %a7, _ramvec /* Set up vector addr */ + move.l %a7, _rambase /* Set up base RAM addr */ + + + /* + * Set memory size. + */ + move.l #MEM_SIZE, %a0 + + move.l %a0, %d0 /* Mem end addr is in a0 */ + move.l %d0, %sp /* Set up initial stack ptr */ + move.l %d0, _ramend /* Set end ram addr */ + + /* + * Enable CPU internal cache. + */ + move.l #0x01000000, %d0 /* Invalidate cache cmd */ + movec %d0, %CACR /* Invalidate cache */ + move.l #0x80000100, %d0 /* Setup cache mask */ + movec %d0, %CACR /* Enable cache */ + + /* + * Move ROM filesystem above bss :-) + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Set up destination */ + move.l %a0, %a2 /* Copy of bss start */ + + move.l 8(%a0), %d0 /* Get size of ROMFS */ + addq.l #8, %d0 /* Allow for rounding */ + and.l #0xfffffffc, %d0 /* Whole words */ + + add.l %d0, %a0 /* Copy from end */ + add.l %d0, %a1 /* Copy from end */ + move.l %a1, _ramstart /* Set start of ram */ + +_copy_romfs: + move.l -(%a0), %d0 /* Copy dword */ + move.l %d0, -(%a1) + cmp.l %a0, %a2 /* Check if at end */ + bne _copy_romfs + + /* + * Zero out the bss region. + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Get end of bss */ + clr.l %d0 /* Set value */ +_clear_bss: + move.l %d0, (%a0)+ /* Clear each word */ + cmp.l %a0, %a1 /* Check if at end */ + bne _clear_bss + + /* + * Load the current thread pointer and stack. + */ + lea init_thread_union, %a0 + lea 0x2000(%a0), %sp + + /* + * Assember start up done, start code proper. + */ + jsr start_kernel /* Start Linux kernel */ + +_exit: + jmp _exit /* Should never get here */ + +/*****************************************************************************/ diff -Nru a/arch/m68knommu/platform/5272/MOTOROLA/ram.ld b/arch/m68knommu/platform/5272/MOTOROLA/ram.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5272/MOTOROLA/ram.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,76 @@ + +MEMORY { + ram : ORIGIN = 0x20000, LENGTH = 0x3e0000 +} + +jiffies = jiffies_64 + 4; + +SECTIONS { + + .text : { + _stext = . ; + *(.text) + *(.exit.text) + *(.text.lock) + *(.exitcall.exit) + *(.rodata) + *(.modinfo) + . = ALIGN(0x4) ; + *(.kstrtab) + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + *(__ksymtab) + __stop___ksymtab = .; + . = ALIGN(4) ; + _etext = . ; + } > ram + + .data BLOCK(0x4) : { + . = ALIGN(4); + _sdata = . ; + __data_start = . ; + *(.data) + *(.data.exit) + . = ALIGN(8192) ; + *(.data.init_task) + . = ALIGN(8192) ; + _edata = . ; + } > ram + + .init BLOCK(4096) : { + . = ALIGN(4096); + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(4); + __init_end = .; + } > ram + + .bss BLOCK(0x4) : { + . = ALIGN(4); + _sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN(4) ; + _ebss = . ; + _end = . ; + } > ram +} + diff -Nru a/arch/m68knommu/platform/5272/Makefile b/arch/m68knommu/platform/5272/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5272/Makefile Mon Nov 4 14:31:03 2002 @@ -0,0 +1,24 @@ +# +# Makefile for the linux kernel. +# + +# +# If you want to play with the HW breakpoints then you will +# need to add define this, which will give you a stack backtrace +# on the console port whenever a DBG interrupt occurs. You have to +# set up you HW breakpoints to trigger a DBG interrupt: +# +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT +# + +ifdef CONFIG_FULLDEBUG +AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 +endif + +obj-y := config.o + +EXTRA_TARGETS := $(BOARD)/crt0_$(MODEL).o + +include $(TOPDIR)/Rules.make + diff -Nru a/arch/m68knommu/platform/5272/NETtel/crt0_ram.S b/arch/m68knommu/platform/5272/NETtel/crt0_ram.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5272/NETtel/crt0_ram.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,188 @@ +/*****************************************************************************/ + +/* + * crt0_ram.S -- startup code for MCF5307 ColdFire based NETtel. + * + * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com). + * Copyright (C) 2000 Lineo Inc. (www.lineo.com) + * + * 1999/02/24 Modified for the 5307 processor David W. Miller + */ + +/*****************************************************************************/ + +#include "linux/autoconf.h" +#include "asm/coldfire.h" +#include "asm/mcfsim.h" +#include "asm/nettel.h" + +/*****************************************************************************/ + +/* + * Lineo NETtel board memory setup. + */ +#define MEM_BASE 0x00000000 /* Memory base at address 0 */ +#define VBR_BASE MEM_BASE /* Vector address */ + +#if defined(CONFIG_RAM16MB) +#define MEM_SIZE 0x01000000 /* Memory size 16Mb */ +#elif defined(CONFIG_RAM8MB) +#define MEM_SIZE 0x00800000 /* Memory size 8Mb */ +#else +#define MEM_SIZE 0x00400000 /* Memory size 4Mb */ +#endif + +/*****************************************************************************/ + +.global _start +.global _rambase +.global _ramvec +.global _ramstart +.global _ramend + +/*****************************************************************************/ + +.data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +_rambase: +.long 0 +_ramvec: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +/*****************************************************************************/ + +/* + * The NETtel platform has some funky LEDs! + */ +.global ppdata +ppdata: +.short 0x0000 + +.global ledbank +ledbank: +.byte 0xff + +/*****************************************************************************/ + +.text + +/* + * This is the codes first entry point. This is where it all + * begins... + */ + +_start: + nop /* Filler */ + move.w #0x2700, %sr /* No interrupts */ + + /* + * Setup VBR here, otherwise buserror remap will not work. + * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996) + * + * bkr@cut.de 19990306 + * + * Note: this is because dBUG points VBR to ROM, making vectors read + * only, so the bus trap can't be changed. (RS) + */ + move.l #VBR_BASE, %a7 /* Note VBR can't be read */ + movec %a7, %VBR + move.l %a7, _ramvec /* Set up vector addr */ + move.l %a7, _rambase /* Set up base RAM addr */ + + + /* + * Determine size of RAM, then set up initial stack. + */ + move.l #MEM_SIZE, %a0 + + move.l %a0, %d0 /* Mem end addr is in a0 */ + move.l %d0, %sp /* Set up initial stack ptr */ + move.l %d0, _ramend /* Set end ram addr */ + + /* + * Enable CPU internal cache. + */ + move.l #0x01000000, %d0 /* Invalidate cache cmd */ + movec %d0, %CACR /* Invalidate cache */ + move.l #0x80000100, %d0 /* Setup cache mask */ + movec %d0, %CACR /* Enable cache */ + nop + +#ifdef CONFIG_ROMFS_FROM_ROM + /* + * check for an in RAM romfs + */ + lea.l _sbss, %a0 /* Get start of bss */ + mov.l (%a0), %d0 + cmp.l #0x2d726f6d, %d0 /* check for "-rom" */ + bne use_xip_romfs + add.l #4, %a0 + mov.l (%a0), %d0 + cmp.l #0x3166732d, %d0 /* check for "1fs-" */ + bne use_xip_romfs +#endif + + /* + * Move ROM filesystem above bss :-) + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Set up destination */ + move.l %a0, %a2 /* Copy of bss start */ + + move.l 8(%a0), %d0 /* Get size of ROMFS */ + addq.l #8, %d0 /* Allow for rounding */ + and.l #0xfffffffc, %d0 /* Whole words */ + + add.l %d0, %a0 /* Copy from end */ + add.l %d0, %a1 /* Copy from end */ + move.l %a1, _ramstart /* Set start of ram */ + +_copy_romfs: + move.l -(%a0), %d0 /* Copy dword */ + move.l %d0, -(%a1) + cmp.l %a0, %a2 /* Check if at end */ + bne _copy_romfs + +#ifdef CONFIG_ROMFS_FROM_ROM + bra done_romfs + use_xip_romfs: + lea.l _ebss, %a1 /* Set up destination */ + mov.l #0, (%a1) /* make sure we don't use an old RAM version */ + move.l %a1, _ramstart /* Set start of ram */ + done_romfs: +#endif + + /* + * Zero out the bss region. + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Get end of bss */ + clr.l %d0 /* Set value */ +_clear_bss: + move.l %d0, (%a0)+ /* Clear each word */ + cmp.l %a0, %a1 /* Check if at end */ + bne _clear_bss + + /* + * load the current task pointer and stack + */ + lea init_thread_union, %a0 + lea 0x2000(%a0), %sp + + /* + * Assember start up done, start code proper. + */ + jsr start_kernel /* Start Linux kernel */ + +_exit: + jmp _exit /* Should never get here */ + +/*****************************************************************************/ diff -Nru a/arch/m68knommu/platform/5272/NETtel/ram.ld b/arch/m68knommu/platform/5272/NETtel/ram.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5272/NETtel/ram.ld Mon Nov 4 14:31:03 2002 @@ -0,0 +1,76 @@ + +MEMORY { + ram : ORIGIN = 0x400, LENGTH = 0x400000 +} + +jiffies = jiffies_64 + 4; + +SECTIONS { + + .text : { + _stext = . ; + *(.text) + *(.exit.text) + *(.text.lock) + *(.exitcall.exit) + *(.rodata) + *(.modinfo) + . = ALIGN(0x4) ; + *(.kstrtab) + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + *(__ksymtab) + __stop___ksymtab = .; + . = ALIGN(4) ; + _etext = . ; + } > ram + + .data BLOCK(0x4) : { + . = ALIGN(4); + _sdata = . ; + __data_start = . ; + *(.data) + *(.data.exit) + . = ALIGN(8192) ; + *(.data.init_task) + . = ALIGN(8192) ; + _edata = . ; + } > ram + + .init BLOCK(4096) : { + . = ALIGN(4096); + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(4); + __init_end = .; + } > ram + + .bss BLOCK(0x4) : { + . = ALIGN(4); + _sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN(4) ; + _ebss = . ; + _end = . ; + } > ram +} + diff -Nru a/arch/m68knommu/platform/5272/config.c b/arch/m68knommu/platform/5272/config.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5272/config.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,247 @@ +/***************************************************************************/ + +/* + * linux/arch/m68knommu/platform/5272/config.c + * + * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 2001-2002, SnapGear Inc. (www.snapgear.com) + */ + +/***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/***************************************************************************/ + +void reset_setupbutton(void); + +/***************************************************************************/ + +/* + * DMA channel base address table. + */ +unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { + MCF_MBAR + MCFDMA_BASE0, +}; + +unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; + +/***************************************************************************/ + +void coldfire_tick(void) +{ + volatile unsigned char *timerp; + + /* Reset the ColdFire timer */ + timerp = (volatile unsigned char *) (MCF_MBAR + MCFTIMER_BASE4); + timerp[MCFTIMER_TER] = MCFTIMER_TER_CAP | MCFTIMER_TER_REF; +} + +/***************************************************************************/ + +void coldfire_timer_init(void (*handler)(int, void *, struct pt_regs *)) +{ + volatile unsigned short *timerp; + volatile unsigned long *icrp; + + /* Set up TIMER 4 as poll clock */ + timerp = (volatile unsigned short *) (MCF_MBAR + MCFTIMER_BASE4); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_DISABLE; + + timerp[MCFTIMER_TRR] = (unsigned short) ((MCF_CLK / 16) / HZ); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | + MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE; + + icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); + *icrp = 0x0000000d; /* TMR4 with priority 5 */ + request_irq(72, handler, SA_INTERRUPT, "ColdFire Timer", NULL); + +#ifdef CONFIG_RESETSWITCH + /* This is not really the right place to do this... */ + reset_setupbutton(); +#endif +} + +/***************************************************************************/ + +/* + * Program the vector to be an auto-vectored. + */ + +void mcf_autovector(unsigned int vec) +{ + /* Everything is auto-vectored on the 5272 */ +} + +/***************************************************************************/ + +extern e_vector *_ramvec; + +void set_evector(int vecnum, void (*handler)(void)) +{ + if (vecnum >= 0 && vecnum <= 255) + _ramvec[vecnum] = handler; +} + +/***************************************************************************/ + +/* assembler routines */ +asmlinkage void buserr(void); +asmlinkage void trap(void); +asmlinkage void system_call(void); +asmlinkage void inthandler(void); + +void coldfire_trap_init(void) +{ + int i; + +#ifndef ENABLE_dBUG + volatile unsigned long *icrp; + + icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); + icrp[0] = 0x88888888; + icrp[1] = 0x88888888; + icrp[2] = 0x88888888; + icrp[3] = 0x88888888; +#endif + + /* + * There is a common trap handler and common interrupt + * handler that handle almost every vector. We treat + * the system call and bus error special, they get their + * own first level handlers. + */ +#ifndef ENABLE_dBUG + for (i = 3; (i <= 23); i++) + _ramvec[i] = trap; + for (i = 33; (i <= 63); i++) + _ramvec[i] = trap; +#endif + + for (i = 24; (i <= 30); i++) + _ramvec[i] = inthandler; +#ifndef ENABLE_dBUG + _ramvec[31] = inthandler; // Disables the IRQ7 button +#endif + + for (i = 64; (i < 255); i++) + _ramvec[i] = inthandler; + _ramvec[255] = 0; + + _ramvec[2] = buserr; + _ramvec[32] = system_call; +} + +/***************************************************************************/ + +void coldfire_reset(void) +{ + HARD_RESET_NOW(); +} + +/***************************************************************************/ + +void config_BSP(char *commandp, int size) +{ +#if 0 + volatile unsigned long *pivrp; + + /* Set base of device vectors to be 64 */ + pivrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PIVR); + *pivrp = 0x40; +#endif + +#if defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || \ + defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) + /* Copy command line from FLASH to local buffer... */ + memcpy(commandp, (char *) 0xf0004000, size); + commandp[size-1] = 0; +#elif defined(CONFIG_MTD_KeyTechnology) + /* Copy command line from FLASH to local buffer... */ + memcpy(commandp, (char *) 0xffe06000, size); + commandp[size-1] = 0; +#else + memset(commandp, 0, size); +#endif + + mach_sched_init = coldfire_timer_init; + mach_tick = coldfire_tick; + mach_trap_init = coldfire_trap_init; + mach_reset = coldfire_reset; +} + +/***************************************************************************/ +#ifdef CONFIG_RESETSWITCH +/***************************************************************************/ + +/* + * Routines to support the NETtel software reset button. + */ +void reset_button(int irq, void *dev_id, struct pt_regs *regs) +{ + volatile unsigned long *icrp, *isrp; + extern void flash_eraseconfig(void); + static int inbutton = 0; + + /* + * IRQ7 is not maskable by the CPU core. It is possible + * that switch bounce mey get us back here before we have + * really serviced the interrupt. + */ + if (inbutton) + return; + inbutton = 1; + + /* Disable interrupt at SIM - best we can do... */ + icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); + *icrp = (*icrp & 0x07777777) | 0x80000000; + + /* Try and de-bounce the switch a little... */ + udelay(10000); + + flash_eraseconfig(); + + /* Don't leave here 'till button is no longer pushed! */ + isrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ISR); + for (;;) { + if (*isrp & 0x80000000) + break; + } + + HARD_RESET_NOW(); + /* Should never get here... */ + + inbutton = 0; + /* Interrupt service done, acknowledge it */ + icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); + *icrp = (*icrp & 0x07777777) | 0xf0000000; +} + +/***************************************************************************/ + +void reset_setupbutton(void) +{ + volatile unsigned long *icrp; + + icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); + *icrp = (*icrp & 0x07777777) | 0xf0000000; + request_irq(65, reset_button, (SA_INTERRUPT | IRQ_FLG_FAST), + "Reset Button", NULL); +} + +/***************************************************************************/ +#endif /* CONFIG_RESETSWITCH */ +/***************************************************************************/ diff -Nru a/arch/m68knommu/platform/5307/ARNEWSH/crt0_ram.S b/arch/m68knommu/platform/5307/ARNEWSH/crt0_ram.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5307/ARNEWSH/crt0_ram.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,159 @@ +/*****************************************************************************/ + +/* + * crt0_ram.S -- startup code for MCF5307 ColdFire Arnewsh board. + * + * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com). + * Copyright (C) 2000 Lineo Inc. (www.lineo.com) + * + * 1999/02/24 Modified for the 5307 processor David W. Miller + */ + +/*****************************************************************************/ + +#include "linux/autoconf.h" +#include "asm/coldfire.h" +#include "asm/mcfsim.h" +#include "asm/nettel.h" + +/*****************************************************************************/ + +/* + * SnapGear/NETtel board memory setup. + */ +#define MEM_BASE 0x00000000 /* Memory base at address 0 */ +#define MEM_SIZE 0x00800000 /* Memory size 8Mb */ +#define VBR_BASE MEM_BASE /* Vector address */ + +/*****************************************************************************/ + +.global _start +.global _rambase +.global _ramvec +.global _ramstart +.global _ramend + +/*****************************************************************************/ + +.data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +_rambase: +.long 0 +_ramvec: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +/*****************************************************************************/ + +.text + +/* + * This is the codes first entry point. This is where it all + * begins... + */ + +_start: + nop /* Filler */ + move.w #0x2700, %sr /* No interrupts */ + + /* + * Setup VBR here, otherwise buserror remap will not work. + * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996) + * + * bkr@cut.de 19990306 + * + * Note: this is because dBUG points VBR to ROM, making vectors read + * only, so the bus trap can't be changed. (RS) + */ + move.l #VBR_BASE, %a7 /* Note VBR can't be read */ + movec %a7, %VBR + move.l %a7, _ramvec /* Set up vector addr */ + move.l %a7, _rambase /* Set up base RAM addr */ + + + /* + * Determine size of RAM, then set up initial stack. + */ + move.l #MEM_SIZE, %a0 + + move.l %a0, %d0 /* Mem end addr is in a0 */ + move.l %d0, %sp /* Set up initial stack ptr */ + move.l %d0, _ramend /* Set end ram addr */ + + /* make region ROM cachable (turn off for flash programming?) */ + /* 0xff000000 - 0xffffffff */ +#ifdef DEBUGGER_COMPATIBLE_CACHE + movl #(0xff< ram + + .data BLOCK(0x4) : { + _sdata = . ; + __data_start = . ; + *(.data) + *(.data.exit) + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + _edata = . ; + } > ram + + .init BLOCK(4096) : { + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(4) ; + __init_end = .; + } > ram + + .bss BLOCK(0x4) : { + _sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN(4) ; + _ebss = . ; + _end = . ; + } > ram +} + diff -Nru a/arch/m68knommu/platform/5307/CLEOPATRA/crt0_ram.S b/arch/m68knommu/platform/5307/CLEOPATRA/crt0_ram.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5307/CLEOPATRA/crt0_ram.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,176 @@ +/*****************************************************************************/ + +/* + * crt0_ram.S -- startup code for Feith CLEOPATRA board. + * + * (C) Copyright 2001, Roman Wagner. + * + * 1999/02/24 Modified for the 5307 processor David W. Miller + */ + +/*****************************************************************************/ + +#include "linux/autoconf.h" +#include "asm/coldfire.h" +#include "asm/mcfsim.h" + +/*****************************************************************************/ + +/* + * Feith CLEOPATRA board, chip select and memory setup. +*/ + +#define MEM_BASE 0x00000000 /* Memory base at address 0 */ +#define VBR_BASE MEM_BASE /* Vector address */ + +#if defined(CONFIG_RAM16MB) +#define MEM_SIZE 0x01000000 /* Memory size 16Mb */ +#else +#define MEM_SIZE 0x00800000 /* Memory size 8Mb */ +#endif + +/*****************************************************************************/ + +.global _start +.global _rambase +.global _ramvec +.global _ramstart +.global _ramend + +/*****************************************************************************/ + +.data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +_rambase: +.long 0 +_ramvec: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +/*****************************************************************************/ + +.text + +/* + * This is the codes first entry point. This is where it all + * begins... + */ + +_start: + nop /* Filler */ + move.w #0x2700, %sr /* No interrupts */ + + + /* + * Setup VBR here, otherwise buserror remap will not work. + * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996) + * + * bkr@cut.de 19990306 + * + * Note: this is because dBUG points VBR to ROM, making vectors read + * only, so the bus trap can't be changed. (RS) + */ + move.l #VBR_BASE, %a7 /* Note VBR can't be read */ + movec %a7, %VBR + move.l %a7, _ramvec /* Set up vector addr */ + move.l %a7, _rambase /* Set up base RAM addr */ + + + /* + * Determine size of RAM, then set up initial stack. + */ +/* + * The current version of the 5307 processor + * SWT does not work. Probing invalid addresses + * will hang the system. + * + * For now, set the memory size to 8 meg + */ + move.l #MEM_SIZE, %a0 + + move.l %a0, %d0 /* Mem end addr is in a0 */ + move.l %d0, %sp /* Set up initial stack ptr */ + move.l %d0, _ramend /* Set end ram addr */ + + + /* now fire off the cache, remember to invalidate it first */ + movl #0,%d0 + movc %d0,%CACR + nop + movc %d0,%CACR /* cache is off */ + + movl #CACR_CINVA,%d0 /* invalidate whole cache */ + movc %d0,%CACR + nop + movc %d0,%CACR + nop + + /* make region ROM cachable (turn off for flash programming?) */ + /* 0xff000000 - 0xffffffff */ + movl #(0xff< ram + + .data BLOCK(0x4) : { + _sdata = . ; + __data_start = . ; + *(.data) + *(.data.exit) + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + _edata = . ; + } > ram + + .init BLOCK(4096) : { + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = . ; + . = ALIGN(4); + __init_end = .; + } > ram + + .bss BLOCK(0x4) : { + _sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN(4) ; + _ebss = . ; + _end = . ; + } > ram +} + diff -Nru a/arch/m68knommu/platform/5307/MOTOROLA/crt0_ram.S b/arch/m68knommu/platform/5307/MOTOROLA/crt0_ram.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5307/MOTOROLA/crt0_ram.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,159 @@ +/*****************************************************************************/ + +/* + * crt0_ram.S -- startup code for MCF5307C3 Cadre-III ColdFire board. + * + * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com). + * Copyright (C) 2000 Lineo Inc. (www.lineo.com) + * + * 1999/02/24 Modified for the 5307 processor David W. Miller + */ + +/*****************************************************************************/ + +#include "linux/autoconf.h" +#include "asm/coldfire.h" +#include "asm/mcfsim.h" +#include "asm/nettel.h" + +/*****************************************************************************/ + +/* + * SnapGear/NETtel board memory setup. + */ +#define MEM_BASE 0x00000000 /* Memory base at address 0 */ +#define MEM_SIZE 0x00800000 /* Memory size 8Mb */ +#define VBR_BASE MEM_BASE /* Vector address */ + +/*****************************************************************************/ + +.global _start +.global _rambase +.global _ramvec +.global _ramstart +.global _ramend + +/*****************************************************************************/ + +.data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +_rambase: +.long 0 +_ramvec: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +/*****************************************************************************/ + +.text + +/* + * This is the codes first entry point. This is where it all + * begins... + */ + +_start: + nop /* Filler */ + move.w #0x2700, %sr /* No interrupts */ + + /* + * Setup VBR here, otherwise buserror remap will not work. + * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996) + * + * bkr@cut.de 19990306 + * + * Note: this is because dBUG points VBR to ROM, making vectors read + * only, so the bus trap can't be changed. (RS) + */ + move.l #VBR_BASE, %a7 /* Note VBR can't be read */ + movec %a7, %VBR + move.l %a7, _ramvec /* Set up vector addr */ + move.l %a7, _rambase /* Set up base RAM addr */ + + + /* + * Determine size of RAM, then set up initial stack. + */ + move.l #MEM_SIZE, %a0 + + move.l %a0, %d0 /* Mem end addr is in a0 */ + move.l %d0, %sp /* Set up initial stack ptr */ + move.l %d0, _ramend /* Set end ram addr */ + + /* make region ROM cachable (turn off for flash programming?) */ + /* 0xff000000 - 0xffffffff */ +#ifdef DEBUGGER_COMPATIBLE_CACHE + movl #(0xff< ram + + .data BLOCK(0x4) : { + _sdata = . ; + __data_start = . ; + *(.data) + *(.data.exit) + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + _edata = . ; + } > ram + + .init BLOCK(4096) : { + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(4) ; + __init_end = .; + } > ram + + .bss BLOCK(0x4) : { + _sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN(4) ; + _ebss = . ; + _end = . ; + } > ram +} + diff -Nru a/arch/m68knommu/platform/5307/MP3/crt0_ram.S b/arch/m68knommu/platform/5307/MP3/crt0_ram.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5307/MP3/crt0_ram.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,173 @@ +/*****************************************************************************/ + +/* + * crt0_ram.S -- startup code for MCF5307 ColdFire based MP3. + * + * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com). + * Copyright (C) 2000-2001 Lineo Inc. (www.lineo.com) + * + * 1999/02/24 Modified for the 5307 processor David W. Miller + */ + +/*****************************************************************************/ + +#include "linux/autoconf.h" +#include "asm/coldfire.h" +#include "asm/mcfsim.h" +#include "asm/nettel.h" + +/*****************************************************************************/ + +/* + * SnapGear/NETtel board memory setup. + */ +#define MEM_BASE 0x00000000 /* Memory base at address 0 */ +#define VBR_BASE MEM_BASE /* Vector address */ + +#if defined(CONFIG_RAM16MB) +#define MEM_SIZE 0x01000000 /* Memory size 16Mb */ +#else +#define MEM_SIZE 0x00800000 /* Memory size 8Mb */ +#endif + +/*****************************************************************************/ + +.global _start +.global _rambase +.global _ramvec +.global _ramstart +.global _ramend + +/*****************************************************************************/ + +.data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +_rambase: +.long 0 +_ramvec: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +/*****************************************************************************/ + +.text + +/* + * This is the codes first entry point. This is where it all + * begins... + */ + +_start: + nop /* Filler */ + move.w #0x2700, %sr /* No interrupts */ + + /* + * Disable watchdog timer. + */ + move.l #MCF_MBAR, %a0 /* Get MBAR address */ + clr.l %d0 /* Disable SWT */ + move.b %d0, MCFSIM_SYPCR(%a0) + move.b #0x55, %d0 /* Clear SWT as well */ + move.b %d0, MCFSIM_SWSR(%a0) + move.b #0xaa, %d0 + move.b %d0, MCFSIM_SWSR(%a0) + move.l #0xffffffff, %d0 /* Mask out all interrupts */ + move.l %d0, MCFSIM_IMR(%a0) + + /* + * Setup VBR here, otherwise buserror remap will not work. + * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996) + * + * bkr@cut.de 19990306 + * + * Note: this is because dBUG points VBR to ROM, making vectors read + * only, so the bus trap can't be changed. (RS) + */ + move.l #VBR_BASE, %a7 /* Note VBR can't be read */ + movec %a7, %VBR + move.l %a7, _ramvec /* Set up vector addr */ + move.l %a7, _rambase /* Set up base RAM addr */ + + + /* + * Determine size of RAM, then set up initial stack. + */ + move.l #MEM_SIZE, %a0 + + move.l %a0, %d0 /* Mem end addr is in a0 */ + move.l %d0, %sp /* Set up initial stack ptr */ + move.l %d0, _ramend /* Set end ram addr */ + + /* + * Enable CPU internal cache. + */ + move.l #0x01000000, %d0 /* invalidate whole cache */ + movec %d0,%CACR + nop + + /* MUST be write-through for DMA to work... */ + /* This also makes this debugger safe */ + move.l #0x0000c000, %d0 /* Set SDRAM cached only */ + movec %d0, %ACR0 + move.l #0x00000000, %d0 /* No other regions cached */ + movec %d0, %ACR1 + + /* Enable cache */ + move.l #0xa0000200, %d0 + movec %d0,%CACR + nop + + /* + * Move ROM filesystem above bss :-) + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Set up destination */ + move.l %a0, %a2 /* Copy of bss start */ + + move.l 8(%a0), %d0 /* Get size of ROMFS */ + addq.l #8, %d0 /* Allow for rounding */ + and.l #0xfffffffc, %d0 /* Whole words */ + + add.l %d0, %a0 /* Copy from end */ + add.l %d0, %a1 /* Copy from end */ + move.l %a1, _ramstart /* Set start of ram */ + +_copy_romfs: + move.l -(%a0), %d0 /* Copy dword */ + move.l %d0, -(%a1) + cmp.l %a0, %a2 /* Check if at end */ + bne _copy_romfs + + /* + * Zero out the bss region. + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Get end of bss */ + clr.l %d0 /* Set value */ +_clear_bss: + move.l %d0, (%a0)+ /* Clear each word */ + cmp.l %a0, %a1 /* Check if at end */ + bne _clear_bss + + /* + * load the current task pointer and stack + */ + lea init_thread_union, %a0 + lea 0x2000(%a0), %sp + + /* + * Assember start up done, start code proper. + */ + jsr start_kernel /* Start Linux kernel */ + +_exit: + jmp _exit /* Should never get here */ + +/*****************************************************************************/ diff -Nru a/arch/m68knommu/platform/5307/MP3/ram.ld b/arch/m68knommu/platform/5307/MP3/ram.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5307/MP3/ram.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,72 @@ + +MEMORY { + ram : ORIGIN = 0x400, LENGTH = 0x1000000 +} + +jiffies = jiffies_64 + 4; + +SECTIONS { + + .text : { + _stext = . ; + *(.text) + *(.exit.text) + *(.text.lock) + *(.exitcall.exit) + *(.rodata) + . = ALIGN(0x4) ; + *(.kstrtab) + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + *(__ksymtab) + __stop___ksymtab = .; + . = ALIGN(4) ; + _etext = . ; + } > ram + + .data BLOCK(0x4) : { + _sdata = . ; + __data_start = . ; + *(.data) + *(.data.exit) + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + _edata = . ; + } > ram + + .init BLOCK(4096) : { + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = . ; + . = ALIGN(4); + __init_end = .; + } > ram + + .bss BLOCK(0x4) : { + _sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN(4) ; + _ebss = . ; + _end = . ; + } > ram +} + diff -Nru a/arch/m68knommu/platform/5307/Makefile b/arch/m68knommu/platform/5307/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5307/Makefile Mon Nov 4 14:31:04 2002 @@ -0,0 +1,27 @@ +# +# Makefile for the m68knommu kernel. +# + +# +# If you want to play with the HW breakpoints then you will +# need to add define this, which will give you a stack backtrace +# on the console port whenever a DBG interrupt occurs. You have to +# set up you HW breakpoints to trigger a DBG interrupt: +# +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT +# + +ifdef CONFIG_FULLDEBUG +AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 +endif + +obj-$(CONFIG_COLDFIRE) += entry.o +obj-$(CONFIG_M5307) += config.o + +ifeq ($(CONFIG_M5307),y) +EXTRA_TARGETS := $(BOARD)/crt0_$(MODEL).o +endif + +include $(TOPDIR)/Rules.make + diff -Nru a/arch/m68knommu/platform/5307/NETtel/crt0_ram.S b/arch/m68knommu/platform/5307/NETtel/crt0_ram.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5307/NETtel/crt0_ram.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,196 @@ +/*****************************************************************************/ + +/* + * crt0_ram.S -- startup code for MCF5307 ColdFire based NETtel. + * + * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com). + * Copyright (C) 2000 Lineo Inc. (www.lineo.com) + * + * 1999/02/24 Modified for the 5307 processor David W. Miller + */ + +/*****************************************************************************/ + +#include "linux/autoconf.h" +#include "asm/coldfire.h" +#include "asm/mcfsim.h" +#include "asm/nettel.h" + +/*****************************************************************************/ + +/* + * SnapGear/NETtel board memory setup. + */ +#define MEM_BASE 0x00000000 /* Memory base at address 0 */ +#define VBR_BASE MEM_BASE /* Vector address */ + +#if defined(CONFIG_RAM16MB) +#define MEM_SIZE 0x01000000 /* Memory size 16Mb */ +#elif defined(CONFIG_RAM8MB) +#define MEM_SIZE 0x00800000 /* Memory size 8Mb */ +#else +#define MEM_SIZE 0x00400000 /* Memory size 4Mb */ +#endif + +/*****************************************************************************/ + +.global _start +.global _rambase +.global _ramvec +.global _ramstart +.global _ramend + +/*****************************************************************************/ + +.data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +_rambase: +.long 0 +_ramvec: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +/*****************************************************************************/ + +/* + * The NETtel platform has some funky LEDs! + */ +.global ppdata +ppdata: +.short 0x0000 + +.global ledbank +ledbank: +.byte 0xff + +/*****************************************************************************/ + +.text + +/* + * This is the codes first entry point. This is where it all + * begins... + */ + +_start: + nop /* Filler */ + move.w #0x2700, %sr /* No interrupts */ + + /* + * Set LEDs to known startup state. + */ + move.l #NETtel_LEDADDR, %a5 /* Addr of LED bank */ + move.b #0xff, (%a5) /* Turn them all off */ + + + /* + * Disable watchdog timer. + */ + move.l #MCF_MBAR, %a0 /* Get MBAR address */ + clr.l %d0 /* Disable SWT */ + move.b %d0, MCFSIM_SYPCR(%a0) + move.b #0x55, %d0 /* Clear SWT as well */ + move.b %d0, MCFSIM_SWSR(%a0) + move.b #0xaa, %d0 + move.b %d0, MCFSIM_SWSR(%a0) + move.l #0xffffffff, %d0 /* Mask out all interrupts */ + move.l %d0, MCFSIM_IMR(%a0) + + /* + * Setup VBR here, otherwise buserror remap will not work. + * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996) + * + * bkr@cut.de 19990306 + * + * Note: this is because dBUG points VBR to ROM, making vectors read + * only, so the bus trap can't be changed. (RS) + */ + move.l #VBR_BASE, %a7 /* Note VBR can't be read */ + movec %a7, %VBR + move.l %a7, _ramvec /* Set up vector addr */ + move.l %a7, _rambase /* Set up base RAM addr */ + + + /* + * Determine size of RAM, then set up initial stack. + */ + move.l #MEM_SIZE, %a0 + + move.l %a0, %d0 /* Mem end addr is in a0 */ + move.l %d0, %sp /* Set up initial stack ptr */ + move.l %d0, _ramend /* Set end ram addr */ + + /* + * Enable CPU internal cache. + */ + move.l #0x01000000, %d0 /* invalidate whole cache */ + movec %d0,%CACR + nop +#ifdef DEBUGGER_COMPATIBLE_CACHE + move.l #0x0000c000, %d0 /* Set SDRAM cached only */ +#else + move.l #0x0000c020, %d0 /* Set SDRAM cached only (copyback) */ +#endif + movec %d0, %ACR0 + move.l #0x00000000, %d0 /* No other regions cached */ + movec %d0, %ACR1 + + /* Enable cache */ + move.l #0xa0000200, %d0 + movec %d0,%CACR + nop + + /* + * Move ROM filesystem above bss :-) + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Set up destination */ + move.l %a0, %a2 /* Copy of bss start */ + + move.l 8(%a0), %d0 /* Get size of ROMFS */ + addq.l #8, %d0 /* Allow for rounding */ + and.l #0xfffffffc, %d0 /* Whole words */ + + add.l %d0, %a0 /* Copy from end */ + add.l %d0, %a1 /* Copy from end */ + move.l %a1, _ramstart /* Set start of ram */ + +_copy_romfs: + move.l -(%a0), %d0 /* Copy dword */ + move.l %d0, -(%a1) + cmp.l %a0, %a2 /* Check if at end */ + bne _copy_romfs + + /* + * Zero out the bss region. + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Get end of bss */ + clr.l %d0 /* Set value */ +_clear_bss: + move.l %d0, (%a0)+ /* Clear each word */ + cmp.l %a0, %a1 /* Check if at end */ + bne _clear_bss + + /* + * load the current task pointer and stack + */ + lea init_thread_union, %a0 + lea 0x2000(%a0), %sp + + /* + * Assember start up done, start code proper. + */ + jsr start_kernel /* Start Linux kernel */ + +_exit: + jmp _exit /* Should never get here */ + +/*****************************************************************************/ diff -Nru a/arch/m68knommu/platform/5307/NETtel/ram.ld b/arch/m68knommu/platform/5307/NETtel/ram.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5307/NETtel/ram.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,72 @@ + +MEMORY { + ram : ORIGIN = 0x400, LENGTH = 0x400000 +} + +jiffies = jiffies_64 + 4; + +SECTIONS { + + .text : { + _stext = . ; + *(.text) + *(.exit.text) + *(.text.lock) + *(.exitcall.exit) + *(.rodata) + . = ALIGN(0x4) ; + *(.kstrtab) + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + *(__ksymtab) + __stop___ksymtab = .; + . = ALIGN(4) ; + _etext = . ; + } > ram + + .data BLOCK(0x4) : { + _sdata = . ; + __data_start = . ; + *(.data) + *(.data.exit) + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + _edata = . ; + } > ram + + .init BLOCK(4096) : { + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(4) ; + __init_end = .; + } > ram + + .bss BLOCK(0x4) : { + _sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN(4) ; + _ebss = . ; + _end = . ; + } > ram +} + diff -Nru a/arch/m68knommu/platform/5307/config.c b/arch/m68knommu/platform/5307/config.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5307/config.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,337 @@ +/***************************************************************************/ + +/* + * linux/arch/m68knommu/platform/5307/config.c + * + * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 2000, Lineo (www.lineo.com) + */ + +/***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_eLIA) +#include +#endif + +#include + +/***************************************************************************/ + +void reset_setupbutton(void); +void coldfire_profile_init(void); + +/***************************************************************************/ + +/* + * DMA channel base address table. + */ +unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { + MCF_MBAR + MCFDMA_BASE0, + MCF_MBAR + MCFDMA_BASE1, + MCF_MBAR + MCFDMA_BASE2, + MCF_MBAR + MCFDMA_BASE3, +}; + +unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; + +/***************************************************************************/ + +void coldfire_tick(void) +{ + volatile unsigned char *timerp; + + /* Reset the ColdFire timer */ + timerp = (volatile unsigned char *) (MCF_MBAR + MCFTIMER_BASE1); + timerp[MCFTIMER_TER] = MCFTIMER_TER_CAP | MCFTIMER_TER_REF; +} + +/***************************************************************************/ + +void coldfire_timer_init(void (*handler)(int, void *, struct pt_regs *)) +{ + volatile unsigned short *timerp; + volatile unsigned char *icrp; + + /* Set up TIMER 1 as poll clock */ + timerp = (volatile unsigned short *) (MCF_MBAR + MCFTIMER_BASE1); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_DISABLE; + + timerp[MCFTIMER_TRR] = (unsigned short) ((MCF_CLK / 16) / HZ); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | + MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE; + + icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_TIMER1ICR); + +#if defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || \ + defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) || \ + defined(CONFIG_CLEOPATRA) + *icrp = MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3; + request_irq(30, handler, SA_INTERRUPT, "ColdFire Timer", NULL); +#else + *icrp = MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL5 | MCFSIM_ICR_PRI3; + request_irq(29, handler, SA_INTERRUPT, "ColdFire Timer", NULL); +#endif + +#if defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || \ + defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) + /* This is not really the right place to do this... */ + reset_setupbutton(); +#endif +#ifdef CONFIG_HIGHPROFILE + coldfire_profile_init(); +#endif + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_TIMER1); +} + +/***************************************************************************/ +#ifdef CONFIG_HIGHPROFILE +/***************************************************************************/ + +#define PROFILEHZ 1013 + +/* + * Use the other timer to provide high accuracy profiling info. + */ + +void coldfire_profile_tick(int irq, void *dummy, struct pt_regs *regs) +{ + volatile unsigned char *timerp; + + /* Reset the ColdFire timer2 */ + timerp = (volatile unsigned char *) (MCF_MBAR + MCFTIMER_BASE2); + timerp[MCFTIMER_TER] = MCFTIMER_TER_CAP | MCFTIMER_TER_REF; + + if (!user_mode(regs)) { + if (prof_buffer && current->pid) { + extern int _stext; + unsigned long ip = instruction_pointer(regs); + ip -= (unsigned long) &_stext; + ip >>= prof_shift; + if (ip < prof_len) + prof_buffer[ip]++; + } + } +} + +void coldfire_profile_init(void) +{ + volatile unsigned short *timerp; + volatile unsigned char *icrp; + + printk("PROFILE: lodging timer2=%d as profile timer\n", PROFILEHZ); + + /* Set up TIMER 2 as poll clock */ + timerp = (volatile unsigned short *) (MCF_MBAR + MCFTIMER_BASE2); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_DISABLE; + + timerp[MCFTIMER_TRR] = (unsigned short) ((MCF_CLK / 16) / PROFILEHZ); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | + MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE; + + icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_TIMER2ICR); + + *icrp = MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3; + request_irq(31, coldfire_profile_tick, (SA_INTERRUPT | IRQ_FLG_FAST), + "Profile Timer", NULL); + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_TIMER2); +} + +/***************************************************************************/ +#endif /* CONFIG_HIGHPROFILE */ +/***************************************************************************/ + +/* + * Program the vector to be an auto-vectored. + */ + +void mcf_autovector(unsigned int vec) +{ + volatile unsigned char *mbar; + + if ((vec >= 25) && (vec <= 31)) { + mbar = (volatile unsigned char *) MCF_MBAR; + vec = 0x1 << (vec - 24); + *(mbar + MCFSIM_AVR) |= vec; + mcf_setimr(mcf_getimr() & ~vec); + } +} + +/***************************************************************************/ + +extern e_vector *_ramvec; + +void set_evector(int vecnum, void (*handler)(void)) +{ + if (vecnum >= 0 && vecnum <= 255) + _ramvec[vecnum] = handler; +} + +/***************************************************************************/ + +/* assembler routines */ +asmlinkage void buserr(void); +asmlinkage void trap(void); +asmlinkage void system_call(void); +asmlinkage void inthandler(void); + +#ifdef TRAP_DBG_INTERRUPT +asmlinkage void dbginterrupt(void); +#endif + +void __init coldfire_trap_init(void) +{ + int i; + +#ifndef ENABLE_dBUG + mcf_setimr(MCFSIM_IMR_MASKALL); +#endif + + /* + * There is a common trap handler and common interrupt + * handler that handle almost every vector. We treat + * the system call and bus error special, they get their + * own first level handlers. + */ +#ifndef ENABLE_dBUG + for (i = 3; (i <= 23); i++) + _ramvec[i] = trap; + for (i = 33; (i <= 63); i++) + _ramvec[i] = trap; +#endif +#ifdef TRAP_DBG_INTERRUPT + _ramvec[12] = dbginterrupt; +#endif + + for (i = 24; (i <= 30); i++) + _ramvec[i] = inthandler; +#ifndef ENABLE_dBUG + _ramvec[31] = inthandler; // Disables the IRQ7 button +#endif + + for (i = 64; (i < 255); i++) + _ramvec[i] = inthandler; + _ramvec[255] = 0; + + _ramvec[2] = buserr; + _ramvec[32] = system_call; +#ifdef MCF_BDM_DISABLE + /* Disable the BDM clocking. This also turns off most of the rest of + * the BDM device. This is good for EMC reasons. This option is not + * incompatible with the memory protection option. + */ + wdebug(MCFDEBUG_CSR, MCFDEBUG_CSR_PSTCLK); +#endif + +} + +/***************************************************************************/ + +#if defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || \ + defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) + +/* + * Routines to support the NETtel software reset button. + */ +void reset_button(int irq, void *dev_id, struct pt_regs *regs) +{ + extern void flash_eraseconfig(void); + static int inbutton = 0; + + /* + * IRQ7 is not maskable by the CPU core. It is possible + * that switch bounce mey get us back here before we have + * really serviced the interrupt. + */ + if (inbutton) + return; + inbutton = 1; + /* Disable interrupt at SIM - best we can do... */ + mcf_setimr(mcf_getimr() | MCFSIM_IMR_EINT7); + /* Try and de-bounce the switch a little... */ + udelay(10000); + + flash_eraseconfig(); + + /* Don't leave here 'till button is no longer pushed! */ + for (;;) { + if ((mcf_getipr() & MCFSIM_IMR_EINT7) == 0) + break; + } + + HARD_RESET_NOW(); + /* Should never get here... */ + + inbutton = 0; + /* Interrupt service done, enable it again */ + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_EINT7); +} + +/***************************************************************************/ + +void reset_setupbutton(void) +{ + volatile unsigned char *mbar; + + mbar = (volatile unsigned char *) MCF_MBAR; + *(mbar + MCFSIM_AVR) |= MCFSIM_IMR_EINT7; + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_EINT7); + request_irq(31, reset_button, (SA_INTERRUPT | IRQ_FLG_FAST), + "Reset Button", NULL); +} + +#endif /* CONFIG_NETtel || CONFIG_eLIA || CONFIG_DISKtel || CONFIG_SECUREEDGEMP3 */ + +/***************************************************************************/ + +void coldfire_reset(void) +{ + HARD_RESET_NOW(); +} + +/***************************************************************************/ + +void config_BSP(char *commandp, int size) +{ +#if defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || \ + defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) + /* Copy command line from FLASH to local buffer... */ + memcpy(commandp, (char *) 0xf0004000, size); + commandp[size-1] = 0; +#else + memset(commandp, 0, size); +#endif /* CONFIG_NETtel || CONFIG_eLIA || CONFIG_DISKtel || CONFIG_SECUREEDGEMP3 */ + + mach_sched_init = coldfire_timer_init; + mach_tick = coldfire_tick; + mach_trap_init = coldfire_trap_init; + mach_reset = coldfire_reset; +} + +/***************************************************************************/ +#ifdef TRAP_DBG_INTERRUPT + +asmlinkage void dbginterrupt_c(struct frame *fp) +{ + extern void dump(struct pt_regs *fp); + printk("%s(%d): BUS ERROR TRAP\n", __FILE__, __LINE__); + dump((struct pt_regs *) fp); + asm("halt"); +} + +#endif +/***************************************************************************/ diff -Nru a/arch/m68knommu/platform/5307/entry.S b/arch/m68knommu/platform/5307/entry.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5307/entry.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,557 @@ +/* -*- mode: asm -*- + * + * linux/arch/m68knommu/platform/5307/entry.S + * + * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 1998 D. Jeff Dionne , + * Kenneth Albanowski , + * Copyright (C) 2000 Lineo Inc. (www.lineo.com) + * + * Based on: + * + * linux/arch/m68k/kernel/entry.S + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * + * Linux/m68k support by Hamish Macdonald + * + * 68060 fixes by Jesper Skov + * ColdFire support by Greg Ungerer (gerg@snapgear.com) + * 5307 fixes by David W. Miller + * linux 2.4 support David McCullough + */ + +/* + * entry.S contains the system-call and fault low-level handling routines. + * This also contains the timer-interrupt handler, as well as all interrupts + * and faults that can result in a task-switch. + * + * NOTE: This code handles signal-recognition, which happens every time + * after a timer-interrupt and after each system call. + * + * Stack layout in 'ret_from_exception': + * + * This allows access to the syscall arguments in registers d1-d5 + * + * 0(sp) - d1 + * 4(sp) - d2 + * 8(sp) - d3 + * C(sp) - d4 + * 10(sp) - d5 + * 14(sp) - a0 + * 18(sp) - a1 + * 1C(sp) - a2 + * 20(sp) - d0 + * 24(sp) - orig_d0 + * 28(sp) - stack adjustment + * 2C(sp) - format & vector } + * 2E(sp) - sr } different to m68k + * 30(sp) - pc } + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +LENOSYS = 38 + +/* the following macro is used when enabling interrupts */ +#define ALLOWINT 0xf8ff +#define MAX_NOINT_IPL 0 + + +LD0 = 0x20 +LORIG_D0 = 0x24 +LFORMATVEC = 0x2c +LSR = 0x2e +LPC = 0x30 + +/* + * This defines the normal kernel pt-regs layout. + * + * regs are a2-a6 and d6-d7 preserved by C code + * the kernel doesn't mess with usp unless it needs to + * + * This is made a little more tricky on the ColdFire. There is no + * separate kernel and user stack pointers. Need to artificially + * construct a usp in software... When doing this we need to disable + * interrupts, otherwise bad things could happen. + */ +#define SAVE_ALL \ + move #0x2700,%sr; /* disable intrs */ \ + btst #5,%sp@(2); /* from user? */ \ + bnes 6f; /* no, skip */ \ + movel %sp,sw_usp; /* save user sp */ \ + addql #8,sw_usp; /* remove exception */ \ + movel sw_ksp,%sp; /* kernel sp */ \ + subql #8,%sp; /* room for exception */\ + clrl %sp@-; /* stk_adj */ \ + movel %d0,%sp@-; /* orig d0 */ \ + movel %d0,%sp@-; /* d0 */ \ + subl #32,%sp; /* space for 8 regs */ \ + moveml %d1-%d5/%a0-%a2,%sp@; \ + movel sw_usp,%a0; /* get usp */ \ + moveml %a0@(-8),%d1-%d2; /* get exception */ \ + moveml %d1-%d2,%sp@(LFORMATVEC); /* copy exception */ \ + bra 7f; \ + 6: \ + clrl %sp@-; /* stk_adj */ \ + movel %d0,%sp@-; /* orig d0 */ \ + movel %d0,%sp@-; /* d0 */ \ + subl #32,%sp; /* space for 7 regs */ \ + moveml %d1-%d5/%a0-%a2,%sp@; \ + 7: + +#define RESTORE_ALL \ + btst #5,%sp@(LSR); /* going user? */ \ + bnes 8f; /* no, skip */ \ + move #0x2700,%sr; /* disable intrs */ \ + movel sw_usp,%a0; /* get usp */ \ + moveml %sp@(LFORMATVEC),%d1-%d2; /* copy exception */ \ + moveml %d1-%d2,%a0@(-8); \ + moveml %sp@,%d1-%d5/%a0-%a2; \ + addl #32,%sp; /* space for 8 regs */ \ + movel %sp@+,%d0; \ + addql #4,%sp; /* orig d0 */ \ + addl %sp@+,%sp; /* stk adj */ \ + addql #8,%sp; /* remove exception */ \ + movel %sp,sw_ksp; /* save ksp */ \ + subql #8,sw_usp; /* set exception */ \ + movel sw_usp,%sp; /* restore usp */ \ + rte; \ + 8: \ + moveml %sp@,%d1-%d5/%a0-%a2; \ + addl #32,%sp; /* space for 8 regs */ \ + movel %sp@+,%d0; \ + addql #4,%sp; /* orig d0 */ \ + addl %sp@+,%sp; /* stk adj */ \ + rte + +/* + * Quick exception save, use current stack only. + */ +#define SAVE_LOCAL \ + move #0x2700,%sr; /* disable intrs */ \ + clrl %sp@-; /* stk_adj */ \ + movel %d0,%sp@-; /* orig d0 */ \ + movel %d0,%sp@-; /* d0 */ \ + subl #32,%sp; /* space for 8 regs */ \ + moveml %d1-%d5/%a0-%a2,%sp@; + +#define RESTORE_LOCAL \ + moveml %sp@,%d1-%d5/%a0-%a2; \ + addl #32,%sp; /* space for 8 regs */ \ + movel %sp@+,%d0; \ + addql #4,%sp; /* orig d0 */ \ + addl %sp@+,%sp; /* stk adj */ \ + rte + + +#define SWITCH_STACK_SIZE (6*4+4) /* includes return address */ + +#define SAVE_SWITCH_STACK \ + subl #24,%sp; /* 6 regs */ \ + moveml %a3-%a6/%d6-%d7,%sp@ + +#define RESTORE_SWITCH_STACK \ + moveml %sp@,%a3-%a6/%d6-%d7; \ + addl #24,%sp /* 6 regs */ + +/* + * Software copy of the user and kernel stack pointers... Ugh... + * Need these to get around ColdFire not having separate kernel + * and user stack pointers. + */ +.globl sw_usp +.globl sw_ksp + +.data + +sw_ksp: +.long 0 + +sw_usp: +.long 0 + +.text + + +.globl buserr +.globl trap +.globl system_call +.globl resume, ret_from_exception +.globl ret_from_signal +.globl sys_call_table +.globl sys_fork, sys_clone, sys_vfork +.globl ret_from_interrupt +.globl inthandler +.globl fasthandler + +#ifdef TRAP_DBG_INTERRUPT +.globl dbginterrupt +#endif + +/*--------------------------------------------------------------------------*/ + +.text + +ENTRY(buserr) + SAVE_ALL + moveq #-1,%d0 + movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field + | signifies that the stack frame + | is NOT for syscall + + movel %sp,%sp@- | stack frame pointer argument + jsr buserr_c + addql #4,%sp + jra ret_from_exception + + +#ifdef TRAP_DBG_INTERRUPT +ENTRY(dbginterrupt) + SAVE_ALL + moveq #-1,%d0 + movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field + | signifies that the stack frame + | is NOT for syscall + + movel %sp,%sp@- | stack frame pointer argument + jsr dbginterrupt_c + addql #4,%sp + jra ret_from_exception +#endif + + +ENTRY(reschedule) + | save top of frame + pea %sp@ + jbsr set_esp0 + addql #4,%sp + + pea ret_from_exception + jmp schedule + + | After a fork we jump here directly from resume, + | so that %d1 contains the previous task + | Theoretically only needed on SMP, but lets watch + | what happens in schedule_tail() in future... +ENTRY(ret_from_fork) +#ifdef CONFIG_SMP + movel %d1,%sp@- + jsr schedule_tail + addql #4,%sp +#endif + jra ret_from_exception + +ENTRY(system_call) + SAVE_ALL + move #0x2000,%sr; | enable intrs again + + movel #-LENOSYS,%d2 + movel %d2,LD0(%sp) | default return value in d0 + | original D0 is in orig_d0 + movel %d0,%d2 + + | save top of frame + pea %sp@ + jbsr set_esp0 + addql #4,%sp + + cmpl #NR_syscalls,%d2 + jcc ret_from_exception + lea sys_call_table,%a0 + lsll #2,%d2 | movel %a0@(%d2:l:4),%d3 + movel %a0@(%d2),%d3 + jeq ret_from_exception + lsrl #2,%d2 + + movel %sp,%d2 | get thread_info pointer + andl #0xffffe000,%d2 | at start of 8k kernel stack + movel %d2,%a0 + btst #TIF_SYSCALL_TRACE,%a0@(TI_FLAGS) + bnes 1f + + movel %d3,%a0 + jbsr %a0@ + movel %d0,%sp@(LD0) | save the return value + jra ret_from_exception +1: + subql #4,%sp + SAVE_SWITCH_STACK + jbsr syscall_trace + RESTORE_SWITCH_STACK + addql #4,%sp + movel %d3,%a0 + jbsr %a0@ + movel %d0,%sp@(LD0) | save the return value + subql #4,%sp | dummy return address + SAVE_SWITCH_STACK + jbsr syscall_trace + +ret_from_signal: + RESTORE_SWITCH_STACK + addql #4,%sp + +ret_from_exception: + btst #5,%sp@(LSR) | check if returning to kernel + jeq Luser_return | if so, skip resched, signals + +Lkernel_return: + moveml %sp@,%d1-%d5/%a0-%a2 + addl #32,%sp | space for 8 regs + movel %sp@+,%d0 + addql #4,%sp | orig d0 + addl %sp@+,%sp | stk adj + rte + +Luser_return: + movel %sp,%d1 | get thread_info pointer + andl #0xffffe000,%d1 | at base of 8k kernel stack + movel %d1,%a0 + movel %a0@(TI_FLAGS),%d1 | get thread_info->flags + andl #_TIF_WORK_MASK,%d1 + jne Lwork_to_do | still work to do + +Lreturn: + move #0x2700,%sr | disable intrs + movel sw_usp,%a0 | get usp + moveml %sp@(LFORMATVEC),%d1-%d2 | copy exception + moveml %d1-%d2,%a0@(-8) + bclr #5,%a0@(-8) | clear format byte, bit 5 to make + | stack appear modulo 4 which it WILL + | be when we do the rte because it was + | generated in setup_frame + bclr #4,%a0@(-8) | clear format byte, bit 4 to make + | stack appear modulo 4 which it WILL + | be when we do the rte because it was + | generated in setup_frame + moveml %sp@,%d1-%d5/%a0-%a2 + addl #32,%sp | space for 8 regs + movel %sp@+,%d0 + addql #4,%sp | orig d0 + addl %sp@+,%sp | stk adj + addql #8,%sp | remove exception + movel %sp,sw_ksp | save ksp + movel sw_usp,%sp | restore usp + subql #8,%sp | set exception + rte + +Lwork_to_do: + movel %a0@(TI_FLAGS),%d1 | get thread_info->flags + btst #TIF_NEED_RESCHED,%d1 + jne reschedule + + /* GERG: do we need something here for TRACEing?? */ + +Lsignal_return: + subql #4,%sp | dummy return address + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + clr %d1 + movel %d1,%sp@- + jsr do_signal + addql #8,%sp + RESTORE_SWITCH_STACK + addql #4,%sp + jmp Lreturn + +/*--------------------------------------------------------------------------*/ + +/* + * Common ColdFire trap handler. Most traps come through here first. + */ +ENTRY(trap) + SAVE_ALL + moveq #-1,%d0 + movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field + | signifies that the stack frame + | is NOT for syscall + movel %sp,%sp@- | stack frame pointer argument + jsr trap_c + addql #4,%sp + jra ret_from_exception + +/* + * This is the generic interrupt handler (for all hardware interrupt + * sources). It figures out the vector number and calls the appropriate + * interrupt service routine directly. + */ +ENTRY(inthandler) + SAVE_ALL + moveq #-1,%d0 + movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field + | signifies that the stack frame + | is NOT for syscall + addql #1,local_irq_count + | put exception # in d0 + movew %sp@(LFORMATVEC),%d0 + andl #0x03fc,%d0 | mask out vector only + + movel mach_kstat_irqs,%a0 + | get addr of kstat struct + addql #1,%a0@(%d0) | incr irq intr count + + lsrl #2,%d0 | calculate real vector # + movel %d0,%d1 | calculate array offset + lsll #4,%d1 + lea irq_list,%a0 + addl %d1,%a0 | pointer to array struct + + movel %sp,%sp@- | push regs arg onto stack + movel %a0@(8),%sp@- | push devid arg + movel %d0,%sp@- | push vector # on stack + + movel %a0@,%a0 | get function to call + jbsr %a0@ | call vector handler + addl #12,%sp | pop parameters off stack + + bra ret_from_interrupt | this was fallthrough + + +/* + * This is the fast interrupt handler (for certain hardware interrupt + * sources). Unlike the normal interrupt handler it just uses the + * current stack (doesn't care if it is user or kernel). It also + * doesn't bother doing the bottom half handlers. + */ +ENTRY(fasthandler) + SAVE_LOCAL + + movew %sp@(LFORMATVEC),%d0 + andl #0x03fc,%d0 | mask out vector only + + movel mach_kstat_irqs,%a0 + | get addr of kstat struct + addql #1,%a0@(%d0) | incr irq intr count + + movel %sp,%sp@- | push regs arg onto stack + clrl %d1 + movel %d1,%sp@- | push devid arg + lsrl #2,%d0 | calculate real vector # + movel %d0,%sp@- | push vector # on stack + + lsll #4,%d0 | adjust for array offset + lea irq_list,%a0 + movel %a0@(%d0),%a0 | get function to call + jbsr %a0@ | call vector handler + addl #12,%sp | pop parameters off stack + + RESTORE_LOCAL + +/*--------------------------------------------------------------------------*/ + +ENTRY(ret_from_interrupt) + subql #1,local_irq_count + jeq 2f +1: + RESTORE_ALL +2: + moveb %sp@(LSR),%d0 + andl #0x7,%d0 +#if MAX_NOINT_IPL > 0 + cmpiw #MAX_NOINT_IPL,%d0 +#endif + jhi 1b + + /* check if we need to do software interrupts */ + movel irq_stat+CPUSTAT_SOFTIRQ_PENDING,%d0 + jeq ret_from_exception + + pea ret_from_exception + jmp do_softirq + +ENTRY(sys_fork) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr m68k_fork + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_vfork) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr m68k_vfork + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_clone) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr m68k_clone + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_sigsuspend) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr do_sigsuspend + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_rt_sigsuspend) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr do_rt_sigsuspend + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_sigreturn) + SAVE_SWITCH_STACK + jbsr do_sigreturn + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_rt_sigreturn) + SAVE_SWITCH_STACK + jbsr do_rt_sigreturn + RESTORE_SWITCH_STACK + rts + +/*--------------------------------------------------------------------------*/ + +/* + * Beware - when entering resume, prev (the current task) is + * in a0, next (the new task) is in a1,so don't change these + * registers until their contents are no longer needed. + */ +ENTRY(resume) + + movel %a0, %d1 | get prev thread in d1 + + movew %sr,%d0 | save thread status reg + movew %d0,%a0@(TASK_THREAD+THREAD_SR) + + oril #0x700,%d0 | disable interrupts + move %d0,%sr + + movel sw_usp,%d0 | save usp + movel %d0,%a0@(TASK_THREAD+THREAD_USP) + + SAVE_SWITCH_STACK + movel %sp,%a0@(TASK_THREAD+THREAD_KSP) | save kernel stack pointer + movel %a1@(TASK_THREAD+THREAD_KSP),%sp | restore new thread stack + RESTORE_SWITCH_STACK + + movel %a1@(TASK_THREAD+THREAD_USP),%a0 | restore thread user stack + movel %a0, sw_usp + + movew %a1@(TASK_THREAD+THREAD_SR),%d0 | restore thread status reg + movew %d0, %sr + rts + +/*--------------------------------------------------------------------------*/ diff -Nru a/arch/m68knommu/platform/5407/CLEOPATRA/crt0_ram.S b/arch/m68knommu/platform/5407/CLEOPATRA/crt0_ram.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5407/CLEOPATRA/crt0_ram.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,173 @@ +/*****************************************************************************/ + +/* + * crt0_ram.S -- startup code for Feith Cleopatra 2 board. + * + * (C) Copyright 2001, Roman Wagner. + * + * 1999/02/24 Modified for the 5307 processor David W. Miller + */ + +/*****************************************************************************/ + +#include "linux/autoconf.h" +#include "asm/coldfire.h" +#include "asm/mcfsim.h" + +/*****************************************************************************/ + +/* + * Feith CLEOPATRA board, chip select and memory setup. +*/ + +#define MEM_BASE 0x00000000 /* Memory base at address 0 */ +#define VBR_BASE MEM_BASE /* Vector address */ + +#define MEM_SIZE 0x01000000 /* Memory size 16Mb */ + +/*****************************************************************************/ + +.global _start +.global _rambase +.global _ramvec +.global _ramstart +.global _ramend + +/*****************************************************************************/ + +.data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +_rambase: +.long 0 +_ramvec: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +/*****************************************************************************/ + +.text + +/* + * This is the codes first entry point. This is where it all + * begins... + */ + +_start: + nop /* Filler */ + move.w #0x2700, %sr /* No interrupts */ + + + /* + * Setup VBR here, otherwise buserror remap will not work. + * if dBug was active before (on my SBC with dBug 1.1 of Dec 16 1996) + * + * bkr@cut.de 19990306 + * + * Note: this is because dBUG points VBR to ROM, making vectors read + * only, so the bus trap can't be changed. (RS) + */ + move.l #VBR_BASE, %a7 /* Note VBR can't be read */ + movec %a7, %VBR + move.l %a7, _ramvec /* Set up vector addr */ + move.l %a7, _rambase /* Set up base RAM addr */ + + /* + * Determine size of RAM, then set up initial stack. + */ +/* + * The current version of the 5307 processor + * SWT does not work. Probing invalid addresses + * will hang the system. + * + * For now, set the memory size to 8 meg + */ + move.l #MEM_SIZE, %a0 + + move.l %a0, %d0 /* Mem end addr is in a0 */ + move.l %d0, %sp /* Set up initial stack ptr */ + move.l %d0, _ramend /* Set end ram addr */ + + + /* + * Enable CPU internal cache. + */ + move.l #0x01040100, %d0 /* Invalidate whole cache */ + movec %d0,%CACR + nop + + /* make region ROM cachable (turn off for flash programming?) */ + /* 0xff000000 - 0xffffffff */ + move.l #(0xff< ram + + .data BLOCK(0x4) : { + _sdata = . ; + __data_start = . ; + *(.data) + *(.data.exit) + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + _edata = . ; + } > ram + + .init BLOCK(4096) : { + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = . ; + . = ALIGN(4); + __init_end = .; + } > ram + + .bss BLOCK(0x4) : { + _sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN(4) ; + _ebss = . ; + _end = . ; + } > ram +} + diff -Nru a/arch/m68knommu/platform/5407/MOTOROLA/crt0_ram.S b/arch/m68knommu/platform/5407/MOTOROLA/crt0_ram.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5407/MOTOROLA/crt0_ram.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,152 @@ +/*****************************************************************************/ + +/* + * crt0_ram.S -- startup code for Motorola 5407 eval board. + * + * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com). + * (C) Copyright 2000, Lineo (www.lineo.com). + * + * 1999/02/24 Modified for the 5307 processor David W. Miller + */ + +/*****************************************************************************/ + +#include "linux/autoconf.h" +#include "asm/coldfire.h" +#include "asm/mcfsim.h" + +/*****************************************************************************/ + +/* + * Board setup info. + */ +#define MEM_BASE 0x00000000 /* Memory base at address 0 */ +#define VBR_BASE MEM_BASE /* Vector address */ + +#define MEM_SIZE 0x02000000 /* Memory size 32 */ + +/*****************************************************************************/ + +.global _start +.global _rambase +.global _ramvec +.global _ramstart +.global _ramend + +/*****************************************************************************/ + +.data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +_rambase: +.long 0 +_ramvec: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +/*****************************************************************************/ + +.text + +/* + * This is the codes first entry point. This is where it all + * begins... + */ + +_start: + nop /* Filler */ + move.w #0x2700, %sr /* No interrupts */ + + /* + * Setup VBR as per eval board (really dBUG does this). + * These settings must match it. + */ + move.l #VBR_BASE, %a0 /* Note VBR can't be read */ + movec %a0, %VBR + move.l %a0, _ramvec /* Set up vector addr */ + move.l %a0, _rambase /* Set up base RAM addr */ + + + /* + * Determine size of RAM, then set up initial stack. + */ + move.l #MEM_SIZE, %a0 + + move.l %a0, %d0 /* Mem end addr is in a0 */ + move.l %d0, %sp /* Set up initial stack ptr */ + move.l %d0, _ramend /* Set end ram addr */ + + + /* + * Enable CPU internal cache. + */ + move.l #0x01040100, %d0 /* Invalidate whole cache */ + movec %d0,%CACR + nop + move.l #0x000fc000, %d0 /* Set SDRAM cached only */ + movec %d0, %ACR0 + move.l #0x00000000, %d0 /* No other regions cached */ + movec %d0, %ACR1 + move.l #0x000fc000, %d0 /* Set SDRAM cached only */ + movec %d0, %ACR2 + move.l #0x00000000, %d0 /* No other regions cached */ + movec %d0, %ACR3 + + /* Enable cache */ + move.l #0x86088400, %d0 + movec %d0,%CACR + nop + + /* + * Move ROM filesystem above bss :-) + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Set up destination */ + move.l %a0, %a2 /* Copy of bss start */ + + move.l 8(%a0), %d0 /* Get size of ROMFS */ + addq.l #8, %d0 /* Allow for rounding */ + and.l #0xfffffffc, %d0 /* Whole words */ + + add.l %d0, %a0 /* Copy from end */ + add.l %d0, %a1 /* Copy from end */ + move.l %a1, _ramstart /* Set start of ram */ + +_copy_romfs: + move.l -(%a0), %d0 /* Copy dword */ + move.l %d0, -(%a1) + cmp.l %a0, %a2 /* Check if at end */ + bne _copy_romfs + + /* + * Zero out the bss region. + */ + lea.l _sbss, %a0 /* Get start of bss */ + lea.l _ebss, %a1 /* Get end of bss */ + clr.l %d0 /* Set value */ +_clear_bss: + move.l %d0, (%a0)+ /* Clear each word */ + cmp.l %a0, %a1 /* Check if at end */ + bne _clear_bss + + /* + * Load the current task pointer and stack. + */ + lea init_thread_union, %a0 + lea 0x2000(%a0), %sp + + /* + * Assember start up done, start code proper. + */ + jsr start_kernel /* Start Linux kernel */ + +_exit: + jmp _exit /* Should never get here */ + +/*****************************************************************************/ diff -Nru a/arch/m68knommu/platform/5407/MOTOROLA/ram.ld b/arch/m68knommu/platform/5407/MOTOROLA/ram.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5407/MOTOROLA/ram.ld Mon Nov 4 14:31:03 2002 @@ -0,0 +1,72 @@ + +MEMORY { + ram : ORIGIN = 0x20000, LENGTH = 0x007E0000 +} + +jiffies = jiffies_64 + 4; + +SECTIONS { + + .text : { + _stext = . ; + *(.text) + *(.exit.text) + *(.text.lock) + *(.exitcall.exit) + *(.rodata) + . = ALIGN(0x4) ; + *(.kstrtab) + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + *(__ksymtab) + __stop___ksymtab = .; + . = ALIGN(4) ; + _etext = . ; + } > ram + + .data BLOCK(0x4) : { + _sdata = . ; + __data_start = . ; + *(.data) + *(.data.exit) + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + _edata = . ; + } > ram + + .init BLOCK(4096) : { + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(4) ; + __init_end = .; + } > ram + + .bss BLOCK(0x4) : { + _sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN(4) ; + _ebss = . ; + _end = . ; + } > ram +} + diff -Nru a/arch/m68knommu/platform/5407/Makefile b/arch/m68knommu/platform/5407/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5407/Makefile Mon Nov 4 14:31:03 2002 @@ -0,0 +1,24 @@ +# +# Makefile for the m68knommu linux kernel. +# + +# +# If you want to play with the HW breakpoints then you will +# need to add define this, which will give you a stack backtrace +# on the console port whenever a DBG interrupt occurs. You have to +# set up you HW breakpoints to trigger a DBG interrupt: +# +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT +# + +ifdef CONFIG_FULLDEBUG +AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 +endif + +obj-y := config.o + +EXTRA_TARGETS := $(BOARD)/crt0_$(MODEL).o + +include $(TOPDIR)/Rules.make + diff -Nru a/arch/m68knommu/platform/5407/config.c b/arch/m68knommu/platform/5407/config.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5407/config.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,236 @@ +/***************************************************************************/ + +/* + * linux/arch/m68knommu/platform/5407/config.c + * + * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 2000, Lineo (www.lineo.com) + */ + +/***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/***************************************************************************/ + +void coldfire_profile_init(void); + +/***************************************************************************/ + +/* + * DMA channel base address table. + */ +unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = { + MCF_MBAR + MCFDMA_BASE0, + MCF_MBAR + MCFDMA_BASE1, + MCF_MBAR + MCFDMA_BASE2, + MCF_MBAR + MCFDMA_BASE3, +}; + +unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; + +/***************************************************************************/ + +void coldfire_tick(void) +{ + volatile unsigned char *timerp; + + /* Reset the ColdFire timer */ + timerp = (volatile unsigned char *) (MCF_MBAR + MCFTIMER_BASE1); + timerp[MCFTIMER_TER] = MCFTIMER_TER_CAP | MCFTIMER_TER_REF; +} + +/***************************************************************************/ + +void coldfire_timer_init(void (*handler)(int, void *, struct pt_regs *)) +{ + volatile unsigned short *timerp; + volatile unsigned char *icrp; + + /* Set up TIMER 1 as poll clock */ + timerp = (volatile unsigned short *) (MCF_MBAR + MCFTIMER_BASE1); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_DISABLE; + + timerp[MCFTIMER_TRR] = (unsigned short) ((MCF_CLK / 16) / HZ); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | + MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE; + + icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_TIMER1ICR); + +#if defined(CONFIG_CLEOPATRA) + *icrp = MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3; + request_irq(30, handler, SA_INTERRUPT, "ColdFire Timer", NULL); +#else + *icrp = MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL5 | MCFSIM_ICR_PRI3; + request_irq(29, handler, SA_INTERRUPT, "ColdFire Timer", NULL); +#endif + +#ifdef CONFIG_HIGHPROFILE + coldfire_profile_init(); +#endif + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_TIMER1); +} + +/***************************************************************************/ +#ifdef CONFIG_HIGHPROFILE +/***************************************************************************/ + +#define PROFILEHZ 1013 + +/* + * Use the other timer to provide high accuracy profiling info. + */ + +void coldfire_profile_tick(int irq, void *dummy, struct pt_regs *regs) +{ + volatile unsigned char *timerp; + + /* Reset the ColdFire timer2 */ + timerp = (volatile unsigned char *) (MCF_MBAR + MCFTIMER_BASE2); + timerp[MCFTIMER_TER] = MCFTIMER_TER_CAP | MCFTIMER_TER_REF; + + if (!user_mode(regs)) { + if (prof_buffer && current->pid) { + extern int _stext; + unsigned long ip = instruction_pointer(regs); + ip -= (unsigned long) &_stext; + ip >>= prof_shift; + if (ip < prof_len) + prof_buffer[ip]++; + } + } +} + +void coldfire_profile_init(void) +{ + volatile unsigned short *timerp; + volatile unsigned char *icrp; + + printk("PROFILE: lodging timer2=%d as profile timer\n", PROFILEHZ); + + /* Set up TIMER 2 as poll clock */ + timerp = (volatile unsigned short *) (MCF_MBAR + MCFTIMER_BASE2); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_DISABLE; + + timerp[MCFTIMER_TRR] = (unsigned short) ((MCF_CLK / 16) / PROFILEHZ); + timerp[MCFTIMER_TMR] = MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | + MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE; + + icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_TIMER2ICR); + + *icrp = MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3; + request_irq(31, coldfire_profile_tick, (SA_INTERRUPT | IRQ_FLG_FAST), + "Profile Timer", NULL); + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_TIMER2); +} + +/***************************************************************************/ +#endif /* CONFIG_HIGHPROFILE */ +/***************************************************************************/ + +/* + * Program the vector to be an auto-vectored. + */ + +void mcf_autovector(unsigned int vec) +{ + volatile unsigned char *mbar; + + if ((vec >= 25) && (vec <= 31)) { + mbar = (volatile unsigned char *) MCF_MBAR; + vec = 0x1 << (vec - 24); + *(mbar + MCFSIM_AVR) |= vec; + mcf_setimr(mcf_getimr() & ~vec); + } +} + +/***************************************************************************/ + +extern e_vector *_ramvec; + +void set_evector(int vecnum, void (*handler)(void)) +{ + if (vecnum >= 0 && vecnum <= 255) + _ramvec[vecnum] = handler; +} + +/***************************************************************************/ + +/* assembler routines */ +asmlinkage void buserr(void); +asmlinkage void trap(void); +asmlinkage void system_call(void); +asmlinkage void inthandler(void); + +void __init coldfire_trap_init(void) +{ + int i; + +#ifndef ENABLE_dBUG + mcf_setimr(MCFSIM_IMR_MASKALL); +#endif + + /* + * There is a common trap handler and common interrupt + * handler that handle almost every vector. We treat + * the system call and bus error special, they get their + * own first level handlers. + */ +#ifndef ENABLE_dBUG + for (i = 3; (i <= 23); i++) + _ramvec[i] = trap; + for (i = 33; (i <= 63); i++) + _ramvec[i] = trap; +#endif + + for (i = 24; (i <= 30); i++) + _ramvec[i] = inthandler; +#ifndef ENABLE_dBUG + _ramvec[31] = inthandler; // Disables the IRQ7 button +#endif + + for (i = 64; (i < 255); i++) + _ramvec[i] = inthandler; + _ramvec[255] = 0; + + _ramvec[2] = buserr; + _ramvec[32] = system_call; +} + +/***************************************************************************/ + +void config_BSP(char *commandp, int size) +{ + memset(commandp, 0, size); + + mach_sched_init = coldfire_timer_init; + mach_tick = coldfire_tick; + mach_trap_init = coldfire_trap_init; +} + +/***************************************************************************/ +#ifdef TRAP_DBG_INTERRUPT + +asmlinkage void dbginterrupt_c(struct frame *fp) +{ + extern void dump(struct pt_regs *fp); + printk("%s(%d): BUS ERROR TRAP\n", __FILE__, __LINE__); + dump((struct pt_regs *) fp); + asm("halt"); +} + +#endif +/***************************************************************************/ diff -Nru a/arch/m68knommu/platform/68328/Makefile b/arch/m68knommu/platform/68328/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68328/Makefile Mon Nov 4 14:31:04 2002 @@ -0,0 +1,17 @@ +# +# Makefile for arch/m68knommu/platform/68328. +# + +obj-$(CONFIG_M68328) += entry.o ints.o config.o +obj-$(CONFIG_M68EZ328) += entry.o ints.o +obj-$(CONFIG_M68VZ328) += entry.o ints.o + +ifeq ($(CONFIG_M68328),y) +EXTRA_TARGETS := $(BOARD)/bootlogo.rh $(BOARD/crt0_$(MODEL).o +endif + +include $(TOPDIR)/Rules.make + +$(obj)/$(BOARD)/bootlogo.rh: $(src)/bootlogo.h + perl $(src)/bootlogo.pl < $(src)/bootlogo.h > $(obj)/$(BOARD)/bootlogo.rh + diff -Nru a/arch/m68knommu/platform/68328/bootlogo.h b/arch/m68knommu/platform/68328/bootlogo.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68328/bootlogo.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,270 @@ +#define bootlogo_width 160 +#define bootlogo_height 160 +static unsigned char bootlogo_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x55, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x08, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, + 0x00, 0xff, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0xf8, 0x80, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x04, 0x00, 0x00, 0x00, 0x78, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x03, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x40, + 0xa8, 0x02, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x70, 0x28, 0x01, 0x00, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x70, + 0x54, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x80, 0x01, 0x3a, 0x78, 0x80, 0x0e, + 0x50, 0xc0, 0x03, 0x0e, 0x00, 0x20, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, + 0x00, 0x3e, 0xf0, 0x83, 0x1f, 0xfc, 0xe0, 0x0f, 0x78, 0xf8, 0x87, 0x1f, + 0x00, 0x18, 0x00, 0x30, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xf8, 0xc3, + 0x1f, 0xfc, 0xe0, 0x0f, 0x78, 0xf8, 0x87, 0x0f, 0x00, 0x20, 0x00, 0x10, + 0x55, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xc0, 0x03, 0x9f, 0xf3, 0x80, 0x0f, + 0x78, 0x80, 0xc7, 0x0e, 0x00, 0x18, 0x00, 0x20, 0xaa, 0x00, 0x00, 0x00, + 0x00, 0x1e, 0xe0, 0x03, 0x9f, 0xf1, 0x80, 0x07, 0x78, 0x80, 0x67, 0x00, + 0x00, 0x24, 0x00, 0x18, 0x55, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x01, + 0x5e, 0xf0, 0x80, 0x07, 0x3c, 0x00, 0x2f, 0x00, 0x00, 0x14, 0x00, 0x20, + 0xaa, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x01, 0x7f, 0xf0, 0x80, 0x07, + 0x3c, 0x00, 0x3f, 0x00, 0x00, 0x08, 0x00, 0x18, 0x55, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0xe0, 0x00, 0x3f, 0xf0, 0xc0, 0x03, 0x1e, 0x00, 0x1f, 0x00, + 0x00, 0x14, 0x00, 0x28, 0xaa, 0x00, 0x00, 0x00, 0x80, 0x0f, 0xf0, 0x00, + 0x1f, 0xf0, 0xc0, 0x03, 0x1f, 0x00, 0x1f, 0x00, 0x00, 0x04, 0x00, 0x0c, + 0x54, 0x00, 0x00, 0x00, 0x80, 0x07, 0x78, 0x00, 0x1f, 0x78, 0xc0, 0x03, + 0x1f, 0x00, 0x1e, 0x00, 0x00, 0x0a, 0x00, 0x12, 0xa8, 0x00, 0x00, 0x00, + 0x80, 0x07, 0x78, 0x00, 0x1f, 0x78, 0xe0, 0x03, 0x1f, 0x00, 0x1f, 0x00, + 0x00, 0x04, 0x00, 0x0a, 0x54, 0x00, 0x00, 0x00, 0x80, 0x07, 0x78, 0x80, + 0x0f, 0x78, 0xe0, 0x03, 0x1f, 0x00, 0x1e, 0x00, 0x00, 0x0a, 0x00, 0x08, + 0x50, 0x01, 0x00, 0x00, 0x84, 0x03, 0x78, 0x80, 0x07, 0x3c, 0xe0, 0xc1, + 0x0f, 0x00, 0x1f, 0x00, 0x00, 0x04, 0x00, 0x06, 0xa8, 0x00, 0x00, 0x00, + 0xc0, 0x03, 0x78, 0xc0, 0x07, 0x3c, 0xe0, 0xc1, 0x0f, 0x00, 0x1f, 0x00, + 0x00, 0x0a, 0x00, 0x08, 0x50, 0x01, 0x00, 0x00, 0xc2, 0x01, 0x38, 0xc0, + 0x07, 0x3c, 0xe0, 0x60, 0x0f, 0x80, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x07, + 0xa0, 0x00, 0x00, 0x80, 0xe0, 0x01, 0x3c, 0xc0, 0x07, 0x3c, 0xf0, 0xa0, + 0x07, 0xc0, 0x1c, 0x00, 0x00, 0x0a, 0x80, 0x08, 0xa0, 0x02, 0x00, 0xa0, + 0xe0, 0x21, 0x1c, 0xc0, 0x03, 0x1c, 0x71, 0x90, 0x47, 0x40, 0x3c, 0x04, + 0x00, 0x05, 0x80, 0x06, 0xa0, 0x02, 0x00, 0x20, 0xe0, 0x31, 0x1e, 0xc3, + 0x03, 0x1e, 0x79, 0x98, 0x47, 0x60, 0x38, 0x04, 0x00, 0x15, 0x40, 0x0a, + 0xa0, 0x0a, 0x00, 0x1a, 0xe0, 0x19, 0x9e, 0xe1, 0x01, 0x9e, 0x78, 0xcc, + 0xa7, 0x32, 0x78, 0x02, 0x80, 0x2a, 0x40, 0x05, 0x80, 0x2a, 0x00, 0x05, + 0xe0, 0x0d, 0x9e, 0xe0, 0x01, 0xde, 0x78, 0xc6, 0x97, 0x1b, 0x78, 0x03, + 0x80, 0x52, 0x30, 0x0a, 0x00, 0x95, 0xd2, 0x0a, 0xe0, 0x0f, 0xfe, 0xe0, + 0x00, 0x7e, 0xf8, 0x87, 0x9f, 0x0f, 0xf8, 0x01, 0x00, 0xa1, 0x0e, 0x15, + 0x80, 0x55, 0x55, 0x01, 0xe0, 0x01, 0x3c, 0xf0, 0x00, 0x3c, 0xf0, 0x80, + 0x8f, 0x0f, 0x70, 0x00, 0x00, 0x81, 0x02, 0x14, 0x00, 0x54, 0x55, 0x00, + 0xc0, 0x01, 0x3c, 0x00, 0x00, 0x0c, 0x60, 0x00, 0x07, 0x03, 0x70, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x01, 0x00, 0x11, 0x09, 0x00, 0x04, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x20, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x49, 0x32, 0x49, 0x49, 0x91, + 0x24, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x49, 0x0a, 0x09, 0xc9, 0x92, 0x14, 0x81, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x49, + 0x18, 0x01, 0x49, 0x92, 0x0c, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x49, 0x30, 0x01, 0x49, 0x92, + 0x14, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x69, 0x22, 0x09, 0x49, 0xd2, 0x24, 0x24, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x51, + 0x1a, 0x09, 0x49, 0xa2, 0x44, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x87, 0x08, 0x00, 0x00, 0x00, + 0xf2, 0xf0, 0xf0, 0xf0, 0xf0, 0x00, 0xf0, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x88, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x01, 0x10, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80, + 0x88, 0x86, 0x48, 0x04, 0x09, 0x08, 0x01, 0x01, 0x09, 0x01, 0x10, 0x71, + 0x88, 0x66, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80, 0x88, 0x89, 0x48, 0x84, + 0x08, 0x08, 0x01, 0x01, 0x09, 0x01, 0x10, 0x89, 0x88, 0x99, 0x00, 0x00, + 0x00, 0x40, 0x24, 0x80, 0x88, 0x88, 0x88, 0x82, 0xf8, 0xf0, 0xe0, 0x80, + 0xf0, 0xf8, 0x13, 0x81, 0x88, 0x88, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80, + 0x88, 0x88, 0x08, 0x81, 0x08, 0x09, 0x01, 0x41, 0x08, 0x01, 0xf0, 0xf0, + 0x88, 0x88, 0x00, 0x00, 0x00, 0x40, 0x24, 0x80, 0x88, 0x88, 0x88, 0x42, + 0x08, 0x09, 0x01, 0x21, 0x08, 0x01, 0x10, 0x88, 0x88, 0x88, 0x00, 0x00, + 0x00, 0x40, 0x46, 0x88, 0x88, 0x88, 0x4c, 0x44, 0x08, 0x09, 0x09, 0x11, + 0x08, 0x01, 0x10, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x80, 0x85, 0x87, + 0x88, 0x08, 0x4b, 0x24, 0xf0, 0xf0, 0xf0, 0xf8, 0xf1, 0x00, 0x10, 0x70, + 0x89, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x3f, 0x0f, 0x00, 0x00, 0x08, 0x02, 0x04, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x1f, 0x00, 0x00, 0x48, 0x62, 0xc4, 0x31, 0x4a, 0x18, 0x3c, 0x03, + 0x21, 0x45, 0x92, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x1f, 0x00, 0x00, + 0x48, 0x92, 0x24, 0x48, 0xb6, 0x24, 0x88, 0x04, 0x21, 0x4b, 0x92, 0x00, + 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, 0x00, 0x00, 0xa8, 0xf2, 0x24, 0x48, + 0x92, 0x3c, 0x88, 0x04, 0x21, 0x49, 0x62, 0x00, 0x00, 0x00, 0x80, 0xff, + 0xff, 0x3f, 0x00, 0x00, 0x10, 0x11, 0x24, 0x48, 0x92, 0x04, 0x88, 0x04, + 0x21, 0x49, 0x62, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, 0x00, 0x00, + 0x10, 0x11, 0x24, 0x48, 0x92, 0x04, 0x88, 0x04, 0x21, 0x49, 0x93, 0x00, + 0x00, 0x00, 0x80, 0xff, 0xcf, 0x7e, 0x00, 0x00, 0x10, 0xe1, 0xc4, 0x31, + 0x92, 0x38, 0x30, 0x03, 0x2f, 0x89, 0x92, 0x00, 0x00, 0x00, 0x80, 0xe3, + 0x07, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc1, 0x03, 0x7e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xc9, 0x23, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x95, + 0x33, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xdd, 0xfb, 0x7e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x1d, 0xf8, 0x7e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x40, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9b, + 0x70, 0x7e, 0x00, 0x00, 0x08, 0x00, 0xe0, 0x00, 0x02, 0x00, 0x47, 0x80, + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x80, 0x03, 0x00, 0x7e, 0x00, 0x00, + 0x3c, 0xa3, 0x20, 0x31, 0x52, 0x02, 0x49, 0xcc, 0x3f, 0xa3, 0x94, 0x08, + 0x00, 0x00, 0x00, 0x27, 0x02, 0x7e, 0x00, 0x00, 0x88, 0xe4, 0x20, 0x41, + 0xb2, 0x05, 0x49, 0x90, 0x88, 0xe4, 0x6c, 0x09, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x7e, 0x00, 0x00, 0x88, 0x24, 0xe0, 0x70, 0x92, 0x04, 0x47, 0x9c, + 0x88, 0x24, 0x24, 0x09, 0x00, 0x00, 0x00, 0x13, 0x48, 0x7e, 0x00, 0x00, + 0x88, 0x24, 0x20, 0x48, 0x92, 0x04, 0x41, 0x92, 0x88, 0x24, 0x24, 0x01, + 0x00, 0x00, 0x00, 0x43, 0x00, 0xfe, 0x00, 0x00, 0x88, 0x24, 0x20, 0x48, + 0x92, 0x04, 0x41, 0x92, 0x88, 0x24, 0x24, 0x09, 0x00, 0x00, 0x00, 0x07, + 0x94, 0xce, 0x00, 0x00, 0x08, 0x23, 0x20, 0xb0, 0x92, 0x04, 0x41, 0x2c, + 0x0b, 0x23, 0x24, 0x09, 0x00, 0x00, 0x00, 0x49, 0x02, 0xce, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x11, 0x08, 0xdc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, + 0x01, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xf8, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0x01, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, + 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0xf0, 0x1f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x70, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, + 0x00, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0xe0, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x00, 0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xc0, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1f, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, + 0x00, 0x80, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0xff, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, + 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0xfe, 0x0f, + 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x05, 0x00, 0x00, 0x80, 0x08, 0x00, + 0x00, 0xc0, 0x03, 0x00, 0x78, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x40, 0x10, + 0x12, 0x10, 0x05, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, + 0x84, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x20, 0x26, 0x0a, 0x10, 0x9d, 0x39, + 0xa6, 0xb2, 0x0a, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x02, 0x00, 0xfe, 0x0f, + 0x00, 0x00, 0x20, 0x21, 0x06, 0x28, 0x25, 0x4a, 0xa9, 0x8a, 0x09, 0x00, + 0x00, 0xe0, 0x01, 0x22, 0x02, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x20, 0x21, + 0x0e, 0x38, 0xa5, 0x4b, 0xa9, 0xb2, 0x09, 0x00, 0x00, 0xf0, 0x01, 0x22, + 0x02, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x20, 0x21, 0x12, 0x44, 0xa5, 0x4a, + 0x49, 0xa1, 0x0a, 0x00, 0x00, 0xf8, 0x01, 0x22, 0x02, 0x00, 0xfc, 0x1f, + 0x00, 0x00, 0x20, 0x26, 0x52, 0x44, 0x9d, 0x4d, 0x46, 0x99, 0x0a, 0x00, + 0x00, 0xfc, 0x01, 0x22, 0x02, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x40, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0xb2, + 0x84, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x6e, 0x78, 0x00, 0xfc, 0x1f, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x01, 0x02, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x02, + 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0xfc, 0x0f, + 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x20, 0x01, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x24, 0x06, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x40, 0x10, + 0x1e, 0x20, 0x90, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x80, 0xfc, 0x03, 0x00, 0x00, 0x20, 0x26, 0x22, 0x20, 0xf9, 0x89, + 0x32, 0xe7, 0x08, 0x00, 0x00, 0x92, 0x38, 0x00, 0x00, 0x00, 0xfc, 0x01, + 0x00, 0x00, 0x20, 0x21, 0x22, 0xa0, 0x92, 0x88, 0x4a, 0x29, 0x15, 0x00, + 0x00, 0x00, 0x78, 0x00, 0x00, 0x40, 0xfa, 0x04, 0x00, 0x00, 0x20, 0x21, + 0x22, 0xa0, 0x93, 0x88, 0x4a, 0x29, 0x1d, 0x00, 0x00, 0x11, 0xf2, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x20, 0x21, 0x22, 0xa8, 0x90, 0x88, + 0x4a, 0x29, 0x05, 0x00, 0x48, 0x40, 0xf0, 0x01, 0x00, 0x80, 0x14, 0x04, + 0x00, 0x00, 0x20, 0x26, 0x9e, 0x10, 0x93, 0x78, 0x32, 0x29, 0x19, 0x00, + 0x00, 0x09, 0xe0, 0x03, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00, 0x40, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xc5, 0x03, + 0x00, 0x40, 0x22, 0x00, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0xc0, 0x07, 0x00, 0x20, 0x08, 0x04, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x50, 0x90, 0x03, 0x00, 0xb0, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, + 0x00, 0x38, 0x22, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x48, 0x04, 0x44, 0x00, 0x00, 0x3c, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0xbf, 0x40, 0x42, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x24, 0x80, 0x48, 0x02, + 0xc0, 0x1f, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x05, 0xf0, 0x3f, 0x09, 0x00, + 0x00, 0x10, 0x24, 0x48, 0x10, 0x12, 0x41, 0x52, 0x24, 0x09, 0x46, 0x71, + 0x90, 0x20, 0x02, 0xfc, 0xff, 0x1f, 0x80, 0x22, 0x00, 0x90, 0x24, 0x49, + 0x12, 0x92, 0x40, 0xb2, 0x24, 0x09, 0xc9, 0x49, 0x04, 0x80, 0x90, 0xfc, + 0xff, 0xbf, 0x24, 0x00, 0x00, 0x90, 0x24, 0x49, 0x12, 0x92, 0x40, 0x92, + 0x24, 0x06, 0x49, 0x48, 0x50, 0x0a, 0x02, 0xfe, 0xff, 0x3f, 0x00, 0x05, + 0x00, 0x50, 0xa5, 0x4a, 0x15, 0x92, 0x40, 0x92, 0x24, 0x06, 0x49, 0x48, + 0x80, 0x40, 0x48, 0xfe, 0xff, 0x3f, 0x49, 0x00, 0x00, 0x20, 0x42, 0x84, + 0x88, 0x1a, 0x41, 0x92, 0x34, 0x49, 0x49, 0x68, 0x00, 0x38, 0x10, 0x07, + 0x00, 0x60, 0x80, 0x00, 0x00, 0x20, 0x42, 0x84, 0x88, 0x14, 0x4e, 0x92, + 0x28, 0x49, 0x46, 0x50, 0x00, 0x80, 0x83, 0x01, 0x00, 0xa0, 0x6a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0xfc, 0x00, 0x00, 0xc0, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, }; diff -Nru a/arch/m68knommu/platform/68328/bootlogo.pl b/arch/m68knommu/platform/68328/bootlogo.pl --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68328/bootlogo.pl Mon Nov 4 14:31:04 2002 @@ -0,0 +1,10 @@ + +$_ = join("", <>); + +s/(0x[0-9a-f]{2})/sprintf("0x%.2x",ord(pack("b8",unpack("B8",chr(hex($1))))))/gei; + +s/^ / .byte /gm; +s/[,};]+$//gm; +s/^static.*//gm; + +print $_; diff -Nru a/arch/m68knommu/platform/68328/config.c b/arch/m68knommu/platform/68328/config.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68328/config.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,127 @@ +/* + * linux/arch/$(ARCH)/platform/$(PLATFORM)/config.c + * + * Copyright (C) 1993 Hamish Macdonald + * Copyright (C) 1999 D. Jeff Dionne + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + * VZ Support/Fixes Evan Stawnyczy + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +void BSP_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) +{ + +#ifdef CONFIG_XCOPILOT_BUGS + /* + * The only thing I know is that CLK32 is not available on Xcopilot + * I have little idea about what frequency SYSCLK has on Xcopilot. + * The values for prescaler and compare registers were simply + * taken from the original source + */ + + /* Restart mode, Enable int, SYSCLK, Enable timer */ + TCTL2 = TCTL_OM | TCTL_IRQEN | TCTL_CLKSOURCE_SYSCLK | TCTL_TEN; + /* Set prescaler */ + TPRER2 = 2; + /* Set compare register */ + TCMP2 = 0xd7e4; +#else + /* Restart mode, Enable int, 32KHz, Enable timer */ + TCTL2 = TCTL_OM | TCTL_IRQEN | TCTL_CLKSOURCE_32KHZ | TCTL_TEN; + /* Set prescaler (Divide 32KHz by 32)*/ + TPRER2 = 31; + /* Set compare register 32Khz / 32 / 10 = 100 */ + TCMP2 = 10; +#endif + + request_irq(TMR2_IRQ_NUM, timer_routine, IRQ_FLG_LOCK, "timer", NULL); +} + +void BSP_tick(void) +{ + /* Reset Timer2 */ + TSTAT2 &= 0; +} + +unsigned long BSP_gettimeoffset (void) +{ + return 0; +} + +void BSP_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ +} + +int BSP_hwclk(int op, struct hwclk_time *t) +{ + if (!op) { + /* read */ + } else { + /* write */ + } + return 0; +} + +int BSP_set_clock_mmss (unsigned long nowtime) +{ +#if 0 + short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + + tod->second1 = real_seconds / 10; + tod->second2 = real_seconds % 10; + tod->minute1 = real_minutes / 10; + tod->minute2 = real_minutes % 10; +#endif + return 0; +} + +void BSP_reset (void) +{ + local_irq_disable(); + asm volatile (" + moveal #0x10c00000, %a0; + moveb #0, 0xFFFFF300; + moveal 0(%a0), %sp; + moveal 4(%a0), %a0; + jmp (%a0); + "); +} + +void config_BSP(char *command, int len) +{ + printk("\n68328 support D. Jeff Dionne \n"); + printk("68328 support Kenneth Albanowski \n"); + printk("68328/Pilot support Bernhard Kuhn \n"); + + mach_sched_init = BSP_sched_init; + mach_tick = BSP_tick; + mach_gettimeoffset = BSP_gettimeoffset; + mach_gettod = BSP_gettod; + mach_hwclk = NULL; + mach_set_clock_mmss = NULL; + mach_reset = BSP_reset; + + config_M68328_irq(); +} diff -Nru a/arch/m68knommu/platform/68328/entry.S b/arch/m68knommu/platform/68328/entry.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68328/entry.S Mon Nov 4 14:31:03 2002 @@ -0,0 +1,483 @@ +/* -*- mode: asm -*- + * + * linux/arch/m68k/kernel/entry.S + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * + * Linux/m68k support by Hamish Macdonald + * + */ + +/* + * entry.S contains the system-call and fault low-level handling routines. + * This also contains the timer-interrupt handler, as well as all interrupts + * and faults that can result in a task-switch. + * + * NOTE: This code handles signal-recognition, which happens every time + * after a timer-interrupt and after each system call. + * + */ + +/* + * 12/03/96 Jes: Currently we only support m68k single-cpu systems, so + * all pointers that used to be 'current' are now entry + * number 0 in the 'current_set' list. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IMMED # +#define DBG_PUTC(x) moveb IMMED x,0xfffff907; \ + moveb IMMED '\r',0xfffff907; \ + moveb IMMED '\n',0xfffff907 + +.globl system_call, buserr, trap +.globl resume, ret_from_exception +.globl ret_from_signal +.globl sys_call_table +.globl sys_fork, sys_clone, sys_vfork +.globl ret_from_interrupt, bad_interrupt +.globl inthandler1, inthandler2, inthandler3, inthandler4 +.globl inthandler5, inthandler6, inthandler7 + +.text +ENTRY(buserr) + SAVE_ALL_INT + GET_CURRENT(%d0) + movel %sp,%sp@- /* stack frame pointer argument*/ + bsrw buserr_c + addql #4,%sp + jra ret_from_exception + +ENTRY(trap) + SAVE_ALL_INT + GET_CURRENT(%d0) + movel %sp,%sp@- /* stack frame pointer argument*/ + bsrw trap_c + addql #4,%sp + jra ret_from_exception + +ENTRY(reschedule) + /* save top of frame*/ + pea %sp@ + jbsr set_esp0 + addql #4,%sp + + pea ret_from_exception + jmp schedule + + /* After a fork we jump here directly from resume,*/ + /* so that %d1 contains the previous task*/ + /* Theoretically only needed on SMP, but let's watch*/ + /* what happens in schedule_tail() in future...*/ +ENTRY(ret_from_fork) +#ifdef CONFIG_SMP + movel %d1,%sp@- + jsr schedule_tail + addql #4,%sp +#endif + jra ret_from_exception + +badsys: + movel #-ENOSYS,%sp@(PT_D0) + jra ret_from_exception + +do_trace: + movel #-ENOSYS,%sp@(PT_D0) /* needed for strace*/ + subql #4,%sp + SAVE_SWITCH_STACK + jbsr syscall_trace + RESTORE_SWITCH_STACK + addql #4,%sp + movel %sp@(PT_ORIG_D0),%d1 + movel #-ENOSYS,%d0 + cmpl #NR_syscalls,%d1 + jcc 1f + lsl #2,%d1 + lea sys_call_table, %a0 + jbsr %a0@(%d1) + +1: movel %d0,%sp@(PT_D0) /* save the return value*/ + subql #4,%sp /* dummy return address*/ + SAVE_SWITCH_STACK + jbsr syscall_trace + +ret_from_signal: + RESTORE_SWITCH_STACK + addql #4,%sp + jra ret_from_exception + +ENTRY(system_call) + SAVE_ALL_SYS + + GET_CURRENT(%d1) + /* save top of frame*/ + pea %sp@ + jbsr set_esp0 + addql #4,%sp + + btst #PF_TRACESYS_BIT,%a2@(TASK_FLAGS+PF_TRACESYS_OFF) + jne do_trace + cmpl #NR_syscalls,%d0 + jcc badsys + lsl #2,%d0 + lea sys_call_table,%a0 + movel %a0@(%d0), %a0 + jbsr %a0@ + movel %d0,%sp@(PT_D0) /* save the return value*/ + +ret_from_exception: + btst #5,%sp@(PT_SR) /* check if returning to kernel*/ + jeq Luser_return /* if so, skip resched, signals*/ + +Lkernel_return: + RESTORE_ALL + +Luser_return: + /* only allow interrupts when we are really the last one on the*/ + /* kernel stack, otherwise stack overflow can occur during*/ + /* heavy interupt load*/ + andw #ALLOWINT,%sr + + movel %sp,%d1 /* get thread_info pointer */ + andl #0xffffe000,%d1 + movel %d1,%a2 + move %a2@(TI_FLAGS),%d1 /* thread_info->flags */ + andl #_TIF_WORK_MASK,%d1 + jne Lwork_to_do + RESTORE_ALL + +Lwork_to_do: + movel %a2@(TI_FLAGS),%d1 /* thread_info->flags */ + btst #TIF_NEED_RESCHED,%d1 + jne reschedule + +Lsignal_return: + subql #4,%sp /* dummy return address*/ + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + clrl %sp@- + bsrw do_signal + addql #8,%sp + RESTORE_SWITCH_STACK + addql #4,%sp +Lreturn: + RESTORE_ALL + +/* +** This is the main interrupt handler, responsible for calling process_int() +*/ +inthandler1: + SAVE_ALL_INT + GET_CURRENT(%d0) + addql #1,local_irq_count /* put exception # in d0*/ +/* bfextu %sp@(PT_VECTOR){#4,#10},%d0 */ + movew %sp@(PT_VECTOR), %d0 + and #0x3ff, %d0 + + movel %sp,%sp@- + movel #65,%sp@- /* put vector # on stack*/ + jbsr process_int /* process the IRQ*/ +3: addql #8,%sp /* pop parameters off stack*/ + bra ret_from_interrupt + +inthandler2: + SAVE_ALL_INT + GET_CURRENT(%d0) + addql #1,local_irq_count /* put exception # in d0*/ +/* bfextu %sp@(PT_VECTOR){#4,#10},%d0 */ + movew %sp@(PT_VECTOR), %d0 + and #0x3ff, %d0 + + movel %sp,%sp@- + movel #66,%sp@- /* put vector # on stack*/ + jbsr process_int /* process the IRQ*/ +3: addql #8,%sp /* pop parameters off stack*/ + bra ret_from_interrupt + +inthandler3: + SAVE_ALL_INT + GET_CURRENT(%d0) + addql #1,local_irq_count /* put exception # in d0*/ +/* bfextu %sp@(PT_VECTOR){#4,#10},%d0 */ + movew %sp@(PT_VECTOR), %d0 + and #0x3ff, %d0 + + movel %sp,%sp@- + movel #67,%sp@- /* put vector # on stack*/ + jbsr process_int /* process the IRQ*/ +3: addql #8,%sp /* pop parameters off stack*/ + bra ret_from_interrupt + +inthandler4: + SAVE_ALL_INT + GET_CURRENT(%d0) + addql #1,local_irq_count /* put exception # in d0*/ +/* bfextu %sp@(PT_VECTOR){#4,#10},%d0 */ + movew %sp@(PT_VECTOR), %d0 + and #0x3ff, %d0 + + movel %sp,%sp@- + movel #68,%sp@- /* put vector # on stack*/ + jbsr process_int /* process the IRQ*/ +3: addql #8,%sp /* pop parameters off stack*/ + bra ret_from_interrupt + +inthandler5: + SAVE_ALL_INT + GET_CURRENT(%d0) + addql #1,local_irq_count /* put exception # in d0*/ +/* bfextu %sp@(PT_VECTOR){#4,#10},%d0 */ + movew %sp@(PT_VECTOR), %d0 + and #0x3ff, %d0 + + movel %sp,%sp@- + movel #69,%sp@- /* put vector # on stack*/ + jbsr process_int /* process the IRQ*/ +3: addql #8,%sp /* pop parameters off stack*/ + bra ret_from_interrupt + +inthandler6: + SAVE_ALL_INT + GET_CURRENT(%d0) + addql #1,local_irq_count /* put exception # in d0*/ +/* bfextu %sp@(PT_VECTOR){#4,#10},%d0 */ + movew %sp@(PT_VECTOR), %d0 + and #0x3ff, %d0 + + movel %sp,%sp@- + movel #70,%sp@- /* put vector # on stack*/ + jbsr process_int /* process the IRQ*/ +3: addql #8,%sp /* pop parameters off stack*/ + bra ret_from_interrupt + +inthandler7: + SAVE_ALL_INT + GET_CURRENT(%d0) + addql #1,local_irq_count /* put exception # in d0*/ +/* bfextu %sp@(PT_VECTOR){#4,#10},%d0 */ + movew %sp@(PT_VECTOR), %d0 + and #0x3ff, %d0 + + movel %sp,%sp@- + movel #71,%sp@- /* put vector # on stack*/ + jbsr process_int /* process the IRQ*/ +3: addql #8,%sp /* pop parameters off stack*/ + bra ret_from_interrupt + +inthandler8: + SAVE_ALL_INT + GET_CURRENT(%d0) + addql #1,local_irq_count /* put exception # in d0*/ +/* bfextu %sp@(PT_VECTOR){#4,#10},%d0 */ + movew %sp@(PT_VECTOR), %d0 + and #0x3ff, %d0 + + movel %sp,%sp@- + movel #72,%sp@- /* put vector # on stack*/ + jbsr process_int /* process the IRQ*/ +3: addql #8,%sp /* pop parameters off stack*/ + bra ret_from_interrupt + +timerhandler: + SAVE_ALL_INT + GET_CURRENT(%d0) + addql #1,local_irq_count /* put exception # in d0*/ +/* bfextu %sp@(PT_VECTOR){#4,#10},%d0 */ + movew %sp@(PT_VECTOR), %d0 + and #0x3ff, %d0 + + movel %sp,%sp@- + movel #0x40,%sp@- /* put vector # on stack*/ + jbsr process_int /* process the IRQ*/ +3: addql #8,%sp /* pop parameters off stack*/ + bra ret_from_interrupt + +serialhandler: + SAVE_ALL_INT + GET_CURRENT(%d0) + addql #1,local_irq_count /* put exception # in d0*/ +/* bfextu %sp@(PT_VECTOR){#4,#10},%d0 */ + movew %sp@(PT_VECTOR), %d0 + and #0x3ff, %d0 + + movel %sp,%sp@- + movel #0x42,%sp@- /* put vector # on stack*/ + jbsr process_int /* process the IRQ*/ +3: addql #8,%sp /* pop parameters off stack*/ + bra ret_from_interrupt + +inthandler_wrap: + SAVE_ALL_INT + GET_CURRENT(%d0) + addql #1,local_irq_count /* put exception # in d0*/ +/* bfextu %sp@(PT_VECTOR){#4,#10},%d0 */ + movew %sp@(PT_VECTOR), %d0 + and #0x3ff, %d0 + + movel %sp,%sp@- + movel %d0,%sp@- /* put vector # on stack*/ + jbsr process_int /* process the IRQ*/ +3: addql #8,%sp /* pop parameters off stack*/ + bra ret_from_interrupt + +inthandler: + SAVE_ALL_INT + GET_CURRENT(%d0) + addql #1,local_irq_count /* put exception # in d0*/ +/* bfextu %sp@(PT_VECTOR){#4,#10},%d0 */ + movew %sp@(PT_VECTOR), %d0 + and #0x3ff, %d0 + + movel %sp,%sp@- + movel %d0,%sp@- /* put vector # on stack*/ + jbsr process_int /* process the IRQ*/ +3: addql #8,%sp /* pop parameters off stack*/ + bra ret_from_interrupt + +ret_from_interrupt: + subql #1,local_irq_count + jeq 1f +2: + RESTORE_ALL +1: +#if 1 +/* bfextu %sp@(PT_SR){#5,#3},%d0 */ /* Check for nested interrupt.*/ + moveb %sp@(PT_SR), %d0 + and #7, %d0 + +#if MAX_NOINT_IPL > 0 + cmpiw #MAX_NOINT_IPL,%d0 +#endif + jhi 2b +#endif + /* check if we need to do software interrupts */ + + movel local_irq_count,%d0 + jeq ret_from_exception + + pea ret_from_exception + jra do_softirq + + +/* Handler for uninitialized and spurious interrupts */ + +bad_interrupt: + addql #1,num_spurious + rte + +ENTRY(sys_fork) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr m68k_fork + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_clone) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr m68k_clone + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_vfork) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr m68k_vfork + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_sigsuspend) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr do_sigsuspend + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_rt_sigsuspend) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr do_rt_sigsuspend + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_sigreturn) + SAVE_SWITCH_STACK + jbsr do_sigreturn + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_rt_sigreturn) + SAVE_SWITCH_STACK + jbsr do_rt_sigreturn + RESTORE_SWITCH_STACK + rts + +resume: + /* + * Beware - when entering resume, prev (the current task) is + * in a0, next (the new task) is in a1,so don't change these + * registers until their contents are no longer needed. + */ + + /* save prev thread in d1 */ + movel %a0,%d1 + + /* save sr */ + movew %sr,%a0@(TASK_THREAD+THREAD_SR) +#ifdef USE_SFC_DFC + /* save fs (sfc,%dfc) (may be pointing to kernel memory) */ + movec %sfc,%d0 + movew %d0,%a0@(TASK_THREAD+THREAD_FS) +#endif + + /* save non-scratch registers on stack */ + SAVE_SWITCH_STACK + + /* save usp */ + /* it is better to use a movel here instead of a movew 8*) */ + movel %usp,%a2 + movel %a2,%a0@(TASK_THREAD+THREAD_USP) + + /* save current kernel stack pointer */ + movel %sp,%a0@(TASK_THREAD+THREAD_KSP) + + /* restore the kernel stack pointer */ + movel %a1@(TASK_THREAD+THREAD_KSP),%sp + + /* restore non-scratch registers */ + RESTORE_SWITCH_STACK + + /* restore user stack pointer */ + movel %a1@(TASK_THREAD+THREAD_USP),%a0 + movel %a0,%usp + +#ifdef USE_SFC_DFC + /* restore fs (sfc,%dfc) */ + movew %a1@(TASK_THREAD+THREAD_FS),%a0 + movec %a0,%sfc + movec %a0,%dfc +#endif + /* restore status register */ + movew %a1@(TASK_THREAD+THREAD_SR),%sr + + rts + diff -Nru a/arch/m68knommu/platform/68328/ints.c b/arch/m68knommu/platform/68328/ints.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68328/ints.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,354 @@ +/* + * linux/arch/m68knommu/platform/68328/ints.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + * Copyright 1996 Roman Zippel + * Copyright 1999 D. Jeff Dionne + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_M68328) +#include +#elif defined(CONFIG_M68EZ328) +#include +#elif defined(CONFIG_M68VZ328) +#include +#endif + +#define INTERNAL_IRQS (32) + +/* assembler routines */ +asmlinkage void system_call(void); +asmlinkage void buserr(void); +asmlinkage void trap(void); +asmlinkage void trap3(void); +asmlinkage void trap4(void); +asmlinkage void trap5(void); +asmlinkage void trap6(void); +asmlinkage void trap7(void); +asmlinkage void trap8(void); +asmlinkage void trap9(void); +asmlinkage void trap10(void); +asmlinkage void trap11(void); +asmlinkage void trap12(void); +asmlinkage void trap13(void); +asmlinkage void trap14(void); +asmlinkage void trap15(void); +asmlinkage void trap33(void); +asmlinkage void trap34(void); +asmlinkage void trap35(void); +asmlinkage void trap36(void); +asmlinkage void trap37(void); +asmlinkage void trap38(void); +asmlinkage void trap39(void); +asmlinkage void trap40(void); +asmlinkage void trap41(void); +asmlinkage void trap42(void); +asmlinkage void trap43(void); +asmlinkage void trap44(void); +asmlinkage void trap45(void); +asmlinkage void trap46(void); +asmlinkage void trap47(void); +asmlinkage void bad_interrupt(void); +asmlinkage void inthandler(void); +asmlinkage void inthandler1(void); +asmlinkage void inthandler2(void); +asmlinkage void inthandler3(void); +asmlinkage void inthandler4(void); +asmlinkage void inthandler5(void); +asmlinkage void inthandler6(void); +asmlinkage void inthandler7(void); + +extern e_vector *_ramvec; + +/* irq node variables for the 32 (potential) on chip sources */ +static irq_node_t *int_irq_list[INTERNAL_IRQS]; + +static int int_irq_count[INTERNAL_IRQS]; +static short int_irq_ablecount[INTERNAL_IRQS]; + +static void int_badint(int irq, void *dev_id, struct pt_regs *fp) +{ + num_spurious += 1; +} + +/* + * This function should be called during kernel startup to initialize + * the amiga IRQ handling routines. + */ +void M68328_init_IRQ(void) +{ + int i; + + /* set up the vectors */ + +#ifdef CONFIG_DRAGON2 + for (i=2; i < 32; ++i) + _ramvec[i] = bad_interrupt; + + _ramvec[2] = buserr; + _ramvec[3] = trap3; + _ramvec[4] = trap4; + _ramvec[5] = trap5; + _ramvec[6] = trap6; + _ramvec[7] = trap7; + _ramvec[8] = trap8; + _ramvec[9] = trap9; + _ramvec[10] = trap10; + _ramvec[11] = trap11; + _ramvec[12] = trap12; + _ramvec[13] = trap13; + _ramvec[14] = trap14; + _ramvec[15] = trap15; +#endif + + _ramvec[32] = system_call; + + _ramvec[64] = bad_interrupt; + _ramvec[65] = inthandler1; + _ramvec[66] = inthandler2; + _ramvec[67] = inthandler3; + _ramvec[68] = inthandler4; + _ramvec[69] = inthandler5; + _ramvec[70] = inthandler6; + _ramvec[71] = inthandler7; + + IVR = 0x40; /* Set DragonBall IVR (interrupt base) to 64 */ + + /* initialize handlers */ + for (i = 0; i < INTERNAL_IRQS; i++) { + int_irq_list[i] = NULL; + + int_irq_ablecount[i] = 0; + int_irq_count[i] = 0; + } + + /* turn off all interrupts */ + IMR = ~0; +} + +void M68328_insert_irq(irq_node_t **list, irq_node_t *node) +{ + unsigned long flags; + irq_node_t *cur; + + if (!node->dev_id) + printk("%s: Warning: dev_id of %s is zero\n", + __FUNCTION__, node->devname); + + local_irq_save(flags); + + cur = *list; + while (cur) { + list = &cur->next; + cur = cur->next; + } + + node->next = cur; + *list = node; + + local_irq_restore(flags); +} + +void M68328_delete_irq(irq_node_t **list, void *dev_id) +{ + unsigned long flags; + irq_node_t *node; + + local_irq_save(flags); + + for (node = *list; node; list = &node->next, node = *list) { + if (node->dev_id == dev_id) { + *list = node->next; + /* Mark it as free. */ + node->handler = NULL; + local_irq_restore(flags); + return; + } + } + local_irq_restore(flags); + printk("%s: tried to remove invalid irq\n", __FUNCTION__); +} + +int M68328_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) +{ + if (irq >= INTERNAL_IRQS) { + printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname); + return -ENXIO; + } + + if (!int_irq_list[irq]) { + int_irq_list[irq] = new_irq_node(); + int_irq_list[irq]->flags = IRQ_FLG_STD; + } + + if (!(int_irq_list[irq]->flags & IRQ_FLG_STD)) { + if (int_irq_list[irq]->flags & IRQ_FLG_LOCK) { + printk("%s: IRQ %d from %s is not replaceable\n", + __FUNCTION__, irq, int_irq_list[irq]->devname); + return -EBUSY; + } + if (flags & IRQ_FLG_REPLACE) { + printk("%s: %s can't replace IRQ %d from %s\n", + __FUNCTION__, devname, irq, int_irq_list[irq]->devname); + return -EBUSY; + } + } + int_irq_list[irq]->handler = handler; + int_irq_list[irq]->flags = flags; + int_irq_list[irq]->dev_id = dev_id; + int_irq_list[irq]->devname = devname; + + /* enable in the IMR */ + if (!int_irq_ablecount[irq]) + IMR &= ~(1<= INTERNAL_IRQS) { + printk ("%s: Unknown IRQ %d\n", __FUNCTION__, irq); + return; + } + + if (int_irq_list[irq]->dev_id != dev_id) + printk("%s: removing probably wrong IRQ %d from %s\n", + __FUNCTION__, irq, int_irq_list[irq]->devname); + int_irq_list[irq]->handler = int_badint; + int_irq_list[irq]->flags = IRQ_FLG_STD; + int_irq_list[irq]->dev_id = NULL; + int_irq_list[irq]->devname = NULL; + + IMR |= 1<= INTERNAL_IRQS) { + printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq); + return; + } + + if (--int_irq_ablecount[irq]) + return; + + /* enable the interrupt */ + IMR &= ~(1<= INTERNAL_IRQS) { + printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq); + return; + } + + if (int_irq_ablecount[irq]++) + return; + + /* disable the interrupt */ + IMR |= 1<handler) { + int_irq_list[irq]->handler(irq, int_irq_list[irq]->dev_id, fp); + int_irq_count[irq]++; + } else { + printk("unregistered interrupt %d!\nTurning it off in the IMR...\n", irq); + IMR |= mask; + } + pend &= ~mask; + } +} + +void config_M68328_irq(void) +{ + mach_default_handler = NULL; + mach_init_IRQ = M68328_init_IRQ; + mach_request_irq = M68328_request_irq; + mach_free_irq = M68328_free_irq; + mach_enable_irq = M68328_enable_irq; + mach_disable_irq = M68328_disable_irq; + mach_process_int = M68328_do_irq; +} diff -Nru a/arch/m68knommu/platform/68328/pilot/crt0_rom.S b/arch/m68knommu/platform/68328/pilot/crt0_rom.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68328/pilot/crt0_rom.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,228 @@ +/* linux/arch/m68knommu/kernel/head.S: A startup file for the MC68332 + * + * Copyright (C) 1998 D. Jeff Dionne , + * Kenneth Albanowski , + * The Silver Hammer Group, Ltd. + * + * (c) 1995, Dionne & Associates + * (c) 1995, DKG Display Tech. + */ + +#define ASSEMBLY + +#define IMMED # +#define DBG_PUTC(x) moveb IMMED x, 0xfffff907 + +#include + +.global _stext +.global __bss_start + +.global _start + +.global _rambase +.global __ramvec +.global _ramvec +.global _ramstart +.global _ramend + +.global penguin_bits + +#ifdef CONFIG_PILOT + +#define IMR 0xFFFFF304 + + .data + .align 16 + +penguin_bits: +#include "bootlogo.rh" + +#endif + +/*****************************************************************************/ + +.data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +.align 4 +_ramvec: +.long 0 +_rambase: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +.text + +_start: +_stext: + + +#ifdef CONFIG_M68328 + +#ifdef CONFIG_PILOT + .byte 0x4e, 0xfa, 0x00, 0x0a /* Jmp +X bytes */ + .byte 'b', 'o', 'o', 't' + .word 10000 + + nop +#endif + + moveq #0, %d0 + movew %d0, 0xfffff618 /* Watchdog off */ + movel #0x00011f07, 0xfffff114 /* CS A1 Mask */ + + movew #0x0800, 0xfffff906 /* Ignore CTS */ + movew #0x010b, 0xfffff902 /* BAUD to 9600 */ + + movew #0x2410, 0xfffff200 /* PLLCR */ + movew #0x123, 0xfffff202 /* PLLFSR */ + +#ifdef CONFIG_PILOT + moveb #0, 0xfffffA27 /* LCKCON */ + movel #_start, 0xfffffA00 /* LSSA */ + moveb #0xa, 0xfffffA05 /* LVPW */ + movew #0x9f, 0xFFFFFa08 /* LXMAX */ + movew #0x9f, 0xFFFFFa0a /* LYMAX */ + moveb #9, 0xfffffa29 /* LBAR */ + moveb #0, 0xfffffa25 /* LPXCD */ + moveb #0x04, 0xFFFFFa20 /* LPICF */ + moveb #0x58, 0xfffffA27 /* LCKCON */ + moveb #0x85, 0xfffff429 /* PFDATA */ + moveb #0xd8, 0xfffffA27 /* LCKCON */ + moveb #0xc5, 0xfffff429 /* PFDATA */ + moveb #0xd5, 0xfffff429 /* PFDATA */ + + moveal #0x00100000, %a3 + moveal #0x100ffc00, %a4 + +#endif /* CONFIG_PILOT */ + + +#endif /* CONFIG_M68328 */ + + movew #0x2700, %sr + lea %a4@(-4), %sp + + DBG_PUTC('\r') + DBG_PUTC('\n') + DBG_PUTC('A') + + moveq #0,%d0 + movew #16384, %d0 /* PLL settle wait loop */ +L0: + subw #1, %d0 + bne L0 + + DBG_PUTC('B') + + /* Copy command line from beginning of RAM (+16) to end of bss */ + movel #__ramvec, %d7 + addl #16, %d7 + moveal %d7, %a0 + moveal #end, %a1 + lea %a1@(512), %a2 + + DBG_PUTC('C') + + /* Copy %a0 to %a1 until %a1 == %a2 */ +L2: + movel %a0@+, %d0 + movel %d0, %a1@+ + cmpal %a1, %a2 + bhi L2 + + /* Copy data segment from ROM to RAM */ + moveal #__data_rom_start, %a0 + moveal #__data_start, %a1 + moveal #__data_end, %a2 + + DBG_PUTC('D') + + /* Copy %a0 to %a1 until %a1 == %a2 */ +LD1: + movel %a0@+, %d0 + movel %d0, %a1@+ + cmpal %a1, %a2 + bhi LD1 + + DBG_PUTC('E') + + moveal #__bss_start, %a0 + moveal #end, %a1 + + /* Copy 0 to %a0 until %a0 == %a1 */ +L1: + movel #0, %a0@+ + cmpal %a0, %a1 + bhi L1 + + DBG_PUTC('F') + + /* Copy command line from end of bss to command line */ + moveal #end, %a0 + moveal #command_line, %a1 + lea %a1@(512), %a2 + + DBG_PUTC('G') + + /* Copy %a0 to %a1 until %a1 == %a2 */ +L3: + movel %a0@+, %d0 + movel %d0, %a1@+ + cmpal %a1, %a2 + bhi L3 + + movel #_sdata, %d0 + movel %d0, _rambase + movel #end, %d0 + movel %d0, _ramstart + + movel %a4, %d0 + subl #4096, %d0 /* Reserve 4K of stack */ + moveq #79, %d7 + movel %d0, _ramend + + movel %a3, %d0 + movel %d0, rom_length + + pea 0 + pea env + pea %sp@(4) + pea 0 + + DBG_PUTC('H') + +#ifdef CONFIG_PILOT + + movel #penguin_bits, 0xFFFFFA00 + moveb #10, 0xFFFFFA05 + movew #160, 0xFFFFFA08 + movew #160, 0xFFFFFA0A + +#endif /* CONFIG_PILOT */ + + DBG_PUTC('I') + + lea init_thread_union, %a0 + lea 0x2000(%a0), %sp + + DBG_PUTC('J') + DBG_PUTC('\r') + DBG_PUTC('\n') + + jsr start_kernel +_exit: + + jmp _exit + + + .data +env: + .long 0 diff -Nru a/arch/m68knommu/platform/68328/pilot/rom.ld b/arch/m68knommu/platform/68328/pilot/rom.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68328/pilot/rom.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,105 @@ +OUTPUT_ARCH(m68k) +ENTRY(_start) +MEMORY { + romvec : ORIGIN = 0x10c00000, LENGTH = 0x10400 + flash : ORIGIN = 0x10c10400, LENGTH = 0xfec00 + eflash : ORIGIN = 0x10d00000, LENGTH = 4 + ramvec : ORIGIN = 0x00000000, LENGTH = 0x400 + ram : ORIGIN = 0x10000400, LENGTH = 0x100000-0x400 + eram : ORIGIN = 0x10100000, LENGTH = 4 +} + +jiffies = jiffies_64 + 4; + +SECTIONS { + . = 0x10c00000 ; + .romvec : { + _flashstart = . ; + _romvec = . ; + } > romvec + + . = 0x10c10400 ; + .text : { + _text = .; /* Text and read-only data */ + text_start = . ; + *(.text) + *(.text.*) + *(.rodata) + *(.fixup) + *(__ex_table) + . = ALIGN(4) ; + _etext = . ; + __data_rom_start = . ; + } > flash + + . = 0x10d00000 ; + .eflash : + { + _flashend = . ; + } > eflash + + . = 0 ; + .ramvec : + { + __ramvec = . ; + } > ramvec + + /* . = 0x10000400 ; */ + .data 0x10000400 : + { + _sdata = . ; + __data_start = . ; + + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + + *(.data) + *(.data.*) + *(.setup.init) + *(.exitcall.exit) + + . = ALIGN(4096) ; + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(4) ; + __init_end = .; + + _edata = . ; + edata = . ; + } > ram + + .bss : + { + . = ALIGN(16) ; + _sbss = . ; + __bss_start = . ; + __data_end = . ; + *(.bss) + *(COMMON) + . = ALIGN(16) ; + end = . ; + _ebss = . ; + _end = . ; + } > ram + + . = 0x10100000 ; + .eram : + { + __ramend = . ; + } > eram +} diff -Nru a/arch/m68knommu/platform/68360/Makefile b/arch/m68knommu/platform/68360/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68360/Makefile Mon Nov 4 14:31:04 2002 @@ -0,0 +1,10 @@ +# +# Makefile for arch/m68knommu/platform/68360. +# + +obj-y := config.o commproc.o entry.o ints.o + +EXTRA_TARGETS := $(BOARD)/crt0_$(MODEL).o + +include $(TOPDIR)/Rules.make + diff -Nru a/arch/m68knommu/platform/68360/commproc.c b/arch/m68knommu/platform/68360/commproc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68360/commproc.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,308 @@ +/* + * General Purpose functions for the global management of the + * Communication Processor Module. + * + * Copyright (c) 2000 Michael Leslie + * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) + * + * In addition to the individual control of the communication + * channels, there are a few functions that globally affect the + * communication processor. + * + * Buffer descriptors must be allocated from the dual ported memory + * space. The allocator for that is here. When the communication + * process is reset, we reclaim the memory available. There is + * currently no deallocator for this memory. + * The amount of space available is platform dependent. On the + * MBX, the EPPC software loads additional microcode into the + * communication processor, and uses some of the DP ram for this + * purpose. Current, the first 512 bytes and the last 256 bytes of + * memory are used. Right now I am conservative and only use the + * memory that can never be used for microcode. If there are + * applications that require more DP ram, we can expand the boundaries + * but then we have to be careful of any downloaded microcode. + * + */ + +/* + * Michael Leslie + * adapted Dan Malek's ppc8xx drivers to M68360 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* #include */ +/* #include */ +extern void *_quicc_base; +extern unsigned int system_clock; + + +static uint dp_alloc_base; /* Starting offset in DP ram */ +static uint dp_alloc_top; /* Max offset + 1 */ + +#if 0 +static void *host_buffer; /* One page of host buffer */ +static void *host_end; /* end + 1 */ +#endif + +/* struct cpm360_t *cpmp; */ /* Pointer to comm processor space */ + +QUICC *pquicc; +/* QUICC *quicc_dpram; */ /* mleslie - temporary; use extern pquicc elsewhere instead */ + + +/* CPM interrupt vector functions. */ +struct cpm_action { + void (*handler)(void *); + void *dev_id; +}; +static struct cpm_action cpm_vecs[CPMVEC_NR]; +static void cpm_interrupt(int irq, void * dev, struct pt_regs * regs); +static void cpm_error_interrupt(void *); + +/* prototypes: */ +void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id); +void m360_cpm_reset(void); + + + + +void m360_cpm_reset() +{ +/* pte_t *pte; */ + + pquicc = (struct quicc *)(_quicc_base); /* initialized in crt0_rXm.S */ + + /* Perform a CPM reset. */ + pquicc->cp_cr = (SOFTWARE_RESET | CMD_FLAG); + + /* Wait for CPM to become ready (should be 2 clocks). */ + while (pquicc->cp_cr & CMD_FLAG); + + /* On the recommendation of the 68360 manual, p. 7-60 + * - Set sdma interupt service mask to 7 + * - Set sdma arbitration ID to 4 + */ + pquicc->sdma_sdcr = 0x0740; + + + /* Claim the DP memory for our use. + */ + dp_alloc_base = CPM_DATAONLY_BASE; + dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE; + + + /* Set the host page for allocation. + */ + /* host_buffer = host_page_addr; */ + /* host_end = host_page_addr + PAGE_SIZE; */ + + /* pte = find_pte(&init_mm, host_page_addr); */ + /* pte_val(*pte) |= _PAGE_NO_CACHE; */ + /* flush_tlb_page(current->mm->mmap, host_buffer); */ + + /* Tell everyone where the comm processor resides. + */ +/* cpmp = (cpm360_t *)commproc; */ +} + + +/* This is called during init_IRQ. We used to do it above, but this + * was too early since init_IRQ was not yet called. + */ +void +cpm_interrupt_init(void) +{ + /* Initialize the CPM interrupt controller. + * NOTE THAT pquicc had better have been initialized! + * reference: MC68360UM p. 7-377 + */ + pquicc->intr_cicr = + (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | + (CPM_INTERRUPT << 13) | + CICR_HP_MASK | + (CPM_VECTOR_BASE << 5) | + CICR_SPS; + + /* mask all CPM interrupts from reaching the cpu32 core: */ + pquicc->intr_cimr = 0; + + + /* mles - If I understand correctly, the 360 just pops over to the CPM + * specific vector, obviating the necessity to vector through the IRQ + * whose priority the CPM is set to. This needs a closer look, though. + */ + + /* Set our interrupt handler with the core CPU. */ +/* if (request_irq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0) */ +/* panic("Could not allocate CPM IRQ!"); */ + + /* Install our own error handler. + */ + /* I think we want to hold off on this one for the moment - mles */ + /* cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL); */ + + /* master CPM interrupt enable */ + /* pquicc->intr_cicr |= CICR_IEN; */ /* no such animal for 360 */ +} + + + +/* CPM interrupt controller interrupt. +*/ +static void +cpm_interrupt(int irq, void * dev, struct pt_regs * regs) +{ + /* uint vec; */ + + /* mles: Note that this stuff is currently being performed by + * M68360_do_irq(int vec, struct pt_regs *fp), in ../ints.c */ + + /* figure out the vector */ + /* call that vector's handler */ + /* clear the irq's bit in the service register */ + +#if 0 /* old 860 stuff: */ + /* Get the vector by setting the ACK bit and then reading + * the register. + */ + ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1; + vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr; + vec >>= 11; + + + if (cpm_vecs[vec].handler != 0) + (*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id); + else + ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); + + /* After servicing the interrupt, we have to remove the status + * indicator. + */ + ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr |= (1 << vec); +#endif + +} + +/* The CPM can generate the error interrupt when there is a race condition + * between generating and masking interrupts. All we have to do is ACK it + * and return. This is a no-op function so we don't need any special + * tests in the interrupt handler. + */ +static void +cpm_error_interrupt(void *dev) +{ +} + +/* Install a CPM interrupt handler. +*/ +void +cpm_install_handler(int vec, void (*handler)(void *), void *dev_id) +{ + + request_irq(vec, handler, IRQ_FLG_LOCK, "timer", dev_id); + +/* if (cpm_vecs[vec].handler != 0) */ +/* printk("CPM interrupt %x replacing %x\n", */ +/* (uint)handler, (uint)cpm_vecs[vec].handler); */ +/* cpm_vecs[vec].handler = handler; */ +/* cpm_vecs[vec].dev_id = dev_id; */ + + /* ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec); */ +/* pquicc->intr_cimr |= (1 << vec); */ + +} + +/* Free a CPM interrupt handler. +*/ +void +cpm_free_handler(int vec) +{ + cpm_vecs[vec].handler = NULL; + cpm_vecs[vec].dev_id = NULL; + /* ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); */ + pquicc->intr_cimr &= ~(1 << vec); +} + + + + +/* Allocate some memory from the dual ported ram. We may want to + * enforce alignment restrictions, but right now everyone is a good + * citizen. + */ +uint +m360_cpm_dpalloc(uint size) +{ + uint retloc; + + if ((dp_alloc_base + size) >= dp_alloc_top) + return(CPM_DP_NOSPACE); + + retloc = dp_alloc_base; + dp_alloc_base += size; + + return(retloc); +} + + +#if 0 /* mleslie - for now these are simply kmalloc'd */ +/* We also own one page of host buffer space for the allocation of + * UART "fifos" and the like. + */ +uint +m360_cpm_hostalloc(uint size) +{ + uint retloc; + + if ((host_buffer + size) >= host_end) + return(0); + + retloc = host_buffer; + host_buffer += size; + + return(retloc); +} +#endif + + +/* Set a baud rate generator. This needs lots of work. There are + * four BRGs, any of which can be wired to any channel. + * The internal baud rate clock is the system clock divided by 16. + * This assumes the baudrate is 16x oversampled by the uart. + */ +/* #define BRG_INT_CLK (((bd_t *)__res)->bi_intfreq * 1000000) */ +#define BRG_INT_CLK system_clock +#define BRG_UART_CLK (BRG_INT_CLK/16) + +void +m360_cpm_setbrg(uint brg, uint rate) +{ + volatile uint *bp; + + /* This is good enough to get SMCs running..... + */ + /* bp = (uint *)&cpmp->cp_brgc1; */ + bp = (volatile uint *)(&pquicc->brgc[0].l); + bp += brg; + *bp = ((BRG_UART_CLK / rate - 1) << 1) | CPM_BRG_EN; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -Nru a/arch/m68knommu/platform/68360/config.c b/arch/m68knommu/platform/68360/config.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68360/config.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,213 @@ +/* + * linux/arch/m68knommu/platform/68360/config.c + * + * Copyright (c) 2000 Michael Leslie + * Copyright (C) 1993 Hamish Macdonald + * Copyright (C) 1999 D. Jeff Dionne + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_UCQUICC +#include +#endif + +extern void m360_cpm_reset(void); + +// Mask to select if the PLL prescaler is enabled. +#define MCU_PREEN ((unsigned short)(0x0001 << 13)) + +#if defined(CONFIG_UCQUICC) +#define OSCILLATOR (unsigned long int)33000000 +#endif + +unsigned long int system_clock; + +void M68360_init_IRQ(void); + +extern QUICC *pquicc; + +/* TODO DON"T Hard Code this */ +/* calculate properly using the right PLL and prescaller */ +// unsigned int system_clock = 33000000l; +extern unsigned long int system_clock; //In kernel setup.c + +extern void config_M68360_irq(void); + +void BSP_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) +{ + unsigned char prescaler; + unsigned short tgcr_save; + int return_value; + +#if 0 + /* Restart mode, Enable int, 32KHz, Enable timer */ + TCTL = TCTL_OM | TCTL_IRQEN | TCTL_CLKSOURCE_32KHZ | TCTL_TEN; + /* Set prescaler (Divide 32KHz by 32)*/ + TPRER = 31; + /* Set compare register 32Khz / 32 / 10 = 100 */ + TCMP = 10; + + request_irq(IRQ_MACHSPEC | 1, timer_routine, IRQ_FLG_LOCK, "timer", NULL); +#endif + + /* General purpose quicc timers: MC68360UM p7-20 */ + + /* Set up timer 1 (in [1..4]) to do 100Hz */ + tgcr_save = pquicc->timer_tgcr & 0xfff0; + pquicc->timer_tgcr = tgcr_save; /* stop and reset timer 1 */ + /* pquicc->timer_tgcr |= 0x4444; */ /* halt timers when FREEZE (ie bdm freeze) */ + + prescaler = 8; + pquicc->timer_tmr1 = 0x001a | /* or=1, frr=1, iclk=01b */ + (unsigned short)((prescaler - 1) << 8); + + pquicc->timer_tcn1 = 0x0000; /* initial count */ + /* calculate interval for 100Hz based on the _system_clock: */ + pquicc->timer_trr1 = (system_clock/ prescaler) / HZ; /* reference count */ + + pquicc->timer_ter1 = 0x0003; /* clear timer events */ + + /* enable timer 1 interrupt in CIMR */ +// request_irq(IRQ_MACHSPEC | CPMVEC_TIMER1, timer_routine, IRQ_FLG_LOCK, "timer", NULL); + //return_value = request_irq( CPMVEC_TIMER1, timer_routine, IRQ_FLG_LOCK, "timer", NULL); + return_value = request_irq(CPMVEC_TIMER1 , timer_routine, IRQ_FLG_LOCK, + "Timer", NULL); + + /* Start timer 1: */ + tgcr_save = (pquicc->timer_tgcr & 0xfff0) | 0x0001; + pquicc->timer_tgcr = tgcr_save; +} + + +void BSP_tick(void) +{ + /* Reset Timer1 */ + /* TSTAT &= 0; */ + + pquicc->timer_ter1 = 0x0002; /* clear timer event */ +} + +unsigned long BSP_gettimeoffset (void) +{ + return 0; +} + +void BSP_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ +} + +int BSP_hwclk(int op, struct hwclk_time *t) +{ + if (!op) { + /* read */ + } else { + /* write */ + } + return 0; +} + +int BSP_set_clock_mmss (unsigned long nowtime) +{ +#if 0 + short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + + tod->second1 = real_seconds / 10; + tod->second2 = real_seconds % 10; + tod->minute1 = real_minutes / 10; + tod->minute2 = real_minutes % 10; +#endif + return 0; +} + +void BSP_reset (void) +{ + local_irq_disable(); + asm volatile (" + moveal #_start, %a0; + moveb #0, 0xFFFFF300; + moveal 0(%a0), %sp; + moveal 4(%a0), %a0; + jmp (%a0); + "); +} + +unsigned char *scc1_hwaddr; +static int errno; + +#if defined (CONFIG_UCQUICC) +_bsc0(char *, getserialnum) +_bsc1(unsigned char *, gethwaddr, int, a) +_bsc1(char *, getbenv, char *, a) +#endif + + +void config_BSP(char *command, int len) +{ + unsigned char *p; + + m360_cpm_reset(); + + /* Calculate the real system clock value. */ + { + unsigned int local_pllcr = (unsigned int)(pquicc->sim_pllcr); + if( local_pllcr & MCU_PREEN ) // If the prescaler is dividing by 128 + { + int mf = (int)(pquicc->sim_pllcr & 0x0fff); + system_clock = (OSCILLATOR / 128) * (mf + 1); + } + else + { + int mf = (int)(pquicc->sim_pllcr & 0x0fff); + system_clock = (OSCILLATOR) * (mf + 1); + } + } + + printk("\n68360 QUICC support (C) 2000 Lineo Inc.\n"); + +#if defined(CONFIG_UCQUICC) && 0 + printk("uCquicc serial string [%s]\n",getserialnum()); + p = scc1_hwaddr = gethwaddr(0); + printk("uCquicc hwaddr %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", + p[0], p[1], p[2], p[3], p[4], p[5]); + + p = getbenv("APPEND"); + if (p) + strcpy(p,command); + else + command[0] = 0; +#else + scc1_hwaddr = "\00\01\02\03\04\05"; +#endif + + mach_sched_init = BSP_sched_init; + mach_tick = BSP_tick; + mach_gettimeoffset = BSP_gettimeoffset; + mach_gettod = BSP_gettod; + mach_hwclk = NULL; + mach_set_clock_mmss = NULL; + mach_reset = BSP_reset; + + //Kendrick's Change + mach_trap_init = M68360_init_IRQ; + + config_M68360_irq(); +} diff -Nru a/arch/m68knommu/platform/68360/entry.S b/arch/m68knommu/platform/68360/entry.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68360/entry.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,344 @@ +/* -*- mode: asm -*- + * + * linux/arch/m68knommu/platform/68360/entry.S + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 2001 SED Systems, a Division of Calian Ltd. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file README.legal in the main directory of this archive + * for more details. + * + * Linux/m68k support by Hamish Macdonald + * M68360 Port by SED Systems, and Lineo. + * + */ + +/* + * entry.S contains the system-call and fault low-level handling routines. + * This also contains the timer-interrupt handler, as well as all interrupts + * and faults that can result in a task-switch. + * + * NOTE: This code handles signal-recognition, which happens every time + * after a timer-interrupt and after each system call. + * + */ + +/* + * 12/03/96 Jes: Currently we only support m68k single-cpu systems, so + * all pointers that used to be 'current' are now entry + * number 0 in the 'current_set' list. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IMMED # +#define DBG_PUTC(x) moveb IMMED x,0xfffff907; \ + moveb IMMED '\r',0xfffff907; \ + moveb IMMED '\n',0xfffff907 +LD0 = 0x20 +LORIG_D0 = 0x24 + +.globl system_call +.globl buserr +.globl trap +.globl resume +.globl ret_from_exception +.globl ret_from_signal +.globl sys_call_table +.globl sys_fork +.globl sys_clone +.globl sys_vfork +.globl ret_from_interrupt +.globl bad_interrupt +.globl inthandler + +.text +ENTRY(buserr) + SAVE_ALL_INT + /* GET_CURRENT(%d0) */ + movel %sp,%sp@- /* stack frame pointer argument*/ + bsrw buserr_c + addql #4,%sp + jra ret_from_exception + +ENTRY(trap) + SAVE_ALL_INT + GET_CURRENT(%d0) + moveq.l #-1,%d0 + move.l %d0,%sp@(LORIG_D0) +/* may have to test for LFORMATVEC here as was done in teh 2.0 module */ + movel %sp,%sp@- /* stack frame pointer argument*/ + bsrw trap_c + addql #4,%sp + jra ret_from_exception + + +ENTRY(reschedule) + /* save top of frame*/ + pea %sp@ + jbsr set_esp0 + addql #4,%sp + + pea ret_from_exception + jmp schedule + + /* After a fork we jump here directly from resume,*/ + /* so that %d1 contains the previous task*/ + /* Theoretically only needed on SMP, but let's watch*/ + /* what happens in schedule_tail() in future...*/ +ENTRY(ret_from_fork) +#ifdef CONFIG_SMP + movel %d1,%sp@- + jsr schedule_tail + addql #4,%sp +#endif + jra ret_from_exception + +badsys: + movel #-ENOSYS,%sp@(PT_D0) + jra ret_from_exception + +do_trace: + movel #-ENOSYS,%sp@(PT_D0) /* needed for strace*/ + subql #4,%sp + SAVE_SWITCH_STACK + jbsr syscall_trace + RESTORE_SWITCH_STACK + addql #4,%sp + movel %sp@(PT_ORIG_D0),%d1 + movel #-ENOSYS,%d0 + cmpl #NR_syscalls,%d1 + jcc 1f + lsl #2,%d1 + lea sys_call_table, %a0 + jbsr %a0@(%d1) + +1: movel %d0,%sp@(PT_D0) /* save the return value*/ + subql #4,%sp /* dummy return address*/ + SAVE_SWITCH_STACK + jbsr syscall_trace + +ret_from_signal: + RESTORE_SWITCH_STACK + addql #4,%sp + jra ret_from_exception + +ENTRY(system_call) + SAVE_ALL_SYS + + GET_CURRENT(%d1) + /* save top of frame*/ + pea %sp@ + jbsr set_esp0 + addql #4,%sp + + btst #PF_TRACESYS_BIT,%a2@(TASK_FLAGS+PF_TRACESYS_OFF) + jne do_trace + cmpl #NR_syscalls,%d0 + jcc badsys + lsl #2,%d0 + lea sys_call_table,%a0 + movel %a0@(%d0), %a0 + jbsr %a0@ + movel %d0,%sp@(PT_D0) /* save the return value*/ + +ret_from_exception: + btst #5,%sp@(PT_SR) /* check if returning to kernel*/ + jeq Luser_return /* if so, skip resched, signals*/ + +Lkernel_return: + RESTORE_ALL + +Luser_return: + /* only allow interrupts when we are really the last one on the*/ + /* kernel stack, otherwise stack overflow can occur during*/ + /* heavy interupt load*/ + andw #ALLOWINT,%sr + + movel %sp,%d1 /* get thread_info pointer */ + andl #0xffffe000,%d1 + movel %d1,%a2 + move %a2@(TI_FLAGS),%d1 /* thread_info->flags */ + andl #_TIF_WORK_MASK,%d1 + jne Lwork_to_do + RESTORE_ALL + +Lwork_to_do: + movel %a2@(TI_FLAGS),%d1 /* thread_info->flags */ + btst #TIF_NEED_RESCHED,%d1 + jne reschedule + +Lsignal_return: + subql #4,%sp /* dummy return address*/ + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + clrl %sp@- + bsrw do_signal + addql #8,%sp + RESTORE_SWITCH_STACK + addql #4,%sp +Lreturn: + RESTORE_ALL + +/* +** This is the main interrupt handler, responsible for calling process_int() +*/ + +inthandler: + SAVE_ALL_INT + GET_CURRENT(%d0) + addql #1,local_irq_count /* put exception # in d0*/ +/* bfextu %sp@(PT_VECTOR){#4,#10},%d0 */ + movew %sp@(PT_VECTOR), %d0 + and.l #0x3ff, %d0 + lsr.l #0x02, %d0 + + movel %sp,%sp@- + movel %d0,%sp@- /* put vector # on stack*/ + jbsr process_int /* process the IRQ*/ +3: addql #8,%sp /* pop parameters off stack*/ + bra ret_from_interrupt + +ret_from_interrupt: + subql #1,local_irq_count + jeq 1f +2: + RESTORE_ALL +1: +#if 1 +/* bfextu %sp@(PT_SR){#5,#3},%d0 */ /* Check for nested interrupt.*/ + moveb %sp@(PT_SR), %d0 + and #7, %d0 + +#if MAX_NOINT_IPL > 0 + cmpiw #MAX_NOINT_IPL,%d0 +#endif + jhi 2b +#endif + /* check if we need to do software interrupts */ + + movel irq_stat+CPUSTAT_SOFTIRQ_PENDING,%d0 + jeq ret_from_exception + + pea ret_from_exception + jra do_softirq + + +/* Handler for uninitialized and spurious interrupts */ + +bad_interrupt: + addql #1,num_spurious + rte + +ENTRY(sys_fork) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr m68k_fork + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_clone) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr m68k_clone + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_vfork) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr m68k_vfork + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_sigsuspend) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr do_sigsuspend + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_rt_sigsuspend) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr do_rt_sigsuspend + addql #4,%sp + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_sigreturn) + SAVE_SWITCH_STACK + jbsr do_sigreturn + RESTORE_SWITCH_STACK + rts + +ENTRY(sys_rt_sigreturn) + SAVE_SWITCH_STACK + jbsr do_rt_sigreturn + RESTORE_SWITCH_STACK + rts + +resume: + /* + * Beware - when entering resume, prev (the current task) is + * in a0, next (the new task) is in a1,so don't change these + * registers until their contents are no longer needed. + */ + + /* save prev thread in d1 */ + movel %a0,%d1 + + /* save sr */ + movew %sr,%a0@(TASK_THREAD+THREAD_SR) +#ifdef USE_SFC_DFC + /* save fs (sfc,%dfc) (may be pointing to kernel memory) */ + movec %sfc,%d0 + movew %d0,%a0@(TASK_THREAD+THREAD_FS) +#endif + + /* save non-scratch registers on stack */ + SAVE_SWITCH_STACK + + /* save usp */ + /* it is better to use a movel here instead of a movew 8*) */ + movel %usp,%a2 + movel %a2,%a0@(TASK_THREAD+THREAD_USP) + + /* save current kernel stack pointer */ + movel %sp,%a0@(TASK_THREAD+THREAD_KSP) + + /* restore the kernel stack pointer */ + movel %a1@(TASK_THREAD+THREAD_KSP),%sp + + /* restore non-scratch registers */ + RESTORE_SWITCH_STACK + + /* restore user stack pointer */ + movel %a1@(TASK_THREAD+THREAD_USP),%a0 + movel %a0,%usp + +#ifdef USE_SFC_DFC + /* restore fs (sfc,%dfc) */ + movew %a1@(TASK_THREAD+THREAD_FS),%a0 + movec %a0,%sfc + movec %a0,%dfc +#endif + /* restore status register */ + movew %a1@(TASK_THREAD+THREAD_SR),%sr + + rts + diff -Nru a/arch/m68knommu/platform/68360/ints.c b/arch/m68knommu/platform/68360/ints.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68360/ints.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,318 @@ +/* + * linux/arch/$(ARCH)/platform/$(PLATFORM)/ints.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + * Copyright (c) 2000 Michael Leslie + * Copyright (c) 1996 Roman Zippel + * Copyright (c) 1999 D. Jeff Dionne + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* from quicc/commproc.c: */ +extern QUICC *pquicc; +extern void cpm_interrupt_init(void); + +#define INTERNAL_IRQS (96) + +/* assembler routines */ +asmlinkage void system_call(void); +asmlinkage void buserr(void); +asmlinkage void trap(void); +asmlinkage void bad_interrupt(void); +asmlinkage void inthandler(void); + +extern void *_ramvec[]; + +/* irq node variables for the 32 (potential) on chip sources */ +static irq_node_t *int_irq_list[INTERNAL_IRQS]; + +static int int_irq_count[INTERNAL_IRQS]; +static short int_irq_ablecount[INTERNAL_IRQS]; + +static void int_badint(int irq, void *dev_id, struct pt_regs *fp) +{ + num_spurious += 1; +} + +/* + * This function should be called during kernel startup to initialize + * IRQ handling routines. + */ + +void M68360_init_IRQ(void) +{ + int i; + int vba = (CPM_VECTOR_BASE<<4); + + /* set up the vectors */ + _ramvec[2] = buserr; + _ramvec[3] = trap; + _ramvec[4] = trap; + _ramvec[5] = trap; + _ramvec[6] = trap; + _ramvec[7] = trap; + _ramvec[8] = trap; + _ramvec[9] = trap; + _ramvec[10] = trap; + _ramvec[11] = trap; + _ramvec[12] = trap; + _ramvec[13] = trap; + _ramvec[14] = trap; + _ramvec[15] = trap; + + _ramvec[32] = system_call; + _ramvec[33] = trap; + + + cpm_interrupt_init(); + + /* set up CICR for vector base address and irq level */ + /* irl = 4, hp = 1f - see MC68360UM p 7-377 */ + pquicc->intr_cicr = 0x00e49f00 | vba; + + /* CPM interrupt vectors: (p 7-376) */ + _ramvec[vba+CPMVEC_ERROR] = bad_interrupt; /* Error */ + _ramvec[vba+CPMVEC_PIO_PC11] = inthandler; /* pio - pc11 */ + _ramvec[vba+CPMVEC_PIO_PC10] = inthandler; /* pio - pc10 */ + _ramvec[vba+CPMVEC_SMC2] = inthandler; /* smc2/pip */ + _ramvec[vba+CPMVEC_SMC1] = inthandler; /* smc1 */ + _ramvec[vba+CPMVEC_SPI] = inthandler; /* spi */ + _ramvec[vba+CPMVEC_PIO_PC9] = inthandler; /* pio - pc9 */ + _ramvec[vba+CPMVEC_TIMER4] = inthandler; /* timer 4 */ + _ramvec[vba+CPMVEC_RESERVED1] = inthandler; /* reserved */ + _ramvec[vba+CPMVEC_PIO_PC8] = inthandler; /* pio - pc8 */ + _ramvec[vba+CPMVEC_PIO_PC7] = inthandler; /* pio - pc7 */ + _ramvec[vba+CPMVEC_PIO_PC6] = inthandler; /* pio - pc6 */ + _ramvec[vba+CPMVEC_TIMER3] = inthandler; /* timer 3 */ + _ramvec[vba+CPMVEC_RISCTIMER] = inthandler; /* reserved */ + _ramvec[vba+CPMVEC_PIO_PC5] = inthandler; /* pio - pc5 */ + _ramvec[vba+CPMVEC_PIO_PC4] = inthandler; /* pio - pc4 */ + _ramvec[vba+CPMVEC_RESERVED2] = inthandler; /* reserved */ + _ramvec[vba+CPMVEC_RISCTIMER] = inthandler; /* timer table */ + _ramvec[vba+CPMVEC_TIMER2] = inthandler; /* timer 2 */ + _ramvec[vba+CPMVEC_RESERVED3] = inthandler; /* reserved */ + _ramvec[vba+CPMVEC_IDMA2] = inthandler; /* idma 2 */ + _ramvec[vba+CPMVEC_IDMA1] = inthandler; /* idma 1 */ + _ramvec[vba+CPMVEC_SDMA_CB_ERR] = inthandler; /* sdma channel bus error */ + _ramvec[vba+CPMVEC_PIO_PC3] = inthandler; /* pio - pc3 */ + _ramvec[vba+CPMVEC_PIO_PC2] = inthandler; /* pio - pc2 */ + /* _ramvec[vba+CPMVEC_TIMER1] = cpm_isr_timer1; */ /* timer 1 */ + _ramvec[vba+CPMVEC_TIMER1] = inthandler; /* timer 1 */ + _ramvec[vba+CPMVEC_PIO_PC1] = inthandler; /* pio - pc1 */ + _ramvec[vba+CPMVEC_SCC4] = inthandler; /* scc 4 */ + _ramvec[vba+CPMVEC_SCC3] = inthandler; /* scc 3 */ + _ramvec[vba+CPMVEC_SCC2] = inthandler; /* scc 2 */ + _ramvec[vba+CPMVEC_SCC1] = inthandler; /* scc 1 */ + _ramvec[vba+CPMVEC_PIO_PC0] = inthandler; /* pio - pc0 */ + + + /* turn off all CPM interrupts */ + pquicc->intr_cimr = 0x00000000; + + /* initialize handlers */ + for (i = 0; i < INTERNAL_IRQS; i++) { + int_irq_list[i] = NULL; + + int_irq_ablecount[i] = 0; + int_irq_count[i] = 0; + } +} + +void M68360_insert_irq(irq_node_t **list, irq_node_t *node) +{ + unsigned long flags; + irq_node_t *cur; + + if (!node->dev_id) + printk("%s: Warning: dev_id of %s is zero\n", + __FUNCTION__, node->devname); + + local_irq_save(flags); + + cur = *list; + + while (cur) { + list = &cur->next; + cur = cur->next; + } + + node->next = cur; + *list = node; + + local_irq_restore(flags); +} + +void M68360_delete_irq(irq_node_t **list, void *dev_id) +{ + unsigned long flags; + irq_node_t *node; + + local_irq_save(flags); + + for (node = *list; node; list = &node->next, node = *list) { + if (node->dev_id == dev_id) { + *list = node->next; + /* Mark it as free. */ + node->handler = NULL; + local_irq_restore(flags); + return; + } + } + local_irq_restore(flags); + printk ("%s: tried to remove invalid irq\n", __FUNCTION__); +} + +int M68360_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) +{ + int mask = (1<= INTERNAL_IRQS) { + printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname); + return -ENXIO; + } + + if (!int_irq_list[irq]) { + int_irq_list[irq] = new_irq_node(); + int_irq_list[irq]->flags = IRQ_FLG_STD; + } + + if (!(int_irq_list[irq]->flags & IRQ_FLG_STD)) { + if (int_irq_list[irq]->flags & IRQ_FLG_LOCK) { + printk("%s: IRQ %d from %s is not replaceable\n", + __FUNCTION__, irq, int_irq_list[irq]->devname); + return -EBUSY; + } + if (flags & IRQ_FLG_REPLACE) { + printk("%s: %s can't replace IRQ %d from %s\n", + __FUNCTION__, devname, irq, int_irq_list[irq]->devname); + return -EBUSY; + } + } + int_irq_list[irq]->handler = handler; + int_irq_list[irq]->flags = flags; + int_irq_list[irq]->dev_id = dev_id; + int_irq_list[irq]->devname = devname; + + /* enable in the CIMR */ + if (!int_irq_ablecount[irq]) + pquicc->intr_cimr |= mask; + /* *(volatile unsigned long *)0xfffff304 &= ~(1<= INTERNAL_IRQS) { + printk ("%s: Unknown IRQ %d\n", __FUNCTION__, irq); + return; + } + + if (int_irq_list[irq]->dev_id != dev_id) + printk("%s: removing probably wrong IRQ %d from %s\n", + __FUNCTION__, irq, int_irq_list[irq]->devname); + int_irq_list[irq]->handler = int_badint; + int_irq_list[irq]->flags = IRQ_FLG_STD; + int_irq_list[irq]->dev_id = NULL; + int_irq_list[irq]->devname = NULL; + + *(volatile unsigned long *)0xfffff304 |= 1<= INTERNAL_IRQS) { + printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq); + return; + } + + if (--int_irq_ablecount[irq]) + return; + + /* enable the interrupt */ + *(volatile unsigned long *)0xfffff304 &= ~(1<= INTERNAL_IRQS) { + printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq); + return; + } + + if (int_irq_ablecount[irq]++) + return; + + /* disable the interrupt */ + *(volatile unsigned long *)0xfffff304 |= 1<intr_cipr; */ + + /* Bugger all that wierdness. For the moment, I seem to know where I came from; + * vec is passed from a specific ISR, so I'll use it. */ + + if (int_irq_list[irq] && int_irq_list[irq]->handler) { + int_irq_list[irq]->handler(irq , int_irq_list[irq]->dev_id, fp); + int_irq_count[irq]++; + pquicc->intr_cisr = (1 << vec); /* indicate that irq has been serviced */ + } else { + printk("unregistered interrupt %d!\nTurning it off in the CIMR...\n", irq); + /* *(volatile unsigned long *)0xfffff304 |= mask; */ + pquicc->intr_cimr &= ~(1 << vec); + } +} + +void config_M68360_irq(void) +{ + mach_default_handler = NULL; + mach_init_IRQ = M68360_init_IRQ; + mach_request_irq = M68360_request_irq; + mach_free_irq = M68360_free_irq; + mach_enable_irq = M68360_enable_irq; + mach_disable_irq = M68360_disable_irq; + mach_process_int = M68360_do_irq; +} + diff -Nru a/arch/m68knommu/platform/68360/uCquicc/crt0_ram.S b/arch/m68knommu/platform/68360/uCquicc/crt0_ram.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68360/uCquicc/crt0_ram.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,415 @@ +/* arch/m68knommu/platform/68360/uCquicc/crt0_rom.S + * + * Startup code for Motorola 68360 + * + * Copyright 2001 (C) SED Systems, a Division of Calian Ltd. + * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S + * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7 + * uClinux Kernel + * Copyright (C) Michael Leslie + * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S + * Copyright (C) 1998 D. Jeff Dionne , + * + */ +#define ASSEMBLY +#include + +.global _stext +.global __bss_start +.global _start + +.global _rambase +.global __ramvec +.global _ramvec +.global _ramstart +.global _ramend + +.global _quicc_base +.global _periph_base +.global _dprbase + +#define REGB 0x1000 +#define PEPAR (_dprbase + REGB + 0x0016) +#define GMR (_dprbase + REGB + 0x0040) +#define OR0 (_dprbase + REGB + 0x0054) +#define BR0 (_dprbase + REGB + 0x0050) +#define OR1 (_dprbase + REGB + 0x0064) +#define BR1 (_dprbase + REGB + 0x0060) +#define OR4 (_dprbase + REGB + 0x0094) +#define BR4 (_dprbase + REGB + 0x0090) +#define OR6 (_dprbase + REGB + 0x00b4) +#define BR6 (_dprbase + REGB + 0x00b0) +#define OR7 (_dprbase + REGB + 0x00c4) +#define BR7 (_dprbase + REGB + 0x00c0) + +#define MCR (_dprbase + REGB + 0x0000) +#define AVR (_dprbase + REGB + 0x0008) + +#define SYPCR (_dprbase + REGB + 0x0022) + +#define PLLCR (_dprbase + REGB + 0x0010) +#define CLKOCR (_dprbase + REGB + 0x000C) +#define CDVCR (_dprbase + REGB + 0x0014) + +#define BKAR (_dprbase + REGB + 0x0030) +#define BKCR (_dprbase + REGB + 0x0034) +#define SWIV (_dprbase + REGB + 0x0023) +#define PICR (_dprbase + REGB + 0x0026) +#define PITR (_dprbase + REGB + 0x002A) + +/* Define for all memory configuration */ +#define MCU_SIM_GMR 0x00000000 +#define SIM_OR_MASK 0x0fffffff + +/* Defines for chip select zero - the flash */ +#define SIM_OR0_MASK 0x20000002 +#define SIM_BR0_MASK 0x00000001 + + +/* Defines for chip select one - the RAM */ +#define SIM_OR1_MASK 0x10000000 +#define SIM_BR1_MASK 0x00000001 + +#define MCU_SIM_MBAR_ADRS 0x0003ff00 +#define MCU_SIM_MBAR_BA_MASK 0xfffff000 +#define MCU_SIM_MBAR_AS_MASK 0x00000001 + +#define MCU_SIM_PEPAR 0x00B4 + +#define MCU_DISABLE_INTRPTS 0x2700 +#define MCU_SIM_AVR 0x00 + +#define MCU_SIM_MCR 0x00005cff + +#define MCU_SIM_CLKOCR 0x00 +#define MCU_SIM_PLLCR 0x8000 +#define MCU_SIM_CDVCR 0x0000 + +#define MCU_SIM_SYPCR 0x0000 +#define MCU_SIM_SWIV 0x00 +#define MCU_SIM_PICR 0x0000 +#define MCU_SIM_PITR 0x0000 + + +#include + + +/* By the time this RAM specific code begins to execute, DPRAM + * and DRAM should already be mapped and accessible. */ + + .text +_start: +_stext: + nop + ori.w #MCU_DISABLE_INTRPTS, %sr /* disable interrupts: */ + /* We should not need to setup the boot stack the reset should do it. */ + movea.l #_boot_stack, %sp /*set up stack at the end of DRAM:*/ + + +set_mbar_register: + moveq.l #0x07, %d1 /* Setup MBAR */ + movec %d1, %dfc + + lea.l MCU_SIM_MBAR_ADRS, %a0 + move.l #_dprbase, %d0 + andi.l #MCU_SIM_MBAR_BA_MASK, %d0 + ori.l #MCU_SIM_MBAR_AS_MASK, %d0 + moves.l %d0, %a0@ + + moveq.l #0x05, %d1 + movec.l %d1, %dfc + +/* Now we can begin to access registers in DPRAM */ + +set_sim_mcr: + /* Set Module Configuration Register */ + move.l #MCU_SIM_MCR, MCR + +/* to do: Determine cause of reset */ + + + /* + * configure system clock MC68360 p. 6-40 + * (value +1)*osc/128 = system clock + */ +set_sim_clock: + move.w #MCU_SIM_PLLCR, PLLCR + move.b #MCU_SIM_CLKOCR, CLKOCR + move.w #MCU_SIM_CDVCR, CDVCR + + // Wait for the PLL to settle + move.w #16384, %d0 +pll_settle_wait: + subi.w #1, %d0 + bne pll_settle_wait + + /* Setup the system protection register, and watchdog timer register */ + + move.b #MCU_SIM_SWIV, SWIV + move.w #MCU_SIM_PICR, PICR + move.w #MCU_SIM_PITR, PITR + move.w #MCU_SIM_SYPCR, SYPCR + +/* Clear DPRAM - system + parameter */ + movea.l #_dprbase, %a0 + movea.l #_dprbase+0x2000, %a1 + + /* Copy 0 to %a0 until %a0 == %a1 */ +clear_dpram: + movel #0, %a0@+ + cmpal %a0, %a1 + bhi clear_dpram + +configure_memory_controller: + /* + * Set up Global Memory Register (GMR) + */ + move.l #MCU_SIM_GMR, %d0 + move.l %d0, GMR + +configure_chip_select_0: + move.l #__ramend, %d0 + subi.l #__ramstart, %d0 + subq.l #0x01, %d0 + eori.l #SIM_OR_MASK, %d0 + ori.l #SIM_OR0_MASK, %d0 + move.l %d0, OR0 + + move.l #__ramstart, %d0 + ori.l #SIM_BR0_MASK, %d0 + move.l %d0, BR0 + + +configure_chip_select_1: + move.l #__flashend, %d0 + subi.l #__flashstart, %d0 + subq.l #0x01, %d0 + eori.l #SIM_OR_MASK, %d0 + ori.l #SIM_OR1_MASK, %d0 + move.l %d0, OR1 + + move.l #__flashstart, %d0 + ori.l #SIM_BR1_MASK, %d0 + move.l %d0, BR1 + + + move.w #MCU_SIM_PEPAR, PEPAR + +/* point to vector table: */ + move.l #_romvec, %a0 + move.l #_ramvec, %a1 +copy_vectors: + move.l %a0@, %d0 + move.l %d0, %a1@ + move.l %a0@, %a1@ + addq.l #0x04, %a0 + addq.l #0x04, %a1 + cmp.l #_start, %a0 + blt copy_vectors + + move.l #_ramvec, %a1 + movec %a1, %vbr + + + /* Copy data segment from ROM to RAM */ + moveal #__data_rom_start, %a0 + moveal #__data_start, %a1 + moveal #__data_end, %a2 + + /* Copy %a0 to %a1 until %a1 == %a2 */ +LD1: + move.l %a0@, %d0 + addq.l #0x04, %a0 + move.l %d0, %a1@ + addq.l #0x04, %a1 + cmp.l #__data_end, %a1 + blt LD1 + + moveal #__bss_start, %a0 + moveal #end, %a1 + + /* Copy 0 to %a0 until %a0 == %a1 */ +L1: + movel #0, %a0@+ + cmpal %a0, %a1 + bhi L1 + +load_quicc: + move.l #_dprbase, _quicc_base + +store_ram_size: + /* Set ram size information */ + move.l #_sdata, _rambase + move.l #end, _ramstart + move.l #__ramend, %d0 + sub.l #0x1000, %d0 /* Reserve 4K for stack space.*/ + move.l %d0, _ramend /* Different from __ramend.*/ + +store_flash_size: + /* Set rom size information */ + move.l #__flashend, %d0 + sub.l #__flashstart, %d0 + move.l %d0, rom_length + + pea 0 + pea env + pea %sp@(4) + pea 0 + + lea init_thread_union, %a2 + lea 0x2000(%a2), %sp + +lp: + jsr start_kernel + /* jmp lp */ + +_exit: + + jmp _exit + + + + .data + .align 4 +env: + .long 0 +_quicc_base: + .long 0 +_periph_base: + .long 0 +_ramvec: + .long 0 +_rambase: + .long 0 +_ramstart: + .long 0 +_ramend: + .long 0 + .text + + /* + * These are the exception vectors at boot up, they are copied into RAM + * and then overwritten as needed. + */ + +.section ".data.initvect","awx" + .long _boot_stack /* Reset: Initial Stack Pointer - 0. */ + .long _start /* Reset: Initial Program Counter - 1. */ + .long buserr /* Bus Error - 2. */ + .long trap /* Address Error - 3. */ + .long trap /* Illegal Instruction - 4. */ + .long trap /* Divide by zero - 5. */ + .long trap /* CHK, CHK2 Instructions - 6. */ + .long trap /* TRAPcc, TRAPV Instructions - 7. */ + .long trap /* Privilege Violation - 8. */ + .long trap /* Trace - 9. */ + .long trap /* Line 1010 Emulator - 10. */ + .long trap /* Line 1111 Emualtor - 11. */ + .long trap /* Harware Breakpoint - 12. */ + .long trap /* (Reserved for Coprocessor Protocol Violation)- 13. */ + .long trap /* Format Error - 14. */ + .long trap /* Uninitialized Interrupt - 15. */ + .long trap /* (Unassigned, Reserver) - 16. */ + .long trap /* (Unassigned, Reserver) - 17. */ + .long trap /* (Unassigned, Reserver) - 18. */ + .long trap /* (Unassigned, Reserver) - 19. */ + .long trap /* (Unassigned, Reserver) - 20. */ + .long trap /* (Unassigned, Reserver) - 21. */ + .long trap /* (Unassigned, Reserver) - 22. */ + .long trap /* (Unassigned, Reserver) - 23. */ + .long trap /* Spurious Interrupt - 24. */ + .long trap /* Level 1 Interrupt Autovector - 25. */ + .long trap /* Level 2 Interrupt Autovector - 26. */ + .long trap /* Level 3 Interrupt Autovector - 27. */ + .long trap /* Level 4 Interrupt Autovector - 28. */ + .long trap /* Level 5 Interrupt Autovector - 29. */ + .long trap /* Level 6 Interrupt Autovector - 30. */ + .long trap /* Level 7 Interrupt Autovector - 31. */ + .long system_call /* Trap Instruction Vectors 0 - 32. */ + .long trap /* Trap Instruction Vectors 1 - 33. */ + .long trap /* Trap Instruction Vectors 2 - 34. */ + .long trap /* Trap Instruction Vectors 3 - 35. */ + .long trap /* Trap Instruction Vectors 4 - 36. */ + .long trap /* Trap Instruction Vectors 5 - 37. */ + .long trap /* Trap Instruction Vectors 6 - 38. */ + .long trap /* Trap Instruction Vectors 7 - 39. */ + .long trap /* Trap Instruction Vectors 8 - 40. */ + .long trap /* Trap Instruction Vectors 9 - 41. */ + .long trap /* Trap Instruction Vectors 10 - 42. */ + .long trap /* Trap Instruction Vectors 11 - 43. */ + .long trap /* Trap Instruction Vectors 12 - 44. */ + .long trap /* Trap Instruction Vectors 13 - 45. */ + .long trap /* Trap Instruction Vectors 14 - 46. */ + .long trap /* Trap Instruction Vectors 15 - 47. */ + .long 0 /* (Reserved for Coprocessor) - 48. */ + .long 0 /* (Reserved for Coprocessor) - 49. */ + .long 0 /* (Reserved for Coprocessor) - 50. */ + .long 0 /* (Reserved for Coprocessor) - 51. */ + .long 0 /* (Reserved for Coprocessor) - 52. */ + .long 0 /* (Reserved for Coprocessor) - 53. */ + .long 0 /* (Reserved for Coprocessor) - 54. */ + .long 0 /* (Reserved for Coprocessor) - 55. */ + .long 0 /* (Reserved for Coprocessor) - 56. */ + .long 0 /* (Reserved for Coprocessor) - 57. */ + .long 0 /* (Reserved for Coprocessor) - 58. */ + .long 0 /* (Unassigned, Reserved) - 59. */ + .long 0 /* (Unassigned, Reserved) - 60. */ + .long 0 /* (Unassigned, Reserved) - 61. */ + .long 0 /* (Unassigned, Reserved) - 62. */ + .long 0 /* (Unassigned, Reserved) - 63. */ + /* The assignment of these vectors to the CPM is */ + /* dependant on the configuration of the CPM vba */ + /* fields. */ + .long 0 /* (User-Defined Vectors 1) CPM Error - 64. */ + .long 0 /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */ + .long 0 /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */ + .long 0 /* (User-Defined Vectors 4) CPM SMC2 / PIP - 67. */ + .long 0 /* (User-Defined Vectors 5) CPM SMC1 - 68. */ + .long 0 /* (User-Defined Vectors 6) CPM SPI - 69. */ + .long 0 /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */ + .long 0 /* (User-Defined Vectors 8) CPM Timer 4 - 71. */ + .long 0 /* (User-Defined Vectors 9) CPM Reserved - 72. */ + .long 0 /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */ + .long 0 /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */ + .long 0 /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */ + .long 0 /* (User-Defined Vectors 13) CPM Timer 3 - 76. */ + .long 0 /* (User-Defined Vectors 14) CPM Reserved - 77. */ + .long 0 /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */ + .long 0 /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */ + .long 0 /* (User-Defined Vectors 17) CPM Reserved - 80. */ + .long 0 /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */ + .long 0 /* (User-Defined Vectors 19) CPM Timer 2 - 82. */ + .long 0 /* (User-Defined Vectors 21) CPM Reserved - 83. */ + .long 0 /* (User-Defined Vectors 22) CPM IDMA2 - 84. */ + .long 0 /* (User-Defined Vectors 23) CPM IDMA1 - 85. */ + .long 0 /* (User-Defined Vectors 24) CPM SDMA Bus Err - 86. */ + .long 0 /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */ + .long 0 /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */ + .long 0 /* (User-Defined Vectors 27) CPM Timer 1 - 89. */ + .long 0 /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */ + .long 0 /* (User-Defined Vectors 29) CPM SCC 4 - 91. */ + .long 0 /* (User-Defined Vectors 30) CPM SCC 3 - 92. */ + .long 0 /* (User-Defined Vectors 31) CPM SCC 2 - 93. */ + .long 0 /* (User-Defined Vectors 32) CPM SCC 1 - 94. */ + .long 0 /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */ + /* I don't think anything uses the vectors after here. */ + .long 0 /* (User-Defined Vectors 34) - 96. */ + .long 0,0,0,0,0 /* (User-Defined Vectors 35 - 39). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 40 - 49). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 50 - 59). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 60 - 69). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 70 - 79). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 80 - 89). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 90 - 99). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 100 - 109). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 110 - 119). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 120 - 129). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 130 - 139). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 140 - 149). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 150 - 159). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 160 - 169). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 170 - 179). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 180 - 189). */ + .long 0,0,0 /* (User-Defined Vectors 190 - 192). */ +.text +ignore: rte diff -Nru a/arch/m68knommu/platform/68360/uCquicc/crt0_rom.S b/arch/m68knommu/platform/68360/uCquicc/crt0_rom.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68360/uCquicc/crt0_rom.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,424 @@ +/* arch/m68knommu/platform/68360/uCquicc/crt0_rom.S + * + * Startup code for Motorola 68360 + * + * Copyright (C) SED Systems, a Division of Calian Ltd. + * Based on: arch/m68knommu/platform/68328/pilot/crt0_rom.S + * Based on: arch/m68knommu/platform/68360/uCquicc/crt0_rom.S, 2.0.38.1.pre7 + * uClinux Kernel + * Copyright (C) Michael Leslie + * Based on: arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S + * Copyright (C) 1998 D. Jeff Dionne , + * + */ +#define ASSEMBLY +#include + +.global _stext +.global __bss_start +.global _start + +.global _rambase +.global __ramvec +.global _ramvec +.global _ramstart +.global _ramend + +.global _quicc_base +.global _periph_base +.global _dprbase + +#define REGB 0x1000 +#define PEPAR (_dprbase + REGB + 0x0016) +#define GMR (_dprbase + REGB + 0x0040) +#define OR0 (_dprbase + REGB + 0x0054) +#define BR0 (_dprbase + REGB + 0x0050) + +#define OR1 (_dprbase + REGB + 0x0064) +#define BR1 (_dprbase + REGB + 0x0060) + +#define OR2 (_dprbase + REGB + 0x0074) +#define BR2 (_dprbase + REGB + 0x0070) + +#define OR3 (_dprbase + REGB + 0x0084) +#define BR3 (_dprbase + REGB + 0x0080) + +#define OR4 (_dprbase + REGB + 0x0094) +#define BR4 (_dprbase + REGB + 0x0090) + +#define OR5 (_dprbase + REGB + 0x00A4) +#define BR5 (_dprbase + REGB + 0x00A0) + +#define OR6 (_dprbase + REGB + 0x00b4) +#define BR6 (_dprbase + REGB + 0x00b0) + +#define OR7 (_dprbase + REGB + 0x00c4) +#define BR7 (_dprbase + REGB + 0x00c0) + +#define MCR (_dprbase + REGB + 0x0000) +#define AVR (_dprbase + REGB + 0x0008) + +#define SYPCR (_dprbase + REGB + 0x0022) + +#define PLLCR (_dprbase + REGB + 0x0010) +#define CLKOCR (_dprbase + REGB + 0x000C) +#define CDVCR (_dprbase + REGB + 0x0014) + +#define BKAR (_dprbase + REGB + 0x0030) +#define BKCR (_dprbase + REGB + 0x0034) +#define SWIV (_dprbase + REGB + 0x0023) +#define PICR (_dprbase + REGB + 0x0026) +#define PITR (_dprbase + REGB + 0x002A) + +/* Define for all memory configuration */ +#define MCU_SIM_GMR 0x00000000 +#define SIM_OR_MASK 0x0fffffff + +/* Defines for chip select zero - the flash */ +#define SIM_OR0_MASK 0x20000000 +#define SIM_BR0_MASK 0x00000001 + + +/* Defines for chip select one - the RAM */ +#define SIM_OR1_MASK 0x10000000 +#define SIM_BR1_MASK 0x00000001 + +#define MCU_SIM_MBAR_ADRS 0x0003ff00 +#define MCU_SIM_MBAR_BA_MASK 0xfffff000 +#define MCU_SIM_MBAR_AS_MASK 0x00000001 + +#define MCU_SIM_PEPAR 0x00B4 + +#define MCU_DISABLE_INTRPTS 0x2700 +#define MCU_SIM_AVR 0x00 + +#define MCU_SIM_MCR 0x00005cff + +#define MCU_SIM_CLKOCR 0x00 +#define MCU_SIM_PLLCR 0x8000 +#define MCU_SIM_CDVCR 0x0000 + +#define MCU_SIM_SYPCR 0x0000 +#define MCU_SIM_SWIV 0x00 +#define MCU_SIM_PICR 0x0000 +#define MCU_SIM_PITR 0x0000 + + +#include + + +/* By the time this RAM specific code begins to execute, DPRAM + * and DRAM should already be mapped and accessible. */ + + .text +_start: +_stext: + nop + ori.w #MCU_DISABLE_INTRPTS, %sr /* disable interrupts: */ + /* We should not need to setup the boot stack the reset should do it. */ + movea.l #_boot_stack, %sp /*set up stack at the end of DRAM:*/ + + +set_mbar_register: + moveq.l #0x07, %d1 /* Setup MBAR */ + movec %d1, %dfc + + lea.l MCU_SIM_MBAR_ADRS, %a0 + move.l #_dprbase, %d0 + andi.l #MCU_SIM_MBAR_BA_MASK, %d0 + ori.l #MCU_SIM_MBAR_AS_MASK, %d0 + moves.l %d0, %a0@ + + moveq.l #0x05, %d1 + movec.l %d1, %dfc + +/* Now we can begin to access registers in DPRAM */ + +set_sim_mcr: + /* Set Module Configuration Register */ + move.l #MCU_SIM_MCR, MCR + +/* to do: Determine cause of reset */ + + + /* + * configure system clock MC68360 p. 6-40 + * (value +1)*osc/128 = system clock + * or + * (value + 1)*osc = system clock + * You do not need to divide the oscillator by 128 unless you want to. + */ +set_sim_clock: + move.w #MCU_SIM_PLLCR, PLLCR + move.b #MCU_SIM_CLKOCR, CLKOCR + move.w #MCU_SIM_CDVCR, CDVCR + + // Wait for the PLL to settle + move.w #16384, %d0 +pll_settle_wait: + subi.w #1, %d0 + bne pll_settle_wait + + /* Setup the system protection register, and watchdog timer register */ + + move.b #MCU_SIM_SWIV, SWIV + move.w #MCU_SIM_PICR, PICR + move.w #MCU_SIM_PITR, PITR + move.w #MCU_SIM_SYPCR, SYPCR + +/* Clear DPRAM - system + parameter */ + movea.l #_dprbase, %a0 + movea.l #_dprbase+0x2000, %a1 + + /* Copy 0 to %a0 until %a0 == %a1 */ +clear_dpram: + movel #0, %a0@+ + cmpal %a0, %a1 + bhi clear_dpram + +configure_memory_controller: + /* + * Set up Global Memory Register (GMR) + */ + move.l #MCU_SIM_GMR, %d0 + move.l %d0, GMR + +configure_chip_select_0: + move.l #0x00400000, %d0 + subq.l #0x01, %d0 + eori.l #SIM_OR_MASK, %d0 + ori.l #SIM_OR0_MASK, %d0 + move.l %d0, OR0 + + move.l #__flashstart, %d0 + ori.l #SIM_BR0_MASK, %d0 + move.l %d0, BR0 + + move.l #0x0, BR1 + move.l #0x0, BR2 + move.l #0x0, BR3 + move.l #0x0, BR4 + move.l #0x0, BR5 + move.l #0x0, BR6 + move.l #0x0, BR7 + + move.w #MCU_SIM_PEPAR, PEPAR + +/* point to vector table: */ + move.l #_romvec, %a0 + move.l #_ramvec, %a1 +copy_vectors: + move.l %a0@, %d0 + move.l %d0, %a1@ + move.l %a0@, %a1@ + addq.l #0x04, %a0 + addq.l #0x04, %a1 + cmp.l #_start, %a0 + blt copy_vectors + + move.l #_ramvec, %a1 + movec %a1, %vbr + + + /* Copy data segment from ROM to RAM */ + moveal #__data_rom_start, %a0 + moveal #__data_start, %a1 + moveal #__data_end, %a2 + + /* Copy %a0 to %a1 until %a1 == %a2 */ +LD1: + move.l %a0@, %d0 + addq.l #0x04, %a0 + move.l %d0, %a1@ + addq.l #0x04, %a1 + cmp.l #__data_end, %a1 + blt LD1 + + moveal #__bss_start, %a0 + moveal #end, %a1 + + /* Copy 0 to %a0 until %a0 == %a1 */ +L1: + movel #0, %a0@+ + cmpal %a0, %a1 + bhi L1 + +load_quicc: + move.l #_dprbase, _quicc_base + +store_ram_size: + /* Set ram size information */ + move.l #_sdata, _rambase + move.l #end, _ramstart + move.l #__ramend, %d0 + sub.l #0x1000, %d0 /* Reserve 4K for stack space.*/ + move.l %d0, _ramend /* Different from __ramend.*/ + +store_flash_size: + /* Set rom size information */ + move.l #__flashend, %d0 + sub.l #__flashstart, %d0 + move.l %d0, rom_length + + pea 0 + pea env + pea %sp@(4) + pea 0 + + lea init_thread_union, %a2 + lea 0x2000(%a2), %sp + +lp: + jsr start_kernel + /* jmp lp */ + +_exit: + + jmp _exit + + + + .data + .align 4 +env: + .long 0 +_quicc_base: + .long 0 +_periph_base: + .long 0 +_ramvec: + .long 0 +_rambase: + .long 0 +_ramstart: + .long 0 +_ramend: + .long 0 + .text + + /* + * These are the exception vectors at boot up, they are copied into RAM + * and then overwritten as needed. + */ + +.section ".data.initvect","awx" + .long _boot_stack /* Reset: Initial Stack Pointer - 0. */ + .long _start /* Reset: Initial Program Counter - 1. */ + .long buserr /* Bus Error - 2. */ + .long trap /* Address Error - 3. */ + .long trap /* Illegal Instruction - 4. */ + .long trap /* Divide by zero - 5. */ + .long trap /* CHK, CHK2 Instructions - 6. */ + .long trap /* TRAPcc, TRAPV Instructions - 7. */ + .long trap /* Privilege Violation - 8. */ + .long trap /* Trace - 9. */ + .long trap /* Line 1010 Emulator - 10. */ + .long trap /* Line 1111 Emualtor - 11. */ + .long trap /* Harware Breakpoint - 12. */ + .long trap /* (Reserved for Coprocessor Protocol Violation)- 13. */ + .long trap /* Format Error - 14. */ + .long trap /* Uninitialized Interrupt - 15. */ + .long trap /* (Unassigned, Reserver) - 16. */ + .long trap /* (Unassigned, Reserver) - 17. */ + .long trap /* (Unassigned, Reserver) - 18. */ + .long trap /* (Unassigned, Reserver) - 19. */ + .long trap /* (Unassigned, Reserver) - 20. */ + .long trap /* (Unassigned, Reserver) - 21. */ + .long trap /* (Unassigned, Reserver) - 22. */ + .long trap /* (Unassigned, Reserver) - 23. */ + .long trap /* Spurious Interrupt - 24. */ + .long trap /* Level 1 Interrupt Autovector - 25. */ + .long trap /* Level 2 Interrupt Autovector - 26. */ + .long trap /* Level 3 Interrupt Autovector - 27. */ + .long trap /* Level 4 Interrupt Autovector - 28. */ + .long trap /* Level 5 Interrupt Autovector - 29. */ + .long trap /* Level 6 Interrupt Autovector - 30. */ + .long trap /* Level 7 Interrupt Autovector - 31. */ + .long system_call /* Trap Instruction Vectors 0 - 32. */ + .long trap /* Trap Instruction Vectors 1 - 33. */ + .long trap /* Trap Instruction Vectors 2 - 34. */ + .long trap /* Trap Instruction Vectors 3 - 35. */ + .long trap /* Trap Instruction Vectors 4 - 36. */ + .long trap /* Trap Instruction Vectors 5 - 37. */ + .long trap /* Trap Instruction Vectors 6 - 38. */ + .long trap /* Trap Instruction Vectors 7 - 39. */ + .long trap /* Trap Instruction Vectors 8 - 40. */ + .long trap /* Trap Instruction Vectors 9 - 41. */ + .long trap /* Trap Instruction Vectors 10 - 42. */ + .long trap /* Trap Instruction Vectors 11 - 43. */ + .long trap /* Trap Instruction Vectors 12 - 44. */ + .long trap /* Trap Instruction Vectors 13 - 45. */ + .long trap /* Trap Instruction Vectors 14 - 46. */ + .long trap /* Trap Instruction Vectors 15 - 47. */ + .long 0 /* (Reserved for Coprocessor) - 48. */ + .long 0 /* (Reserved for Coprocessor) - 49. */ + .long 0 /* (Reserved for Coprocessor) - 50. */ + .long 0 /* (Reserved for Coprocessor) - 51. */ + .long 0 /* (Reserved for Coprocessor) - 52. */ + .long 0 /* (Reserved for Coprocessor) - 53. */ + .long 0 /* (Reserved for Coprocessor) - 54. */ + .long 0 /* (Reserved for Coprocessor) - 55. */ + .long 0 /* (Reserved for Coprocessor) - 56. */ + .long 0 /* (Reserved for Coprocessor) - 57. */ + .long 0 /* (Reserved for Coprocessor) - 58. */ + .long 0 /* (Unassigned, Reserved) - 59. */ + .long 0 /* (Unassigned, Reserved) - 60. */ + .long 0 /* (Unassigned, Reserved) - 61. */ + .long 0 /* (Unassigned, Reserved) - 62. */ + .long 0 /* (Unassigned, Reserved) - 63. */ + /* The assignment of these vectors to the CPM is */ + /* dependant on the configuration of the CPM vba */ + /* fields. */ + .long 0 /* (User-Defined Vectors 1) CPM Error - 64. */ + .long 0 /* (User-Defined Vectors 2) CPM Parallel IO PC11- 65. */ + .long 0 /* (User-Defined Vectors 3) CPM Parallel IO PC10- 66. */ + .long 0 /* (User-Defined Vectors 4) CPM SMC2 / PIP - 67. */ + .long 0 /* (User-Defined Vectors 5) CPM SMC1 - 68. */ + .long 0 /* (User-Defined Vectors 6) CPM SPI - 69. */ + .long 0 /* (User-Defined Vectors 7) CPM Parallel IO PC9 - 70. */ + .long 0 /* (User-Defined Vectors 8) CPM Timer 4 - 71. */ + .long 0 /* (User-Defined Vectors 9) CPM Reserved - 72. */ + .long 0 /* (User-Defined Vectors 10) CPM Parallel IO PC8- 73. */ + .long 0 /* (User-Defined Vectors 11) CPM Parallel IO PC7- 74. */ + .long 0 /* (User-Defined Vectors 12) CPM Parallel IO PC6- 75. */ + .long 0 /* (User-Defined Vectors 13) CPM Timer 3 - 76. */ + .long 0 /* (User-Defined Vectors 14) CPM Reserved - 77. */ + .long 0 /* (User-Defined Vectors 15) CPM Parallel IO PC5- 78. */ + .long 0 /* (User-Defined Vectors 16) CPM Parallel IO PC4- 79. */ + .long 0 /* (User-Defined Vectors 17) CPM Reserved - 80. */ + .long 0 /* (User-Defined Vectors 18) CPM RISC Timer Tbl - 81. */ + .long 0 /* (User-Defined Vectors 19) CPM Timer 2 - 82. */ + .long 0 /* (User-Defined Vectors 21) CPM Reserved - 83. */ + .long 0 /* (User-Defined Vectors 22) CPM IDMA2 - 84. */ + .long 0 /* (User-Defined Vectors 23) CPM IDMA1 - 85. */ + .long 0 /* (User-Defined Vectors 24) CPM SDMA Bus Err - 86. */ + .long 0 /* (User-Defined Vectors 25) CPM Parallel IO PC3- 87. */ + .long 0 /* (User-Defined Vectors 26) CPM Parallel IO PC2- 88. */ + .long 0 /* (User-Defined Vectors 27) CPM Timer 1 - 89. */ + .long 0 /* (User-Defined Vectors 28) CPM Parallel IO PC1- 90. */ + .long 0 /* (User-Defined Vectors 29) CPM SCC 4 - 91. */ + .long 0 /* (User-Defined Vectors 30) CPM SCC 3 - 92. */ + .long 0 /* (User-Defined Vectors 31) CPM SCC 2 - 93. */ + .long 0 /* (User-Defined Vectors 32) CPM SCC 1 - 94. */ + .long 0 /* (User-Defined Vectors 33) CPM Parallel IO PC0- 95. */ + /* I don't think anything uses the vectors after here. */ + .long 0 /* (User-Defined Vectors 34) - 96. */ + .long 0,0,0,0,0 /* (User-Defined Vectors 35 - 39). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 40 - 49). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 50 - 59). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 60 - 69). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 70 - 79). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 80 - 89). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 90 - 99). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 100 - 109). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 110 - 119). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 120 - 129). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 130 - 139). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 140 - 149). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 150 - 159). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 160 - 169). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 170 - 179). */ + .long 0,0,0,0,0,0,0,0,0,0 /* (User-Defined Vectors 180 - 189). */ + .long 0,0,0 /* (User-Defined Vectors 190 - 192). */ +.text +ignore: rte diff -Nru a/arch/m68knommu/platform/68360/uCquicc/ram.ld b/arch/m68knommu/platform/68360/uCquicc/ram.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68360/uCquicc/ram.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,113 @@ +MEMORY +{ + romvec : ORIGIN = 0x00000000, LENGTH = 1028 + flash : ORIGIN = 1028, LENGTH = 0x00080000 - 1028 + eflash : ORIGIN = 0x00000000 + 0x00100000, LENGTH = 1 + ramvec : ORIGIN = 0x00200000, LENGTH = 1028 + ram : ORIGIN = 0x00200000 + 1028, LENGTH = 0x00080000 - 1028 + eram : ORIGIN = 0x00200000 + 0x00080000, LENGTH = 1 + dpram : ORIGIN = 0xffffe000, LENGTH = 0x00002000 +} + +jiffies = jiffies_64 + 4; + +SECTIONS +{ + .dpram : + { + _dprbase = . ; + } > dpram + + .romvec : + { + _romvec = . ; + __flashstart = . ; + *(.data.initvect) + . = ALIGN(4); + } > romvec + + .text : + { + text_start = . ; + *(.text) + *(.exit.text) + *(.text.*) + *(.rodata) + *(.fixup) + *(.kstrtab) + __start___ksymtab = . ; + *(__ksymtab) + __stop___ksymtab = . ; + __start___ex_table = . ; + *(___ex_table) + __stop___ex_table = . ; + . = ALIGN(4) ;_etext = . ; + __data_rom_start = ALIGN ( 4 ) ; + } > flash + + .eflash : + { + __flashend = . ; + } > eflash + + + .ramvec : + { + __ramstart = . ; + _ramvec = . ; + } > ramvec + + .data : + { + _sdata = . ; + __data_start = . ; + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + *(.data) + *(.data.*) + *(.setup.init) + *(.exitcall.exit) + . = ALIGN(4096) ; + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(4) ; + __init_end = .; + _edata = . ; + edata = .; + } > ram + + .bss : + { + _sbss = ALIGN( 0x10 ) ; + __bss_start = ALIGN( 0x10 ) ; + __data_end = ALIGN( 0x10 ) ; + *(.bss) + *(COMMON) + _ebss = . ; + __bss_end = . ; + end = ALIGN( 0x10 ) ; + _end = ALIGN( 0x10 ) ; + } > ram + + .eram : + { + _boot_stack = . - 4; + __ramend = . ; + + } > eram +} diff -Nru a/arch/m68knommu/platform/68360/uCquicc/rom.ld b/arch/m68knommu/platform/68360/uCquicc/rom.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68360/uCquicc/rom.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,113 @@ +MEMORY +{ + romvec : ORIGIN = 0x00000000, LENGTH = 1028 + flash : ORIGIN = 1028, LENGTH = 0x00200000 - 1028 + eflash : ORIGIN = 0x00000000 + 0x00200000, LENGTH = 1 + ramvec : ORIGIN = 0x00200000, LENGTH = 1028 + ram : ORIGIN = 0x00200000 + 1028, LENGTH = 0x00200000 - 1028 + eram : ORIGIN = 0x00200000 + 0x00200000, LENGTH = 1 + dpram : ORIGIN = 0xffffe000, LENGTH = 0x00002000 +} + +jiffies = jiffies_64 + 4; + +SECTIONS +{ + .dpram : + { + _dprbase = . ; + } > dpram + + .romvec : + { + _romvec = . ; + __flashstart = . ; + *(.data.initvect) + . = ALIGN(4); + } > romvec + + .text : + { + text_start = . ; + *(.text) + *(.exit.text) + *(.text.*) + *(.rodata) + *(.fixup) + *(.kstrtab) + __start___ksymtab = . ; + *(__ksymtab) + __stop___ksymtab = . ; + __start___ex_table = . ; + *(___ex_table) + __stop___ex_table = . ; + . = ALIGN(4) ;_etext = . ; + __data_rom_start = ALIGN ( 4 ) ; + } > flash + + .eflash : + { + __flashend = . ; + } > eflash + + + .ramvec : + { + __ramstart = . ; + _ramvec = . ; + } > ramvec + + .data : + { + _sdata = . ; + __data_start = . ; + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + *(.data) + *(.data.*) + *(.setup.init) + *(.exitcall.exit) + . = ALIGN(4096) ; + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(4) ; + __init_end = .; + _edata = . ; + edata = .; + } > ram + + .bss : + { + _sbss = ALIGN( 0x10 ) ; + __bss_start = ALIGN( 0x10 ) ; + __data_end = ALIGN( 0x10 ) ; + *(.bss) + *(COMMON) + _ebss = . ; + __bss_end = . ; + end = ALIGN( 0x10 ) ; + _end = ALIGN( 0x10 ) ; + } > ram + + .eram : + { + _boot_stack = . - 4; + __ramend = . ; + + } > eram +} diff -Nru a/arch/m68knommu/platform/68EZ328/Makefile b/arch/m68knommu/platform/68EZ328/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68EZ328/Makefile Mon Nov 4 14:31:03 2002 @@ -0,0 +1,14 @@ +# +# Makefile for arch/m68knommu/platform/68EZ328. +# + +obj-y := config.o + +EXTRA_TARGETS := $(BOARD)/bootlogo.rh $(BOARD)/crt0_$(MODEL).o + +include $(TOPDIR)/Rules.make + +$(obj)/$(BOARD)/bootlogo.rh: $(src)/bootlogo.h + perl $(src)/../68328/bootlogo.pl < $(src)/bootlogo.h \ + > $(obj)/$(BOARD)/bootlogo.rh + diff -Nru a/arch/m68knommu/platform/68EZ328/bootlogo.h b/arch/m68knommu/platform/68EZ328/bootlogo.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68EZ328/bootlogo.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,3204 @@ +#define splash_width 640 +#define splash_height 480 +static unsigned char splash_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0x03, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0xfe, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, + 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0xe0, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, + 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3e, 0xf8, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, + 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0xfe, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff, + 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff, + 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xe0, 0xff, 0x07, 0xfe, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, + 0x03, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0xff, 0x01, 0xf8, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, + 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, + 0x00, 0xf0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0xe0, 0xff, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x03, + 0x3f, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x3f, 0x00, 0xc0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x0f, 0xfc, 0x00, 0x00, 0x00, + 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, + 0x00, 0x80, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0xff, 0xff, 0xff, 0x3f, 0xf0, 0x01, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x80, 0xff, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0xc0, 0xff, + 0xc1, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfc, 0x07, 0x07, 0x00, 0x00, + 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, + 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, + 0x07, 0x00, 0x00, 0xe0, 0x07, 0x0e, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x00, + 0x3f, 0x1c, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x38, 0x00, 0x00, + 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, + 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x70, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0xe0, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc3, 0x01, 0x00, + 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, + 0x00, 0x80, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, + 0x00, 0x00, 0x00, 0x00, 0x80, 0xc7, 0x03, 0x00, 0xf8, 0xff, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x80, 0xff, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x87, 0x03, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x3f, 0x00, 0xc0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x07, 0x00, + 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, + 0x00, 0xe0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0e, 0x00, 0xf0, 0xff, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x00, 0xf0, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x0c, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0xff, 0x01, 0xf8, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x1c, 0x00, + 0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x07, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x38, 0x00, 0xf0, 0xff, 0x7f, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x38, 0x00, 0xf0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x00, + 0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0xe0, 0xff, 0x7f, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe2, 0x00, 0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, + 0xe0, 0xff, 0x7f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0xc0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x01, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, + 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x80, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0x07, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0xfe, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0x07, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, + 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0x07, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, + 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0xf0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x9f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, + 0xf8, 0xff, 0x1f, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x80, 0xff, 0xff, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x00, 0xfe, 0xff, 0x0f, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0xf8, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xc0, 0xff, 0xff, + 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, + 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, + 0xff, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x1f, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, + 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, + 0xfe, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xf0, 0xff, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0xf8, 0xff, 0x01, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0xc0, 0xff, 0x01, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0xfc, 0x01, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x41, 0x08, 0x04, 0xb3, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0xe0, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x41, 0x08, 0x04, 0xb3, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x18, 0x8e, 0x31, 0x7b, 0x30, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x18, 0x8e, 0x31, 0x7b, 0x30, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0xf8, + 0x41, 0xc6, 0x84, 0x0c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0xf8, 0x41, 0xc6, 0x84, 0x0c, + 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, + 0x0f, 0x00, 0x00, 0x18, 0x0c, 0x08, 0x00, 0x40, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xe4, + 0xb1, 0xc1, 0x98, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x09, 0x00, 0x00, 0xe4, 0xb1, 0xc1, 0x98, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, + 0x08, 0x00, 0x00, 0x1c, 0x02, 0x08, 0x04, 0x4c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0xff, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, + 0x02, 0x08, 0x04, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x1f, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x10, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x64, 0x4c, 0x00, 0x00, 0x00, + 0x36, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x09, 0x00, 0x00, 0x64, 0x4c, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x9c, + 0x01, 0x08, 0x83, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0xf0, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x64, 0x8c, 0x01, 0x18, 0x40, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0x0f, 0x00, 0x00, 0x64, 0x8c, 0x01, 0x18, 0x40, 0x30, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x03, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x9b, + 0x01, 0xc0, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x09, 0x00, 0x00, 0x9b, 0x01, 0xc0, 0x00, 0x00, + 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, + 0x00, 0x00, 0x00, 0x07, 0x32, 0x06, 0x18, 0x43, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0xc1, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x02, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x07, + 0x32, 0x06, 0x18, 0x43, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x10, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x08, 0x00, 0x00, 0x7b, 0x00, 0x30, 0x03, 0x0c, + 0x08, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe0, 0x07, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x09, 0x00, 0xc0, 0x84, 0x8d, 0x01, 0x80, 0x00, 0xc0, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0xfd, 0x03, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xc0, 0x84, + 0x8d, 0x01, 0x80, 0x00, 0xc0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfd, 0x03, 0xf0, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xc0, 0x1b, 0x00, 0x30, 0x00, 0x40, + 0x08, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xfc, 0x01, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0xc0, 0x1b, 0x00, 0x30, 0x00, 0x40, 0x08, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0x07, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, + 0xf8, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xc0, 0x64, + 0x42, 0x06, 0x1b, 0x03, 0x00, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0x64, 0x42, 0x06, 0x1b, 0x03, + 0x00, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xff, 0x03, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x0f, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x80, 0x30, 0x08, 0x86, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, + 0xff, 0x3f, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x1b, + 0x00, 0x00, 0x80, 0x30, 0x08, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xc3, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0xe0, 0x84, 0x31, 0x30, 0x04, 0x80, + 0xc1, 0x18, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x09, 0x00, 0xc0, 0x63, 0x02, 0x06, 0x00, 0x00, 0x00, 0x60, 0x6c, 0xfc, + 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0xe0, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x08, 0x00, 0xc0, 0x63, + 0x02, 0x06, 0x00, 0x00, 0x00, 0x60, 0x6c, 0xfc, 0xff, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xe0, 0x1c, 0x40, 0x00, 0x1b, 0x4c, + 0x06, 0x81, 0x80, 0xfd, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x00, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0xe0, 0x1c, 0x40, 0x00, 0x1b, 0x4c, 0x06, 0x81, 0x80, 0xfd, + 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, + 0x00, 0x80, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x09, 0x00, 0x20, 0x63, + 0x0c, 0x08, 0x80, 0x00, 0x30, 0x06, 0x0c, 0xfc, 0xff, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x20, 0x63, 0x0c, 0x08, 0x80, 0x00, + 0x30, 0x06, 0x0c, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x0f, 0x00, 0xd8, 0x84, 0x01, 0xc0, 0x00, 0x00, 0x06, 0x00, 0x80, 0xf1, + 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf8, 0x1b, + 0x40, 0x08, 0x84, 0x0c, 0xc0, 0x18, 0x13, 0xcc, 0xff, 0xff, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xe0, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0xf8, 0x1b, 0x40, 0x08, 0x84, 0x0c, + 0xc0, 0x18, 0x13, 0xcc, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe0, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0xf0, 0xe4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x09, 0x00, 0x38, 0x80, 0x01, 0x00, 0x18, 0x30, 0x06, 0x01, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, + 0x07, 0x00, 0x30, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x38, 0x80, + 0x01, 0x00, 0x18, 0x30, 0x06, 0x01, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x10, 0x84, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xd8, 0x1f, 0x30, 0x36, 0x80, 0x00, + 0x00, 0x00, 0x03, 0xf2, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x4f, 0x0e, 0x00, 0x10, 0x84, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x08, 0x00, 0xd8, 0x1f, 0x30, 0x36, 0x80, 0x00, 0x00, 0x00, 0x03, 0xf2, + 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, + 0xff, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, + 0x08, 0x00, 0x10, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x09, 0x00, 0x3e, 0x00, + 0x82, 0x01, 0x03, 0x40, 0x30, 0x98, 0x10, 0xf0, 0xe7, 0xff, 0xff, 0xff, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x1f, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x08, 0x00, 0x10, 0xe4, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xe6, 0x1b, 0x00, 0x00, 0x18, 0x0c, + 0x00, 0x00, 0x00, 0xfc, 0xff, 0xfb, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x41, 0x08, 0x00, 0x30, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0xe6, 0x1b, 0x00, 0x00, 0x18, 0x0c, 0x00, 0x00, 0x00, 0xfc, + 0xff, 0xfb, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, + 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, + 0x08, 0x00, 0x20, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1e, 0x64, + 0x30, 0xc6, 0x80, 0x80, 0x09, 0x06, 0x63, 0xfe, 0xf9, 0xff, 0xff, 0xff, + 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xf8, 0xff, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0e, 0x00, 0xc0, 0x3c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1e, 0x64, 0x30, 0xc6, 0x80, 0x80, + 0x09, 0x06, 0x63, 0xfe, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc3, 0x07, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x39, 0x03, 0x00, 0x00, 0x04, 0x0c, 0xc0, 0x60, 0x80, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, + 0x00, 0xfc, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x39, 0x03, + 0x00, 0x00, 0x04, 0x0c, 0xc0, 0x60, 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x80, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0xe7, 0x04, 0x42, 0xc6, 0x00, 0x00, + 0x00, 0x00, 0xec, 0xcf, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0x0f, 0xc0, 0x1f, 0x80, 0x01, 0x00, 0x98, 0x4c, 0x06, 0x06, 0xf0, 0x01, + 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, + 0x01, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x09, 0xc0, 0x1f, 0x80, + 0x01, 0x00, 0x98, 0x4c, 0x06, 0x06, 0xf0, 0x01, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3f, 0x08, 0xc0, 0xe6, 0x04, 0x0c, 0x08, 0x00, 0x00, + 0xc0, 0x60, 0x7c, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0xc0, 0xe6, 0x04, 0x0c, 0x08, 0x00, 0x00, 0xc0, 0x60, 0x7c, 0x00, + 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xc0, 0x19, 0x60, + 0x40, 0x00, 0x63, 0x30, 0x08, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0xff, 0xf3, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x3f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x09, 0xc0, 0x19, 0x60, 0x40, 0x00, 0x63, 0x30, + 0x08, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xf3, 0xff, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x78, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xc0, 0x27, 0x03, 0x00, 0x30, 0x00, 0x03, 0x00, 0xe6, 0x1f, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0xcf, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0xc0, 0x27, 0x03, + 0x00, 0x30, 0x00, 0x03, 0x00, 0xe6, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0x0f, 0xc0, 0xde, 0x04, 0x0c, 0x06, 0x03, 0x80, + 0xc1, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0f, 0x03, 0x00, 0xf8, 0xff, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0x0f, 0xc0, 0x19, 0x00, 0x32, 0x00, 0x60, 0x30, 0x08, 0xff, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9f, + 0x07, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x09, 0xc0, 0x19, 0x00, + 0x32, 0x00, 0x60, 0x30, 0x08, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9f, 0x07, 0x00, 0x18, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3f, 0x00, 0xc0, 0x27, 0x63, 0x80, 0x31, 0x04, 0x03, + 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1c, 0xfe, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x1f, 0x07, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0xc0, 0x27, 0x63, 0x80, 0x31, 0x04, 0x03, 0xf0, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0x7f, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, + 0xe0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x31, + 0x04, 0x00, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x08, 0x00, 0xd9, 0x04, + 0x00, 0x08, 0x00, 0x80, 0xf9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0xfe, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x04, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x09, 0x00, 0xd9, 0x04, 0x00, 0x08, 0x00, 0x80, + 0xf9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, + 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x78, 0x00, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xc0, 0x27, 0x00, 0x30, 0xc0, 0x60, 0xb0, 0xff, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x60, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xde, 0x9b, + 0x8d, 0x01, 0x04, 0xc3, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xf1, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x03, 0x00, 0xf0, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xde, 0x9b, 0x8d, 0x01, 0x04, 0xc3, + 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf1, 0xff, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3e, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x39, 0x04, 0x00, 0xc8, 0x00, 0xfc, 0xff, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xf8, 0xff, 0x3f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0x39, 0x04, + 0x00, 0xc8, 0x00, 0xfc, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1f, 0x00, 0xc0, 0xc7, 0x60, 0x42, 0x00, 0x60, 0xff, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, + 0x00, 0xc0, 0xc7, 0x60, 0x42, 0x00, 0x60, 0xff, 0xff, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0xc0, 0xff, 0x07, + 0xb0, 0x09, 0xe4, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x00, 0xfc, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0xde, 0x78, 0x02, 0x00, 0xfb, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f, 0xf0, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xde, 0x78, 0x02, 0x00, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x1f, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x08, + 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0x3f, 0x07, + 0xb0, 0xc9, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0x3f, 0x07, 0xb0, 0xc9, 0xf8, 0xff, + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0x0f, 0x00, 0xe7, 0xfb, 0x43, 0x30, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0xe7, 0xfb, + 0x43, 0x30, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0xe0, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xfe, 0x1c, 0xb2, 0x0f, 0xe0, 0xff, + 0x07, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x0f, 0x00, 0xf8, 0xe7, 0xfd, 0x01, 0xe0, 0xff, 0x07, 0x00, 0xe0, 0xff, + 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xe0, + 0xb1, 0x3f, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0xf8, + 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0xc0, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0xf8, 0xe7, + 0xfd, 0x01, 0xe0, 0xff, 0x07, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xe0, 0xb1, 0x3f, 0x00, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x80, 0xff, + 0x01, 0x00, 0xe0, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x98, 0x4f, 0x0e, 0x18, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0x07, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x01, 0x00, 0xe0, 0x03, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, + 0x4f, 0x0e, 0xf8, 0x1f, 0xf6, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xf8, 0xff, + 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xb1, 0x01, 0xff, 0x1f, + 0xf6, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x1f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0xf8, 0xff, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0xb1, 0x01, 0xff, 0x7f, 0xc0, 0xff, 0xff, 0xff, + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x0f, 0x00, 0xe0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0xce, 0xff, 0x7f, 0xc0, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, + 0xff, 0xe3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xe0, 0xff, + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0xce, 0xff, 0x7f, + 0x00, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x1b, 0xb2, 0x31, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff, + 0x3f, 0x00, 0x00, 0xe0, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x0f, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x1c, + 0x00, 0xc0, 0xff, 0x73, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf0, + 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, + 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc0, 0xff, + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x1c, 0x00, 0xc0, 0x7f, 0x1c, + 0x30, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x78, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x87, 0x31, 0x06, 0x7c, 0x1c, 0x30, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x87, + 0x31, 0x06, 0xfc, 0x0f, 0xc8, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x38, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0xff, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe6, 0x04, 0x00, 0x30, 0xe3, 0x0f, + 0xc8, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0xe0, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0xe6, 0x04, 0x00, 0x30, 0x03, 0x00, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, + 0x07, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1b, + 0x4c, 0x00, 0x04, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0xc0, 0xff, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x07, 0x04, 0x00, 0x06, 0x18, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0f, 0x0e, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x07, 0x04, 0x00, 0x06, 0x78, 0xf3, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x07, 0x00, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x08, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3e, 0x04, + 0x02, 0x30, 0x60, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0xf8, + 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0xc0, 0xff, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3e, 0x04, 0x02, 0x30, 0xe0, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x04, 0x40, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x07, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x08, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x04, + 0x40, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x08, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0xff, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x39, 0x67, 0x00, 0x06, 0xe0, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x04, 0x30, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x04, + 0x30, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x08, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x00, 0x00, 0xff, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x7e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3e, 0x9b, 0x01, 0x30, 0xe0, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x08, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x3e, 0x9b, 0x01, 0x30, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x02, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0x01, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x1c, + 0x0c, 0x06, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x38, + 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xe0, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0xff, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0xf0, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x1c, 0x0c, 0x06, 0xfb, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x68, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf8, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x18, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0xc0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0xfe, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x03, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc6, 0x9b, + 0x81, 0x01, 0x60, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x80, + 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xc0, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc6, 0x9b, 0x81, 0x01, 0x00, 0x00, + 0xf6, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x78, 0x0c, 0x30, 0x04, 0x00, 0xf6, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0xe8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, + 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x78, + 0x0c, 0x30, 0x04, 0x00, 0xc8, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xf8, + 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x64, 0x40, 0x00, 0x1c, 0x00, + 0xc8, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xf8, 0x58, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0x64, 0x40, 0x00, 0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0x78, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x08, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, + 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0, + 0x01, 0x36, 0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x38, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xff, + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0, 0x01, 0x36, 0xfc, 0x1f, + 0x30, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x8f, 0x01, 0x00, 0xff, 0x3f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x87, 0x0f, 0x00, 0xff, 0x1f, 0x30, 0xff, 0xff, 0xff, + 0xff, 0x07, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xcf, 0x03, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x40, 0xc0, 0xff, 0x7f, 0xc0, 0xfe, 0xff, 0xff, 0xff, 0x07, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xcf, 0x03, 0x00, 0xff, + 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xc0, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40, 0xc0, 0xff, 0x7f, + 0x00, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x8f, 0x01, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x0e, 0xc6, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x0e, 0xc6, 0xff, 0x7f, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, + 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0xf0, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x9c, 0x01, 0x30, 0xff, 0x7f, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x9c, 0x01, 0x30, 0xff, 0x63, 0x30, 0xff, 0xff, 0xff, + 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x08, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x07, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, + 0x4c, 0x00, 0xff, 0x63, 0x30, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xff, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x31, 0xfc, 0x1f, + 0x00, 0xff, 0xff, 0xfd, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb2, 0x31, 0xfc, 0x0f, 0x00, 0xff, 0xff, 0x03, + 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x0f, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, + 0x41, 0x00, 0xe0, 0x0f, 0x00, 0xff, 0xff, 0x03, 0xff, 0x03, 0x00, 0x38, + 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, + 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x41, 0x00, 0x00, 0x80, + 0xc9, 0xf9, 0xff, 0x3d, 0xff, 0x03, 0x00, 0x78, 0xc0, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x32, 0x08, 0x00, 0x80, 0xc9, 0xf9, 0xff, 0x3d, + 0xff, 0x03, 0x00, 0xf8, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x00, 0x00, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, + 0x32, 0x08, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xcf, 0xff, 0x00, 0x00, 0xf8, + 0x81, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0xff, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0, 0x01, 0xf8, 0x00, 0x00, + 0xf0, 0xff, 0xff, 0xcf, 0xff, 0x00, 0x00, 0x38, 0x03, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x03, 0x80, 0xff, 0xff, 0xff, 0xff, + 0x3f, 0x00, 0x00, 0x38, 0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0xff, 0xff, 0x03, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x38, + 0x1e, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0xff, + 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0x03, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x38, 0xfc, 0x1f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x1f, 0x00, 0x00, 0x38, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, + 0x80, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x0f, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x78, + 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xe0, 0x1f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0xf8, 0xc1, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0xf8, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc0, 0xff, + 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x67, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x13, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xc0, 0xff, + 0xff, 0xff, 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0x67, 0xfe, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0xff, 0xff, 0x98, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, + 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, + 0x0f, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x98, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xf8, 0xff, + 0xff, 0xff, 0x7f, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, 0xe7, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0xff, 0xfc, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, + 0xff, 0xff, 0x3f, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x00, 0xc0, 0xff, 0x67, 0x8c, 0xf9, 0xfb, 0x73, 0x00, 0x67, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xc0, 0xff, 0x67, + 0x8c, 0xf9, 0xfb, 0x73, 0x00, 0x67, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x1f, 0xe7, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0xc0, 0x27, 0xfc, 0x73, 0xc6, 0x1c, 0x8c, + 0x37, 0x80, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0xff, 0x1f, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0xc0, 0x27, 0xfc, 0x73, 0xc6, 0x1c, 0x8c, 0x37, 0x80, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0xc0, 0xfe, 0x03, + 0x8c, 0x09, 0xe3, 0x73, 0xc8, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x0f, 0xc0, 0xfe, 0x03, 0x8c, 0x09, 0xe3, 0x73, + 0xc8, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x0f, 0xc0, 0x27, 0xe7, 0x31, 0x36, 0x04, 0x8c, 0x01, 0x60, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0xc0, 0xde, 0x18, + 0x42, 0xc0, 0x98, 0x30, 0x08, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x0f, 0xc0, 0xde, 0x18, 0x42, 0xc0, 0x98, 0x30, + 0x08, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0xc0, 0x27, 0x63, 0x00, 0x08, 0x63, 0x03, 0x06, 0x60, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x27, 0x63, + 0x00, 0x08, 0x63, 0x03, 0x06, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0xc0, 0xd9, 0x04, 0xb2, 0x01, 0x00, 0xb0, + 0x31, 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf9, 0xff, + 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x08, 0xc0, 0xd9, 0x04, 0xb2, 0x01, 0x00, 0xb0, 0x31, 0x19, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, 0xc0, 0x1e, 0x63, + 0x00, 0x30, 0x04, 0x03, 0xc8, 0x60, 0x00, 0x0e, 0x00, 0x00, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x0e, 0xc0, 0xe1, 0x18, 0x80, 0x01, 0x60, 0xb0, + 0x01, 0xe7, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x0f, 0xc0, 0xe1, 0x18, 0x80, 0x01, 0x60, 0xb0, 0x01, 0xe7, 0xf3, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x0f, 0xc0, 0x1e, 0x03, + 0x02, 0x08, 0x04, 0x00, 0xc8, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xd8, 0x0f, 0xc0, 0x1e, 0x03, 0x02, 0x08, 0x04, 0x00, + 0xc8, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x0f, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0x0b, 0x00, 0x21, 0x64, 0x40, 0xc0, 0x00, 0xb3, 0xf1, 0xfe, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xfb, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x21, 0x64, + 0x40, 0xc0, 0x00, 0xb3, 0xf1, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfb, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfd, 0x00, 0xc0, 0xdf, 0x00, 0x00, 0x06, 0x60, 0x00, + 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xf9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, + 0x01, 0xc0, 0xdf, 0x00, 0x00, 0x06, 0x60, 0x00, 0x0e, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xf0, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x0b, 0xc0, 0xc0, 0x84, + 0x31, 0xc0, 0x00, 0x4c, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x83, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1e, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0f, 0x0e, 0xc0, 0x3f, 0x18, 0x00, 0x06, 0x84, 0x80, + 0x09, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0xc3, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x0c, 0xc0, 0x3f, 0x18, 0x00, 0x06, 0x84, 0x80, 0x09, 0xff, 0xff, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, + 0xc1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x08, 0xc0, 0xc1, 0x03, + 0x4c, 0x00, 0x00, 0x30, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x90, 0x13, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x08, 0xc0, 0xc1, 0x03, 0x4c, 0x00, 0x00, 0x30, + 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0xc0, 0x3f, 0x98, 0x01, 0x08, 0x1b, 0x43, 0xc8, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x98, + 0x01, 0x08, 0x1b, 0x43, 0xc8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0e, 0x00, 0xc0, 0xc6, 0x03, 0x40, 0x00, 0x00, 0x80, + 0x31, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0xef, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, + 0x00, 0x00, 0x3f, 0x18, 0x0c, 0x30, 0x60, 0x0c, 0xce, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0xef, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x3f, 0x18, + 0x0c, 0x30, 0x60, 0x0c, 0xce, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xc7, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xde, 0x63, 0x40, 0x06, 0x03, 0x30, + 0x30, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x83, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, + 0x00, 0x00, 0xde, 0x63, 0x40, 0x06, 0x03, 0x30, 0x30, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x04, + 0x02, 0x00, 0x00, 0x83, 0xc9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x38, 0x04, 0x02, 0x00, 0x00, 0x83, + 0xc9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0x03, 0x00, 0xe0, 0x1b, 0x0c, 0x08, 0x18, 0x40, 0x30, 0xfe, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0xc0, 0x84, + 0x81, 0x01, 0x03, 0x0c, 0xc6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0xc0, 0x84, 0x81, 0x01, 0x03, 0x0c, + 0xc6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x0e, 0x00, 0x00, 0x1b, 0x0c, 0x30, 0x80, 0x00, 0x30, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x10, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x1b, + 0x0c, 0x30, 0x80, 0x00, 0x30, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x67, 0xc0, 0x01, 0x04, 0x40, + 0x00, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x08, 0x00, 0x00, 0x67, 0xc0, 0x01, 0x04, 0x40, 0x00, 0xe1, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x30, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x9c, + 0x01, 0x08, 0x60, 0x0c, 0x06, 0x86, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xbf, 0x1f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x0e, 0x00, 0x00, 0x18, 0x0c, 0xc0, 0x00, 0x00, + 0xc0, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0x9f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, + 0x07, 0x00, 0x00, 0x18, 0x0c, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0x1f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0xe0, + 0x01, 0x06, 0x00, 0x30, 0x06, 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x06, 0x00, 0x30, + 0x06, 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0x00, 0x00, 0x00, 0x60, 0x30, 0x00, 0x63, 0x03, 0x30, 0x00, 0xe0, 0xff, + 0xff, 0xff, 0xff, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, + 0x30, 0x00, 0x63, 0x03, 0x30, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x80, 0x83, 0x09, 0x18, 0x00, + 0x00, 0x06, 0x83, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x08, 0x00, 0x00, 0x80, 0x83, 0x09, 0x18, 0x00, 0x00, 0x06, 0x83, 0xff, + 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x8c, 0xc9, 0x60, 0x00, 0xfe, 0xff, 0xff, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x84, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x0f, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x84, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x04, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x60, 0x83, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0xc8, 0x60, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x06, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x80, 0xc1, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x80, 0xc1, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf8, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xc6, + 0x03, 0x00, 0x00, 0x00, 0x40, 0x08, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xef, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xd8, 0xef, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xf3, + 0x0f, 0x00, 0x00, 0x00, 0x80, 0x09, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x33, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x88, 0x13, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x13, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x33, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x88, 0xf3, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xe3, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0xe1, 0x1f, 0x00, 0x00, 0x00, + 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0xc1, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xc0, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; diff -Nru a/arch/m68knommu/platform/68EZ328/config.c b/arch/m68knommu/platform/68EZ328/config.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68EZ328/config.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,131 @@ +/* + * linux/arch/$(ARCH)/platform/$(PLATFORM)/config.c + * + * Copyright (C) 1993 Hamish Macdonald + * Copyright (C) 1999 D. Jeff Dionne + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_UCSIMM +#include +#endif +#ifdef CONFIG_PILOT +#include "PalmV/romfs.h" +#endif + +void BSP_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) +{ + /* Restart mode, Enable int, 32KHz, Enable timer */ + TCTL = TCTL_OM | TCTL_IRQEN | TCTL_CLKSOURCE_32KHZ | TCTL_TEN; + /* Set prescaler (Divide 32KHz by 32)*/ + TPRER = 31; + /* Set compare register 32Khz / 32 / 10 = 100 */ + TCMP = 10; + + request_irq(TMR_IRQ_NUM, timer_routine, IRQ_FLG_LOCK, "timer", NULL); +} + +void BSP_tick(void) +{ + /* Reset Timer1 */ + TSTAT &= 0; +} + +unsigned long BSP_gettimeoffset (void) +{ + return 0; +} + +void BSP_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ +} + +int BSP_hwclk(int op, struct hwclk_time *t) +{ + if (!op) { + /* read */ + } else { + /* write */ + } + return 0; +} + +int BSP_set_clock_mmss (unsigned long nowtime) +{ +#if 0 + short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + + tod->second1 = real_seconds / 10; + tod->second2 = real_seconds % 10; + tod->minute1 = real_minutes / 10; + tod->minute2 = real_minutes % 10; +#endif + return 0; +} + +void BSP_reset (void) +{ + local_irq_disable(); + asm volatile (" + moveal #0x10c00000, %a0; + moveb #0, 0xFFFFF300; + moveal 0(%a0), %sp; + moveal 4(%a0), %a0; + jmp (%a0); + "); +} + +unsigned char *cs8900a_hwaddr; +static int errno; + +#ifdef CONFIG_UCSIMM +_bsc0(char *, getserialnum) +_bsc1(unsigned char *, gethwaddr, int, a) +_bsc1(char *, getbenv, char *, a) +#endif + +void config_BSP(char *command, int len) +{ + unsigned char *p; + + printk("\n68EZ328 DragonBallEZ support (C) 1999 Rt-Control, Inc\n"); + +#ifdef CONFIG_UCSIMM + printk("uCsimm serial string [%s]\n",getserialnum()); + p = cs8900a_hwaddr = gethwaddr(0); + printk("uCsimm hwaddr %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", + p[0], p[1], p[2], p[3], p[4], p[5]); + + p = getbenv("APPEND"); + if (p) strcpy(p,command); + else command[0] = 0; +#endif + + mach_sched_init = BSP_sched_init; + mach_tick = BSP_tick; + mach_gettimeoffset = BSP_gettimeoffset; + mach_gettod = BSP_gettod; + mach_hwclk = NULL; + mach_set_clock_mmss = NULL; + mach_reset = BSP_reset; + + config_M68328_irq(); +} diff -Nru a/arch/m68knommu/platform/68EZ328/ucsimm/crt0_fixed.S b/arch/m68knommu/platform/68EZ328/ucsimm/crt0_fixed.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68EZ328/ucsimm/crt0_fixed.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,109 @@ +#include + + .global _start + .global _stext + + .global _rambase + .global _ramvec + .global _ramstart + .global _ramend + +#ifdef CONFIG_INIT_LCD + .global splash_bits +#endif + + .data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +.align 4 +_ramvec: +.long 0 +_rambase: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +#ifdef CONFIG_INIT_LCD +splash_bits: +#include "bootlogo.rh" +#endif + + .text +_start: +_stext: movew #0x2700,%sr +#ifdef CONFIG_INIT_LCD + movel #splash_bits, 0xfffffA00 /* LSSA */ + moveb #0x28, 0xfffffA05 /* LVPW */ + movew #0x280, 0xFFFFFa08 /* LXMAX */ + movew #0x1df, 0xFFFFFa0a /* LYMAX */ + moveb #0, 0xfffffa29 /* LBAR */ + moveb #0, 0xfffffa25 /* LPXCD */ + moveb #0x08, 0xFFFFFa20 /* LPICF */ + moveb #0x01, 0xFFFFFA21 /* -ve pol */ + moveb #0x81, 0xfffffA27 /* LCKCON */ + movew #0xff00, 0xfffff412 /* LCD pins */ +#endif + moveal #__ramend-CONFIG_MEMORY_RESERVE*0x100000 - 0x10, %sp + movew #32767, %d0 /* PLL settle wait loop */ +1: subq #1, %d0 + bne 1b + + /* Copy data segment from ROM to RAM */ + moveal #__data_rom_start, %a0 + moveal #_sdata, %a1 + moveal #_edata, %a2 + + /* Copy %a0 to %a1 until %a1 == %a2 */ +1: movel %a0@+, %a1@+ + cmpal %a1, %a2 + bhi 1b + + moveal #_sbss, %a0 + moveal #_ebss, %a1 + /* Copy 0 to %a0 until %a0 == %a1 */ + +1: + clrl %a0@+ + cmpal %a0, %a1 + bhi 1b + + movel #_sdata, %d0 + movel %d0, _rambase + movel #_ebss, %d0 + movel %d0, _ramstart + movel #__ramend-CONFIG_MEMORY_RESERVE*0x100000, %d0 + movel %d0, _ramend + movel #__ramvec, %d0 + movel %d0, _ramvec + +/* + * load the current task pointer and stack + */ + lea init_thread_union, %a0 + lea 0x2000(%a0), %sp + +1: jsr start_kernel + bra 1b +_exit: + + jmp _exit + + +putc: + moveb %d7,0xfffff907 +1: + movew 0xfffff906, %d7 + andw #0x2000, %d7 + beq 1b + rts + + .data +env: + .long 0 + .text + diff -Nru a/arch/m68knommu/platform/68EZ328/ucsimm/crt0_himem.S b/arch/m68knommu/platform/68EZ328/ucsimm/crt0_himem.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68EZ328/ucsimm/crt0_himem.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include "crt0_fixed.S" diff -Nru a/arch/m68knommu/platform/68EZ328/ucsimm/crt0_ram.S b/arch/m68knommu/platform/68EZ328/ucsimm/crt0_ram.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68EZ328/ucsimm/crt0_ram.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,172 @@ + .global __text_start + .global __main + .global __bss_start + .global __bss_end + .global __ram_start + .global __ram_end + .global __rom_start + .global __rom_end + .global __data_start + .global __data_end + + .global _rambase + .global _ramstart + + .global splash_bits + .global _start + .global _stext + +#define DEBUG +#define ROM_OFFSET 0x10C00000 +#define STACK_GAURD 0x10 + + .text + +_start: +_stext: + movew #0x2700, %sr /* Exceptions off! */ + + /* Init chip registers. uCsimm specific */ + moveb #0x00, 0xfffffb0b /* Watchdog off */ + moveb #0x10, 0xfffff000 /* SCR */ + + movew #0x2400, 0xfffff200 /* PLLCR */ + movew #0x0123, 0xfffff202 /* PLLFSR */ + + moveb #0x00, 0xfffff40b /* enable chip select */ + moveb #0x00, 0xfffff423 /* enable /DWE */ + moveb #0x08, 0xfffffd0d /* disable hardmap */ + moveb #0x07, 0xfffffd0e /* level 7 interrupt clear */ + + movew #0x8600, 0xfffff100 /* FLASH at 0x10c00000 */ + movew #0x018b, 0xfffff110 /* 2Meg, enable, 0ws */ + + movew #0x8f00, 0xfffffc00 /* DRAM configuration */ + movew #0x9667, 0xfffffc02 /* DRAM control */ + movew #0x0000, 0xfffff106 /* DRAM at 0x00000000 */ + movew #0x068f, 0xfffff116 /* 8Meg, enable, 0ws */ + + moveb #0x40, 0xfffff300 /* IVR */ + movel #0x007FFFFF, %d0 /* IMR */ + movel %d0, 0xfffff304 + + moveb 0xfffff42b, %d0 + andb #0xe0, %d0 + moveb %d0, 0xfffff42b + + moveb #0x08, 0xfffff907 /* Ignore CTS */ + movew #0x010b, 0xfffff902 /* BAUD to 9600 */ + movew #0xe100, 0xfffff900 /* enable */ + + movew #16384, %d0 /* PLL settle wait loop */ +L0: + subw #1, %d0 + bne L0 +#ifdef DEBUG + moveq #70, %d7 /* 'F' */ + moveb %d7,0xfffff907 /* No absolute addresses */ +pclp1: + movew 0xfffff906, %d7 + andw #0x2000, %d7 + beq pclp1 +#endif /* DEBUG */ + +#ifdef CONFIG_RELOCATE + /* Copy me to RAM */ + moveal #__rom_start, %a0 + moveal #__ram_start, %a1 + moveal #__data_end, %a2 + + /* Copy %a0 to %a1 until %a1 == %a2 */ +LD1: + movel %a0@+, %d0 + movel %d0, %a1@+ + cmpal %a1, %a2 + bhi LD1 + +#ifdef DEBUG + moveq #74, %d7 /* 'J' */ + moveb %d7,0xfffff907 /* No absolute addresses */ +pclp2: + movew 0xfffff906, %d7 + andw #0x2000, %d7 + beq pclp2 +#endif /* DEBUG */ + /* jump into the RAM copy */ + jmp ram_jump +ram_jump: + +#endif /* CONFIG_RELOCATE */ + +#ifdef DEBUG + moveq #82, %d7 /* 'R' */ + moveb %d7,0xfffff907 /* No absolute addresses */ +pclp3: + movew 0xfffff906, %d7 + andw #0x2000, %d7 + beq pclp3 +#endif /* DEBUG */ + moveal #0x007ffff0, %ssp + moveal #__bss_start, %a0 + moveal #__bss_end, %a1 + + /* Copy 0 to %a0 until %a0 >= %a1 */ +L1: + movel #0, %a0@+ + cmpal %a0, %a1 + bhi L1 + +#ifdef DEBUG + moveq #67, %d7 /* 'C' */ + jsr putc +#endif /* DEBUG */ + + pea 0 + pea env + pea %sp@(4) + pea 0 + +#ifdef DEBUG + moveq #70, %d7 /* 'F' */ + jsr putc +#endif /* DEBUG */ + +lp: + jsr start_kernel + jmp lp +_exit: + + jmp _exit + +__main: + /* nothing */ + rts + +#ifdef DEBUG +putc: + moveb %d7,0xfffff907 +pclp: + movew 0xfffff906, %d7 + andw #0x2000, %d7 + beq pclp + rts +#endif /* DEBUG */ + + .data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +.align 4 +_ramvec: +.long 0 +_rambase: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +env: + .long 0 diff -Nru a/arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S b/arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68EZ328/ucsimm/crt0_rom.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include "crt0_fixed.S" diff -Nru a/arch/m68knommu/platform/68EZ328/ucsimm/fixed.ld b/arch/m68knommu/platform/68EZ328/ucsimm/fixed.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68EZ328/ucsimm/fixed.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,108 @@ + +jiffies = jiffies_64 + 4; + +SECTIONS +{ + .romvec : + { + _flashstart = . ; + _romvec = . ; + __rom_start = . ; + } > romvec + + .text : + { + _stext = . ; + *(.text) + *(.exit.text) + . = ALIGN(0x4) ; + *(.text.*) + . = ALIGN(0x4) ; + *(.exitcall.exit) + . = ALIGN(0x4) ; + *(.kstrtab) + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + *(__ksymtab) + __stop___ksymtab = .; + + . = ALIGN(0x4) ; + _etext = . ; + __data_rom_start = . ; + } > flash + + .eflash : + { + _flashend = . ; + } > eflash + + .ramvec : + { + __ram_start = . ; + __ramvec = . ; + } > ramvec + + .data : + { + . = ALIGN(0x4) ; + _sdata = . ; + __data_start = . ; + + . = ALIGN(0x4) ; + *(.rodata) + . = ALIGN(0x4) ; + *(.data) + . = ALIGN(0x4) ; + *(.data.*) + + . = ALIGN(0x4) ; + __init_begin = .; + *(.init.text) + *(.init.data) + + . = ALIGN(0x4) ; + __setup_start = .; + *(.init.setup) + . = ALIGN(0x4) ; + __setup_end = .; + + . = ALIGN(0x4) ; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(0x4) ; + + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + + _edata = . ; + } > ram + + .bss : + { + . = ALIGN(0x4) ; + _sbss = . ; + *(.bss) + . = ALIGN(0x4) ; + *(COMMON) + . = ALIGN(0x4) ; + _ebss = . ; + _end = . ; + } > ram + + .eram : + { + __ramend = . ; + } > eram +} diff -Nru a/arch/m68knommu/platform/68EZ328/ucsimm/himem.ld b/arch/m68knommu/platform/68EZ328/ucsimm/himem.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68EZ328/ucsimm/himem.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,11 @@ +MEMORY + { + romvec : ORIGIN = 0x00600000, LENGTH = 0x00000400 + flash : ORIGIN = 0x00600400, LENGTH = 0x00200000 - 0x00010400 + eflash : ORIGIN = 0x007f0000, LENGTH = 0 + ramvec : ORIGIN = 0x00000000, LENGTH = 0x00000400 + ram : ORIGIN = 0x00020000, LENGTH = 0x00600000 - 0x00020000 + eram : ORIGIN = 0x00600000, LENGTH = 0 + } + +INCLUDE arch/m68knommu/platform/68EZ328/ucsimm/fixed.ld diff -Nru a/arch/m68knommu/platform/68EZ328/ucsimm/ram.ld b/arch/m68knommu/platform/68EZ328/ucsimm/ram.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68EZ328/ucsimm/ram.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,110 @@ +MEMORY + { + romvec : ORIGIN = 0x10c10000, LENGTH = 0x00000400 + flash : ORIGIN = 0x10c10400, LENGTH = 0x00200000 - 0x00010400 + eflash : ORIGIN = 0x10e00000, LENGTH = 0 + ramvec : ORIGIN = 0x00000000, LENGTH = 0x00000400 + bvec : ORIGIN = 0x00020000, LENGTH = 0x00000400 + ram : ORIGIN = 0x00020400, LENGTH = 0x00800000 - 0x00020400 + eram : ORIGIN = 0x00800000, LENGTH = 0 + } + +jiffies = jiffies_64 + 4; + +SECTIONS +{ + .fakevec : + { + } > romvec + .rom : + { + __rom_start = . ; + } > flash + .eflash : + { + _flashend = . ; + } > eflash + .realvec : + { + _ramvec = . ; + } > ramvec + .romvec : + { + _romvec = . ; + } > bvec + .text : + { + __ram_start = . ; + text_start = . ; + *(.text) + *(.exit.text) + *(.text.*) + *(.rodata) + . = ALIGN(0x4) ; + *(.kstrtab) + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + *(__ksymtab) + __stop___ksymtab = .; + + _etext = . ; + __data_rom_start = ALIGN ( 4 ) ; + } > ram + .data : + { + _sdata = . ; + __data_start = . ; + + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + + *(.data) + *(.data.*) + *(.exitcall.exit) + + . = ALIGN(4096) ; + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(4) ; + __init_end = .; + + _edata = . ; + edata = ALIGN( 0x10 ) ; + } > ram + .bss : + { + _sbss = ALIGN( 0x10 ) ; + __bss_start = ALIGN( 0x10 ) ; + __data_end = ALIGN( 0x10 ) ; + *(.bss) + *(COMMON) + _ebss = . ; + __bss_end = . ; + end = ALIGN( 0x10 ) ; + _end = ALIGN( 0x10 ) ; + } > ram + .eram : + { + __ramend = . ; + _ramend = . ; + } > eram +} diff -Nru a/arch/m68knommu/platform/68EZ328/ucsimm/rom.ld b/arch/m68knommu/platform/68EZ328/ucsimm/rom.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68EZ328/ucsimm/rom.ld Mon Nov 4 14:31:03 2002 @@ -0,0 +1,11 @@ +MEMORY + { + romvec : ORIGIN = 0x10c10000, LENGTH = 0x00000400 + flash : ORIGIN = 0x10c10400, LENGTH = 0x001fec00 + eflash : ORIGIN = 0x10d00000, LENGTH = 0 + ramvec : ORIGIN = 0x00000000, LENGTH = 1024 + ram : ORIGIN = 0x00020000, LENGTH = 0x00800000 - 0x00020000 + eram : ORIGIN = 0x00800000, LENGTH = 0 + } + +INCLUDE arch/m68knommu/platform/68EZ328/ucsimm/fixed.ld diff -Nru a/arch/m68knommu/platform/68VZ328/Makefile b/arch/m68knommu/platform/68VZ328/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/Makefile Mon Nov 4 14:31:03 2002 @@ -0,0 +1,14 @@ +# +# Makefile for arch/m68knommu/platform/68VZ328. +# + +obj-y := $(BOARD)/config.o + +EXTRA_TARGETS := $(BOARD)/bootlogo.rh $(BOARD)/crt0_$(MODEL).o + +include $(TOPDIR)/Rules.make + +$(obj)/$(BOARD)/bootlogo.rh: $(src)/../68EZ328/bootlogo.h + perl $(src)/../68328/bootlogo.pl < $(src)/../68EZ328/bootlogo.h \ + > $(obj)/$(BOARD)/bootlogo.rh + diff -Nru a/arch/m68knommu/platform/68VZ328/de2/config.c b/arch/m68knommu/platform/68VZ328/de2/config.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/de2/config.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,151 @@ +/* + * linux/arch/m68knommu/platform/MC68VZ328/de2/config.c + * + * Copyright (C) 1993 Hamish Macdonald + * Copyright (C) 1999 D. Jeff Dionne + * Copyright (C) 2001 Georges Menie, Ken Desmet + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define CLOCK_COMPARE (32768/HZ) + +static void dragen2_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) +{ + /* disable timer 1 */ + TCTL = 0; + + /* set ISR */ + request_irq(TMR_IRQ_NUM, timer_routine, IRQ_FLG_LOCK, "timer", NULL); + + /* Restart mode, Enable int, 32KHz */ + TCTL = TCTL_OM | TCTL_IRQEN | TCTL_CLKSOURCE_32KHZ; + TPRER = 0; + TCMP = CLOCK_COMPARE-1; + + /* Enable timer 1 */ + TCTL |= TCTL_TEN; +} + +static void dragen2_tick(void) +{ + /* Reset Timer1 */ + TSTAT &= 0; +} + +static unsigned long dragen2_gettimeoffset(void) +{ + unsigned long ticks, offset = 0; + + ticks = TCN; + + if (ticks > (CLOCK_COMPARE>>1)) { + /* check for pending interrupt */ + if (ISR & (1<>24)%24; + *min = (now>>16)%60; + *sec = now%60; +} + +static void dragen2_reset(void) +{ + local_irq_disable(); + asm volatile (" + movel #-1, 0xFFFFF304; + moveb #0, 0xFFFFF300; + moveal #0x04000000, %a0; + moveal 0(%a0), %sp; + moveal 4(%a0), %a0; + jmp (%a0); + "); +} + +int dragen2_cs8900_setup(struct net_device *dev) +{ + /* Set the ETH hardware address from its flash monitor location */ + memcpy(dev->dev_addr, (void *)0x400fffa, 6); + dev->irq = INT1_IRQ_NUM; + return dev->base_addr = 0x08000041; +} + +static void init_hardware(void) +{ + /* CSGB Init */ + CSGBB = 0x4000; + CSB = 0x1a1; + + /* CS8900 init */ + /* PK3: hardware sleep function pin, active low */ + PKSEL |= PK(3); /* select pin as I/O */ + PKDIR |= PK(3); /* select pin as output */ + PKDATA |= PK(3); /* set pin high */ + + /* PF5: hardware reset function pin, active high */ + PFSEL |= PF(5); /* select pin as I/O */ + PFDIR |= PF(5); /* select pin as output */ + PFDATA &= ~PF(5); /* set pin low */ + + /* cs8900 hardware reset */ + PFDATA |= PF(5); + { volatile int i; for (i = 0; i < 32000; ++i); } + PFDATA &= ~PF(5); + + /* INT1 enable (cs8900 IRQ) */ + PDPOL &= ~PD(1); /* active high signal */ + PDIQEG &= ~PD(1); + PDIRQEN |= PD(1); /* IRQ enabled */ + +#ifdef CONFIG_68328_SERIAL_UART2 + /* Enable RXD TXD port bits to enable UART2 */ + PJSEL &= ~(PJ(5)|PJ(4)); +#endif +} + +void config_BSP(char *command, int len) +{ + printk("68VZ328 DragonBallVZ support (c) 2001 Lineo, Inc.\n"); + command[0] = '\0'; /* no specific boot option */ + + init_hardware(); + + mach_sched_init = dragen2_sched_init; + mach_tick = dragen2_tick; + mach_gettimeoffset = dragen2_gettimeoffset; + mach_reset = dragen2_reset; + mach_gettod = dragen2_gettod; + + config_M68VZ328_irq(); +} diff -Nru a/arch/m68knommu/platform/68VZ328/de2/crt0_fixed.S b/arch/m68knommu/platform/68VZ328/de2/crt0_fixed.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/de2/crt0_fixed.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,159 @@ +#include + + .global _start + .global _stext + + .global _rambase + .global _ramvec + .global _ramstart + .global _ramend + +#ifdef CONFIG_INIT_LCD + .global splash_bits +#endif + + .data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +.align 4 +_ramvec: +.long 0 +_rambase: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +#ifdef CONFIG_INIT_LCD +splash_bits: +#include "bootlogo.rh" +#endif + + .text +_start: +_stext: + movew #0x2700,%sr + moveal #__ramend-CONFIG_MEMORY_RESERVE*0x100000 - 0x10, %sp + movel #0xffffffff, 0xfffff304 /* disable all interrupts */ + +#ifdef CONFIG_RAMKERNEL + /* Copy me from ROM to RAM */ + moveal #__rom_start, %a0 + moveal #__ram_start, %a1 + moveal #__data_end, %a2 + + /* Copy %a0 to %a1 until %a1 == %a2 */ +2: cmpal %a1, %a2 + beq 1f + movel %a0@+, %a1@+ + bra 2b +1: + /* jump into the RAM copy */ + jmp ram_jump +ram_jump: +#endif + +#ifdef CONFIG_INIT_LCD + movel #splash_bits, 0xfffffA00 /* LSSA */ + moveb #0x28, 0xfffffA05 /* LVPW */ + movew #0x280, 0xFFFFFa08 /* LXMAX */ + movew #0x1df, 0xFFFFFa0a /* LYMAX */ + moveb #0, 0xfffffa29 /* LBAR */ + moveb #0, 0xfffffa25 /* LPXCD */ + moveb #0x08, 0xFFFFFa20 /* LPICF */ + moveb #0x01, 0xFFFFFA21 /* -ve pol */ + moveb #0x81, 0xfffffA27 /* LCKCON */ + movew #0xff00, 0xfffff412 /* LCD pins */ +#endif + + moveq #13, %d7 /* '\r' */ + jsr putc + moveq #10, %d7 /* '\n' */ + jsr putc + moveq #65, %d7 /* 'A' */ + jsr putc + + movew #32767, %d0 /* PLL settle wait loop */ +1: subq #1, %d0 + bne 1b + + moveq #66, %d7 /* 'B' */ + jsr putc + +#ifndef CONFIG_RAMKERNEL + /* Copy data segment from ROM to RAM */ + moveal #__data_rom_start, %a0 + moveal #_sdata, %a1 + moveal #_edata, %a2 + + /* Copy %a0 to %a1 until %a1 == %a2 */ +2: cmpal %a1, %a2 + beq 1f + movel %a0@+, %a1@+ + bra 2b +1: +#endif + moveq #67, %d7 /* 'C' */ + jsr putc + + /* Initialize BSS segment to 0 */ + moveal #_sbss, %a0 + moveal #_ebss, %a1 + + /* Copy 0 to %a0 until %a0 == %a1 */ +2: cmpal %a0, %a1 + beq 1f + clrl %a0@+ + bra 2b +1: + moveq #68, %d7 /* 'D' */ + jsr putc + + movel #_sdata, %d0 + movel %d0, _rambase + movel #_ebss, %d0 + movel %d0, _ramstart + movel #__ramend-CONFIG_MEMORY_RESERVE*0x100000, %d0 + movel %d0, _ramend + movel #__ramvec, %d0 + movel %d0, _ramvec + + moveq #69, %d7 /* 'E' */ + jsr putc + +/* + * load the current task pointer and stack + */ + lea init_thread_union, %a0 + lea 0x2000(%a0), %sp + + moveq #70, %d7 /* 'F' */ + jsr putc + moveq #13, %d7 /* '\r' */ + jsr putc + moveq #10, %d7 /* '\n' */ + jsr putc + +1: jsr start_kernel + bra 1b + +_exit: + bra _exit + +putc: + moveb %d7,0xfffff907 +1: + movew 0xfffff906, %d7 + andw #0x2000, %d7 + beq 1b + rts + + .data +env: + .long 0 + .text + diff -Nru a/arch/m68knommu/platform/68VZ328/de2/crt0_himem.S b/arch/m68knommu/platform/68VZ328/de2/crt0_himem.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/de2/crt0_himem.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include "crt0_fixed.S" diff -Nru a/arch/m68knommu/platform/68VZ328/de2/crt0_ram.S b/arch/m68knommu/platform/68VZ328/de2/crt0_ram.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/de2/crt0_ram.S Mon Nov 4 14:31:03 2002 @@ -0,0 +1 @@ +#include "crt0_fixed.S" diff -Nru a/arch/m68knommu/platform/68VZ328/de2/crt0_rom.S b/arch/m68knommu/platform/68VZ328/de2/crt0_rom.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/de2/crt0_rom.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include "crt0_fixed.S" diff -Nru a/arch/m68knommu/platform/68VZ328/de2/fixed.ld b/arch/m68knommu/platform/68VZ328/de2/fixed.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/de2/fixed.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,102 @@ + +jiffies = jiffies_64 + 4; + +SECTIONS +{ + .romvec : + { + _flashstart = . ; + _romvec = . ; + __rom_start = . ; + } > romvec + + .text : + { + _stext = . ; + *(.text) + . = ALIGN(0x4) ; + *(.text.*) + . = ALIGN(0x4) ; + *(.exitcall.exit) + . = ALIGN(0x4) ; + *(.kstrtab) + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + *(__ksymtab) + __stop___ksymtab = .; + + . = ALIGN(0x4) ; + _etext = . ; + __data_rom_start = . ; + } > flash + + .eflash : + { + _flashend = . ; + } > eflash + + .ramvec : + { + __ram_start = . ; + __ramvec = . ; + } > ramvec + + .data : + { + . = ALIGN(0x4) ; + _sdata = . ; + __data_start = . ; + + . = ALIGN(0x4) ; + *(.rodata) + . = ALIGN(0x4) ; + *(.data) + . = ALIGN(0x4) ; + *(.data.*) + + . = ALIGN(0x4) ; + __setup_start = .; + *(.init.setup) + . = ALIGN(0x4) ; + __setup_end = .; + + . = ALIGN(0x4) ; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(0x4) ; + + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + + _edata = . ; + } > ram + + .bss : + { + . = ALIGN(0x4) ; + _sbss = . ; + *(.bss) + . = ALIGN(0x4) ; + *(COMMON) + . = ALIGN(0x4) ; + _ebss = . ; + _end = . ; + } > ram + + .eram : + { + __ramend = . ; + } > eram +} diff -Nru a/arch/m68knommu/platform/68VZ328/de2/himem.ld b/arch/m68knommu/platform/68VZ328/de2/himem.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/de2/himem.ld Mon Nov 4 14:31:03 2002 @@ -0,0 +1,11 @@ +MEMORY + { + romvec : ORIGIN = 0x01e00000, LENGTH = 1k + flash : ORIGIN = 0x01e00400, LENGTH = 2M - 1k + eflash : ORIGIN = 0x02000000, LENGTH = 0 + ramvec : ORIGIN = 0x00000000, LENGTH = 1k + ram : ORIGIN = 0x00010000, LENGTH = 30M - 64k + eram : ORIGIN = 0x01e00000, LENGTH = 0 + } + +INCLUDE arch/m68knommu/platform/68VZ328/de2/fixed.ld diff -Nru a/arch/m68knommu/platform/68VZ328/de2/ram.ld b/arch/m68knommu/platform/68VZ328/de2/ram.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/de2/ram.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,109 @@ +MEMORY + { + romvec : ORIGIN = 0x04030000, LENGTH = 1k + flash : ORIGIN = 0x04030400, LENGTH = 2M - 197k + eflash : ORIGIN = 0x04200000, LENGTH = 0 + ramvec : ORIGIN = 0x00000000, LENGTH = 1k + bvec : ORIGIN = 0x00010000, LENGTH = 1k + ram : ORIGIN = 0x00010400, LENGTH = 32M - 65k + eram : ORIGIN = 0x02000000, LENGTH = 0 + } + +jiffies = jiffies_64 + 4; + +SECTIONS +{ + .fakevec : + { + } > romvec + .rom : + { + __rom_start = . ; + } > flash + .eflash : + { + _flashend = . ; + } > eflash + .realvec : + { + __ramvec = . ; + } > ramvec + .romvec : + { + _romvec = . ; + } > bvec + .text : + { + __ram_start = . ; + text_start = . ; + *(.text) + *(.text.*) + *(.rodata) + . = ALIGN(0x4) ; + *(.kstrtab) + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + *(__ksymtab) + __stop___ksymtab = .; + + _etext = . ; + __data_rom_start = ALIGN ( 4 ) ; + } > ram + .data : + { + _sdata = . ; + __data_start = . ; + + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + + *(.data) + *(.data.*) + *(.exitcall.exit) + + . = ALIGN(4096) ; + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(4) ; + __init_end = .; + + _edata = . ; + edata = ALIGN( 0x10 ) ; + } > ram + .bss : + { + _sbss = ALIGN( 0x10 ) ; + __bss_start = ALIGN( 0x10 ) ; + __data_end = ALIGN( 0x10 ) ; + *(.bss) + *(COMMON) + _ebss = . ; + __bss_end = . ; + end = ALIGN( 0x10 ) ; + _end = ALIGN( 0x10 ) ; + } > ram + .eram : + { + __ramend = . ; + _ramend = . ; + } > eram +} diff -Nru a/arch/m68knommu/platform/68VZ328/de2/rom.ld b/arch/m68knommu/platform/68VZ328/de2/rom.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/de2/rom.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,11 @@ +MEMORY + { + romvec : ORIGIN = 0x04030000, LENGTH = 1k + flash : ORIGIN = 0x04030400, LENGTH = 2M - 197k + eflash : ORIGIN = 0x04200000, LENGTH = 0 + ramvec : ORIGIN = 0x00000000, LENGTH = 1k + ram : ORIGIN = 0x00010000, LENGTH = 32M - 64k + eram : ORIGIN = 0x02000000, LENGTH = 0 + } + +INCLUDE arch/m68knommu/platform/68VZ328/de2/fixed.ld diff -Nru a/arch/m68knommu/platform/68VZ328/ucdimm/crt0_fixed.S b/arch/m68knommu/platform/68VZ328/ucdimm/crt0_fixed.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/ucdimm/crt0_fixed.S Mon Nov 4 14:31:03 2002 @@ -0,0 +1,109 @@ +#include + + .global _start + .global _stext + + .global _rambase + .global _ramvec + .global _ramstart + .global _ramend + +#ifdef CONFIG_INIT_LCD + .global splash_bits +#endif + + .data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +.align 4 +_ramvec: +.long 0 +_rambase: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +#ifdef CONFIG_INIT_LCD +splash_bits: +#include "bootlogo.rh" +#endif + + .text +_start: +_stext: movew #0x2700,%sr +#ifdef CONFIG_INIT_LCD + movel #splash_bits, 0xfffffA00 /* LSSA */ + moveb #0x28, 0xfffffA05 /* LVPW */ + movew #0x280, 0xFFFFFa08 /* LXMAX */ + movew #0x1df, 0xFFFFFa0a /* LYMAX */ + moveb #0, 0xfffffa29 /* LBAR */ + moveb #0, 0xfffffa25 /* LPXCD */ + moveb #0x08, 0xFFFFFa20 /* LPICF */ + moveb #0x01, 0xFFFFFA21 /* -ve pol */ + moveb #0x81, 0xfffffA27 /* LCKCON */ + movew #0xff00, 0xfffff412 /* LCD pins */ +#endif + moveal #__ramend-CONFIG_MEMORY_RESERVE*0x100000 - 0x10, %sp + movew #32767, %d0 /* PLL settle wait loop */ +1: subq #1, %d0 + bne 1b + + /* Copy data segment from ROM to RAM */ + moveal #__data_rom_start, %a0 + moveal #_sdata, %a1 + moveal #_edata, %a2 + + /* Copy %a0 to %a1 until %a1 == %a2 */ +1: movel %a0@+, %a1@+ + cmpal %a1, %a2 + bhi 1b + + moveal #_sbss, %a0 + moveal #_ebss, %a1 + /* Copy 0 to %a0 until %a0 == %a1 */ + +1: + clrl %a0@+ + cmpal %a0, %a1 + bhi 1b + + movel #_sdata, %d0 + movel %d0, _rambase + movel #_ebss, %d0 + movel %d0, _ramstart + movel #__ramend-CONFIG_MEMORY_RESERVE*0x100000, %d0 + movel %d0, _ramend + movel #__ramvec, %d0 + movel %d0, _ramvec + +/* + * load the current task pointer and stack + */ + lea init_thread_union, %a0 + lea 0x2000(%a0), %sp + +1: jsr start_kernel + bra 1b +_exit: + + jmp _exit + + +putc: + moveb %d7,0xfffff907 +1: + movew 0xfffff906, %d7 + andw #0x2000, %d7 + beq 1b + rts + + .data +env: + .long 0 + .text + diff -Nru a/arch/m68knommu/platform/68VZ328/ucdimm/crt0_himem.S b/arch/m68knommu/platform/68VZ328/ucdimm/crt0_himem.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/ucdimm/crt0_himem.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include "crt0_fixed.S" diff -Nru a/arch/m68knommu/platform/68VZ328/ucdimm/crt0_ram.S b/arch/m68knommu/platform/68VZ328/ucdimm/crt0_ram.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/ucdimm/crt0_ram.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,176 @@ +#include + + .global __text_start + .global __main + .global __bss_start + .global __bss_end + .global __ram_start + .global __ram_end + .global __rom_start + .global __rom_end + .global __data_start + .global __data_end + + .global _rambase + .global _ramstart + + .global splash_bits + .global _start + .global _stext + +#define DEBUG +#define ROM_OFFSET 0x10C00000 +#define STACK_GAURD 0x10 + + .text + +_start: +_stext: + movew #0x2700, %sr /* Exceptions off! */ + +#if 0 + /* Init chip registers. uCsimm specific */ + moveb #0x00, 0xfffffb0b /* Watchdog off */ + moveb #0x10, 0xfffff000 /* SCR */ + + movew #0x2400, 0xfffff200 /* PLLCR */ + movew #0x0123, 0xfffff202 /* PLLFSR */ + + moveb #0x00, 0xfffff40b /* enable chip select */ + moveb #0x00, 0xfffff423 /* enable /DWE */ + moveb #0x08, 0xfffffd0d /* disable hardmap */ + moveb #0x07, 0xfffffd0e /* level 7 interrupt clear */ + + movew #0x8600, 0xfffff100 /* FLASH at 0x10c00000 */ + movew #0x018b, 0xfffff110 /* 2Meg, enable, 0ws */ + + movew #0x8f00, 0xfffffc00 /* DRAM configuration */ + movew #0x9667, 0xfffffc02 /* DRAM control */ + movew #0x0000, 0xfffff106 /* DRAM at 0x00000000 */ + movew #0x068f, 0xfffff116 /* 8Meg, enable, 0ws */ + + moveb #0x40, 0xfffff300 /* IVR */ + movel #0x007FFFFF, %d0 /* IMR */ + movel %d0, 0xfffff304 + + moveb 0xfffff42b, %d0 + andb #0xe0, %d0 + moveb %d0, 0xfffff42b + + moveb #0x08, 0xfffff907 /* Ignore CTS */ + movew #0x010b, 0xfffff902 /* BAUD to 9600 */ + movew #0xe100, 0xfffff900 /* enable */ +#endif + + movew #16384, %d0 /* PLL settle wait loop */ +L0: + subw #1, %d0 + bne L0 +#ifdef DEBUG + moveq #70, %d7 /* 'F' */ + moveb %d7,0xfffff907 /* No absolute addresses */ +pclp1: + movew 0xfffff906, %d7 + andw #0x2000, %d7 + beq pclp1 +#endif /* DEBUG */ + +#ifdef CONFIG_RELOCATE + /* Copy me to RAM */ + moveal #__rom_start, %a0 + moveal #__ram_start, %a1 + moveal #__data_end, %a2 + + /* Copy %a0 to %a1 until %a1 == %a2 */ +LD1: + movel %a0@+, %d0 + movel %d0, %a1@+ + cmpal %a1, %a2 + bhi LD1 + +#ifdef DEBUG + moveq #74, %d7 /* 'J' */ + moveb %d7,0xfffff907 /* No absolute addresses */ +pclp2: + movew 0xfffff906, %d7 + andw #0x2000, %d7 + beq pclp2 +#endif /* DEBUG */ + /* jump into the RAM copy */ + jmp ram_jump +ram_jump: + +#endif /* CONFIG_RELOCATE */ + +#ifdef DEBUG + moveq #82, %d7 /* 'R' */ + moveb %d7,0xfffff907 /* No absolute addresses */ +pclp3: + movew 0xfffff906, %d7 + andw #0x2000, %d7 + beq pclp3 +#endif /* DEBUG */ + moveal #0x007ffff0, %ssp + moveal #__bss_start, %a0 + moveal #__bss_end, %a1 + + /* Copy 0 to %a0 until %a0 >= %a1 */ +L1: + movel #0, %a0@+ + cmpal %a0, %a1 + bhi L1 + +#ifdef DEBUG + moveq #67, %d7 /* 'C' */ + jsr putc +#endif /* DEBUG */ + + pea 0 + pea env + pea %sp@(4) + pea 0 + +#ifdef DEBUG + moveq #70, %d7 /* 'F' */ + jsr putc +#endif /* DEBUG */ + +lp: + jsr start_kernel + jmp lp +_exit: + + jmp _exit + +__main: + /* nothing */ + rts + +#ifdef DEBUG +putc: + moveb %d7,0xfffff907 +pclp: + movew 0xfffff906, %d7 + andw #0x2000, %d7 + beq pclp + rts +#endif /* DEBUG */ + + .data + +/* + * Set up the usable of RAM stuff. Size of RAM is determined then + * an initial stack set up at the end. + */ +.align 4 +_ramvec: +.long 0 +_rambase: +.long 0 +_ramstart: +.long 0 +_ramend: +.long 0 + +env: + .long 0 diff -Nru a/arch/m68knommu/platform/68VZ328/ucdimm/crt0_rom.S b/arch/m68knommu/platform/68VZ328/ucdimm/crt0_rom.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/ucdimm/crt0_rom.S Mon Nov 4 14:31:03 2002 @@ -0,0 +1 @@ +#include "crt0_fixed.S" diff -Nru a/arch/m68knommu/platform/68VZ328/ucdimm/fixed.ld b/arch/m68knommu/platform/68VZ328/ucdimm/fixed.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/ucdimm/fixed.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,102 @@ + +jiffies = jiffies_64 + 4; + +SECTIONS +{ + .romvec : + { + _flashstart = . ; + _romvec = . ; + __rom_start = . ; + } > romvec + + .text : + { + _stext = . ; + *(.text) + . = ALIGN(0x4) ; + *(.text.*) + . = ALIGN(0x4) ; + *(.exitcall.exit) + . = ALIGN(0x4) ; + *(.kstrtab) + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + *(__ksymtab) + __stop___ksymtab = .; + + . = ALIGN(0x4) ; + _etext = . ; + __data_rom_start = . ; + } > flash + + .eflash : + { + _flashend = . ; + } > eflash + + .ramvec : + { + __ram_start = . ; + __ramvec = . ; + } > ramvec + + .data : + { + . = ALIGN(0x4) ; + _sdata = . ; + __data_start = . ; + + . = ALIGN(0x4) ; + *(.rodata) + . = ALIGN(0x4) ; + *(.data) + . = ALIGN(0x4) ; + *(.data.*) + + . = ALIGN(0x4) ; + __setup_start = .; + *(.init.setup) + . = ALIGN(0x4) ; + __setup_end = .; + + . = ALIGN(0x4) ; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(0x4) ; + + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + + _edata = . ; + } > ram + + .bss : + { + . = ALIGN(0x4) ; + _sbss = . ; + *(.bss) + . = ALIGN(0x4) ; + *(COMMON) + . = ALIGN(0x4) ; + _ebss = . ; + _end = . ; + } > ram + + .eram : + { + __ramend = . ; + } > eram +} diff -Nru a/arch/m68knommu/platform/68VZ328/ucdimm/himem.ld b/arch/m68knommu/platform/68VZ328/ucdimm/himem.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/ucdimm/himem.ld Mon Nov 4 14:31:03 2002 @@ -0,0 +1,11 @@ +MEMORY + { + romvec : ORIGIN = 0x00600000, LENGTH = 0x00000400 + flash : ORIGIN = 0x00600400, LENGTH = 0x00200000 - 0x00010400 + eflash : ORIGIN = 0x007f0000, LENGTH = 0 + ramvec : ORIGIN = 0x00000000, LENGTH = 0x00000400 + ram : ORIGIN = 0x00020000, LENGTH = 0x00600000 - 0x00020000 + eram : ORIGIN = 0x00600000, LENGTH = 0 + } + +INCLUDE arch/m68knommu/platform/68VZ328/ucdimm/fixed.ld diff -Nru a/arch/m68knommu/platform/68VZ328/ucdimm/ram.ld b/arch/m68knommu/platform/68VZ328/ucdimm/ram.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/ucdimm/ram.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,109 @@ +MEMORY + { + romvec : ORIGIN = 0x10c10000, LENGTH = 0x00000400 + flash : ORIGIN = 0x10c10400, LENGTH = 0x00200000 - 0x00010400 + eflash : ORIGIN = 0x10e00000, LENGTH = 0 + ramvec : ORIGIN = 0x00000000, LENGTH = 0x00000400 + bvec : ORIGIN = 0x00020000, LENGTH = 0x00000400 + ram : ORIGIN = 0x00020400, LENGTH = 0x00800000 - 0x00020400 + eram : ORIGIN = 0x00800000, LENGTH = 0 + } + +jiffies = jiffies_64 + 4; + +SECTIONS +{ + .fakevec : + { + } > romvec + .rom : + { + __rom_start = . ; + } > flash + .eflash : + { + _flashend = . ; + } > eflash + .realvec : + { + _ramvec = . ; + } > ramvec + .romvec : + { + _romvec = . ; + } > bvec + .text : + { + __ram_start = . ; + text_start = . ; + *(.text) + *(.text.*) + *(.rodata) + . = ALIGN(0x4) ; + *(.kstrtab) + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + *(__ksymtab) + __stop___ksymtab = .; + + _etext = . ; + __data_rom_start = ALIGN ( 4 ) ; + } > ram + .data : + { + _sdata = . ; + __data_start = . ; + + . = ALIGN(0x2000) ; + *(.data.init_task) + . = ALIGN(0x2000) ; + + *(.data) + *(.data.*) + *(.exitcall.exit) + + . = ALIGN(4096) ; + __init_begin = .; + *(.init.text) + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + . = ALIGN(4) ; + __init_end = .; + + _edata = . ; + edata = ALIGN( 0x10 ) ; + } > ram + .bss : + { + _sbss = ALIGN( 0x10 ) ; + __bss_start = ALIGN( 0x10 ) ; + __data_end = ALIGN( 0x10 ) ; + *(.bss) + *(COMMON) + _ebss = . ; + __bss_end = . ; + end = ALIGN( 0x10 ) ; + _end = ALIGN( 0x10 ) ; + } > ram + .eram : + { + __ramend = . ; + _ramend = . ; + } > eram +} diff -Nru a/arch/m68knommu/platform/68VZ328/ucdimm/rom.ld b/arch/m68knommu/platform/68VZ328/ucdimm/rom.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/68VZ328/ucdimm/rom.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,11 @@ +MEMORY + { + romvec : ORIGIN = 0x10c10000, LENGTH = 0x00000400 + flash : ORIGIN = 0x10c10400, LENGTH = 0x001fec00 + eflash : ORIGIN = 0x10d00000, LENGTH = 0 + ramvec : ORIGIN = 0x00000000, LENGTH = 1024 + ram : ORIGIN = 0x00020000, LENGTH = 0x00800000 - 0x00020000 + eram : ORIGIN = 0x00800000, LENGTH = 0 + } + +INCLUDE arch/m68knommu/platform/68VZ328/ucdimm/fixed.ld diff -Nru a/arch/m68knommu/platform/Makefile b/arch/m68knommu/platform/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/Makefile Mon Nov 4 14:31:04 2002 @@ -0,0 +1,6 @@ +# +# Makefile for the arch/m68knommu/platform. +# + +include $(TOPDIR)/Rules.make + diff -Nru a/arch/m68knommu/vmlinux.lds.S b/arch/m68knommu/vmlinux.lds.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/vmlinux.lds.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,115 @@ + +#include + +#ifdef CONFIG_PILOT3 +#ifdef CONFIG_ROMKERNEL +#include "platform/68328/pilot/rom.ld" +#endif +#ifdef CONFIG_RAMKERNEL +#include "platform/68328/pilot/ram.ld" +#endif +#endif + +#ifdef CONFIG_UCSIMM +#ifdef CONFIG_RAMKERNEL +#include "platform/68EZ328/ucsimm/ram.ld" +#endif +#ifdef CONFIG_ROMKERNEL +#include "platform/68EZ328/ucsimm/rom.ld" +#endif +#ifdef CONFIG_HIMEMKERNEL +#include "platform/68EZ328/ucsimm/himem.ld" +#endif +#endif + +#ifdef CONFIG_UCDIMM +#ifdef CONFIG_RAMKERNEL +#include "platform/68VZ328/ucdimm/ram.ld" +#endif +#ifdef CONFIG_ROMKERNEL +#include "platform/68VZ328/ucdimm/rom.ld" +#endif +#ifdef CONFIG_HIMEMKERNEL +#include "platform/68VZ328/ucdimm/himem.ld" +#endif +#endif +#ifdef CONFIG_DRAGEN2 +#ifdef CONFIG_RAMKERNEL +#include "platform/68VZ328/de2/ram.ld" +#endif +#ifdef CONFIG_ROMKERNEL +#include "platform/68VZ328/de2/rom.ld" +#endif +#ifdef CONFIG_HIMEMKERNEL +#include "platform/68VZ328/de2/himem.ld" +#endif +#endif + +#ifdef CONFIG_UCQUICC +#ifdef CONFIG_RAMKERNEL +#include "platform/68360/uCquicc/ram.ld" +#endif +#ifdef CONFIG_ROMKERNEL +#include "platform/68360/uCquicc/rom.ld" +#endif +#endif + +#ifdef CONFIG_ARN5206 +#include "platform/5206/ARNEWSH/ram.ld" +#endif + +#ifdef CONFIG_M5206eC3 +#include "platform/5206e/MOTOROLA/ram.ld" +#endif +#ifdef CONFIG_ELITE +#include "platform/5206e/eLITE/ram.ld" +#endif + +#ifdef CONFIG_M5249C3 +#include "platform/5249/MOTOROLA/ram.ld" +#endif + +#ifdef CONFIG_M5272C3 +#include "platform/5272/MOTOROLA/ram.ld" +#endif + +#ifdef CONFIG_ARN5307 +#include "platform/5307/ARNEWSH/ram.ld" +#endif +#ifdef CONFIG_M5307C3 +#include "platform/5307/MOTOROLA/ram.ld" +#endif +#ifdef CONFIG_eLIA +#include "platform/5307/eLIA/ram.ld" +#endif +#ifdef CONFIG_DISKtel +#include "platform/5307/DISKtel/ram.ld" +#endif +#ifdef CONFIG_SECUREEDGEMP3 +#include "platform/5307/MP3/ram.ld" +#endif + +#ifdef CONFIG_M5407 +#include "platform/5407/MOTOROLA/ram.ld" +#endif + +#ifdef CONFIG_CLEOPATRA +#ifdef CONFIG_M5307 +#include "platform/5307/CLEOPATRA/ram.ld" +#endif +#ifdef CONFIG_M5407 +#include "platform/5407/CLEOPATRA/ram.ld" +#endif +#endif + +#ifdef CONFIG_NETtel +#ifdef CONFIG_M5206e +#include "platform/5206e/NETtel/ram.ld" +#endif +#ifdef CONFIG_M5272 +#include "platform/5272/NETtel/ram.ld" +#endif +#ifdef CONFIG_M5307 +#include "platform/5307/NETtel/ram.ld" +#endif +#endif diff -Nru a/arch/mips/Kconfig b/arch/mips/Kconfig --- a/arch/mips/Kconfig Mon Nov 4 14:31:01 2002 +++ b/arch/mips/Kconfig Mon Nov 4 14:31:01 2002 @@ -6,6 +6,14 @@ bool default y +config MMU + bool + default y + +config SWAP + bool + default y + config SMP bool ---help--- diff -Nru a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c --- a/arch/mips/au1000/common/time.c Mon Nov 4 14:31:01 2002 +++ b/arch/mips/au1000/common/time.c Mon Nov 4 14:31:01 2002 @@ -68,7 +68,7 @@ goto null; do { - kstat.irqs[0][irq]++; + kstat_cpu(0).irqs[irq]++; do_timer(regs); r4k_cur += r4k_offset; ack_r4ktimer(r4k_cur); diff -Nru a/arch/mips/baget/irq.c b/arch/mips/baget/irq.c --- a/arch/mips/baget/irq.c Mon Nov 4 14:31:02 2002 +++ b/arch/mips/baget/irq.c Mon Nov 4 14:31:02 2002 @@ -152,7 +152,7 @@ if (!action) continue; seq_printf(p, "%2d: %8d %c %s", - i, kstat.irqs[0][i], + i, kstat_cpu(0).irqs[i], (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); for (action=action->next; action; action = action->next) { @@ -180,7 +180,7 @@ cpu = smp_processor_id(); irq_enter(cpu, irq); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; mask_irq(irq); action = *(irq + irq_action); diff -Nru a/arch/mips/dec/irq.c b/arch/mips/dec/irq.c --- a/arch/mips/dec/irq.c Mon Nov 4 14:31:02 2002 +++ b/arch/mips/dec/irq.c Mon Nov 4 14:31:02 2002 @@ -103,7 +103,7 @@ if (!action) continue; seq_printf(p, "%2d: %8d %c %s", - i, kstat.irqs[0][i], + i, kstat_cpu(0).irqs[i], (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); for (action = action->next; action; action = action->next) { @@ -130,7 +130,7 @@ cpu = smp_processor_id(); irq_enter(cpu, irq); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; mask_irq(irq); action = *(irq + irq_action); diff -Nru a/arch/mips/ite-boards/generic/irq.c b/arch/mips/ite-boards/generic/irq.c --- a/arch/mips/ite-boards/generic/irq.c Mon Nov 4 14:31:02 2002 +++ b/arch/mips/ite-boards/generic/irq.c Mon Nov 4 14:31:02 2002 @@ -256,7 +256,7 @@ cpu = smp_processor_id(); irq_enter(cpu, irq); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; #if 0 if (irq_desc[irq].handler && irq_desc[irq].handler->ack) { // printk("invoking ack handler\n"); diff -Nru a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c --- a/arch/mips/kernel/irq.c Mon Nov 4 14:31:01 2002 +++ b/arch/mips/kernel/irq.c Mon Nov 4 14:31:01 2002 @@ -244,7 +244,7 @@ struct irqaction * action; unsigned int status; - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; spin_lock(&desc->lock); desc->handler->ack(irq); /* diff -Nru a/arch/mips/kernel/old-irq.c b/arch/mips/kernel/old-irq.c --- a/arch/mips/kernel/old-irq.c Mon Nov 4 14:31:02 2002 +++ b/arch/mips/kernel/old-irq.c Mon Nov 4 14:31:02 2002 @@ -134,7 +134,7 @@ if (!action) continue; seq_printf(p, "%2d: %8d %c %s", - i, kstat.irqs[0][i], + i, kstat_cpu(0).irqs[i], (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); for (action=action->next; action; action = action->next) { @@ -176,7 +176,7 @@ i8259_mask_and_ack_irq(irq); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; action = *(irq + irq_action); if (!action) @@ -214,7 +214,7 @@ cpu = smp_processor_id(); irq_enter(cpu, irq); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; action = *(irq + irq_action); if (action) { diff -Nru a/arch/mips/kernel/old-time.c b/arch/mips/kernel/old-time.c --- a/arch/mips/kernel/old-time.c Mon Nov 4 14:31:02 2002 +++ b/arch/mips/kernel/old-time.c Mon Nov 4 14:31:02 2002 @@ -424,7 +424,7 @@ */ write_32bit_cp0_register (CP0_COMPARE, (unsigned long) (count + r4k_interval)); - kstat.irqs[0][irq]++; + kstat_cpu(0).irqs[irq]++; #endif timer_interrupt(irq, dev_id, regs); diff -Nru a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c --- a/arch/mips/kernel/process.c Mon Nov 4 14:31:01 2002 +++ b/arch/mips/kernel/process.c Mon Nov 4 14:31:01 2002 @@ -176,7 +176,7 @@ :"=r" (retval) :"i" (__NR_clone), "i" (__NR_exit), "r" (arg), "r" (fn), - "r" (flags | CLONE_VM) + "r" (flags | CLONE_VM | CLONE_UNTRACED) /* * The called subroutine might have destroyed any of the * at, result, argument or temporary registers ... diff -Nru a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c --- a/arch/mips/kernel/ptrace.c Mon Nov 4 14:31:03 2002 +++ b/arch/mips/kernel/ptrace.c Mon Nov 4 14:31:03 2002 @@ -304,16 +304,8 @@ res = ptrace_detach(child, data); break; - case PTRACE_SETOPTIONS: - if (data & PTRACE_O_TRACESYSGOOD) - child->ptrace |= PT_TRACESYSGOOD; - else - child->ptrace &= ~PT_TRACESYSGOOD; - res = 0; - break; - default: - res = -EIO; + res = ptrace_request(child, request, addr, data); goto out; } out_tsk: diff -Nru a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c --- a/arch/mips/kernel/time.c Mon Nov 4 14:31:01 2002 +++ b/arch/mips/kernel/time.c Mon Nov 4 14:31:01 2002 @@ -369,7 +369,7 @@ int cpu = smp_processor_id(); irq_enter(cpu, irq); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; /* we keep interrupt disabled all the time */ timer_interrupt(irq, NULL, regs); diff -Nru a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c --- a/arch/mips/mips-boards/atlas/atlas_int.c Mon Nov 4 14:31:02 2002 +++ b/arch/mips/mips-boards/atlas/atlas_int.c Mon Nov 4 14:31:02 2002 @@ -105,7 +105,7 @@ if (!action) continue; seq_printf(p, "%2d: %8d %c %s", - num, kstat.irqs[0][num], + num, kstat_cpu(0).irqs[num], (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); for (action=action->next; action; action = action->next) { @@ -202,7 +202,7 @@ } irq_enter(cpu, irq); - kstat.irqs[0][irq]++; + kstat_cpu(0).irqs[irq]++; action->handler(irq, action->dev_id, regs); irq_exit(cpu, irq); diff -Nru a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c --- a/arch/mips/mips-boards/generic/time.c Mon Nov 4 14:31:02 2002 +++ b/arch/mips/mips-boards/generic/time.c Mon Nov 4 14:31:02 2002 @@ -139,7 +139,7 @@ goto null; do { - kstat.irqs[0][irq]++; + kstat_cpu(0).irqs[irq]++; do_timer(regs); /* Historical comment/code: diff -Nru a/arch/mips/philips/nino/irq.c b/arch/mips/philips/nino/irq.c --- a/arch/mips/philips/nino/irq.c Mon Nov 4 14:31:00 2002 +++ b/arch/mips/philips/nino/irq.c Mon Nov 4 14:31:00 2002 @@ -125,7 +125,7 @@ if (!action) continue; seq_printf(p, "%2d: %8d %c %s", - i, kstat.irqs[0][i], + i, kstat_cpu(0).irqs[i], (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); for (action = action->next; action; action = action->next) { @@ -161,7 +161,7 @@ cpu = smp_processor_id(); irq_enter(cpu, irq); - kstat.irqs[cpu][irq]++; + kstat_cpu(0).irqs[irq]++; if (irq == 20) { printk("20 %08lx %08lx\n %08lx %08lx\n %08lx\n", diff -Nru a/arch/mips/sgi/kernel/indy_int.c b/arch/mips/sgi/kernel/indy_int.c --- a/arch/mips/sgi/kernel/indy_int.c Mon Nov 4 14:31:00 2002 +++ b/arch/mips/sgi/kernel/indy_int.c Mon Nov 4 14:31:00 2002 @@ -418,7 +418,7 @@ int irq = 6; irq_enter(cpu, irq); - kstat.irqs[0][irq]++; + kstat_cpu(0).irqs[irq]++; printk("Got a bus error IRQ, shouldn't happen yet\n"); show_regs(regs); printk("Spinning...\n"); diff -Nru a/arch/mips/sgi/kernel/time.c b/arch/mips/sgi/kernel/time.c --- a/arch/mips/sgi/kernel/time.c Mon Nov 4 14:31:01 2002 +++ b/arch/mips/sgi/kernel/time.c Mon Nov 4 14:31:01 2002 @@ -13,7 +13,7 @@ int irq = 4; irq_enter(cpu, irq); - kstat.irqs[0][irq]++; + kstat_cpu(0).irqs[irq]++; printk("indy_8254timer_irq: Whoops, should not have gotten this IRQ\n"); prom_getchar(); ArcEnterInteractiveMode(); diff -Nru a/arch/mips64/Kconfig b/arch/mips64/Kconfig --- a/arch/mips64/Kconfig Mon Nov 4 14:31:01 2002 +++ b/arch/mips64/Kconfig Mon Nov 4 14:31:01 2002 @@ -5,6 +5,14 @@ mainmenu "Linux Kernel Configuration" +config MMU + bool + default y + +config SWAP + bool + default y + source "init/Kconfig" diff -Nru a/arch/mips64/kernel/ioctl32.c b/arch/mips64/kernel/ioctl32.c --- a/arch/mips64/kernel/ioctl32.c Mon Nov 4 14:31:02 2002 +++ b/arch/mips64/kernel/ioctl32.c Mon Nov 4 14:31:02 2002 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -790,6 +791,20 @@ IOCTL32_DEFAULT(STOP_ARRAY_RO), IOCTL32_DEFAULT(RESTART_ARRAY_RW), #endif /* CONFIG_MD */ + +#if defined(CONFIG_BLK_DEV_DM) || defined(CONFIG_BLK_DEV_DM_MODULE) + IOCTL32_DEFAULT(DM_VERSION), + IOCTL32_DEFAULT(DM_REMOVE_ALL), + IOCTL32_DEFAULT(DM_DEV_CREATE), + IOCTL32_DEFAULT(DM_DEV_REMOVE), + IOCTL32_DEFAULT(DM_DEV_RELOAD), + IOCTL32_DEFAULT(DM_DEV_SUSPEND), + IOCTL32_DEFAULT(DM_DEV_RENAME), + IOCTL32_DEFAULT(DM_DEV_DEPS), + IOCTL32_DEFAULT(DM_DEV_STATUS), + IOCTL32_DEFAULT(DM_TARGET_STATUS), + IOCTL32_DEFAULT(DM_TARGET_WAIT), +#endif /* CONFIG_BLK_DEV_DM */ IOCTL32_DEFAULT(MTIOCTOP), /* mtio.h ioctls */ IOCTL32_HANDLER(MTIOCGET32, mt_ioctl_trans), diff -Nru a/arch/mips64/kernel/process.c b/arch/mips64/kernel/process.c --- a/arch/mips64/kernel/process.c Mon Nov 4 14:31:01 2002 +++ b/arch/mips64/kernel/process.c Mon Nov 4 14:31:01 2002 @@ -167,7 +167,7 @@ "1:\tmove\t%0, $2" :"=r" (retval) :"i" (__NR_clone), "i" (__NR_exit), "r" (arg), "r" (fn), - "r" (flags | CLONE_VM) + "r" (flags | CLONE_VM | CLONE_UNTRACED) /* The called subroutine might have destroyed any of the * at, result, argument or temporary registers ... */ diff -Nru a/arch/mips64/kernel/ptrace.c b/arch/mips64/kernel/ptrace.c --- a/arch/mips64/kernel/ptrace.c Mon Nov 4 14:31:01 2002 +++ b/arch/mips64/kernel/ptrace.c Mon Nov 4 14:31:01 2002 @@ -275,17 +275,8 @@ ret = ptrace_detach(child, data); break; - case PTRACE_SETOPTIONS: { - if (data & PTRACE_O_TRACESYSGOOD) - child->ptrace |= PT_TRACESYSGOOD; - else - child->ptrace &= ~PT_TRACESYSGOOD; - ret = 0; - break; - } - default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); break; } @@ -535,17 +526,8 @@ ret = ptrace_detach(child, data); break; - case PTRACE_SETOPTIONS: { - if (data & PTRACE_O_TRACESYSGOOD) - child->ptrace |= PT_TRACESYSGOOD; - else - child->ptrace &= ~PT_TRACESYSGOOD; - ret = 0; - break; - } - default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); break; } diff -Nru a/arch/mips64/mips-boards/atlas/atlas_int.c b/arch/mips64/mips-boards/atlas/atlas_int.c --- a/arch/mips64/mips-boards/atlas/atlas_int.c Mon Nov 4 14:31:01 2002 +++ b/arch/mips64/mips-boards/atlas/atlas_int.c Mon Nov 4 14:31:01 2002 @@ -101,7 +101,7 @@ if (!action) continue; seq_printf(p, "%2d: %8d %c %s", - num, kstat.irqs[0][num], + num, kstat_cpu(0).irqs[num], (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); for (action=action->next; action; action = action->next) { @@ -198,7 +198,7 @@ } irq_enter(cpu, irq); - kstat.irqs[0][irq]++; + kstat_cpu(0).irqs[irq]++; action->handler(irq, action->dev_id, regs); irq_exit(cpu, irq); diff -Nru a/arch/mips64/mips-boards/generic/time.c b/arch/mips64/mips-boards/generic/time.c --- a/arch/mips64/mips-boards/generic/time.c Mon Nov 4 14:31:01 2002 +++ b/arch/mips64/mips-boards/generic/time.c Mon Nov 4 14:31:01 2002 @@ -138,7 +138,7 @@ goto null; do { - kstat.irqs[0][irq]++; + kstat_cpu(0).irqs[irq]++; do_timer(regs); /* Historical comment/code: diff -Nru a/arch/mips64/mips-boards/malta/malta_int.c b/arch/mips64/mips-boards/malta/malta_int.c --- a/arch/mips64/mips-boards/malta/malta_int.c Mon Nov 4 14:31:02 2002 +++ b/arch/mips64/mips-boards/malta/malta_int.c Mon Nov 4 14:31:02 2002 @@ -131,7 +131,7 @@ if (!action) continue; seq_printf(p, "%2d: %8d %c %s", - num, kstat.irqs[0][num], + num, kstat_cpu(0).irqs[num], (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); for (action=action->next; action; action = action->next) { @@ -146,7 +146,7 @@ if (!action) continue; seq_printf(p, "%2d: %8d %c %s", - num, kstat.irqs[0][num], + num, kstat_cpu(0).irqs[num], (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); for (action=action->next; action; action = action->next) { @@ -322,7 +322,7 @@ return; irq_enter(cpu, irq); - kstat.irqs[0][irq + 8]++; + kstat_cpu(0).irqs[irq + 8]++; do { action->handler(irq, action->dev_id, regs); action = action->next; diff -Nru a/arch/mips64/sgi-ip22/ip22-int.c b/arch/mips64/sgi-ip22/ip22-int.c --- a/arch/mips64/sgi-ip22/ip22-int.c Mon Nov 4 14:31:00 2002 +++ b/arch/mips64/sgi-ip22/ip22-int.c Mon Nov 4 14:31:00 2002 @@ -243,7 +243,7 @@ if (!action) continue; seq_printf(p, "%2d: %8d %c %s", - num, kstat.irqs[0][num], + num, kstat_cpu(0).irqs[num], (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); for (action=action->next; action; action = action->next) { @@ -258,7 +258,7 @@ if (!action) continue; seq_printf(p, "%2d: %8d %c %s", - num, kstat.irqs[0][num], + num, kstat_cpu(0).irqs[num], (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); for (action=action->next; action; action = action->next) { @@ -285,7 +285,7 @@ cpu = smp_processor_id(); irq_enter(cpu, irq); - kstat.irqs[0][irq]++; + kstat_cpu(0).irqs[irq]++; panic(KERN_DEBUG "Got irq %d, press a key.", irq); @@ -444,7 +444,7 @@ } irq_enter(cpu, irq); - kstat.irqs[0][irq + 16]++; + kstat_cpu(0).irqs[irq + 16]++; action->handler(irq, action->dev_id, regs); irq_exit(cpu, irq); } @@ -468,7 +468,7 @@ action = local_irq_action[irq]; } irq_enter(cpu, irq); - kstat.irqs[0][irq + 24]++; + kstat_cpu(0).irqs[irq + 24]++; action->handler(irq, action->dev_id, regs); irq_exit(cpu, irq); } @@ -479,7 +479,7 @@ int irq = 6; irq_enter(cpu, irq); - kstat.irqs[0][irq]++; + kstat_cpu(0).irqs[irq]++; printk("Got a bus error IRQ, shouldn't happen yet\n"); show_regs(regs); printk("Spinning...\n"); diff -Nru a/arch/mips64/sgi-ip22/ip22-timer.c b/arch/mips64/sgi-ip22/ip22-timer.c --- a/arch/mips64/sgi-ip22/ip22-timer.c Mon Nov 4 14:31:02 2002 +++ b/arch/mips64/sgi-ip22/ip22-timer.c Mon Nov 4 14:31:02 2002 @@ -98,7 +98,7 @@ else r4k_cur += r4k_offset; ack_r4ktimer(r4k_cur); - kstat.irqs[0][irq]++; + kstat_cpu(0).irqs[irq]++; do_timer(regs); /* We update the Dallas time of day approx. every 11 minutes, @@ -236,7 +236,7 @@ int irq = 4; irq_enter(cpu, irq); - kstat.irqs[0][irq]++; + kstat_cpu(0).irqs[irq]++; panic("indy_8254timer_irq: Whoops, should not have gotten this IRQ\n"); irq_exit(cpu, irq); } diff -Nru a/arch/mips64/sgi-ip27/ip27-irq.c b/arch/mips64/sgi-ip27/ip27-irq.c --- a/arch/mips64/sgi-ip27/ip27-irq.c Mon Nov 4 14:31:02 2002 +++ b/arch/mips64/sgi-ip27/ip27-irq.c Mon Nov 4 14:31:02 2002 @@ -146,7 +146,7 @@ action = irq_action[i]; if (!action) continue; - seq_printf(p, "%2d: %8d %c %s", i, kstat.irqs[0][i], + seq_printf(p, "%2d: %8d %c %s", i, kstat_cpu(0).irqs[i], (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); for (action=action->next; action; action = action->next) { @@ -170,7 +170,7 @@ int do_random; irq_enter(thiscpu, irq); - kstat.irqs[thiscpu][irq]++; + kstat_cpu(thiscpu).irqs[irq]++; action = *(irq + irq_action); if (action) { diff -Nru a/arch/mips64/sgi-ip27/ip27-timer.c b/arch/mips64/sgi-ip27/ip27-timer.c --- a/arch/mips64/sgi-ip27/ip27-timer.c Mon Nov 4 14:31:01 2002 +++ b/arch/mips64/sgi-ip27/ip27-timer.c Mon Nov 4 14:31:01 2002 @@ -103,7 +103,7 @@ if (LOCAL_HUB_L(PI_RT_COUNT) >= ct_cur[cpu]) goto again; - kstat.irqs[cpu][irq]++; /* kstat only for bootcpu? */ + kstat_cpu(cpu).irqs[irq]++; /* kstat only for bootcpu? */ if (cpu == 0) do_timer(regs); diff -Nru a/arch/parisc/Kconfig b/arch/parisc/Kconfig --- a/arch/parisc/Kconfig Mon Nov 4 14:31:02 2002 +++ b/arch/parisc/Kconfig Mon Nov 4 14:31:02 2002 @@ -3,15 +3,24 @@ # see the Configure script. # -mainmenu "Linux Kernel Configuration" +mainmenu "Linux/PA-RISC Kernel Configuration" config PARISC bool default y help - The PA-RISC microprocessor is a RISC chip designed by - Hewlett-Packard and used in their line of workstations. The PA-RISC - Linux project has a home page at . + The PA-RISC microprocessor is designed by Hewlett-Packard and used + in many of their workstations & servers (HP9000 700 and 800 series, + and later HP3000 series). The PA-RISC Linux project home page is + at . + +config MMU + bool + default y + +config SWAP + bool + default y config UID16 bool @@ -25,16 +34,72 @@ config GENERIC_ISA_DMA bool - default y + +# unless you want to implement ACPI on PA-RISC ... ;-) +config PM + bool source "init/Kconfig" -menu "General options" +menu "Processor type and features" -# bool 'Symmetric multi-processing support' CONFIG_SMP -config SMP +choice + prompt "Processor type" + default PA7000 + +config PA7000 + bool "PA7000/PA7100" + ---help--- + This is the processor type of your CPU. This information is used for + optimizing purposes. In order to compile a kernel that can run on + all PA CPUs (albeit not optimally fast), you can specify "PA7000" + here. + + Specifying "PA8000" here will allow you to select a 64-bit kernel + which is required on some machines. + +config PA7100LC + bool "PA7100LC/PA7300LC" + help + Select this option for a 7100LC or 7300LC processor, as used + in the 712, 715/Mirage, A180, B132, C160L and some other machines. + +config PA7200 + bool "PA7200" + help + Select this option for the PCX-T' processor, as used in C110, D100 + and similar machines. + +config PA8X00 + bool "PA8000 and up" + help + Select this option for PCX-U to PCX-W2 processors. + +endchoice + +# Define implied options from the CPU selection here + +config PA20 bool + depends on PA8X00 + default y + +config PA11 + bool + depends on PA7000 || PA7100LC || PA7200 + default y + +config PARISC64 + bool "64-bit kernel" + depends on PA8X00 + +config PDC_NARROW + bool "32-bit firmware" + depends on PARISC64 + +config SMP + bool "Symmetric multi-processing support" ---help--- This enables support for systems with more than one CPU. If you have a system with only one CPU, like most personal computers, say N. If @@ -46,97 +111,36 @@ singleprocessor machines. On a singleprocessor machine, the kernel will run faster if you say N here. - Note that if you say Y here and choose architecture "586" or - "Pentium" under "Processor family", the kernel will not work on 486 - architectures. Similarly, multiprocessor kernels for the "PPro" - architecture may not work on all Pentium based boards. - - People using multiprocessor machines who say Y here should also say - Y to "Enhanced Real Time Clock Support", below. The "Advanced Power - Management" code will be disabled if you say Y here. - See also the , - , , - and the SMP-HOWTO available at + , + and the SMP-HOWTO available at . If you don't know what to do here, say N. +config PREEMPT + bool +# bool "Preemptible Kernel" + default n + config NR_CPUS int "Maximum number of CPUs (2-32)" depends on SMP default "32" -config KWDB - bool "Kernel Debugger support" - help - Include in-kernel hooks for kdb, the source level debugger for the - PA-RISC port. +endmenu -# define_bool CONFIG_KWDB n -# bool 'GSC/Gecko bus support' CONFIG_GSC y -config GSC - bool - default y -config IOMMU_CCIO - bool "U2/Uturn I/O MMU" - help - Say Y here to enable DMA management routines for the first - generation of PA-RISC cache-coherent machines. Programs the - U2/Uturn chip in "Virtual Mode" and use the I/O MMU. +source "drivers/parisc/Kconfig" -config GSC_LASI - bool "LASI I/O support" - help - Say Y here to directly support the LASI controller chip found on - PA-RISC workstations. Linux-oriented documentation for this chip - can be found at . -config PCI - bool "PCI support" - help - Find out whether you have a PCI motherboard. PCI is the name of a - bus system, i.e. the way the CPU talks to the other stuff inside - your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or - VESA. If you have PCI, say Y, otherwise N. - - The PCI-HOWTO, available from - , contains valuable - information about which PCI hardware does work under Linux and which - doesn't. - -config GSC_DINO - bool "GSCtoPCI/DINO PCI support" - depends on PCI - -config PCI_LBA - bool "LBA/Elroy PCI support" - depends on PCI - help - Say Y here to give the PA-RISC kernel access to PCI configuration - and IO-port space on PA-RISC workstations equipped with a Lower Bus - Adapter (LBA). This includes A, B, C, J, L, and N-class machines - with 4-digit model numbers, also the A300. +menu "Executable file formats" -config IOSAPIC +config KCORE_ELF bool - depends on PCI_LBA + depends on PROC_FS default y -config IOMMU_SBA - bool - depends on PCI_LBA - default y - -# -# if [ "$CONFIG_PCI_EPIC" = "y" ]; then... -# -endmenu - - -menu "General setup" - config BINFMT_SOM tristate "Kernel support for SOM binaries" help @@ -197,116 +201,25 @@ you have use for it; the module is called binfmt_misc.o. If you don't know what to answer at this point, say Y. -config BINFMT_JAVA - tristate "Kernel support for JAVA binaries (obsolete)" - depends on EXPERIMENTAL - help - If you say Y here, the kernel will load and execute Java J-code - binaries directly. Note: this option is obsolete and scheduled for - removal, use CONFIG_BINFMT_MISC instead. - endmenu -##source drivers/parport/Config.in +# source "drivers/mtd/Kconfig" -menu "Parallel port support" +source "drivers/parport/Kconfig" -config PARPORT - tristate "Parallel port support" - ---help--- - If you want to use devices connected to your machine's parallel port - (the connector at the computer with 25 holes), e.g. printer, ZIP - drive, PLIP link (Parallel Line Internet Protocol is mainly used to - create a mini network by connecting the parallel ports of two local - machines) etc., then you need to say Y here; please read - and - . - - For extensive information about drivers for many devices attaching - to the parallel port see on - the WWW. - - It is possible to share a single parallel port among several devices - and it is safe to compile all the corresponding drivers into the - kernel. If you want to compile parallel port support as a module - ( = code which can be inserted in and removed from the running - kernel whenever you want), say M here and read - . The module will be called - parport.o. If you have more than one parallel port and want to - specify which port and IRQ to be used by this driver at module load - time, take a look at . - - If unsure, say Y. - -config PARPORT_PC - tristate "PC-style hardware" - depends on PCI && PARPORT - ---help--- - You should say Y here if you have a PC-style parallel port. All IBM - PC compatible computers and some Alphas have PC-style parallel - ports. - - This code is also available as a module. If you want to compile it - as a module ( = code which can be inserted in and removed from the - running kernel whenever you want), say M here and read - . The module will be called - parport_pc.o. - - If unsure, say Y. - -config PARPORT_PC_FIFO - bool "Use FIFO/DMA if available" - depends on PARPORT_PC - help - Many parallel port chipsets provide hardware that can speed up - printing. Say Y here if you want to take advantage of that. +# source "drivers/pnp/Kconfig" - As well as actually having a FIFO, or DMA capability, the kernel - will need to know which IRQ the parallel port has. By default, - parallel port interrupts will not be used, and so neither will the - FIFO. See to find out how to - specify which IRQ/DMA to use. - -config PARPORT_PC_SUPERIO - bool "SuperIO chipset support (EXPERIMENTAL)" - depends on PARPORT_PC && EXPERIMENTAL - help - Saying Y here enables some probes for Super-IO chipsets in order to - find out things like base addresses, IRQ lines and DMA channels. It - is safe to say N. - -config PARPORT_GSC - tristate "LASI/ASP builtin parallel-port" - depends on GSC_LASI && PARPORT - help - Say Y here to build in low-level parallel-support for PC-style - hardware integrated in the LASI-Controller (on the GSC Bus) for - HP-PARISC workstations. - -# If exactly one hardware type is selected then parport will optimise away -# support for loading any others. Defeat this if the user is keen. -config PARPORT_OTHER - bool "Support foreign hardware" - depends on PARPORT - help - Say Y here if you want to be able to load driver modules to support - other non-standard types of parallel ports. This causes a - performance loss, so most people say N. - -config PARPORT_1284 - bool "IEEE 1284 transfer modes" - depends on PARPORT - help - If you have a printer that supports status readback or device ID, or - want to use a device that uses enhanced parallel port transfer modes - such as EPP and ECP, say Y here to enable advanced IEEE 1284 - transfer modes. Also say Y if you want device ID information to - appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N. +source "drivers/block/Kconfig" -endmenu +menu "ATA/IDE/MFM/RLL support" + depends on SUPERIO -source "drivers/block/Kconfig" +config IDE + tristate "ATA/IDE/MFM/RLL support" +source "drivers/ide/Kconfig" + +endmenu menu "SCSI support" @@ -330,304 +243,20 @@ module if your root file system (the one containing the directory /) is located on a SCSI device. -comment "SCSI support type (disk, tape, CDrom)" - depends on SCSI - -config BLK_DEV_SD - tristate "SCSI disk support" - depends on SCSI - ---help--- - If you want to use a SCSI hard disk or the SCSI or parallel port - version of the IOMEGA ZIP drive under Linux, say Y and read the - SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from - . This is NOT for SCSI - CD-ROMs. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called sd_mod.o. If you want to compile it as a - module, say M here and read and - . Do not compile this driver as a - module if your root file system (the one containing the directory /) - is located on a SCSI disk. In this case, do not compile the driver - for your SCSI host adapter (below) as a module either. +source drivers/scsi/Kconfig -config SD_EXTRA_DEVS - int "Maximum number of SCSI disks that can be loaded as modules" - depends on BLK_DEV_SD - default "40" - ---help--- - This controls the amount of additional space allocated in tables for - drivers that are loaded as modules after the kernel is booted. In - the event that the SCSI core itself was loaded as a module, this - value is the number of additional disks that can be loaded after the - first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - - If you don't understand what's going on, go with the default. - -config CHR_DEV_ST - tristate "SCSI tape support" - depends on SCSI - ---help--- - If you want to use a SCSI tape drive under Linux, say Y and read the - SCSI-HOWTO, available from - , and - in the kernel source. This is NOT for - SCSI CD-ROMs. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called st.o. If you want to compile it as a - module, say M here and read and - . - -config BLK_DEV_SR - tristate "SCSI CDROM support" - depends on SCSI - ---help--- - If you want to use a SCSI CD-ROM under Linux, say Y and read the - SCSI-HOWTO and the CD-ROM-HOWTO at - . Also make sure to say Y - or M to "ISO 9660 CD-ROM file system support" later. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called sr_mod.o. If you want to compile it as a - module, say M here and read and - . - -config BLK_DEV_SR_VENDOR - bool "Enable vendor-specific extensions (for SCSI CDROM)" - depends on BLK_DEV_SR - help - This enables the usage of vendor specific SCSI commands. This is - required to support multisession CDs with old NEC/TOSHIBA cdrom - drives (and HP Writers). If you have such a drive and get the first - session only, try saying Y here; everybody else says N. - -config SR_EXTRA_DEVS - int "Maximum number of CDROM devices that can be loaded as modules" - depends on BLK_DEV_SR - default "2" - ---help--- - This controls the amount of additional space allocated in tables for - drivers that are loaded as modules after the kernel is booted. In - the event that the SCSI core itself was loaded as a module, this - value is the number of additional CD-ROMs that can be loaded after - the first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - - If you don't understand what's going on, go with the default. - -config CHR_DEV_SG - tristate "SCSI generic support" - depends on SCSI - ---help--- - If you want to use SCSI scanners, synthesizers or CD-writers or just - about anything having "SCSI" in its name other than hard disks, - CD-ROMs or tapes, say Y here. These won't be supported by the kernel - directly, so you need some additional software which knows how to - talk to these devices using the SCSI protocol: - - For scanners, look at SANE (). For CD - writer software look at Cdrtools - () - and for burning a "disk at once": CDRDAO - (). Cdparanoia is a high - quality digital reader of audio CDs (). - For other devices, it's possible that you'll have to write the - driver software yourself. Please read the file - for more information. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read and - . The module will be called sg.o. If unsure, - say N. - -comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs" - depends on SCSI - -config SCSI_MULTI_LUN - bool "Probe all LUNs on each SCSI device" - depends on SCSI - help - If you have a SCSI device that supports more than one LUN (Logical - Unit Number), e.g. a CD jukebox, and only one LUN is detected, you - can say Y here to force the SCSI driver to probe for multiple LUNs. - A SCSI device with multiple LUNs acts logically like multiple SCSI - devices. The vast majority of SCSI devices have only one LUN, and - so most people can say N here and should in fact do so, because it - is safer. - -config SCSI_CONSTANTS - bool "Verbose SCSI error reporting (kernel size +=12K)" - depends on SCSI - help - The error messages regarding your SCSI hardware will be easier to - understand if you say Y here; it will enlarge your kernel by about - 12 KB. If in doubt, say Y. - - -menu "SCSI low-level drivers" - depends on SCSI!=n - -config SCSI_LASI - tristate "Lasi SCSI support" - depends on GSC_LASI && SCSI +endmenu -config SCSI_ZALON - tristate "Zalon SCSI support" - depends on GSC_LASI && SCSI - help - The Zalon is an interface chip that sits between the PA-RISC - processor and the NCR 53c720 SCSI controller on K-series PA-RISC - boards (these are used, among other places, on some HP 780 - workstations). Say Y here to make sure it gets initialized - correctly before the Linux kernel tries to talk to the controller. - -config SCSI_SYM53C8XX - tristate "SYM53C8XX SCSI support" - depends on PCI && SCSI - ---help--- - This driver supports all the features of recent 53C8XX chips (used - in PCI SCSI controllers), notably the hardware phase mismatch - feature of the SYM53C896. - - Older versions of the 53C8XX chips are not supported by this - driver. If your system uses either a 810 rev. < 16, a 815, or a 825 - rev. < 16 PCI SCSI processor, you must use the generic NCR53C8XX - driver ("NCR53C8XX SCSI support" above) or configure both the - NCR53C8XX and this SYM53C8XX drivers either as module or linked to - the kernel image. - - When both drivers are linked into the kernel, the SYM53C8XX driver - is called first at initialization and you can use the 'excl=ioaddr' - driver boot option to exclude attachment of adapters by the - SYM53C8XX driver. For example, entering - 'sym53c8xx=excl:0xb400,excl=0xc000' at the lilo prompt prevents - adapters at io address 0xb400 and 0xc000 from being attached by the - SYM53C8XX driver, thus allowing the NCR53C8XX driver to attach them. - The 'excl' option is also supported by the NCR53C8XX driver. - - Please read for more - information. - -config SCSI_NCR53C8XX_DEFAULT_TAGS - int "default tagged command queue depth" - depends on SCSI_ZALON || SCSI_SYM53C8XX - default "8" - ---help--- - "Tagged command queuing" is a feature of SCSI-2 which improves - performance: the host adapter can send several SCSI commands to a - device's queue even if previous commands haven't finished yet. - Because the device is intelligent, it can optimize its operations - (like head positioning) based on its own request queue. Some SCSI - devices don't implement this properly; if you want to disable this - feature, enter 0 or 1 here (it doesn't matter which). - - The default value is 8 and should be supported by most hard disks. - This value can be overridden from the boot command line using the - 'tags' option as follows (example): - 'ncr53c8xx=tags:4/t2t3q16/t0u2q10' will set default queue depth to - 4, set queue depth to 16 for target 2 and target 3 on controller 0 - and set queue depth to 10 for target 0 / lun 2 on controller 1. - - The normal answer therefore is to go with the default 8 and to use - a boot command line option for devices that need to use a different - command queue depth. - - There is no safe option other than using good SCSI devices. - -config SCSI_NCR53C8XX_MAX_TAGS - int "maximum number of queued commands" - depends on SCSI_ZALON || SCSI_SYM53C8XX - default "32" - ---help--- - This option allows you to specify the maximum number of commands - that can be queued to any device, when tagged command queuing is - possible. The default value is 32. Minimum is 2, maximum is 64. - Modern hard disks are able to support 64 tags and even more, but - do not seem to be faster when more than 32 tags are being used. - - So, the normal answer here is to go with the default value 32 unless - you are using very large hard disks with large cache (>= 1 MB) that - are able to take advantage of more than 32 tagged commands. - - There is no safe option and the default answer is recommended. - -config SCSI_NCR53C8XX_SYNC - int "synchronous transfers frequency in MHz" - depends on SCSI_ZALON || SCSI_SYM53C8XX - default "20" - ---help--- - The SCSI Parallel Interface-2 Standard defines 5 classes of transfer - rates: FAST-5, FAST-10, FAST-20, FAST-40 and FAST-80. The numbers - are respectively the maximum data transfer rates in mega-transfers - per second for each class. For example, a FAST-20 Wide 16 device is - able to transfer data at 20 million 16 bit packets per second for a - total rate of 40 MB/s. - - You may specify 0 if you want to only use asynchronous data - transfers. This is the safest and slowest option. Otherwise, specify - a value between 5 and 80, depending on the capability of your SCSI - controller. The higher the number, the faster the data transfer. - Note that 80 should normally be ok since the driver decreases the - value automatically according to the controller's capabilities. - - Your answer to this question is ignored for controllers with NVRAM, - since the driver will get this information from the user set-up. It - also can be overridden using a boot setup option, as follows - (example): 'ncr53c8xx=sync:12' will allow the driver to negotiate - for FAST-20 synchronous data transfer (20 mega-transfers per - second). - - The normal answer therefore is not to go with the default but to - select the maximum value 80 allowing the driver to use the maximum - value supported by each controller. If this causes problems with - your SCSI devices, you should come back and decrease the value. - - There is no safe option other than using good cabling, right - terminations and SCSI conformant devices. - -config SCSI_NCR53C8XX_PROFILE - bool "enable profiling" - depends on SCSI_ZALON || SCSI_SYM53C8XX - help - This option allows you to enable profiling information gathering. - These statistics are not very accurate due to the low frequency - of the kernel clock (100 Hz on i386) and have performance impact - on systems that use very fast devices. - - The normal answer therefore is N. - -config SCSI_NCR53C8XX_IOMAPPED - bool "use normal IO" - depends on SCSI_ZALON || SCSI_SYM53C8XX - help - If you say Y here, the driver will use normal IO, as opposed to - memory mapped IO. Memory mapped IO has less latency than normal IO - and works for most Intel-based hardware. Under Linux/Alpha only - normal IO is currently supported by the driver and so, this option - has no effect on those systems. +source "drivers/md/Kconfig" - The normal answer therefore is N; try Y only if you encounter SCSI - related problems. +#source drivers/message/fusion/Kconfig -endmenu +#source drivers/ieee1394/Kconfig -endmenu +#source drivers/message/i2o/Kconfig source "net/Kconfig" - menu "Network device support" depends on NET @@ -662,23 +291,52 @@ Guide", to be found in . If unsure, say Y. -config LASI_82596 - tristate "Lasi ethernet" - depends on NETDEVICES && GSC_LASI - help - Say Y here to support the on-board Intel 82596 ethernet controller - built into Hewlett-Packard PA-RISC machines. - source "drivers/net/Kconfig" +source "drivers/atm/Kconfig" + endmenu +#source "net/ax25/Kconfig" + +source "net/irda/Kconfig" + +#source "drivers/isdn/Kconfig" + +#source "drivers/telephony/Kconfig" + +# input before char - char/joystick depends on it. As does USB. +source "drivers/input/Kconfig" + source "drivers/char/Kconfig" +#source "drivers/misc/Kconfig" + +source "drivers/media/Kconfig" + source "fs/Kconfig" -menu "Sound Drivers" +menu "Console drivers" + depends on VT + +config STI_CONSOLE + bool "STI console" + help + The STI console is the builtin display/keyboard on HP-PARISC + machines. Say Y here to build support for it into your kernel. + The alternative is to use your primary serial port as a console. + +config DUMMY_CONSOLE + bool + depends on STI_CONSOLE || SERIAL_8250_CONSOLE + default y + +source "drivers/video/Kconfig" + +endmenu + +menu "Sound" config SOUND tristate "Sound card support" @@ -714,34 +372,29 @@ endmenu +source "drivers/usb/Kconfig" -menu "Console drivers" - depends on VT +source "net/bluetooth/Kconfig" -source "drivers/video/Kconfig" +menu "Kernel hacking" -# bool 'IODC console' CONFIG_IODC_CONSOLE -config STI_CONSOLE - bool "STI console" +config DEBUG_KERNEL + bool "Kernel debugging" help - The STI console is the builtin display/keyboard on HP-PARISC - machines. Say Y here to build support for it into your kernel. - The alternative is to use your primary serial port as a console. + Say Y here if you are developing drivers or trying to debug and + identify kernel problems. -config DUMMY_CONSOLE - bool - depends on STI_CONSOLE || !IODC_CONSOLE && GSC_PS2 - default y - -endmenu +config DEBUG_SLAB + bool "Debug memory allocations" + depends on DEBUG_KERNEL + help + Say Y here to have the kernel do limited verification on memory + allocation as well as poisoning memory on free to catch use of freed + memory. -# endmenu - -menu "Kernel hacking" - -#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC config MAGIC_SYSRQ bool "Magic SysRq key" + depends on DEBUG_KERNEL help If you say Y here, you will have some control over the system even if the system crashes for example during kernel debugging (e.g., you @@ -752,6 +405,14 @@ send a BREAK and then within 5 seconds a command keypress. The keys are documented in . Don't say Y unless you really know what this hack does. + +config KALLSYMS + bool "Load all symbols for debugging/kksymoops" + depends on DEBUG_KERNEL + help + Say Y here to let the kernel print out symbolic crash information and + symbolic stack backtraces. This increases the size of the kernel + somewhat, as all symbols have to be loaded into the kernel image. endmenu diff -Nru a/arch/parisc/Makefile b/arch/parisc/Makefile --- a/arch/parisc/Makefile Mon Nov 4 14:31:02 2002 +++ b/arch/parisc/Makefile Mon Nov 4 14:31:02 2002 @@ -80,7 +80,6 @@ arch/parisc/kernel/init_task.o libs-y += arch/parisc/lib/ \ `$(CC) -print-libgcc-file-name` -drivers-$(CONFIG_MATH_EMULATION) += arch/parisc/math-emu/ palo: vmlinux @if [ $$(palo -f /dev/null >/dev/null 2>&1 ; echo $$?) != 2 ]; then \ diff -Nru a/arch/parisc/hpux/Makefile b/arch/parisc/hpux/Makefile --- a/arch/parisc/hpux/Makefile Mon Nov 4 14:31:02 2002 +++ b/arch/parisc/hpux/Makefile Mon Nov 4 14:31:02 2002 @@ -1,9 +1,5 @@ # -# Makefile for the linux kernel. +# Makefile for HPUX emulation # obj-y := entry_hpux.o gate.o wrappers.o fs.o ioctl.o sys_hpux.o - -EXTRA_AFLAGS := -traditional - -include $(TOPDIR)/Rules.make diff -Nru a/arch/parisc/hpux/entry_hpux.S b/arch/parisc/hpux/entry_hpux.S --- a/arch/parisc/hpux/entry_hpux.S Mon Nov 4 14:31:01 2002 +++ b/arch/parisc/hpux/entry_hpux.S Mon Nov 4 14:31:01 2002 @@ -1,6 +1,6 @@ -/* ----------------------------------------------------------------------------- +/* * - * Native PARISC/Linux Project (http://www.puffingroup.com/parisc) + * Linux/PARISC Project (http://www.parisc-linux.org/) * * modified by Matthew Wilcox 1999-07-26 */ @@ -10,13 +10,13 @@ #include #include - .text #define ENTRY_NAME(_name_) .word _name_ .align 4 .export hpux_call_table + .import hpux_unimplemented_wrapper hpux_call_table: ENTRY_NAME(sys_ni_syscall) /* 0 */ ENTRY_NAME(sys_exit) @@ -36,7 +36,7 @@ ENTRY_NAME(sys_chmod) /* 15 */ ENTRY_NAME(sys_chown) ENTRY_NAME(hpux_brk) - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(sys_lseek) ENTRY_NAME(sys_getpid) /* 20 */ ENTRY_NAME(hpux_mount) @@ -46,34 +46,34 @@ ENTRY_NAME(sys_stime) /* 25 */ ENTRY_NAME(hpux_ptrace) ENTRY_NAME(sys_alarm) - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(sys_pause) ENTRY_NAME(sys_utime) /* 30 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(sys_access) ENTRY_NAME(hpux_nice) - ENTRY_NAME(sys_ni_syscall) /* 35 */ + ENTRY_NAME(hpux_unimplemented_wrapper) /* 35 */ ENTRY_NAME(sys_sync) - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(sys_newstat) - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_setpgrp3) ENTRY_NAME(sys_newlstat) /* 40 */ ENTRY_NAME(sys_dup) ENTRY_NAME(hpux_pipe_wrapper) ENTRY_NAME(sys_times) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 45 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 45 */ ENTRY_NAME(sys_setgid) ENTRY_NAME(sys_getgid) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 50 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 50 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(hpux_ioctl) - ENTRY_NAME(sys_ni_syscall) /* 55 */ + ENTRY_NAME(hpux_unimplemented_wrapper) /* 55 */ ENTRY_NAME(sys_symlink) ENTRY_NAME(hpux_utssys) ENTRY_NAME(sys_readlink) @@ -81,218 +81,218 @@ ENTRY_NAME(sys_umask) /* 60 */ ENTRY_NAME(sys_chroot) ENTRY_NAME(sys_fcntl) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 65 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 65 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(hpux_sbrk) - ENTRY_NAME(sys_ni_syscall) /* 70 */ + ENTRY_NAME(hpux_unimplemented_wrapper) /* 70 */ ENTRY_NAME(sys_mmap) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 75 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 80 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 75 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 80 */ ENTRY_NAME(sys_getpgid) ENTRY_NAME(sys_setpgid) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 85 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(sys_setitimer) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 85 */ + ENTRY_NAME(sys_getitimer) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(sys_dup2) /* 90 */ - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(sys_newfstat) ENTRY_NAME(sys_select) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 95 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 100 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 105 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 110 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 115 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 95 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 100 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 105 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 110 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 115 */ ENTRY_NAME(sys_gettimeofday) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 120 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 120 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(sys_fchown) ENTRY_NAME(sys_fchmod) - ENTRY_NAME(sys_ni_syscall) /* 125 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 125 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(sys_rename) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 130 */ - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 130 */ + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(hpux_sysconf) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 135 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 135 */ ENTRY_NAME(sys_mkdir) ENTRY_NAME(sys_rmdir) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 140 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 145 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 150 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 155 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 160 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 165 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 170 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 175 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 180 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 185 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 190 */ - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 140 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(sys_getrlimit) + ENTRY_NAME(sys_setrlimit) /* 145 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 150 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_lockf) /* 155 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 160 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 165 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 170 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 175 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 180 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(sys_sigprocmask) /* 185 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 190 */ + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(hpux_getdomainname) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 195 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 195 */ + ENTRY_NAME(hpux_statfs) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(sys_waitpid) /* 200 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 205 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 210 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 215 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 220 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 225 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 230 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 235 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 240 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 245 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 250 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 255 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 260 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 265 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 270 */ - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 205 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 210 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 215 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 220 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 225 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 230 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 235 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 240 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 245 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 250 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 255 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 260 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 265 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 270 */ + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(sys_fchdir) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(sys_accept) /* 275 */ ENTRY_NAME(sys_bind) ENTRY_NAME(sys_connect) @@ -309,227 +309,227 @@ ENTRY_NAME(sys_setsockopt) ENTRY_NAME(sys_shutdown) ENTRY_NAME(sys_socket) /* 290 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 295 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 300 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 305 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 310 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 315 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 320 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 325 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 330 */ - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 295 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 300 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 305 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 310 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 315 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 320 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 325 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 330 */ + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(sys_lchown) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 335 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 340 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 345 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 350 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_sysfs) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 335 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 340 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 345 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 350 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(sys_nanosleep) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 355 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 355 */ ENTRY_NAME(hpux_getdents) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 360 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 360 */ ENTRY_NAME(hpux_fstat64) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 365 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 365 */ ENTRY_NAME(hpux_lstat64) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) ENTRY_NAME(hpux_stat64) - ENTRY_NAME(sys_ni_syscall) /* 370 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 375 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 380 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 385 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 390 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 395 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 400 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 405 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 410 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 415 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 420 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 425 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 430 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 435 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 440 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 445 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 450 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 455 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 460 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 465 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 470 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 475 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 480 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 485 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 490 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 495 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 500 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 505 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) /* 510 */ - ENTRY_NAME(sys_ni_syscall) - ENTRY_NAME(sys_ni_syscall) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 370 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 375 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 380 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_setpgrp) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 385 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 390 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 395 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 400 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 405 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 410 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 415 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 420 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 425 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 430 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 435 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 440 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 445 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 450 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 455 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 460 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 465 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 470 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 475 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 480 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 485 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 490 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 495 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 500 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 505 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) /* 510 */ + ENTRY_NAME(hpux_unimplemented_wrapper) + ENTRY_NAME(hpux_unimplemented_wrapper) .end diff -Nru a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c --- a/arch/parisc/hpux/fs.c Mon Nov 4 14:31:01 2002 +++ b/arch/parisc/hpux/fs.c Mon Nov 4 14:31:01 2002 @@ -34,8 +34,7 @@ } struct hpux_dirent { - long d_off_pad; /* we only have a 32-bit off_t */ - long d_off; + loff_t d_off; ino_t d_ino; short d_reclen; short d_namlen; @@ -52,7 +51,8 @@ #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) #define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1)) -static int filldir(void * __buf, const char * name, int namlen, loff_t offset, ino_t ino) +static int filldir(void * __buf, const char * name, int namlen, loff_t offset, + ino_t ino, unsigned d_type) { struct hpux_dirent * dirent; struct getdents_callback * buf = (struct getdents_callback *) __buf; @@ -96,7 +96,7 @@ buf.count = count; buf.error = 0; - error = vfs_readdir(file, &buf, filldir); + error = vfs_readdir(file, filldir, &buf); if (error < 0) goto out_putf; error = buf.error; @@ -139,7 +139,7 @@ return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; } -long hpux_stat64(const char *path, struct hpux_stat64 *buf) +long hpux_stat64(char *filename, struct hpux_stat64 *statbuf) { struct kstat stat; int error = vfs_stat(filename, &stat); diff -Nru a/arch/parisc/hpux/gate.S b/arch/parisc/hpux/gate.S --- a/arch/parisc/hpux/gate.S Mon Nov 4 14:31:02 2002 +++ b/arch/parisc/hpux/gate.S Mon Nov 4 14:31:02 2002 @@ -1,6 +1,6 @@ -/* ------------------------------------------------------------------------------ +/* * - * Linux/PARISC Project (http://www.thepuffingroup.com/parisc) + * Linux/PARISC Project (http://www.parisc-linux.org/) * * System call entry code Copyright (c) Matthew Wilcox 1999 * Licensed under the GNU GPL. @@ -8,14 +8,23 @@ * sorry about the wall, puffin.. */ -#define __ASSEMBLY__ #include -#include +#include #include #include +#ifdef __LP64__ + .level 2.0w +#else + .level 1.1 +#endif .text +#ifdef __LP64__ +#define FRAME_SIZE 128 +#else +#define FRAME_SIZE 64 +#endif .import hpux_call_table .import hpux_syscall_exit,code .export hpux_gateway_page @@ -23,35 +32,70 @@ .align 4096 hpux_gateway_page: nop - mfsp %sr7,%r1 ;! we must set sr3 to the space - mtsp %r1,%sr3 ;! of the user before the gate #ifdef __LP64__ #warning NEEDS WORK for 64-bit #endif - ldw -64(%r30), %r28 ;! 8th argument + ldw -64(%r30), %r29 ;! 8th argument ldw -60(%r30), %r19 ;! 7th argument ldw -56(%r30), %r20 ;! 6th argument ldw -52(%r30), %r21 ;! 5th argument - gate .+8, %r0 ;! become privileged - mtsp %r0,%sr4 ;! get kernel space into sr4 - mtsp %r0,%sr5 ;! get kernel space into sr5 - mtsp %r0,%sr6 ;! get kernel space into sr6 - mtsp %r0,%sr7 ;! get kernel space into sr7 - mfctl %cr30,%r1 ;! get the kernel task ptr - mtctl %r0,%cr30 ;! zero it (flag) - STREG %r30,TASK_PT_GR30(%r1) ;! preserve userspace sp - STREG %r2,TASK_PT_GR2(%r1) ;! preserve rp - STREG %r27,TASK_PT_GR27(%r1) ;! user dp - STREG %r31,TASK_PT_GR31(%r1) ;! preserve syscall return ptr + gate .+8, %r0 /* become privileged */ + mtsp %r0,%sr4 /* get kernel space into sr4 */ + mtsp %r0,%sr5 /* get kernel space into sr5 */ + mtsp %r0,%sr6 /* get kernel space into sr6 */ + mfsp %sr7,%r1 /* save user sr7 */ + mtsp %r1,%sr3 /* and store it in sr3 */ + + mtctl %r30,%cr28 + mfctl %cr30,%r1 + xor %r1,%r30,%r30 /* ye olde xor trick */ + xor %r1,%r30,%r1 + xor %r1,%r30,%r30 + ldo TASK_SZ_ALGN+FRAME_SIZE(%r30),%r30 /* set up kernel stack */ + + /* N.B.: It is critical that we don't set sr7 to 0 until r30 + * contains a valid kernel stack pointer. It is also + * critical that we don't start using the kernel stack + * until after sr7 has been set to 0. + */ + + mtsp %r0,%sr7 /* get kernel space into sr7 */ + STREG %r1,TASK_PT_GR30-TASK_SZ_ALGN-FRAME_SIZE(%r30) /* save usp */ + ldo -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr in %r1 */ + + /* Save some registers for sigcontext and potential task + switch (see entry.S for the details of which ones are + saved/restored). TASK_PT_PSW is zeroed so we can see whether + a process is on a syscall or not. For an interrupt the real + PSW value is stored. This is needed for gdb and sys_ptrace. */ + STREG %r0, TASK_PT_PSW(%r1) + STREG %r2, TASK_PT_GR2(%r1) /* preserve rp */ + STREG %r19, TASK_PT_GR19(%r1) /* 7th argument */ + STREG %r20, TASK_PT_GR20(%r1) /* 6th argument */ + STREG %r21, TASK_PT_GR21(%r1) /* 5th argument */ + STREG %r22, TASK_PT_GR22(%r1) /* syscall # */ + STREG %r23, TASK_PT_GR23(%r1) /* 4th argument */ + STREG %r24, TASK_PT_GR24(%r1) /* 3rd argument */ + STREG %r25, TASK_PT_GR25(%r1) /* 2nd argument */ + STREG %r26, TASK_PT_GR26(%r1) /* 1st argument */ + STREG %r27, TASK_PT_GR27(%r1) /* user dp */ + STREG %r28, TASK_PT_GR28(%r1) /* return value 0 */ + STREG %r28, TASK_PT_ORIG_R28(%r1) /* return value 0 (saved for signals) */ + STREG %r29, TASK_PT_GR29(%r1) /* 8th argument */ + STREG %r31, TASK_PT_GR31(%r1) /* preserve syscall return ptr */ + + ldo TASK_PT_FR0(%r1), %r27 /* save fpregs from the kernel */ + save_fp %r27 /* or potential task switch */ - loadgp ;! setup kernel dp + mfctl %cr11, %r27 /* i.e. SAR */ + STREG %r27, TASK_PT_SAR(%r1) - ldo TASK_SZ_ALGN+64(%r1),%r30 ;! set up kernel stack + loadgp stw %r21, -52(%r30) ;! 5th argument stw %r20, -56(%r30) ;! 6th argument stw %r19, -60(%r30) ;! 7th argument - stw %r28, -64(%r30) ;! 8th argument + stw %r29, -64(%r30) ;! 8th argument ldil L%hpux_call_table, %r21 ldo R%hpux_call_table(%r21), %r21 diff -Nru a/arch/parisc/hpux/ioctl.c b/arch/parisc/hpux/ioctl.c --- a/arch/parisc/hpux/ioctl.c Mon Nov 4 14:31:01 2002 +++ b/arch/parisc/hpux/ioctl.c Mon Nov 4 14:31:01 2002 @@ -19,6 +19,7 @@ * TIOCSPGRP */ +#include #include #include #include @@ -54,10 +55,6 @@ case 't': result = hpux_ioctl_t(fd, cmd, arg); break; - default: - /* If my mother ever sees this, I hope she disowns me. - * Take this out after NYLWE. */ - result = sys_ioctl(fd, cmd, arg); } return result; } diff -Nru a/arch/parisc/hpux/sys_hpux.c b/arch/parisc/hpux/sys_hpux.c --- a/arch/parisc/hpux/sys_hpux.c Mon Nov 4 14:31:02 2002 +++ b/arch/parisc/hpux/sys_hpux.c Mon Nov 4 14:31:02 2002 @@ -4,10 +4,15 @@ * implements HPUX syscalls. */ +#include #include +#include #include #include +#include + #include +#include #include unsigned long sys_brk(unsigned long addr); @@ -41,6 +46,17 @@ return sys_waitpid(-1, stat_loc, 0); } +int hpux_setpgrp(void) +{ + extern int sys_setpgid(int, int); + return sys_setpgid(0,0); +} + +int hpux_setpgrp3(void) +{ + return hpux_setpgrp(); +} + #define _SC_CPU_VERSION 10001 #define _SC_OPEN_MAX 4 #define CPU_PA_RISC1_1 0x210 @@ -127,6 +143,66 @@ return err; } +/* + * Wrapper for hpux statfs call. At the moment, just calls the linux native one + * and ignores the extra fields at the end of the hpux statfs struct. + * + */ + +typedef int32_t hpux_fsid_t[2]; /* file system ID type */ +typedef uint16_t hpux_site_t; + +struct hpux_statfs { + int32_t f_type; /* type of info, zero for now */ + int32_t f_bsize; /* fundamental file system block size */ + int32_t f_blocks; /* total blocks in file system */ + int32_t f_bfree; /* free block in fs */ + int32_t f_bavail; /* free blocks avail to non-superuser */ + int32_t f_files; /* total file nodes in file system */ + int32_t f_ffree; /* free file nodes in fs */ + hpux_fsid_t f_fsid; /* file system ID */ + int32_t f_magic; /* file system magic number */ + int32_t f_featurebits; /* file system features */ + int32_t f_spare[4]; /* spare for later */ + hpux_site_t f_cnode; /* cluster node where mounted */ + int16_t f_pad; +}; + +/* hpux statfs */ +int hpux_statfs(const char *path, struct hpux_statfs *buf) +{ + int error; + int len; + char *kpath; + + len = strlen_user((char *)path); + + kpath = (char *) kmalloc(len+1, GFP_KERNEL); + if ( !kpath ) { + printk(KERN_DEBUG "failed to kmalloc kpath\n"); + return 0; + } + + if ( copy_from_user(kpath, (char *)path, len+1) ) { + printk(KERN_DEBUG "failed to copy_from_user kpath\n"); + kfree(kpath); + return 0; + } + + printk(KERN_DEBUG "hpux_statfs(\"%s\",-)\n", kpath); + + kfree(kpath); + + /* just fake it, beginning of structures match */ + extern int sys_statfs(const char *, struct statfs *); + error = sys_statfs(path, (struct statfs *) buf); + + /* ignoring rest of statfs struct, but it should be zeros. Need to do + something with f_fsid[1], which is the fstype for sysfs */ + + return error; +} + /* This function is called from hpux_utssys(); HP-UX implements * uname() as an option to utssys(). @@ -330,4 +406,542 @@ error = do_pipe(kstack_fildes); unlock_kernel(); return error; +} + +/* lies - says it works, but it really didn't lock anything */ +int hpux_lockf(int fildes, int function, off_t size) +{ + return 0; +} + +int hpux_sysfs(int opcode, unsigned long arg1, unsigned long arg2) +{ + char *fsname = NULL; + int len = 0; + int fstype; + +/*Unimplemented HP-UX syscall emulation. Syscall #334 (sysfs) + Args: 1 80057bf4 0 400179f0 0 0 0 */ + printk(KERN_DEBUG "in hpux_sysfs\n"); + printk(KERN_DEBUG "hpux_sysfs called with opcode = %d\n", opcode); + printk(KERN_DEBUG "hpux_sysfs called with arg1='%lx'\n", arg1); + + if ( opcode == 1 ) { /* GETFSIND */ + len = strlen_user((char *)arg1); + printk(KERN_DEBUG "len of arg1 = %d\n", len); + + fsname = (char *) kmalloc(len+1, GFP_KERNEL); + if ( !fsname ) { + printk(KERN_DEBUG "failed to kmalloc fsname\n"); + return 0; + } + + if ( copy_from_user(fsname, (char *)arg1, len+1) ) { + printk(KERN_DEBUG "failed to copy_from_user fsname\n"); + kfree(fsname); + return 0; + } + + printk(KERN_DEBUG "that is '%s' as (char *)\n", fsname); + if ( !strcmp(fsname, "hfs") ) { + fstype = 0; + } else { + fstype = 0; + }; + + kfree(fsname); + + printk(KERN_DEBUG "returning fstype=%d\n", fstype); + return fstype; /* something other than default */ + } + + + return 0; +} + + +/* Table of syscall names and handle for unimplemented routines */ +static const char *syscall_names[] = { + "nosys", /* 0 */ + "exit", + "fork", + "read", + "write", + "open", /* 5 */ + "close", + "wait", + "creat", + "link", + "unlink", /* 10 */ + "execv", + "chdir", + "time", + "mknod", + "chmod", /* 15 */ + "chown", + "brk", + "lchmod", + "lseek", + "getpid", /* 20 */ + "mount", + "umount", + "setuid", + "getuid", + "stime", /* 25 */ + "ptrace", + "alarm", + NULL, + "pause", + "utime", /* 30 */ + "stty", + "gtty", + "access", + "nice", + "ftime", /* 35 */ + "sync", + "kill", + "stat", + "setpgrp3", + "lstat", /* 40 */ + "dup", + "pipe", + "times", + "profil", + "ki_call", /* 45 */ + "setgid", + "getgid", + NULL, + NULL, + NULL, /* 50 */ + "acct", + "set_userthreadid", + NULL, + "ioctl", + "reboot", /* 55 */ + "symlink", + "utssys", + "readlink", + "execve", + "umask", /* 60 */ + "chroot", + "fcntl", + "ulimit", + NULL, + NULL, /* 65 */ + "vfork", + NULL, + NULL, + NULL, + NULL, /* 70 */ + "mmap", + NULL, + "munmap", + "mprotect", + "madvise", /* 75 */ + "vhangup", + "swapoff", + NULL, + "getgroups", + "setgroups", /* 80 */ + "getpgrp2", + "setpgid/setpgrp2", + "setitimer", + "wait3", + "swapon", /* 85 */ + "getitimer", + NULL, + NULL, + NULL, + "dup2", /* 90 */ + NULL, + "fstat", + "select", + NULL, + "fsync", /* 95 */ + "setpriority", + NULL, + NULL, + NULL, + "getpriority", /* 100 */ + NULL, + NULL, + NULL, + NULL, + NULL, /* 105 */ + NULL, + NULL, + "sigvector", + "sigblock", + "sigsetmask", /* 110 */ + "sigpause", + "sigstack", + NULL, + NULL, + NULL, /* 115 */ + "gettimeofday", + "getrusage", + NULL, + NULL, + "readv", /* 120 */ + "writev", + "settimeofday", + "fchown", + "fchmod", + NULL, /* 125 */ + "setresuid", + "setresgid", + "rename", + "truncate", + "ftruncate", /* 130 */ + NULL, + "sysconf", + NULL, + NULL, + NULL, /* 135 */ + "mkdir", + "rmdir", + NULL, + "sigcleanup", + "setcore", /* 140 */ + NULL, + "gethostid", + "sethostid", + "getrlimit", + "setrlimit", /* 145 */ + NULL, + NULL, + "quotactl", + "get_sysinfo", + NULL, /* 150 */ + "privgrp", + "rtprio", + "plock", + NULL, + "lockf", /* 155 */ + "semget", + NULL, + "semop", + "msgget", + NULL, /* 160 */ + "msgsnd", + "msgrcv", + "shmget", + NULL, + "shmat", /* 165 */ + "shmdt", + NULL, + "csp/nsp_init", + "cluster", + "mkrnod", /* 170 */ + "test", + "unsp_open", + NULL, + "getcontext", + "osetcontext", /* 175 */ + "bigio", + "pipenode", + "lsync", + "getmachineid", + "cnodeid/mysite", /* 180 */ + "cnodes/sitels", + "swapclients", + "rmtprocess", + "dskless_stats", + "sigprocmask", /* 185 */ + "sigpending", + "sigsuspend", + "sigaction", + NULL, + "nfssvc", /* 190 */ + "getfh", + "getdomainname", + "setdomainname", + "async_daemon", + "getdirentries", /* 195 */ + "statfs", + "fstatfs", + "vfsmount", + NULL, + "waitpid", /* 200 */ + NULL, + NULL, + NULL, + NULL, + NULL, /* 205 */ + NULL, + NULL, + NULL, + NULL, + NULL, /* 210 */ + NULL, + NULL, + NULL, + NULL, + NULL, /* 215 */ + NULL, + NULL, + NULL, + NULL, + NULL, /* 220 */ + NULL, + NULL, + NULL, + "sigsetreturn", + "sigsetstatemask", /* 225 */ + "bfactl", + "cs", + "cds", + NULL, + "pathconf", /* 230 */ + "fpathconf", + NULL, + NULL, + "nfs_fcntl", + "ogetacl", /* 235 */ + "ofgetacl", + "osetacl", + "ofsetacl", + "pstat", + "getaudid", /* 240 */ + "setaudid", + "getaudproc", + "setaudproc", + "getevent", + "setevent", /* 245 */ + "audwrite", + "audswitch", + "audctl", + "ogetaccess", + "fsctl", /* 250 */ + "ulconnect", + "ulcontrol", + "ulcreate", + "uldest", + "ulrecv", /* 255 */ + "ulrecvcn", + "ulsend", + "ulshutdown", + "swapfs", + "fss", /* 260 */ + NULL, + NULL, + NULL, + NULL, + NULL, /* 265 */ + NULL, + "tsync", + "getnumfds", + "poll", + "getmsg", /* 270 */ + "putmsg", + "fchdir", + "getmount_cnt", + "getmount_entry", + "accept", /* 275 */ + "bind", + "connect", + "getpeername", + "getsockname", + "getsockopt", /* 280 */ + "listen", + "recv", + "recvfrom", + "recvmsg", + "send", /* 285 */ + "sendmsg", + "sendto", + "setsockopt", + "shutdown", + "socket", /* 290 */ + "socketpair", + "proc_open", + "proc_close", + "proc_send", + "proc_recv", /* 295 */ + "proc_sendrecv", + "proc_syscall", + "ipccreate", + "ipcname", + "ipcnamerase", /* 300 */ + "ipclookup", + "ipcselect", + "ipcconnect", + "ipcrecvcn", + "ipcsend", /* 305 */ + "ipcrecv", + "ipcgetnodename", + "ipcsetnodename", + "ipccontrol", + "ipcshutdown", /* 310 */ + "ipcdest", + "semctl", + "msgctl", + "shmctl", + "mpctl", /* 315 */ + "exportfs", + "getpmsg", + "putpmsg", + "strioctl", + "msync", /* 320 */ + "msleep", + "mwakeup", + "msem_init", + "msem_remove", + "adjtime", /* 325 */ + "kload", + "fattach", + "fdetach", + "serialize", + "statvfs", /* 330 */ + "fstatvfs", + "lchown", + "getsid", + "sysfs", + NULL, /* 335 */ + NULL, + "sched_setparam", + "sched_getparam", + "sched_setscheduler", + "sched_getscheduler", /* 340 */ + "sched_yield", + "sched_get_priority_max", + "sched_get_priority_min", + "sched_rr_get_interval", + "clock_settime", /* 345 */ + "clock_gettime", + "clock_getres", + "timer_create", + "timer_delete", + "timer_settime", /* 350 */ + "timer_gettime", + "timer_getoverrun", + "nanosleep", + "toolbox", + NULL, /* 355 */ + "getdents", + "getcontext", + "sysinfo", + "fcntl64", + "ftruncate64", /* 360 */ + "fstat64", + "getdirentries64", + "getrlimit64", + "lockf64", + "lseek64", /* 365 */ + "lstat64", + "mmap64", + "setrlimit64", + "stat64", + "truncate64", /* 370 */ + "ulimit64", + NULL, + NULL, + NULL, + NULL, /* 375 */ + NULL, + NULL, + NULL, + NULL, + "setcontext", /* 380 */ + "sigaltstack", + "waitid", + "setpgrp", + "recvmsg2", + "sendmsg2", /* 385 */ + "socket2", + "socketpair2", + "setregid", + "lwp_create", + "lwp_terminate", /* 390 */ + "lwp_wait", + "lwp_suspend", + "lwp_resume", + "lwp_self", + "lwp_abort_syscall", /* 395 */ + "lwp_info", + "lwp_kill", + "ksleep", + "kwakeup", + "ksleep_abort", /* 400 */ + "lwp_proc_info", + "lwp_exit", + "lwp_continue", + "getacl", + "fgetacl", /* 405 */ + "setacl", + "fsetacl", + "getaccess", + "lwp_mutex_init", + "lwp_mutex_lock_sys", /* 410 */ + "lwp_mutex_unlock", + "lwp_cond_init", + "lwp_cond_signal", + "lwp_cond_broadcast", + "lwp_cond_wait_sys", /* 415 */ + "lwp_getscheduler", + "lwp_setscheduler", + "lwp_getprivate", + "lwp_setprivate", + "lwp_detach", /* 420 */ + "mlock", + "munlock", + "mlockall", + "munlockall", + "shm_open", /* 425 */ + "shm_unlink", + "sigqueue", + "sigwaitinfo", + "sigtimedwait", + "sigwait", /* 430 */ + "aio_read", + "aio_write", + "lio_listio", + "aio_error", + "aio_return", /* 435 */ + "aio_cancel", + "aio_suspend", + "aio_fsync", + "mq_open", + "mq_unlink", /* 440 */ + "mq_send", + "mq_receive", + "mq_notify", + "mq_setattr", + "mq_getattr", /* 445 */ + "ksem_open", + "ksem_unlink", + "ksem_close", + "ksem_destroy", + "lw_sem_incr", /* 450 */ + "lw_sem_decr", + "lw_sem_read", + "mq_close", +}; +static const int syscall_names_max = 453; + +int +hpux_unimplemented(unsigned long arg1,unsigned long arg2,unsigned long arg3, + unsigned long arg4,unsigned long arg5,unsigned long arg6, + unsigned long arg7,unsigned long sc_num) +{ + /* NOTE: sc_num trashes arg8 for the few syscalls that actually + * have a valid 8th argument. + */ + const char *name = NULL; + if ( sc_num <= syscall_names_max && sc_num >= 0 ) { + name = syscall_names[sc_num]; + } + + if ( name ) { + printk(KERN_DEBUG "Unimplemented HP-UX syscall emulation. Syscall #%lu (%s)\n", + sc_num, name); + } else { + printk(KERN_DEBUG "Unimplemented unknown HP-UX syscall emulation. Syscall #%lu\n", + sc_num); + } + + printk(KERN_DEBUG " Args: %lx %lx %lx %lx %lx %lx %lx\n", + arg1, arg2, arg3, arg4, arg5, arg6, arg7); + + return -ENOSYS; } diff -Nru a/arch/parisc/hpux/wrappers.S b/arch/parisc/hpux/wrappers.S --- a/arch/parisc/hpux/wrappers.S Mon Nov 4 14:31:02 2002 +++ b/arch/parisc/hpux/wrappers.S Mon Nov 4 14:31:02 2002 @@ -1,5 +1,5 @@ -/*------------------------------------------------------------------------------ - * Native PARISC/Linux Project (http://www.puffingroup.com/parisc) +/* + * Linux/PARISC Project (http://www.parisc-linux.org/) * * HP-UX System Call Wrapper routines and System Call Return Path * @@ -24,12 +24,11 @@ #warning Must be changed for PA64 #endif -#include +#include .level 1.1 .text -#define __ASSEMBLY__ #include #include @@ -81,6 +80,7 @@ .export hpux_fork_wrapper + .export hpux_child_return .import sys_fork hpux_fork_wrapper: @@ -91,12 +91,10 @@ stw %r2,-20(%r30) ldo 64(%r30),%r30 stw %r2,PT_GR19(%r1) ;! save for child - stw %r30,PT_GR20(%r1) ;! save for child - ldil L%child_return,%r3 - ldo R%child_return(%r3),%r3 - stw %r3,PT_GR21(%r1) ;! save for child + stw %r30,PT_GR21(%r1) ;! save for child - ldw TASK_PT_GR30(%r1),%r25 + ldw PT_GR30(%r1),%r25 + mtctl %r25,%cr29 copy %r1,%r24 bl sys_clone,%r2 ldi SIGCHLD,%r26 @@ -130,7 +128,12 @@ /* Set the return value for the child */ -child_return: +hpux_child_return: +#if CONFIG_SMP || CONFIG_PREEMPT + bl schedule_tail, %r2 + nop +#endif + ldw TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2 b fork_return copy %r0,%r28 @@ -242,3 +245,10 @@ no_error: b syscall_exit nop + + .export hpux_unimplemented_wrapper + .import hpux_unimplemented + +hpux_unimplemented_wrapper: + b hpux_unimplemented + stw %r22,-64(%r30) /* overwrite arg8 with syscall number */ diff -Nru a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile --- a/arch/parisc/kernel/Makefile Mon Nov 4 14:31:01 2002 +++ b/arch/parisc/kernel/Makefile Mon Nov 4 14:31:01 2002 @@ -1,5 +1,5 @@ # -# Makefile for the linux kernel. +# Makefile for arch/parisc/kernel # ifdef CONFIG_PARISC64 @@ -27,5 +27,3 @@ ioctl32.o signal32.o # only supported for PCX-W/U in 64-bit mode at the moment obj-$(CONFIG_PARISC64) += perf.o perf_asm.o - -include $(TOPDIR)/Rules.make diff -Nru a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c --- a/arch/parisc/kernel/asm-offsets.c Mon Nov 4 14:31:00 2002 +++ b/arch/parisc/kernel/asm-offsets.c Mon Nov 4 14:31:00 2002 @@ -35,6 +35,7 @@ DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); DEFINE(TASK_MM, offsetof(struct task_struct, mm)); DEFINE(TASK_PERSONALITY, offsetof(struct task_struct, personality)); + DEFINE(TASK_PID, offsetof(struct task_struct, pid)); BLANK(); DEFINE(TASK_REGS, offsetof(struct task_struct, thread.regs)); DEFINE(TASK_PT_PSW, offsetof(struct task_struct, thread.regs.gr[ 0])); diff -Nru a/arch/parisc/kernel/ccio-dma.c b/arch/parisc/kernel/ccio-dma.c --- a/arch/parisc/kernel/ccio-dma.c Mon Nov 4 14:31:01 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1209 +0,0 @@ -/* -** ccio-dma.c: -** DMA management routines for first generation cache-coherent machines. -** Program U2/Uturn in "Virtual Mode" and use the I/O MMU. -** -** (c) Copyright 2000 Grant Grundler -** (c) Copyright 2000 Ryan Bradetich -** (c) Copyright 2000 Hewlett-Packard Company -** -** 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. -** -** -** "Real Mode" operation refers to U2/Uturn chip operation. -** U2/Uturn were designed to perform coherency checks w/o using -** the I/O MMU - basically what x86 does. -** -** Philipp Rumpf has a "Real Mode" driver for PCX-W machines at: -** CVSROOT=:pserver:anonymous@198.186.203.37:/cvsroot/linux-parisc -** cvs -z3 co linux/arch/parisc/kernel/dma-rm.c -** -** I've rewritten his code to work under TPG's tree. See ccio-rm-dma.c. -** -** Drawbacks of using Real Mode are: -** o outbound DMA is slower - U2 won't prefetch data (GSC+ XQL signal). -** o Inbound DMA less efficient - U2 can't use DMA_FAST attribute. -** o Ability to do scatter/gather in HW is lost. -** o Doesn't work under PCX-U/U+ machines since they didn't follow -** the coherency design originally worked out. Only PCX-W does. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include /* for L1_CACHE_BYTES */ -#include -#include -#include - -#include -#include /* for gsc_writeN()... */ - -/* -** Choose "ccio" since that's what HP-UX calls it. -** Make it easier for folks to migrate from one to the other :^) -*/ -#define MODULE_NAME "ccio" - -/* -#define DEBUG_CCIO_RES -#define DEBUG_CCIO_RUN -#define DEBUG_CCIO_INIT -#define DUMP_RESMAP -*/ - -#include -#include /* for proc_runway_root */ - -#ifdef DEBUG_CCIO_INIT -#define DBG_INIT(x...) printk(x) -#else -#define DBG_INIT(x...) -#endif - -#ifdef DEBUG_CCIO_RUN -#define DBG_RUN(x...) printk(x) -#else -#define DBG_RUN(x...) -#endif - -#ifdef DEBUG_CCIO_RES -#define DBG_RES(x...) printk(x) -#else -#define DBG_RES(x...) -#endif - -#define CCIO_INLINE /* inline */ -#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr)) - -#define U2_IOA_RUNWAY 0x580 -#define U2_BC_GSC 0x501 -#define UTURN_IOA_RUNWAY 0x581 -#define UTURN_BC_GSC 0x502 -/* We *can't* support JAVA (T600). Venture there at your own risk. */ - -static void dump_resmap(void); - -static int ccio_driver_callback(struct hp_device *, struct pa_iodc_driver *); - -static struct pa_iodc_driver ccio_drivers_for[] = { - - {HPHW_IOA, U2_IOA_RUNWAY, 0x0, 0xb, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "U2 I/O MMU", (void *) ccio_driver_callback}, - - {HPHW_IOA, UTURN_IOA_RUNWAY, 0x0, 0xb, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "Uturn I/O MMU", (void *) ccio_driver_callback}, - -/* -** FIXME: The following claims the GSC bus port, not the IOA. -** And there are two busses below a single I/O TLB. -** -** These should go away once we have a real PA bus walk. -** Firmware wants to tell the PA bus walk code about the GSC ports -** since they are not "architected" PA I/O devices. Ie a PA bus walk -** wouldn't discover them. But the PA bus walk code could check -** the "fixed module table" to add such devices to an I/O Tree -** and proceed with the recursive, depth first bus walk. -*/ - {HPHW_BCPORT, U2_BC_GSC, 0x0, 0xc, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "U2 GSC+ BC", (void *) ccio_driver_callback}, - - {HPHW_BCPORT, UTURN_BC_GSC, 0x0, 0xc, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "Uturn GSC+ BC", (void *) ccio_driver_callback}, - - {0,0,0,0,0,0, - 0, - (char *) NULL, (char *) NULL, (void *) NULL } -}; - - -#define IS_U2(id) ( \ - (((id)->hw_type == HPHW_IOA) && ((id)->hversion == U2_IOA_RUNWAY)) || \ - (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == U2_BC_GSC)) \ -) - -#define IS_UTURN(id) ( \ - (((id)->hw_type == HPHW_IOA) && ((id)->hversion == UTURN_IOA_RUNWAY)) || \ - (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == UTURN_BC_GSC)) \ -) - - -#define IOA_NORMAL_MODE 0x00020080 /* IO_CONTROL to turn on CCIO */ -#define CMD_TLB_DIRECT_WRITE 35 /* IO_COMMAND for I/O TLB Writes */ -#define CMD_TLB_PURGE 33 /* IO_COMMAND to Purge I/O TLB entry */ - -struct ioa_registers { - /* Runway Supervisory Set */ - volatile int32_t unused1[12]; - volatile uint32_t io_command; /* Offset 12 */ - volatile uint32_t io_status; /* Offset 13 */ - volatile uint32_t io_control; /* Offset 14 */ - volatile int32_t unused2[1]; - - /* Runway Auxiliary Register Set */ - volatile uint32_t io_err_resp; /* Offset 0 */ - volatile uint32_t io_err_info; /* Offset 1 */ - volatile uint32_t io_err_req; /* Offset 2 */ - volatile uint32_t io_err_resp_hi; /* Offset 3 */ - volatile uint32_t io_tlb_entry_m; /* Offset 4 */ - volatile uint32_t io_tlb_entry_l; /* Offset 5 */ - volatile uint32_t unused3[1]; - volatile uint32_t io_pdir_base; /* Offset 7 */ - volatile uint32_t io_io_low_hv; /* Offset 8 */ - volatile uint32_t io_io_high_hv; /* Offset 9 */ - volatile uint32_t unused4[1]; - volatile uint32_t io_chain_id_mask; /* Offset 11 */ - volatile uint32_t unused5[2]; - volatile uint32_t io_io_low; /* Offset 14 */ - volatile uint32_t io_io_high; /* Offset 15 */ -}; - - -struct ccio_device { - struct ccio_device *next; /* list of LBA's in system */ - struct hp_device *iodc; /* data about dev from firmware */ - spinlock_t ccio_lock; - - struct ioa_registers *ccio_hpa; /* base address */ - u64 *pdir_base; /* physical base address */ - char *res_map; /* resource map, bit == pdir entry */ - - int res_hint; /* next available IOVP - circular search */ - int res_size; /* size of resource map in bytes */ - int chainid_shift; /* specify bit location of chain_id */ - int flags; /* state/functionality enabled */ -#ifdef DELAYED_RESOURCE_CNT - dma_addr_t res_delay[DELAYED_RESOURCE_CNT]; -#endif - - /* STUFF We don't need in performance path */ - int pdir_size; /* in bytes, determined by IOV Space size */ - int hw_rev; /* HW revision of chip */ -}; - - -/* Ratio of Host MEM to IOV Space size */ -static unsigned long ccio_mem_ratio = 4; -static struct ccio_device *ccio_list = NULL; - -static int ccio_proc_info(char *buffer, char **start, off_t offset, int length); -static unsigned long ccio_used_bytes = 0; -static unsigned long ccio_used_pages = 0; -static int ccio_cujo_bug = 0; - -static unsigned long ccio_alloc_size = 0; -static unsigned long ccio_free_size = 0; - -/************************************************************** -* -* I/O Pdir Resource Management -* -* Bits set in the resource map are in use. -* Each bit can represent a number of pages. -* LSbs represent lower addresses (IOVA's). -* -* This was was copied from sba_iommu.c. Don't try to unify -* the two resource managers unless a way to have different -* allocation policies is also adjusted. We'd like to avoid -* I/O TLB thrashing by having resource allocation policy -* match the I/O TLB replacement policy. -* -***************************************************************/ -#define PAGES_PER_RANGE 1 /* could increase this to 4 or 8 if needed */ -#define IOVP_SIZE PAGE_SIZE -#define IOVP_SHIFT PAGE_SHIFT -#define IOVP_MASK PAGE_MASK - -/* Convert from IOVP to IOVA and vice versa. */ -#define CCIO_IOVA(iovp,offset) ((iovp) | (offset)) -#define CCIO_IOVP(iova) ((iova) & ~(IOVP_SIZE-1) ) - -#define PDIR_INDEX(iovp) ((iovp)>>IOVP_SHIFT) -#define MKIOVP(pdir_idx) ((long)(pdir_idx) << IOVP_SHIFT) -#define MKIOVA(iovp,offset) (dma_addr_t)((long)iovp | (long)offset) - -/* CUJO20 KLUDGE start */ -#define CUJO_20_BITMASK 0x0ffff000 /* upper nibble is a don't care */ -#define CUJO_20_STEP 0x10000000 /* inc upper nibble */ -#define CUJO_20_BADPAGE1 0x01003000 /* pages that hpmc on raven U+ */ -#define CUJO_20_BADPAGE2 0x01607000 /* pages that hpmc on firehawk U+ */ -#define CUJO_20_BADHVERS 0x6821 /* low nibble 1 is cujo rev 2.0 */ -#define CUJO_RAVEN_LOC 0xf1000000UL /* cujo location on raven U+ */ -#define CUJO_FIREHAWK_LOC 0xf1604000UL /* cujo location on firehawk U+ */ -/* CUJO20 KLUDGE end */ - -/* -** Don't worry about the 150% average search length on a miss. -** If the search wraps around, and passes the res_hint, it will -** cause the kernel to panic anyhow. -*/ - -/* ioa->res_hint = idx + (size >> 3); \ */ - -#define CCIO_SEARCH_LOOP(ioa, idx, mask, size) \ - for(; res_ptr < res_end; ++res_ptr) \ - { \ - if(0 == ((*res_ptr) & mask)) { \ - *res_ptr |= mask; \ - idx = (int)((unsigned long)res_ptr - (unsigned long)ioa->res_map); \ - ioa->res_hint = 0;\ - goto resource_found; \ - } \ - } - -#define CCIO_FIND_FREE_MAPPING(ioa, idx, mask, size) { \ - u##size *res_ptr = (u##size *)&((ioa)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \ - u##size *res_end = (u##size *)&(ioa)->res_map[ioa->res_size]; \ - CCIO_SEARCH_LOOP(ioa, idx, mask, size); \ - res_ptr = (u##size *)&(ioa)->res_map[0]; \ - CCIO_SEARCH_LOOP(ioa, idx, mask, size); \ -} - -/* -** Find available bit in this ioa's resource map. -** Use a "circular" search: -** o Most IOVA's are "temporary" - avg search time should be small. -** o keep a history of what happened for debugging -** o KISS. -** -** Perf optimizations: -** o search for log2(size) bits at a time. -** o search for available resource bits using byte/word/whatever. -** o use different search for "large" (eg > 4 pages) or "very large" -** (eg > 16 pages) mappings. -*/ -static int -ccio_alloc_range(struct ccio_device *ioa, size_t size) -{ - int res_idx; - unsigned long mask, flags; - unsigned int pages_needed = size >> PAGE_SHIFT; - - ASSERT(pages_needed); - ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE); - ASSERT(pages_needed < (BITS_PER_LONG - IOVP_SHIFT)); - - mask = (unsigned long) -1L; - mask >>= BITS_PER_LONG - pages_needed; - - DBG_RES(__FUNCTION__ " size: %d pages_needed %d pages_mask 0x%08lx\n", - size, pages_needed, mask); - - spin_lock_irqsave(&ioa->ccio_lock, flags); - - /* - ** "seek and ye shall find"...praying never hurts either... - ** ggg sacrafices another 710 to the computer gods. - */ - - if(pages_needed <= 8) { - CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 8); - } else if(pages_needed <= 16) { - CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 16); - } else if(pages_needed <= 32) { - CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 32); -#ifdef __LP64__ - } else if(pages_needed <= 64) { - CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, 64) -#endif - } else { - panic(__FILE__ ":" __FUNCTION__ "() Too many pages to map.\n"); - } - -#ifdef DUMP_RESMAP - dump_resmap(); -#endif - panic(__FILE__ ":" __FUNCTION__ "() I/O MMU is out of mapping resources\n"); - -resource_found: - - DBG_RES(__FUNCTION__ " res_idx %d mask 0x%08lx res_hint: %d\n", - res_idx, mask, ioa->res_hint); - - ccio_used_pages += pages_needed; - ccio_used_bytes += ((pages_needed >> 3) ? (pages_needed >> 3) : 1); - - spin_unlock_irqrestore(&ioa->ccio_lock, flags); - -#ifdef DUMP_RESMAP - dump_resmap(); -#endif - - /* - ** return the bit address (convert from byte to bit). - */ - return (res_idx << 3); -} - - -#define CCIO_FREE_MAPPINGS(ioa, idx, mask, size) \ - u##size *res_ptr = (u##size *)&((ioa)->res_map[idx + (((size >> 3) - 1) & ~((size >> 3) - 1))]); \ - ASSERT((*res_ptr & mask) == mask); \ - *res_ptr &= ~mask; - -/* -** clear bits in the ioa's resource map -*/ -static void -ccio_free_range(struct ccio_device *ioa, dma_addr_t iova, size_t size) -{ - unsigned long mask, flags; - unsigned long iovp = CCIO_IOVP(iova); - unsigned int res_idx = PDIR_INDEX(iovp)>>3; - unsigned int pages_mapped = (size >> IOVP_SHIFT) + !!(size & ~IOVP_MASK); - - ASSERT(pages_needed); - ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE); - ASSERT(pages_needed < (BITS_PER_LONG - IOVP_SHIFT)); - - mask = (unsigned long) -1L; - mask >>= BITS_PER_LONG - pages_mapped; - - DBG_RES(__FUNCTION__ " res_idx: %d size: %d pages_mapped %d mask 0x%08lx\n", - res_idx, size, pages_mapped, mask); - - spin_lock_irqsave(&ioa->ccio_lock, flags); - - if(pages_mapped <= 8) { - CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 8); - } else if(pages_mapped <= 16) { - CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 16); - } else if(pages_mapped <= 32) { - CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 32); -#ifdef __LP64__ - } else if(pages_mapped <= 64) { - CCIO_FREE_MAPPINGS(ioa, res_idx, mask, 64); -#endif - } else { - panic(__FILE__ ":" __FUNCTION__ "() Too many pages to unmap.\n"); - } - - ccio_used_pages -= (pages_mapped ? pages_mapped : 1); - ccio_used_bytes -= ((pages_mapped >> 3) ? (pages_mapped >> 3) : 1); - - spin_unlock_irqrestore(&ioa->ccio_lock, flags); - -#ifdef DUMP_RESMAP - dump_resmap(); -#endif -} - - -/**************************************************************** -** -** CCIO dma_ops support routines -** -*****************************************************************/ - -typedef unsigned long space_t; -#define KERNEL_SPACE 0 - - -/* -** DMA "Page Type" and Hints -** o if SAFE_DMA isn't set, mapping is for FAST_DMA. SAFE_DMA should be -** set for subcacheline DMA transfers since we don't want to damage the -** other part of a cacheline. -** o SAFE_DMA must be set for "memory" allocated via pci_alloc_consistent(). -** This bit tells U2 to do R/M/W for partial cachelines. "Streaming" -** data can avoid this if the mapping covers full cache lines. -** o STOP_MOST is needed for atomicity across cachelines. -** Apperently only "some EISA devices" need this. -** Using CONFIG_ISA is hack. Only the IOA with EISA under it needs -** to use this hint iff the EISA devices needs this feature. -** According to the U2 ERS, STOP_MOST enabled pages hurt performance. -** o PREFETCH should *not* be set for cases like Multiple PCI devices -** behind GSCtoPCI (dino) bus converter. Only one cacheline per GSC -** device can be fetched and multiply DMA streams will thrash the -** prefetch buffer and burn memory bandwidth. See 6.7.3 "Prefetch Rules -** and Invalidation of Prefetch Entries". -** -** FIXME: the default hints need to be per GSC device - not global. -** -** HP-UX dorks: linux device driver programming model is totally different -** than HP-UX's. HP-UX always sets HINT_PREFETCH since it's drivers -** do special things to work on non-coherent platforms...linux has to -** be much more careful with this. -*/ -#define IOPDIR_VALID 0x01UL -#define HINT_SAFE_DMA 0x02UL /* used for pci_alloc_consistent() pages */ -#ifdef CONFIG_ISA /* EISA support really */ -#define HINT_STOP_MOST 0x04UL /* LSL support */ -#else -#define HINT_STOP_MOST 0x00UL /* only needed for "some EISA devices" */ -#endif -#define HINT_UDPATE_ENB 0x08UL /* not used/supported by U2 */ -#define HINT_PREFETCH 0x10UL /* for outbound pages which are not SAFE */ - - -/* -** Use direction (ie PCI_DMA_TODEVICE) to pick hint. -** ccio_alloc_consistent() depends on this to get SAFE_DMA -** when it passes in BIDIRECTIONAL flag. -*/ -static u32 hint_lookup[] = { - [PCI_DMA_BIDIRECTIONAL] HINT_STOP_MOST | HINT_SAFE_DMA | IOPDIR_VALID, - [PCI_DMA_TODEVICE] HINT_STOP_MOST | HINT_PREFETCH | IOPDIR_VALID, - [PCI_DMA_FROMDEVICE] HINT_STOP_MOST | IOPDIR_VALID, - [PCI_DMA_NONE] 0, /* not valid */ -}; - -/* -** Initialize an I/O Pdir entry -** -** Given a virtual address (vba, arg2) and space id, (sid, arg1), -** load the I/O PDIR entry pointed to by pdir_ptr (arg0). Each IO Pdir -** entry consists of 8 bytes as shown below (MSB == bit 0): -** -** -** WORD 0: -** +------+----------------+-----------------------------------------------+ -** | Phys | Virtual Index | Phys | -** | 0:3 | 0:11 | 4:19 | -** |4 bits| 12 bits | 16 bits | -** +------+----------------+-----------------------------------------------+ -** WORD 1: -** +-----------------------+-----------------------------------------------+ -** | Phys | Rsvd | Prefetch |Update |Rsvd |Lock |Safe |Valid | -** | 20:39 | | Enable |Enable | |Enable|DMA | | -** | 20 bits | 5 bits | 1 bit |1 bit |2 bits|1 bit |1 bit |1 bit | -** +-----------------------+-----------------------------------------------+ -** -** The virtual index field is filled with the results of the LCI -** (Load Coherence Index) instruction. The 8 bits used for the virtual -** index are bits 12:19 of the value returned by LCI. -*/ - -void CCIO_INLINE -ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, void * vba, unsigned long hints) -{ - register unsigned long pa = (volatile unsigned long) vba; - register unsigned long ci; /* coherent index */ - - /* We currently only support kernel addresses */ - ASSERT(sid == 0); - ASSERT(((unsigned long) vba & 0xf0000000UL) == 0xc0000000UL); - - mtsp(sid,1); - - /* - ** WORD 1 - low order word - ** "hints" parm includes the VALID bit! - ** "dep" clobbers the physical address offset bits as well. - */ - pa = virt_to_phys(vba); - asm volatile("depw %1,31,12,%0" : "+r" (pa) : "r" (hints)); - ((u32 *)pdir_ptr)[1] = (u32) pa; - - /* - ** WORD 0 - high order word - */ - -#ifdef __LP64__ - /* - ** get bits 12:15 of physical address - ** shift bits 16:31 of physical address - ** and deposit them - */ - asm volatile ("extrd,u %1,15,4,%0" : "=r" (ci) : "r" (pa)); - asm volatile ("extrd,u %1,31,16,%0" : "+r" (ci) : "r" (ci)); - asm volatile ("depd %1,35,4,%0" : "+r" (pa) : "r" (ci)); -#else - pa = 0; -#endif - /* - ** get CPU coherency index bits - ** Grab virtual index [0:11] - ** Deposit virt_idx bits into I/O PDIR word - */ - asm volatile ("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba)); - asm volatile ("extru %1,19,12,%0" : "+r" (ci) : "r" (ci)); - asm volatile ("depw %1,15,12,%0" : "+r" (pa) : "r" (ci)); - - ((u32 *)pdir_ptr)[0] = (u32) pa; - - - /* FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360) - ** PCX-U/U+ do. (eg C200/C240) - ** PCX-T'? Don't know. (eg C110 or similar K-class) - ** - ** See PDC_MODEL/option 0/SW_CAP word for "Non-coherent IO-PDIR bit". - ** Hopefully we can patch (NOP) these out at boot time somehow. - ** - ** "Since PCX-U employs an offset hash that is incompatible with - ** the real mode coherence index generation of U2, the PDIR entry - ** must be flushed to memory to retain coherence." - */ - asm volatile("fdc 0(%0)" : : "r" (pdir_ptr)); - asm volatile("sync"); -} - - -/* -** Remove stale entries from the I/O TLB. -** Need to do this whenever an entry in the PDIR is marked invalid. -*/ -static CCIO_INLINE void -ccio_clear_io_tlb( struct ccio_device *d, dma_addr_t iovp, size_t byte_cnt) -{ - u32 chain_size = 1 << d->chainid_shift; - - iovp &= ~(IOVP_SIZE-1); /* clear offset bits, just want pagenum */ - byte_cnt += chain_size; - - while (byte_cnt > chain_size) { - WRITE_U32(CMD_TLB_PURGE | iovp, &d->ccio_hpa->io_command); - iovp += chain_size; - byte_cnt -= chain_size; - } -} - - -/*********************************************************** - * - * Mark the I/O Pdir entries invalid and blow away the - * corresponding I/O TLB entries. - * - * FIXME: at some threshhold it might be "cheaper" to just blow - * away the entire I/O TLB instead of individual entries. - * - * FIXME: Uturn has 256 TLB entries. We don't need to purge every - * PDIR entry - just once for each possible TLB entry. - * (We do need to maker I/O PDIR entries invalid regardless). - ***********************************************************/ -static CCIO_INLINE void -ccio_mark_invalid(struct ccio_device *d, dma_addr_t iova, size_t byte_cnt) -{ - u32 iovp = (u32) CCIO_IOVP(iova); - size_t saved_byte_cnt; - - /* round up to nearest page size */ - saved_byte_cnt = byte_cnt = (byte_cnt + IOVP_SIZE - 1) & IOVP_MASK; - - while (byte_cnt > 0) { - /* invalidate one page at a time */ - unsigned int idx = PDIR_INDEX(iovp); - char *pdir_ptr = (char *) &(d->pdir_base[idx]); - - ASSERT( idx < (d->pdir_size/sizeof(u64))); - - pdir_ptr[7] = 0; /* clear only VALID bit */ - - /* - ** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360) - ** PCX-U/U+ do. (eg C200/C240) - ** See PDC_MODEL/option 0/SW_CAP for "Non-coherent IO-PDIR bit". - ** - ** Hopefully someone figures out how to patch (NOP) the - ** FDC/SYNC out at boot time. - */ - asm volatile("fdc 0(%0)" : : "r" (pdir_ptr[7])); - - iovp += IOVP_SIZE; - byte_cnt -= IOVP_SIZE; - } - - asm volatile("sync"); - ccio_clear_io_tlb(d, CCIO_IOVP(iova), saved_byte_cnt); -} - - -/**************************************************************** -** -** CCIO dma_ops -** -*****************************************************************/ - -void __init ccio_init(void) -{ - register_driver(ccio_drivers_for); -} - - -static int ccio_dma_supported( struct pci_dev *dev, u64 mask) -{ - if (dev == NULL) { - printk(MODULE_NAME ": EISA/ISA/et al not supported\n"); - BUG(); - return(0); - } - - dev->dma_mask = mask; /* save it */ - - /* only support 32-bit devices (ie PCI/GSC) */ - return((int) (mask >= 0xffffffffUL)); -} - -/* -** Dump a hex representation of the resource map. -*/ - -#ifdef DUMP_RESMAP -static -void dump_resmap() -{ - struct ccio_device *ioa = ccio_list; - unsigned long *res_ptr = (unsigned long *)ioa->res_map; - unsigned long i = 0; - - printk("res_map: "); - for(; i < (ioa->res_size / sizeof(unsigned long)); ++i, ++res_ptr) - printk("%08lx ", *res_ptr); - - printk("\n"); -} -#endif - -/* -** map_single returns a fully formed IOVA -*/ -static dma_addr_t ccio_map_single(struct pci_dev *dev, void *addr, size_t size, int direction) -{ - struct ccio_device *ioa = ccio_list; /* FIXME : see Multi-IOC below */ - dma_addr_t iovp; - dma_addr_t offset; - u64 *pdir_start; - unsigned long hint = hint_lookup[direction]; - int idx; - - ASSERT(size > 0); - - /* save offset bits */ - offset = ((dma_addr_t) addr) & ~IOVP_MASK; - - /* round up to nearest IOVP_SIZE */ - size = (size + offset + IOVP_SIZE - 1) & IOVP_MASK; - - idx = ccio_alloc_range(ioa, size); - iovp = (dma_addr_t) MKIOVP(idx); - - DBG_RUN(__FUNCTION__ " 0x%p -> 0x%lx", addr, (long) iovp | offset); - - pdir_start = &(ioa->pdir_base[idx]); - - /* If not cacheline aligned, force SAFE_DMA on the whole mess */ - if ((size % L1_CACHE_BYTES) || ((unsigned long) addr % L1_CACHE_BYTES)) - hint |= HINT_SAFE_DMA; - - /* round up to nearest IOVP_SIZE */ - size = (size + IOVP_SIZE - 1) & IOVP_MASK; - - while (size > 0) { - - ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, addr, hint); - - DBG_RUN(" pdir %p %08x%08x\n", - pdir_start, - (u32) (((u32 *) pdir_start)[0]), - (u32) (((u32 *) pdir_start)[1]) - ); - addr += IOVP_SIZE; - size -= IOVP_SIZE; - pdir_start++; - } - /* form complete address */ - return CCIO_IOVA(iovp, offset); -} - - -static void ccio_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction) -{ -#ifdef FIXME -/* Multi-IOC (ie N-class) : need to lookup IOC from dev -** o If we can't know about lba PCI data structs, that eliminates ->sysdata. -** o walking up pcidev->parent dead ends at elroy too -** o leaves hashing dev->bus->number into some lookup. -** (may only work for N-class) -*/ - struct ccio_device *ioa = dev->sysdata -#else - struct ccio_device *ioa = ccio_list; -#endif - dma_addr_t offset; - - offset = iova & ~IOVP_MASK; - - /* round up to nearest IOVP_SIZE */ - size = (size + offset + IOVP_SIZE - 1) & IOVP_MASK; - - /* Mask off offset */ - iova &= IOVP_MASK; - - DBG_RUN(__FUNCTION__ " iovp 0x%lx\n", (long) iova); - -#ifdef DELAYED_RESOURCE_CNT - if (ioa->saved_cnt < DELAYED_RESOURCE_CNT) { - ioa->saved_iova[ioa->saved_cnt] = iova; - ioa->saved_size[ioa->saved_cnt] = size; - ccio_saved_cnt++; - } else { - do { -#endif - ccio_mark_invalid(ioa, iova, size); - ccio_free_range(ioa, iova, size); - -#ifdef DELAYED_RESOURCE_CNT - d->saved_cnt--; - iova = ioa->saved_iova[ioa->saved_cnt]; - size = ioa->saved_size[ioa->saved_cnt]; - } while (ioa->saved_cnt) - } -#endif -} - - -static void * ccio_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) -{ - void *ret; - unsigned long flags; - struct ccio_device *ioa = ccio_list; - - DBG_RUN(__FUNCTION__ " size 0x%x\n", size); - -#if 0 -/* GRANT Need to establish hierarchy for non-PCI devs as well -** and then provide matching gsc_map_xxx() functions for them as well. -*/ - if (!hwdev) { - /* only support PCI */ - *dma_handle = 0; - return 0; - } -#endif - spin_lock_irqsave(&ioa->ccio_lock, flags); - ccio_alloc_size += get_order(size); - spin_unlock_irqrestore(&ioa->ccio_lock, flags); - - ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size)); - - if (ret) { - memset(ret, 0, size); - *dma_handle = ccio_map_single(hwdev, ret, size, PCI_DMA_BIDIRECTIONAL); - } - DBG_RUN(__FUNCTION__ " ret %p\n", ret); - - return ret; -} - - -static void ccio_free_consistent (struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) -{ - unsigned long flags; - struct ccio_device *ioa = ccio_list; - - spin_lock_irqsave(&ioa->ccio_lock, flags); - ccio_free_size += get_order(size); - spin_unlock_irqrestore(&ioa->ccio_lock, flags); - - ccio_unmap_single(hwdev, dma_handle, size, 0); - free_pages((unsigned long) vaddr, get_order(size)); -} - - -static int ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) -{ - int tmp = nents; - - DBG_RUN(KERN_WARNING __FUNCTION__ " START\n"); - - /* KISS: map each buffer seperately. */ - while (nents) { - sg_dma_address(sglist) = ccio_map_single(dev, sglist->address, sglist->length, direction); - sg_dma_len(sglist) = sglist->length; - nents--; - sglist++; - } - - DBG_RUN(KERN_WARNING __FUNCTION__ " DONE\n"); - return tmp; -} - - -static void ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) -{ - DBG_RUN(KERN_WARNING __FUNCTION__ " : unmapping %d entries\n", nents); - while (nents) { - ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); - nents--; - sglist++; - } - return; -} - - -static struct pci_dma_ops ccio_ops = { - ccio_dma_supported, - ccio_alloc_consistent, - ccio_free_consistent, - ccio_map_single, - ccio_unmap_single, - ccio_map_sg, - ccio_unmap_sg, - NULL, /* dma_sync_single : NOP for U2/Uturn */ - NULL, /* dma_sync_sg : ditto */ -}; - -#if 0 -/* GRANT - is this needed for U2 or not? */ - -/* -** Get the size of the I/O TLB for this I/O MMU. -** -** If spa_shift is non-zero (ie probably U2), -** then calculate the I/O TLB size using spa_shift. -** -** Otherwise we are supposed to get the IODC entry point ENTRY TLB -** and execute it. However, both U2 and Uturn firmware supplies spa_shift. -** I think only Java (K/D/R-class too?) systems don't do this. -*/ -static int -ccio_get_iotlb_size(struct hp_device *d) -{ - if(d->spa_shift == 0) { - panic(__FUNCTION__ ": Can't determine I/O TLB size.\n"); - } - return(1 << d->spa_shift); -} -#else - -/* Uturn supports 256 TLB entries */ -#define CCIO_CHAINID_SHIFT 8 -#define CCIO_CHAINID_MASK 0xff - -#endif /* 0 */ - - -/* -** Figure out how big the I/O PDIR should be and alloc it. -** Also sets variables which depend on pdir size. -*/ -static void -ccio_alloc_pdir(struct ccio_device *ioa) -{ - extern unsigned long mem_max; /* arch.../setup.c */ - - u32 iova_space_size = 0; - void * pdir_base; - int pdir_size, iov_order; - - /* - ** Determine IOVA Space size from memory size. - ** Using "mem_max" is a kluge. - ** - ** Ideally, PCI drivers would register the maximum number - ** of DMA they can have outstanding for each device they - ** own. Next best thing would be to guess how much DMA - ** can be outstanding based on PCI Class/sub-class. Both - ** methods still require some "extra" to support PCI - ** Hot-Plug/Removal of PCI cards. (aka PCI OLARD). - */ - /* limit IOVA space size to 1MB-1GB */ - if (mem_max < (ccio_mem_ratio*1024*1024)) { - iova_space_size = 1024*1024; -#ifdef __LP64__ - } else if (mem_max > (ccio_mem_ratio*512*1024*1024)) { - iova_space_size = 512*1024*1024; -#endif - } else { - iova_space_size = (u32) (mem_max/ccio_mem_ratio); - } - - /* - ** iova space must be log2() in size. - ** thus, pdir/res_map will also be log2(). - */ - - /* We could use larger page sizes in order to *decrease* the number - ** of mappings needed. (ie 8k pages means 1/2 the mappings). - ** - ** Note: Grant Grunder says "Using 8k I/O pages isn't trivial either - ** since the pages must also be physically contiguous - typically - ** this is the case under linux." - */ - - iov_order = get_order(iova_space_size); - ASSERT(iov_order <= (30 - IOVP_SHIFT)); /* iova_space_size <= 1GB */ - ASSERT(iov_order >= (20 - IOVP_SHIFT)); /* iova_space_size >= 1MB */ - iova_space_size = 1 << (iov_order + IOVP_SHIFT); - - ioa->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64); - - ASSERT(pdir_size < 4*1024*1024); /* max pdir size < 4MB */ - - /* Verify it's a power of two */ - ASSERT((1 << get_order(pdir_size)) == (pdir_size >> PAGE_SHIFT)); - - DBG_INIT(__FUNCTION__ " hpa 0x%p mem %dMB IOV %dMB (%d bits)\n PDIR size 0x%0x", - ioa->ccio_hpa, (int) (mem_max>>20), iova_space_size>>20, - iov_order + PAGE_SHIFT, pdir_size); - - ioa->pdir_base = - pdir_base = (void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size)); - if (NULL == pdir_base) - { - panic(__FILE__ ":" __FUNCTION__ "() could not allocate I/O Page Table\n"); - } - memset(pdir_base, 0, pdir_size); - - ASSERT((((unsigned long) pdir_base) & PAGE_MASK) == (unsigned long) pdir_base); - - DBG_INIT(" base %p", pdir_base); - - /* - ** Chainid is the upper most bits of an IOVP used to determine - ** which TLB entry an IOVP will use. - */ - ioa->chainid_shift = get_order(iova_space_size)+PAGE_SHIFT-CCIO_CHAINID_SHIFT; - - DBG_INIT(" chainid_shift 0x%x\n", ioa->chainid_shift); -} - - -static void -ccio_hw_init(struct ccio_device *ioa) -{ - int i; - - /* - ** Initialize IOA hardware - */ - WRITE_U32(CCIO_CHAINID_MASK << ioa->chainid_shift, &ioa->ccio_hpa->io_chain_id_mask); - WRITE_U32(virt_to_phys(ioa->pdir_base), &ioa->ccio_hpa->io_pdir_base); - - - /* - ** Go to "Virtual Mode" - */ - WRITE_U32(IOA_NORMAL_MODE, &ioa->ccio_hpa->io_control); - - /* - ** Initialize all I/O TLB entries to 0 (Valid bit off). - */ - WRITE_U32(0, &ioa->ccio_hpa->io_tlb_entry_m); - WRITE_U32(0, &ioa->ccio_hpa->io_tlb_entry_l); - - for (i = 1 << CCIO_CHAINID_SHIFT; i ; i--) { - WRITE_U32((CMD_TLB_DIRECT_WRITE | (i << ioa->chainid_shift)), - &ioa->ccio_hpa->io_command); - } - -} - - -static void -ccio_resmap_init(struct ccio_device *ioa) -{ - u32 res_size; - - /* - ** Ok...we do more than just init resource map - */ - ioa->ccio_lock = SPIN_LOCK_UNLOCKED; - - ioa->res_hint = 16; /* next available IOVP - circular search */ - - /* resource map size dictated by pdir_size */ - res_size = ioa->pdir_size/sizeof(u64); /* entries */ - res_size >>= 3; /* convert bit count to byte count */ - DBG_INIT(__FUNCTION__ "() res_size 0x%x\n", res_size); - - ioa->res_size = res_size; - ioa->res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size)); - if (NULL == ioa->res_map) - { - panic(__FILE__ ":" __FUNCTION__ "() could not allocate resource map\n"); - } - memset(ioa->res_map, 0, res_size); -} - -/* CUJO20 KLUDGE start */ -static struct { - u16 hversion; - u8 spa; - u8 type; - u32 foo[3]; /* 16 bytes total */ -} cujo_iodc __attribute__ ((aligned (64))); -static unsigned long cujo_result[32] __attribute__ ((aligned (16))) = {0,0,0,0}; - -/* -** CUJO 2.0 incorrectly decodes a memory access for specific -** pages (every page at specific iotlb locations dependent -** upon where the cujo is flexed - diff on raven/firehawk. -** resulting in an hpmc and/or silent data corruption. -** Workaround is to prevent use of those I/O TLB entries -** by marking the suspect bitmap range entries as busy. -*/ -static void -ccio_cujo20_hack(struct ccio_device *ioa) -{ - unsigned long status; - unsigned int idx; - u8 *res_ptr = ioa->res_map; - u32 iovp=0x0; - unsigned long mask; - - status = pdc_iodc_read( &cujo_result, (void *) CUJO_RAVEN_LOC, 0, &cujo_iodc, 16); - if (status == 0) { - if (cujo_iodc.hversion==CUJO_20_BADHVERS) - iovp = CUJO_20_BADPAGE1; - } else { - status = pdc_iodc_read( &cujo_result, (void *) CUJO_FIREHAWK_LOC, 0, &cujo_iodc, 16); - if (status == 0) { - if (cujo_iodc.hversion==CUJO_20_BADHVERS) - iovp = CUJO_20_BADPAGE2; - } else { - /* not a defective system */ - return; - } - } - - printk(MODULE_NAME ": Cujo 2.0 bug needs a work around\n"); - ccio_cujo_bug = 1; - - /* - ** mark bit entries that match "bad page" - */ - idx = PDIR_INDEX(iovp)>>3; - mask = 0xff; - - while(idx * sizeof(u8) < ioa->res_size) { - res_ptr[idx] |= mask; - idx += (PDIR_INDEX(CUJO_20_STEP)>>3); - ccio_used_pages += 8; - ccio_used_bytes += 1; - } -} -/* CUJO20 KLUDGE end */ - -#ifdef CONFIG_PROC_FS -static int ccio_proc_info(char *buf, char **start, off_t offset, int len) -{ - unsigned long i = 0; - struct ccio_device *ioa = ccio_list; - unsigned long *res_ptr = (unsigned long *)ioa->res_map; - unsigned long total_pages = ioa->res_size << 3; /* 8 bits per byte */ - - sprintf(buf, "%s\nCujo 2.0 bug : %s\n", - parisc_getHWdescription(ioa->iodc->hw_type, ioa->iodc->hversion, - ioa->iodc->sversion), - (ccio_cujo_bug ? "yes" : "no")); - - sprintf(buf, "%sIO pdir size : %d bytes (%d entries)\n", - buf, ((ioa->res_size << 3) * sizeof(u64)), /* 8 bits per byte */ - ioa->res_size << 3); /* 8 bits per byte */ - - sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", - buf, ioa->res_size, ioa->res_size << 3); /* 8 bits per byte */ - - strcat(buf, " total: free: used: % used:\n"); - sprintf(buf, "%sblocks %8d %8ld %8ld %8ld%%\n", buf, ioa->res_size, - ioa->res_size - ccio_used_bytes, ccio_used_bytes, - (ccio_used_bytes * 100) / ioa->res_size); - - sprintf(buf, "%spages %8ld %8ld %8ld %8ld%%\n", buf, total_pages, - total_pages - ccio_used_pages, ccio_used_pages, - (ccio_used_pages * 100 / total_pages)); - - sprintf(buf, "%sconsistent %8ld %8ld\n", buf, - ccio_alloc_size, ccio_free_size); - - strcat(buf, "\nResource bitmap:\n"); - - for(; i < (ioa->res_size / sizeof(unsigned long)); ++i, ++res_ptr) - len += sprintf(buf, "%s%08lx ", buf, *res_ptr); - - strcat(buf, "\n"); - return strlen(buf); -} -#endif - -/* -** Determine if ccio should claim this chip (return 0) or not (return 1). -** If so, initialize the chip and tell other partners in crime they -** have work to do. -*/ -static int -ccio_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri) -{ - struct ccio_device *ioa; - - printk("%s found %s at 0x%p\n", dri->name, dri->version, d->hpa); - - if (ccio_list) { - printk(MODULE_NAME ": already initialized one device\n"); - return(0); - } - - ioa = kmalloc(sizeof(struct ccio_device), GFP_KERNEL); - if (NULL == ioa) - { - printk(MODULE_NAME " - couldn't alloc ccio_device\n"); - return(1); - } - memset(ioa, 0, sizeof(struct ccio_device)); - - /* - ** ccio list is used mainly as a kluge to support a single instance. - ** Eventually, with core dumps, it'll be useful for debugging. - */ - ccio_list = ioa; - ioa->iodc = d; - -#if 1 -/* KLUGE: determine IOA hpa based on GSC port value. -** Needed until we have a PA bus walk. Can only discover IOA via -** walking the architected PA MMIO space as described by the I/O ACD. -** "Legacy" PA Firmware only tells us about unarchitected devices -** that can't be detected by PA/EISA/PCI bus walks. -*/ - switch((long) d->hpa) { - case 0xf3fbf000L: /* C110 IOA0 LBC (aka GSC port) */ - /* ccio_hpa same as C200 IOA0 */ - case 0xf203f000L: /* C180/C200/240/C360 IOA0 LBC (aka GSC port) */ - ioa->ccio_hpa = (struct ioa_registers *) 0xfff88000L; - break; - case 0xf103f000L: /* C180/C200/240/C360 IOA1 LBC (aka GSC port) */ - ioa->ccio_hpa = (struct ioa_registers *) 0xfff8A000L; - break; - default: - panic("ccio-dma.c doesn't know this GSC port Address!\n"); - break; - }; -#else - ioa->ccio_hpa = d->hpa; -#endif - - ccio_alloc_pdir(ioa); - ccio_hw_init(ioa); - ccio_resmap_init(ioa); - - /* CUJO20 KLUDGE start */ - ccio_cujo20_hack(ioa); - /* CUJO20 KLUDGE end */ - - hppa_dma_ops = &ccio_ops; - - create_proc_info_entry(MODULE_NAME, 0, proc_runway_root, ccio_proc_info); - return(0); -} - - - diff -Nru a/arch/parisc/kernel/ccio-rm-dma.c b/arch/parisc/kernel/ccio-rm-dma.c --- a/arch/parisc/kernel/ccio-rm-dma.c Mon Nov 4 14:31:01 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,212 +0,0 @@ -/* - * ccio-rm-dma.c: - * DMA management routines for first generation cache-coherent machines. - * "Real Mode" operation refers to U2/Uturn chip operation. The chip - * can perform coherency checks w/o using the I/O MMU. That's all we - * need until support for more than 4GB phys mem is needed. - * - * This is the trivial case - basically what x86 does. - * - * Drawbacks of using Real Mode are: - * o outbound DMA is slower since one isn't using the prefetching - * U2 can do for outbound DMA. - * o Ability to do scatter/gather in HW is also lost. - * o only known to work with PCX-W processor. (eg C360) - * (PCX-U/U+ are not coherent with U2 in real mode.) - * - * - * 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. - * - * - * Original version/author: - * CVSROOT=:pserver:anonymous@198.186.203.37:/cvsroot/linux-parisc - * cvs -z3 co linux/arch/parisc/kernel/dma-rm.c - * - * (C) Copyright 2000 Philipp Rumpf - * - * - * Adopted for The Puffin Group's parisc-linux port by Grant Grundler. - * (C) Copyright 2000 Grant Grundler - * - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -/* Only chose "ccio" since that's what HP-UX calls it.... -** Make it easier for folks to migrate from one to the other :^) -*/ -#define MODULE_NAME "ccio" - -#define U2_IOA_RUNWAY 0x580 -#define U2_BC_GSC 0x501 -#define UTURN_IOA_RUNWAY 0x581 -#define UTURN_BC_GSC 0x502 - -static int ccio_driver_callback(struct hp_device *, struct pa_iodc_driver *); - -static struct pa_iodc_driver ccio_drivers_for[] = { - - {HPHW_BCPORT, U2_BC_GSC, 0x0, 0xb, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "U2 I/O MMU", (void *) ccio_driver_callback}, - - {HPHW_BCPORT, UTURN_BC_GSC, 0x0, 0xb, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "Uturn I/O MMU", (void *) ccio_driver_callback}, - - {0,0,0,0,0,0, - 0, - (char *) NULL, (char *) NULL, (void *) NULL } -}; - - -#define IS_U2(id) ( \ - (((id)->hw_type == HPHW_IOA) && ((id)->hversion == U2_IOA_RUNWAY)) || \ - (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == U2_BC_GSC)) \ -) - -#define IS_UTURN(id) ( \ - (((id)->hw_type == HPHW_IOA) && ((id)->hversion == UTURN_IOA_RUNWAY)) || \ - (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == UTURN_BC_GSC)) \ -) - - -void __init ccio_init(void) -{ - register_driver(ccio_drivers_for); -} - - -static int ccio_dma_supported( struct pci_dev *dev, u64 mask) -{ - if (dev == NULL) { - printk(MODULE_NAME ": EISA/ISA/et al not supported\n"); - BUG(); - return(0); - } - - dev->dma_mask = mask; /* save it */ - - /* only support 32-bit devices (ie PCI/GSC) */ - return((int) (mask >= 0xffffffffUL)); -} - - -static void *ccio_alloc_consistent(struct pci_dev *dev, size_t size, - dma_addr_t *handle) -{ - void *ret; - - ret = (void *)__get_free_pages(GFP_ATOMIC, get_order(size)); - - if (ret != NULL) { - memset(ret, 0, size); - *handle = virt_to_phys(ret); - } - return ret; -} - -static void ccio_free_consistent(struct pci_dev *dev, size_t size, - void *vaddr, dma_addr_t handle) -{ - free_pages((unsigned long)vaddr, get_order(size)); -} - -static dma_addr_t ccio_map_single(struct pci_dev *dev, void *ptr, size_t size, - int direction) -{ - return virt_to_phys(ptr); -} - -static void ccio_unmap_single(struct pci_dev *dev, dma_addr_t dma_addr, - size_t size, int direction) -{ - /* Nothing to do */ -} - - -static int ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) -{ - int tmp = nents; - - /* KISS: map each buffer seperately. */ - while (nents) { - sg_dma_address(sglist) = ccio_map_single(dev, sglist->address, sglist->length, direction); - sg_dma_len(sglist) = sglist->length; - nents--; - sglist++; - } - - return tmp; -} - - -static void ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) -{ -#if 0 - while (nents) { - ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); - nents--; - sglist++; - } - return; -#else - /* Do nothing (copied from current ccio_unmap_single() :^) */ -#endif -} - - -static struct pci_dma_ops ccio_ops = { - ccio_dma_supported, - ccio_alloc_consistent, - ccio_free_consistent, - ccio_map_single, - ccio_unmap_single, - ccio_map_sg, - ccio_unmap_sg, - NULL, /* dma_sync_single : NOP for U2 */ - NULL, /* dma_sync_sg : ditto */ - - -}; - - -/* -** Determine if u2 should claim this chip (return 0) or not (return 1). -** If so, initialize the chip and tell other partners in crime they -** have work to do. -*/ -static int -ccio_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri) -{ - printk("%s found %s at 0x%p\n", dri->name, dri->version, d->hpa); - -/* -** FIXME - should check U2 registers to verify it's really running -** in "Real Mode". -*/ - -#if 0 -/* will need this for "Virtual Mode" operation */ - ccio_hw_init(ccio_dev); - ccio_common_init(ccio_dev); -#endif - hppa_dma_ops = &ccio_ops; - return 0; -} diff -Nru a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c --- a/arch/parisc/kernel/drivers.c Mon Nov 4 14:31:02 2002 +++ b/arch/parisc/kernel/drivers.c Mon Nov 4 14:31:02 2002 @@ -23,7 +23,6 @@ #include #include #include -#include /* See comments in include/asm-parisc/pci.h */ struct pci_dma_ops *hppa_dma_ops; diff -Nru a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S --- a/arch/parisc/kernel/entry.S Mon Nov 4 14:31:01 2002 +++ b/arch/parisc/kernel/entry.S Mon Nov 4 14:31:01 2002 @@ -502,7 +502,6 @@ .import handle_real_interruption,code .import do_cpu_irq_mask,code .import parisc_stopkernel,code - .import cpu_irq_region,data /* * r26 = function to be called @@ -515,6 +514,7 @@ */ #define CLONE_VM 0x100 /* Must agree with */ +#define CLONE_UNTRACED 0x00800000 .export __kernel_thread, code .import do_fork @@ -528,23 +528,29 @@ ldd 24(%r26), %r2 STREG %r2, PT_GR27(%r1) /* Store childs %dp */ ldd 16(%r26), %r26 + + STREG %r22, PT_GR22(%r1) /* Store childs %dp */ + copy %r0, %r22 /* user_tid */ #endif STREG %r26, PT_GR26(%r1) /* Store function & argument for child */ STREG %r25, PT_GR25(%r1) - ldo CLONE_VM(%r0), %r26 /* Force CLONE_VM since only init_mm */ + ldil L%CLONE_UNTRACED, %r26 + ldo CLONE_VM(%r26), %r26 /* Force CLONE_VM since only init_mm */ or %r26, %r24, %r26 /* will have kernel mappings. */ - copy %r0, %r25 + copy %r0, %r25 /* stack_start */ + stw %r0, -52(%r30) /* user_tid */ #ifdef __LP64__ ldo -16(%r30),%r29 /* Reference param save area */ #endif bl do_fork, %r2 - copy %r1, %r24 + copy %r1, %r24 /* pt_regs */ /* Parent Returns here */ LDREG -PT_SZ_ALGN-RP_OFFSET(%r30), %r2 - bv %r0(%r2) ldo -PT_SZ_ALGN(%r30), %r30 + bv %r0(%r2) + ldw TASK_PID(%r28), %r28 /* * Child Returns here @@ -566,6 +572,7 @@ LDREG TASK_PT_GR25(%r1), %r26 #ifdef __LP64__ LDREG TASK_PT_GR27(%r1), %r27 + LDREG TASK_PT_GR22(%r1), %r22 #endif LDREG TASK_PT_GR26(%r1), %r1 ble 0(%sr7, %r1) @@ -785,10 +792,10 @@ .import schedule,code intr_do_resched: /* Only do reschedule if we are returning to user space */ - LDREG PT_IASQ0(%r16), %r20 + LDREG PT_IASQ0(%r16), %r20 CMPIB= 0,%r20,intr_restore /* backward */ nop - LDREG PT_IASQ1(%r16), %r20 + LDREG PT_IASQ1(%r16), %r20 CMPIB= 0,%r20,intr_restore /* backward */ nop @@ -796,28 +803,29 @@ ldo -16(%r30),%r29 /* Reference param save area */ #endif - ldil L%intr_return, %r2 + ldil L%intr_check_sig, %r2 b schedule - ldo R%intr_return(%r2), %r2 /* return to intr_return, not here */ + ldo R%intr_check_sig(%r2), %r2 .import do_signal,code intr_do_signal: /* Only do signals if we are returning to user space */ - LDREG PT_IASQ0(%r16), %r20 + LDREG PT_IASQ0(%r16), %r20 CMPIB= 0,%r20,intr_restore /* backward */ nop - LDREG PT_IASQ1(%r16), %r20 + LDREG PT_IASQ1(%r16), %r20 CMPIB= 0,%r20,intr_restore /* backward */ nop copy %r0, %r24 /* unsigned long in_syscall */ copy %r16, %r25 /* struct pt_regs *regs */ - ssm PSW_SM_I, %r0 #ifdef __LP64__ ldo -16(%r30),%r29 /* Reference param save area */ #endif -#warning TAUSQ FIXME, this is wrong + +#warning TAUSQ FIXME - review 2.5 signal return path changes + bl do_signal,%r2 copy %r0, %r26 /* sigset_t *oldset = NULL */ @@ -860,26 +868,19 @@ loadgp - copy %r29, %r25 /* arg1 is pt_regs */ + copy %r29, %r26 /* arg0 is pt_regs */ copy %r29, %r16 /* save pt_regs */ + ldil L%intr_return, %r2 + #ifdef __LP64__ ldo -16(%r30),%r29 /* Reference param save area */ -#else - nop #endif - - /* - * We need to either load the CPU's ID or IRQ region. - * Until we have "per CPU" IRQ regions, this is easy. - */ - ldil L%cpu_irq_region, %r26 - ldil L%intr_return, %r2 - ldo R%cpu_irq_region(%r26), %r26 - + b do_cpu_irq_mask ldo R%intr_return(%r2), %r2 /* return to intr_return, not here */ + /* Generic interruptions (illegal insn, unaligned, page fault, etc) */ .export intr_save, code /* for os_hpmc */ @@ -953,11 +954,11 @@ ldo -16(%r30),%r29 /* Reference param save area */ #endif - ldil L%intr_return, %r2 + ldil L%intr_restore, %r2 copy %r25, %r16 /* save pt_regs */ b handle_interruption - ldo R%intr_return(%r2), %r2 /* return to intr_return */ + ldo R%intr_restore(%r2), %r2 /* diff -Nru a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c --- a/arch/parisc/kernel/hardware.c Mon Nov 4 14:31:01 2002 +++ b/arch/parisc/kernel/hardware.c Mon Nov 4 14:31:01 2002 @@ -403,7 +403,7 @@ {HPHW_BA, 0x01B, 0x00078, 0x0, "Anole 100 VME BA"}, {HPHW_BA, 0x024, 0x00078, 0x0, "Fast Pace VME BA"}, {HPHW_BA, 0x034, 0x00078, 0x0, "Anole T VME BA"}, - {HPHW_BA, 0x04A, 0x00078, 0x0, "Anole L2 132 BME BA"}, + {HPHW_BA, 0x04A, 0x00078, 0x0, "Anole L2 132 VME BA"}, {HPHW_BA, 0x04C, 0x00078, 0x0, "Anole L2 165 VME BA"}, {HPHW_BA, 0x011, 0x00081, 0x0, "WB-96 Core BA"}, {HPHW_BA, 0x012, 0x00081, 0x0, "Orville UX Core BA"}, @@ -805,8 +805,8 @@ {HPHW_FIO, 0x04E, 0x0007B, 0x0, "Kiji L2 132 Core Audio"}, {HPHW_FIO, 0x050, 0x0007B, 0x0, "Merlin Jr 132 Core Audio"}, {HPHW_FIO, 0x051, 0x0007B, 0x0, "Firehawk Audio"}, - {HPHW_FIO, 0x056, 0x0007B, 0x0, "Raven+ w SE FWSCSU Core Audio"}, - {HPHW_FIO, 0x057, 0x0007B, 0x0, "Raven+ w Diff FWSCSU Core Audio"}, + {HPHW_FIO, 0x056, 0x0007B, 0x0, "Raven+ w SE FWSCSI Core Audio"}, + {HPHW_FIO, 0x057, 0x0007B, 0x0, "Raven+ w Diff FWSCSI Core Audio"}, {HPHW_FIO, 0x058, 0x0007B, 0x0, "FireHawk 200 Audio"}, {HPHW_FIO, 0x05C, 0x0007B, 0x0, "SummitHawk 230 Core Audio"}, {HPHW_FIO, 0x800, 0x0007B, 0x0, "Hitachi Tiny 64 Audio"}, diff -Nru a/arch/parisc/kernel/iosapic.c b/arch/parisc/kernel/iosapic.c --- a/arch/parisc/kernel/iosapic.c Mon Nov 4 14:31:01 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1100 +0,0 @@ -/* -** I/O Sapic Driver - PCI interrupt line support -** -** (c) Copyright 1999 Grant Grundler -** (c) Copyright 1999 Hewlett-Packard Company -** -** 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. -** -** The I/O sapic driver manages the Interrupt Redirection Table which is -** the control logic to convert PCI line based interrupts into a Message -** Signaled Interrupt (aka Transaction Based Interrupt, TBI). -** -** Acronyms -** -------- -** HPA Hard Physical Address (aka MMIO address) -** IRQ Interrupt ReQuest. Implies Line based interrupt. -** IRT Interrupt Routing Table (provided by PAT firmware) -** IRdT Interrupt Redirection Table. IRQ line to TXN ADDR/DATA -** table which is implemented in I/O SAPIC. -** ISR Interrupt Service Routine. aka Interrupt handler. -** MSI Message Signaled Interrupt. PCI 2.2 functionality. -** aka Transaction Based Interrupt (or TBI). -** PA Precision Architecture. HP's RISC architecture. -** RISC Reduced Instruction Set Computer. -** -** -** What's a Message Signalled Interrupt? -** ------------------------------------- -** MSI is a write transaction which targets a processor and is similar -** to a processor write to memory or MMIO. MSIs can be generated by I/O -** devices as well as processors and require *architecture* to work. -** -** PA only supports MSI. So I/O subsystems must either natively generate -** MSIs (e.g. GSC or HP-PB) or convert line based interrupts into MSIs -** (e.g. PCI and EISA). IA64 supports MSIs via a "local SAPIC" which -** acts on behalf of a processor. -** -** MSI allows any I/O device to interrupt any processor. This makes -** load balancing of the interrupt processing possible on an SMP platform. -** Interrupts are also ordered WRT to DMA data. It's possible on I/O -** coherent systems to completely eliminate PIO reads from the interrupt -** path. The device and driver must be designed and implemented to -** guarantee all DMA has been issued (issues about atomicity here) -** before the MSI is issued. I/O status can then safely be read from -** DMA'd data by the ISR. -** -** -** PA Firmware -** ----------- -** PA-RISC platforms have two fundementally different types of firmware. -** For PCI devices, "Legacy" PDC initializes the "INTERRUPT_LINE" register -** and BARs similar to a traditional PC BIOS. -** The newer "PAT" firmware supports PDC calls which return tables. -** PAT firmware only initializes PCI Console and Boot interface. -** With these tables, the OS can progam all other PCI devices. -** -** One such PAT PDC call returns the "Interrupt Routing Table" (IRT). -** The IRT maps each PCI slot's INTA-D "output" line to an I/O SAPIC -** input line. If the IRT is not available, this driver assumes -** INTERRUPT_LINE register has been programmed by firmware. The latter -** case also means online addition of PCI cards can NOT be supported -** even if HW support is present. -** -** All platforms with PAT firmware to date (Oct 1999) use one Interrupt -** Routing Table for the entire platform. -** -** Where's the iosapic? -** -------------------- -** I/O sapic is part of the "Core Electronics Complex". And on HP platforms -** it's integrated as part of the PCI bus adapter, "lba". So no bus walk -** will discover I/O Sapic. I/O Sapic driver learns about each device -** when lba driver advertises the presence of the I/O sapic by calling -** iosapic_register(). -** -** -** IRQ region notes -** ---------------- -** The data passed to iosapic_interrupt() is per IRQ line. -** Each IRQ line will get one txn_addr/data pair. Thus each IRQ region, -** will have several txn_addr/data pairs (up to 7 for current I/O SAPIC -** implementations). The IRQ region "sysdata" will NOT be directly passed -** to the interrupt handler like GSCtoPCI (dino.c). -** -** iosapic interrupt handler will NOT call do_irq_mask(). -** It doesn't need to read a bit mask to determine which IRQ line was pulled -** since it already knows based on vector_info passed to iosapic_interrupt(). -** -** One IRQ number represents both an IRQ line and a driver ISR. -** The I/O sapic driver can't manage shared IRQ lines because -** additional data besides the IRQ number must be passed via -** irq_region_ops. do_irq() and request_irq() must manage -** a sharing a bit in the mask. -** -** iosapic_interrupt() replaces do_irq_mask() and calls do_irq(). -** Which IRQ line was asserted is already known since each -** line has unique data associated with it. We could omit -** iosapic_interrupt() from the calling path if it did NOT need -** to write EOI. For unshared lines, it really doesn't. -** -** Unfortunately, can't optimize out EOI if IRQ line isn't "shared". -** N-class console "device" and some sort of heartbeat actually share -** one line though only one driver is registered......this was -** true for HP-UX at least. May not be true for parisc-linux. -** -** -** Overview of exported iosapic functions -** -------------------------------------- -** (caveat: code isn't finished yet - this is just the plan) -** -** iosapic_init: -** o initialize globals (lock, etc) -** o try to read IRT. Presence of IRT determines if this is -** a PAT platform or not. -** -** iosapic_register(): -** o create iosapic_info instance data structure -** o allocate vector_info array for this iosapic -** o initialize vector_info - read corresponding IRdT? -** -** iosapic_xlate_pin: (only called by fixup_irq for PAT platform) -** o intr_pin = read cfg (INTERRUPT_PIN); -** o if (device under PCI-PCI bridge) -** translate slot/pin -** -** iosapic_fixup_irq: -** o if PAT platform (IRT present) -** intr_pin = iosapic_xlate_pin(isi,pcidev): -** intr_line = find IRT entry(isi, PCI_SLOT(pcidev), intr_pin) -** save IRT entry into vector_info later -** write cfg INTERRUPT_LINE (with intr_line)? -** else -** intr_line = pcidev->irq -** IRT pointer = NULL -** endif -** o locate vector_info (needs: isi, intr_line) -** o allocate processor "irq" and get txn_addr/data -** o request_irq(processor_irq, iosapic_interrupt, vector_info,...) -** o pcidev->irq = isi->isi_region...base + intr_line; -** -** iosapic_interrupt: -** o call do_irq(vector->isi->irq_region, vector->irq_line, regs) -** o assume level triggered and write EOI -** -** iosapic_enable_irq: -** o clear any pending IRQ on that line -** o enable IRdT - call enable_irq(vector[line]->processor_irq) -** o write EOI in case line is already asserted. -** -** iosapic_disable_irq: -** o disable IRdT - call disable_irq(vector[line]->processor_irq) -** -** FIXME: mask/unmask -*/ - - -/* FIXME: determine which include files are really needed */ -#include -#include -#include -#include /* pci cfg accessor functions */ -#include -#include -#include -#include /* irqaction */ -#include /* irq_region support */ - -#include /* get in-line asm for swab */ -#include -#include -#include -#include -#include -#include /* gsc_read/write functions */ - -#include -#include "./iosapic_private.h" - -#define MODULE_NAME "iosapic" - -/* "local" compile flags */ -#undef IOSAPIC_CALLBACK -#undef PCI_BRIDGE_FUNCS -#undef DEBUG_IOSAPIC -#undef DEBUG_IOSAPIC_IRT - - -#ifdef DEBUG_IOSAPIC -static char assert_buf[128]; - -static int -assert_failed (char *a, char *f, int l) -{ - sprintf(assert_buf, - "ASSERT(%s) failed!\nline %d in %s\n", - a, /* assertion text */ - l, /* line number */ - f); /* file name */ - panic(assert_buf); - return 0; -} - -#undef ASSERT -#define ASSERT(EX) { if (!(EX)) assert_failed(# EX, __FILE__, __LINE__); } - -#define DBG(x...) printk(x) - -#else /* DEBUG_IOSAPIC */ - -#define DBG(x...) -#define ASSERT(EX) - -#endif /* DEBUG_IOSAPIC */ - -#ifdef DEBUG_IOSAPIC_IRT -#define DBG_IRT(x...) printk(x) -#else -#define DBG_IRT(x...) -#endif - - -#define READ_U8(addr) gsc_readb(addr) -#define READ_U16(addr) le16_to_cpu(gsc_readw((u16 *) (addr))) -#define READ_U32(addr) le32_to_cpu(gsc_readl((u32 *) (addr))) -#define READ_REG16(addr) gsc_readw((u16 *) (addr)) -#define READ_REG32(addr) gsc_readl((u32 *) (addr)) -#define WRITE_U8(value, addr) gsc_writeb(value, addr) -#define WRITE_U16(value, addr) gsc_writew(cpu_to_le16(value), (u16 *) (addr)) -#define WRITE_U32(value, addr) gsc_writel(cpu_to_le32(value), (u32 *) (addr)) -#define WRITE_REG16(value, addr) gsc_writew(value, (u16 *) (addr)) -#define WRITE_REG32(value, addr) gsc_writel(value, (u32 *) (addr)) - - -#define IOSAPIC_REG_SELECT 0 -#define IOSAPIC_REG_WINDOW 0x10 -#define IOSAPIC_REG_EOI 0x40 - -#define IOSAPIC_REG_VERSION 0x1 - -#define IOSAPIC_IRDT_ENTRY(idx) (0x10+(idx)*2) -#define IOSAPIC_IRDT_ENTRY_HI(idx) (0x11+(idx)*2) - -/* -** FIXME: revisit which GFP flags we should really be using. -** GFP_KERNEL includes __GFP_WAIT flag and that may not -** be acceptable. Since this is boot time, we shouldn't have -** to wait ever and this code should (will?) never get called -** from the interrrupt context. -*/ -#define IOSAPIC_KALLOC(a_type, cnt) \ - (a_type *) kmalloc(sizeof(a_type)*(cnt), GFP_KERNEL) -#define IOSAPIC_FREE(addr, f_type, cnt) kfree((void *)addr) - - -#define IOSAPIC_LOCK(lck) spin_lock_irqsave(lck, irqflags) -#define IOSAPIC_UNLOCK(lck) spin_unlock_irqrestore(lck, irqflags) - - -#define IOSAPIC_VERSION_MASK 0x000000ff -#define IOSAPIC_VERSION_SHIFT 0x0 -#define IOSAPIC_VERSION(ver) \ - (int) ((ver & IOSAPIC_VERSION_MASK) >> IOSAPIC_VERSION_SHIFT) - -#define IOSAPIC_MAX_ENTRY_MASK 0x00ff0000 - -#define IOSAPIC_MAX_ENTRY_SHIFT 0x10 -#define IOSAPIC_IRDT_MAX_ENTRY(ver) \ - (int) ((ver&IOSAPIC_MAX_ENTRY_MASK) >> IOSAPIC_MAX_ENTRY_SHIFT) - -/* bits in the "low" I/O Sapic IRdT entry */ -#define IOSAPIC_IRDT_ENABLE 0x10000 -#define IOSAPIC_IRDT_PO_LOW 0x02000 -#define IOSAPIC_IRDT_LEVEL_TRIG 0x08000 -#define IOSAPIC_IRDT_MODE_LPRI 0x00100 - -/* bits in the "high" I/O Sapic IRdT entry */ -#define IOSAPIC_IRDT_ID_EID_SHIFT 0x10 - - - -#define IOSAPIC_EOI(eoi_addr, eoi_data) gsc_writel(eoi_data, eoi_addr) - -#if IOSAPIC_CALLBACK -/* -** Shouldn't use callback since SAPIC doesn't have an officially assigned -** H or S version numbers. Slight long term risk the number chosen would -** collide with something else. -** But benefit is cleaner lba/sapic interface. -** Might be worth it but for just use direct calls for now. -** -** Entry below is copied from lba driver. -** Only thing different is hw_type. -*/ -static struct pa_iodc_driver iosapic_driver_for[] = { - {HPHW_OTHER, 0x782, 0, 0x0000A, 0, 0x00, - DRIVER_CHECK_HWTYPE + DRIVER_CHECK_HVERSION + DRIVER_CHECK_SVERSION, - "I/O Sapic", "",(void *) iosapic_callback}, - {0,0,0,0,0,0, - 0, - (char *) NULL,(char *) NULL,(void *) NULL} -}; -#endif /* IOSAPIO_CALLBACK */ - - -static struct iosapic_info *iosapic_list; -static spinlock_t iosapic_lock; -static int iosapic_count; - - -/* -** REVISIT: future platforms may have more than one IRT. -** If so, the following three fields form a structure which -** then be linked into a list. Names are chosen to make searching -** for them easy - not necessarily accurate (eg "cell"). -** -** Alternative: iosapic_info could point to the IRT it's in. -** iosapic_register() could search a list of IRT's. -*/ -static struct irt_entry *irt_cell; -static size_t irt_num_entry; - - - -/* -** iosapic_load_irt -** -** The "Get PCI INT Routing Table Size" option returns the number of -** entries in the PCI interrupt routing table for the cell specified -** in the cell_number argument. The cell number must be for a cell -** within the caller's protection domain. -** -** The "Get PCI INT Routing Table" option returns, for the cell -** specified in the cell_number argument, the PCI interrupt routing -** table in the caller allocated memory pointed to by mem_addr. -** We assume the IRT only contains entries for I/O SAPIC and -** calculate the size based on the size of I/O sapic entries. -** -** The PCI interrupt routing table entry format is derived from the -** IA64 SAL Specification 2.4. The PCI interrupt routing table defines -** the routing of PCI interrupt signals between the PCI device output -** "pins" and the IO SAPICs' input "lines" (including core I/O PCI -** devices). This table does NOT include information for devices/slots -** behind PCI to PCI bridges. See PCI to PCI Bridge Architecture Spec. -** for the architected method of routing of IRQ's behind PPB's. -*/ - - -static int __init /* return number of entries as success/fail flag */ -iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt) -{ - struct pdc_pat_io_num pdc_io_num; /* PAT PDC return block */ - long status; /* PDC return value status */ - struct irt_entry *table = NULL; /* start of interrupt routing tbl */ - unsigned long num_entries = 0UL; - - ASSERT(NULL != irt); - /* FIXME ASSERT(((&pdc_io_num) & (0x3f)) == 0); enforce 32-byte alignment */ - - /* Try PAT_PDC to get interrupt routing table size */ - DBG(KERN_DEBUG "calling get_irt_size\n"); - status = pdc_pat_get_irt_size( &pdc_io_num, cell_num); - DBG(KERN_DEBUG "get_irt_size: %ld\n", status); - - switch(status) { - - case PDC_RET_OK: /* PAT box. Proceed to get the IRT */ - - /* save the number of entries in the table */ - num_entries = pdc_io_num.num; - ASSERT(0UL != num_entries); - - /* - ** allocate memory for interrupt routing table - ** This interface isn't really right. We are assuming - ** the contents of the table are exclusively - ** for I/O sapic devices. - */ - table = IOSAPIC_KALLOC(struct irt_entry, num_entries); - if (table == NULL) { - printk(KERN_WARNING MODULE_NAME ": read_irt : can not alloc mem for IRT\n"); - return 0; - } - - /* get PCI INT routing table */ - status = pdc_pat_get_irt( (void *) table, cell_num); - DBG(KERN_DEBUG "pdc_pat_get_irt: %ld\n", status); - ASSERT(status == PDC_RET_OK); - break; - - case PDC_RET_NE_PROC: /* Not a PAT platform. Try PDC_PCI extensions */ - /* - ** C3000/J5000 (and similar) platforms with "legacy" PDC - ** will return exactly one IRT. - ** So if we have one, don't need to get it again. - */ - if (NULL != irt_cell) - break; - - status = pdc_pci_irt_size( (void *)&pdc_io_num, - /* elroy HPA (really a NOP) */ 0); - DBG(KERN_WARNING "pdc_pci_irt_size: %ld\n", status); - - if (PDC_RET_OK != status) { - /* Not a "legacy" system with I/O SAPIC either */ - return 0; - } - - num_entries = pdc_io_num.num; - ASSERT(0UL != num_entries); - - table = IOSAPIC_KALLOC(struct irt_entry, num_entries); - if (table == NULL) { - printk(KERN_WARNING MODULE_NAME ": read_irt : can not alloc mem for IRT\n"); - return 0; - } - - status = pdc_pci_irt( (void *) &pdc_io_num, - (void *) NULL, /* Elroy HPA - not used */ - (void *) table); - - ASSERT(PDC_RET_OK == status); - break; - - default: - printk(KERN_WARNING MODULE_NAME ": PDC_PAT_IO call failed with %ld\n", status); - break; - } - - /* return interrupt table address */ - *irt = table; - - -#ifdef DEBUG_IOSAPIC_IRT - { - struct irt_entry *p = table; - int i; - - printk(MODULE_NAME " Interrupt Routing Table (cell %ld)\n", cell_num); - printk(MODULE_NAME " start = 0x%p num_entries %ld entry_size %d\n", - table, - num_entries, - (int) sizeof(struct irt_entry)); - - for (i = 0 ; i < num_entries ; i++, p++) - { - printk(MODULE_NAME " %02x %02x %02x %02x %02x %02x %02x %02x %08x%08x\n", - p->entry_type, p->entry_length, p->interrupt_type, - p->polarity_trigger, p->src_bus_irq_devno, p->src_bus_id, - p->src_seg_id, p->dest_iosapic_intin, - ((u32 *) p)[2], - ((u32 *) p)[3] - ); - } - } -#endif /* DEBUG_IOSAPIC_IRT */ - - return num_entries; -} - - - -void __init -iosapic_init(void) -{ - /* init global data */ - iosapic_lock = SPIN_LOCK_UNLOCKED; - iosapic_list = (struct iosapic_info *) NULL; - iosapic_count = 0; - - DBG("iosapic_init()\n"); - - /* - ** get IRT for this cell. - */ - irt_num_entry = iosapic_load_irt(0L, &irt_cell); - if (0 == irt_num_entry) - irt_cell = NULL; /* old PDC w/o iosapic */ - -#ifdef IOSAPIC_CALLBACK - /* - ** When new I/O SAPICs are discovered, this callback - ** will get invoked. Implies lba driver will register - ** I/O Sapic as a device it "discovered" with faked - ** IODC data. - */ - register_driver(iosapic_driver_for); -#endif /* IOSAPIC_CALLBACK */ -} - - -/* -** Return the IRT entry in case we need to look something else up. -*/ -static struct irt_entry * -irt_find_irqline(struct iosapic_info *isi, u8 slot, u8 intr_pin) -{ - struct irt_entry *i = irt_cell; - int cnt; /* track how many entries we've looked at */ - u8 irq_devno = (slot << IRT_DEV_SHIFT) | (intr_pin-1); - - DBG_IRT("irt_find_irqline() SLOT %d pin %d\n", slot, intr_pin); - - for (cnt=0; cnt < irt_num_entry; cnt++, i++) { - - /* - ** Validate: entry_type, entry_length, interrupt_type - ** - ** Difference between validate vs compare is the former - ** should print debug info and is not expected to "fail" - ** on current platforms. - */ - if (i->entry_type != IRT_IOSAPIC_TYPE) { - DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d type %d\n", i, cnt, i->entry_type); - continue; - } - - if (i->entry_length != IRT_IOSAPIC_LENGTH) { - DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d length %d\n", i, cnt, i->entry_length); - continue; - } - - if (i->interrupt_type != IRT_VECTORED_INTR) { - DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d interrupt_type %d\n", i, cnt, i->interrupt_type); - continue; - } - - /* - ** Compare: dest_iosapic_addr, src_bus_irq_devno - */ - if (i->dest_iosapic_addr != (u64) ((long) isi->isi_hpa)) - continue; - - if ((i->src_bus_irq_devno & IRT_IRQ_DEVNO_MASK) != irq_devno) - continue; - - /* - ** Ignore: src_bus_id and rc_seg_id correlate with - ** iosapic_info->isi_hpa on HP platforms. - ** If needed, pass in "PFA" (aka config space addr) - ** instead of slot. - */ - - /* Found it! */ - return i; - } - - printk(KERN_WARNING MODULE_NAME ": 0x%p : no IRT entry for slot %d, pin %d\n", - isi->isi_hpa, slot, intr_pin); - return NULL; -} - - -/* -** xlate_pin() supports the skewing of IRQ lines done by subsidiary bridges. -** Legacy PDC already does this translation for us and stores it in INTR_LINE. -** -** PAT PDC needs to basically do what legacy PDC does: -** o read PIN -** o adjust PIN in case device is "behind" a PPB -** (eg 4-port 100BT and SCSI/LAN "Combo Card") -** o convert slot/pin to I/O SAPIC input line. -** -** HP platforms only support: -** o one level of skewing for any number of PPBs -** o only support PCI-PCI Bridges. -*/ -static struct irt_entry * -iosapic_xlate_pin(struct iosapic_info *isi, struct pci_dev *pcidev) -{ - u8 intr_pin, intr_slot; - - (void) pci_read_config_byte(pcidev, PCI_INTERRUPT_PIN, &intr_pin); - - DBG_IRT("iosapic_xlate_pin() SLOT %d pin %d\n", PCI_SLOT(pcidev->devfn), intr_pin); - - if (0 == intr_pin) - { - /* - ** The device does NOT support/use IRQ lines. - */ - return NULL; - } - - /* Check if pcidev behind a PPB */ - if (NULL != pcidev->bus->self) - { - /* Convert pcidev INTR_PIN into something we - ** can lookup in the IRT. - */ -#ifdef PCI_BRIDGE_FUNCS - /* - ** Proposal #1: - ** - ** call implementation specific translation function - ** This is architecturally "cleaner". HP-UX doesn't - ** support other secondary bus types (eg. E/ISA) directly. - ** May be needed for other processor (eg IA64) architectures - ** or by some ambitous soul who wants to watch TV. - */ - if (pci_bridge_funcs->xlate_intr_line) { - intr_pin = (*pci_bridge_funcs->xlate_intr_line)(pcidev); - } -#else /* PCI_BRIDGE_FUNCS */ - struct pci_bus *p = pcidev->bus; - /* - ** Proposal #2: - ** The "pin" is skewed ((pin + dev - 1) % 4). - ** - ** This isn't very clean since I/O SAPIC must assume: - ** - all platforms only have PCI busses. - ** - only PCI-PCI bridge (eg not PCI-EISA, PCI-PCMCIA) - ** - IRQ routing is only skewed once regardless of - ** the number of PPB's between iosapic and device. - ** (Bit3 expansion chassis follows this rule) - ** - ** Advantage is it's really easy to implement. - */ - intr_pin = ((intr_pin-1)+PCI_SLOT(pcidev->devfn)) % 4; - intr_pin++; /* convert back to INTA-D (1-4) */ -#endif /* PCI_BRIDGE_FUNCS */ - - /* - ** Locate the host slot the PPB nearest the Host bus - ** adapter. - */ - while (NULL != p->parent->self) - p = p->parent; - - intr_slot = PCI_SLOT(p->self->devfn); - } else { - intr_slot = PCI_SLOT(pcidev->devfn); - } - DBG_IRT("iosapic_xlate_pin: bus %d slot %d pin %d\n", - pcidev->bus->secondary, intr_slot, intr_pin); - - return irt_find_irqline(isi, intr_slot, intr_pin); -} - - -static void -iosapic_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - struct vector_info *vi = (struct vector_info *)dev_id; - extern void do_irq(struct irqaction *a, int i, struct pt_regs *p); - int irq_num = vi->vi_ios->isi_region->data.irqbase + vi->vi_irqline; - - DBG("iosapic_interrupt(): irq %d line %d eoi %p\n", irq, vi->vi_irqline, - vi->vi_eoi_addr); - -/* FIXME: Need to mask/unmask? processor IRQ is already masked... */ - do_irq(&vi->vi_ios->isi_region->action[vi->vi_irqline], irq_num, regs); - - /* - ** PCI only supports level triggered in order to share IRQ lines. - ** I/O SAPIC must always issue EOI. - */ - IOSAPIC_EOI(vi->vi_eoi_addr, vi->vi_eoi_data); -} - - -int -iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev) -{ - struct iosapic_info *isi = (struct iosapic_info *)isi_obj; - struct irt_entry *irte = NULL; /* only used if PAT PDC */ - struct vector_info *vi; - int isi_line; /* line used by device */ - int tmp; - - if (NULL == isi) { - printk(KERN_WARNING MODULE_NAME ": 0x%p hpa not registered\n", isi->isi_hpa); - return(-1); - } - - /* lookup IRT entry for isi/slot/pin set */ - irte = iosapic_xlate_pin(isi, pcidev); - if (NULL == irte) { - return(-1); - } - DBG_IRT("iosapic_fixup_irq(): irte %p %x %x %x %x %x %x %x %x\n", - irte, - irte->entry_type, - irte->entry_length, - irte->polarity_trigger, - irte->src_bus_irq_devno, - irte->src_bus_id, - irte->src_seg_id, - irte->dest_iosapic_intin, - (u32) irte->dest_iosapic_addr); - isi_line = irte->dest_iosapic_intin; - - /* get vector info for this input line */ - ASSERT(NULL != isi->isi_vector); - vi = &(isi->isi_vector[isi_line]); - DBG_IRT("iosapic_fixup_irq: line %d vi 0x%p\n", isi_line, vi); - vi->vi_irte = irte; - - /* Allocate processor IRQ */ - vi->vi_txn_irq = txn_alloc_irq(); - -/* XXX/FIXME The txn_alloc_irq() code and related code should be moved -** to enable_irq(). That way we only allocate processor IRQ bits -** for devices that actually have drivers claiming them. -** Right now we assign an IRQ to every PCI device present regardless -** of whether it's used or not. -*/ - if (vi->vi_txn_irq < 0) - panic("I/O sapic: couldn't get TXN IRQ\n"); - - /* enable_irq() will use txn_* to program IRdT */ - vi->vi_txn_addr = txn_alloc_addr(vi->vi_txn_irq); - vi->vi_txn_data = txn_alloc_data(vi->vi_txn_irq, 8); - ASSERT(vi->vi_txn_data < 256); /* matches 8 above */ - - tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0, "iosapic", vi); - ASSERT(tmp == 0); - - vi->vi_eoi_addr = ((void *) isi->isi_hpa) + IOSAPIC_REG_EOI; - vi->vi_eoi_data = cpu_to_le32(vi->vi_irqline); - - ASSERT(NULL != isi->isi_region); - /* - ** pcidev->irq still needs to be virtualized. - */ - pcidev->irq = isi->isi_region->data.irqbase + isi_line; - - DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n", PCI_SLOT(pcidev->devfn), - PCI_FUNC(pcidev->devfn), pcidev->vendor, pcidev->device, isi_line, pcidev->irq); - - return(pcidev->irq); -} - - -static void -iosapic_rd_irt_entry(struct vector_info *vi , u32 *dp0, u32 *dp1) -{ - struct iosapic_info *isp = vi->vi_ios; - u8 idx = vi->vi_irqline; - - /* point the window register to the lower word */ - WRITE_U32(IOSAPIC_IRDT_ENTRY(idx), isp->isi_hpa+IOSAPIC_REG_SELECT); - *dp0 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); - - /* point the window register to the higher word */ - WRITE_U32(IOSAPIC_IRDT_ENTRY_HI(idx), isp->isi_hpa+IOSAPIC_REG_SELECT); - *dp1 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); -} - - -static void -iosapic_wr_irt_entry(struct vector_info *vi, u32 dp0, u32 dp1) -{ - struct iosapic_info *isp = vi->vi_ios; - - ASSERT(NULL != isp); - ASSERT(NULL != isp->isi_hpa); - DBG_IRT("iosapic_wr_irt_entry(): irq %d hpa %p WINDOW %p 0x%x 0x%x\n", - vi->vi_irqline, - isp->isi_hpa, isp->isi_hpa+IOSAPIC_REG_WINDOW, - dp0, dp1); - - /* point the window register to the lower word */ - WRITE_U32(IOSAPIC_IRDT_ENTRY(vi->vi_irqline), isp->isi_hpa+IOSAPIC_REG_SELECT); - WRITE_U32( dp0, isp->isi_hpa+IOSAPIC_REG_WINDOW); - - /* Read the window register to flush the writes down to HW */ - dp0 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); - - /* point the window register to the higher word */ - WRITE_U32(IOSAPIC_IRDT_ENTRY_HI(vi->vi_irqline), isp->isi_hpa+IOSAPIC_REG_SELECT); - WRITE_U32( dp1, isp->isi_hpa+IOSAPIC_REG_WINDOW); - - /* Read the window register to flush the writes down to HW */ - dp1 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); -} - - -/* -** set_irt prepares the data (dp0, dp1) according to the vector_info -** and target cpu (id_eid). dp0/dp1 are then used to program I/O SAPIC -** IRdT for the given "vector" (aka IRQ line). -*/ -static void -iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1) -{ - u32 mode = 0; - struct irt_entry *p = vi->vi_irte; - ASSERT(NULL != vi->vi_irte); - - if ((p->polarity_trigger & IRT_PO_MASK) == IRT_ACTIVE_LO) - mode |= IOSAPIC_IRDT_PO_LOW; - - if (((p->polarity_trigger >> IRT_EL_SHIFT) & IRT_EL_MASK) == IRT_LEVEL_TRIG) - mode |= IOSAPIC_IRDT_LEVEL_TRIG; - - /* - ** IA64 REVISIT - ** PA doesn't support EXTINT or LPRIO bits. - */ - - ASSERT(vi->vi_txn_data); - *dp0 = mode | (u32) vi->vi_txn_data; - - /* - ** Extracting id_eid isn't a real clean way of getting it. - ** But the encoding is the same for both PA and IA64 platforms. - */ -#ifdef __LP64__ - if (pdc_pat) { - /* - ** PAT PDC just hands it to us "right". - ** vi_txn_addr comes from cpu_data[x].txn_addr. - */ - *dp1 = (u32) (vi->vi_txn_addr); - } else -#endif - { - /* - ** eg if base_addr == 0xfffa0000), - ** we want to get 0xa0ff0000. - ** - ** eid 0x0ff00000 -> 0x00ff0000 - ** id 0x000ff000 -> 0xff000000 - */ - *dp1 = (((u32)vi->vi_txn_addr & 0x0ff00000) >> 4) | - (((u32)vi->vi_txn_addr & 0x000ff000) << 12); - } - DBG_IRT("iosapic_set_irt_data(): 0x%x 0x%x\n", *dp0, *dp1); -} - - -static void -iosapic_disable_irq(void *irq_dev, int irq) -{ - ulong irqflags; - struct vector_info *vi = &(((struct vector_info *) irq_dev)[irq]); - u32 d0, d1; - - ASSERT(NULL != vi); - - IOSAPIC_LOCK(&iosapic_lock); - -#ifdef REVISIT_DESIGN_ISSUE -/* -** XXX/FIXME - -disable_irq()/enable_irq(): drawback of using IRQ as a "handle" - -Current disable_irq interface only allows the irq_region support routines -to manage sharing of "irq" objects. The problem is the disable_irq() -interface specifies which IRQ line needs to be disabled but does not -identify the particular ISR which needs to be disabled. IO sapic -(and similar code in Dino) can only support one handler per IRQ -since they don't further encode the meaning of the IRQ number. -irq_region support has to hide it's implementation of "shared IRQ" -behind a function call. - -Encoding the IRQ would be possible by I/O SAPIC but makes life really -complicated for the IRQ handler and not help performance. - -Need more info on how Linux supports shared IRQ lines on a PC. -*/ -#endif /* REVISIT_DESIGN_ISSUE */ - - iosapic_rd_irt_entry(vi, &d0, &d1); - d0 |= IOSAPIC_IRDT_ENABLE; - iosapic_wr_irt_entry(vi, d0, d1); - - IOSAPIC_UNLOCK(&iosapic_lock); - - /* disable ISR for parent */ - disable_irq(vi->vi_txn_irq); -} - - -static void -iosapic_enable_irq(void *dev, int irq) -{ - struct vector_info *vi = &(((struct vector_info *) dev)[irq]); - u32 d0, d1; - - ASSERT(NULL != vi); - ASSERT(NULL != vi->vi_irte); - - /* data is initialized by fixup_irq */ - ASSERT(0 < vi->vi_txn_irq); - ASSERT(0UL != vi->vi_txn_addr); - ASSERT(0UL != vi->vi_txn_data); - - iosapic_set_irt_data(vi, &d0, &d1); - iosapic_wr_irt_entry(vi, d0, d1); - - -#ifdef DEBUG_IOSAPIC_IRT -{ -u32 *t = (u32 *) ((ulong) vi->vi_eoi_addr & ~0xffUL); -printk("iosapic_enable_irq(): regs %p", vi->vi_eoi_addr); -while (t < vi->vi_eoi_addr) printk(" %x", READ_U32(t++)); -printk("\n"); -} - -printk("iosapic_enable_irq(): sel "); -{ - struct iosapic_info *isp = vi->vi_ios; - - for (d0=0x10; d0<0x1e; d0++) { - /* point the window register to the lower word */ - WRITE_U32(d0, isp->isi_hpa+IOSAPIC_REG_SELECT); - - /* read the word */ - d1 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); - printk(" %x", d1); - } -} -printk("\n"); -#endif - - /* - ** KLUGE: IRQ should not be asserted when Drivers enabling their IRQ. - ** PCI supports level triggered in order to share IRQ lines. - ** - ** Issueing I/O SAPIC an EOI causes an interrupt iff IRQ line is - ** asserted. - */ - IOSAPIC_EOI(vi->vi_eoi_addr, vi->vi_eoi_data); -} - - -static void -iosapic_mask_irq(void *dev, int irq) -{ - BUG(); -} - - -static void -iosapic_unmask_irq(void *dev, int irq) -{ - BUG(); -} - - -static struct irq_region_ops iosapic_irq_ops = { - iosapic_disable_irq, - iosapic_enable_irq, - iosapic_mask_irq, - iosapic_unmask_irq -}; - - -/* -** squirrel away the I/O Sapic Version -*/ -static unsigned int -iosapic_rd_version(struct iosapic_info *isi) -{ - ASSERT(isi); - ASSERT(isi->isi_hpa); - - /* point window to the version register */ - WRITE_U32(IOSAPIC_REG_VERSION, isi->isi_hpa+IOSAPIC_REG_SELECT); - - /* now read the version register */ - return (READ_U32(isi->isi_hpa+IOSAPIC_REG_WINDOW)); -} - - -#ifndef IOSAPIC_CALLBACK -/* -** iosapic_register() is the alternative to iosapic_driver_for(). -** (Only one or the other should be implemented.) -*/ - -/* -** iosapic_register() is called by "drivers" with an integrated I/O SAPIC. -** Caller must be certain they have an I/O SAPIC and know it's MMIO address. -** -** o allocate iosapic_info and add it to the list -** o read iosapic version and squirrel that away -** o read size of IRdT. -** o allocate and initialize isi_vector[] -** o allocate isi_region (registers region handlers) -*/ -void * -iosapic_register(void *hpa) -{ - struct iosapic_info *isi = NULL; - struct irt_entry *irte = irt_cell; - struct vector_info *vip; - int cnt; /* track how many entries we've looked at */ - - /* - ** Astro based platforms can't support PCI OLARD if they - ** implement the legacy PDC (not PAT). Though Legacy PDC - ** supports an IRT, LBA's with no device under them - ** are *not* listed in the IRT. - ** Search the IRT and ignore iosapic's which aren't - ** in the IRT. - */ - ASSERT(NULL != irte); /* always have built-in devices */ - for (cnt=0; cnt < irt_num_entry; cnt++, irte++) { - ASSERT(IRT_IOSAPIC_TYPE == irte->entry_type); - /* - ** We need sign extension of the hpa on 32-bit kernels. - ** The address in the IRT is *always* 64 bit and really - ** is an unsigned quantity (like all physical addresses). - */ - if (irte->dest_iosapic_addr == (s64) ((long) hpa)) - break; - } - - if (cnt >= irt_num_entry) - return (NULL); - - if ((isi = IOSAPIC_KALLOC(struct iosapic_info, 1)) == NULL) { - BUG(); - return (NULL); - } - - memset(isi, 0, sizeof(struct iosapic_info)); - - isi->isi_hpa = (unsigned char *) hpa; - isi->isi_version = iosapic_rd_version(isi); - isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1; - - vip = isi->isi_vector = - IOSAPIC_KALLOC(struct vector_info, isi->isi_num_vectors); - - if (vip == NULL) { - IOSAPIC_FREE(isi, struct iosapic_info, 1); - return (NULL); - } - - memset(vip, 0, sizeof(struct vector_info) * isi->isi_num_vectors); - - /* - ** Initialize vector array - */ - for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) { - vip->vi_irqline = (unsigned char) cnt; - vip->vi_ios = isi; - } - - isi->isi_region = alloc_irq_region(isi->isi_num_vectors, - &iosapic_irq_ops, IRQ_REG_DIS|IRQ_REG_MASK, - "I/O Sapic", (void *) isi->isi_vector); - - ASSERT(NULL != isi->isi_region); - return ((void *) isi); -} -#endif /* !IOSAPIC_CALLBACK */ - - - -#ifdef DEBUG_IOSAPIC - -static void -iosapic_prt_irt(void *irt, long num_entry) -{ - unsigned int i, *irp = (unsigned int *) irt; - - ASSERT(NULL != irt); - - printk(KERN_DEBUG MODULE_NAME ": Interrupt Routing Table (%lx entries)\n", num_entry); - - for (i=0; ivi_irqline, vi); - printk(KERN_DEBUG "\t\tvi_status: %.4x\n", vi->vi_status); - printk(KERN_DEBUG "\t\tvi_txn_irq: %d\n", vi->vi_txn_irq); - printk(KERN_DEBUG "\t\tvi_txn_addr: %lx\n", vi->vi_txn_addr); - printk(KERN_DEBUG "\t\tvi_txn_data: %lx\n", vi->vi_txn_data); - printk(KERN_DEBUG "\t\tvi_eoi_addr: %p\n", vi->vi_eoi_addr); - printk(KERN_DEBUG "\t\tvi_eoi_data: %x\n", vi->vi_eoi_data); -} - - -static void -iosapic_prt_isi(struct iosapic_info *isi) -{ - ASSERT(NULL != isi); - printk(KERN_DEBUG MODULE_NAME ": io_sapic_info at %p\n", isi); - printk(KERN_DEBUG "\t\tisi_hpa: %p\n", isi->isi_hpa); - printk(KERN_DEBUG "\t\tisi_satus: %x\n", isi->isi_status); - printk(KERN_DEBUG "\t\tisi_version: %x\n", isi->isi_version); - printk(KERN_DEBUG "\t\tisi_vector: %p\n", isi->isi_vector); -} -#endif /* DEBUG_IOSAPIC */ diff -Nru a/arch/parisc/kernel/iosapic_private.h b/arch/parisc/kernel/iosapic_private.h --- a/arch/parisc/kernel/iosapic_private.h Mon Nov 4 14:31:01 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,165 +0,0 @@ -/* -** This file is private to iosapic driver. -** If stuff needs to be used by another driver, move it to a common file. -** -** WARNING: fields most data structures here are ordered to make sure -** they pack nicely for 64-bit compilation. (ie sizeof(long) == 8) -*/ - - -/* -** Interrupt Routing Stuff -** ----------------------- -** The interrupt routing table consists of entries derived from -** MP Specification Draft 1.5. There is one interrupt routing -** table per cell. N- and L-class consist of a single cell. -*/ -struct irt_entry { - - /* Entry Type 139 identifies an I/O SAPIC interrupt entry */ - u8 entry_type; - - /* Entry Length 16 indicates entry is 16 bytes long */ - u8 entry_length; - - /* - ** Interrupt Type of 0 indicates a vectored interrupt, - ** all other values are reserved - */ - u8 interrupt_type; - - /* - ** PO and EL - ** Polarity of SAPIC I/O input signals: - ** 00 = Reserved - ** 01 = Active high - ** 10 = Reserved - ** 11 = Active low - ** Trigger mode of SAPIC I/O input signals: - ** 00 = Reserved - ** 01 = Edge-triggered - ** 10 = Reserved - ** 11 = Level-triggered - */ - u8 polarity_trigger; - - /* - ** IRQ and DEVNO - ** irq identifies PCI interrupt signal where - ** 0x0 corresponds to INT_A#, - ** 0x1 corresponds to INT_B#, - ** 0x2 corresponds to INT_C# - ** 0x3 corresponds to INT_D# - ** PCI device number where interrupt originates - */ - u8 src_bus_irq_devno; - - /* Source Bus ID identifies the bus where interrupt signal comes from */ - u8 src_bus_id; - - /* - ** Segment ID is unique across a protection domain and - ** identifies a segment of PCI buses (reserved in - ** MP Specification Draft 1.5) - */ - u8 src_seg_id; - - /* - ** Destination I/O SAPIC INTIN# identifies the INTIN n pin - ** to which the signal is connected - */ - u8 dest_iosapic_intin; - - /* - ** Destination I/O SAPIC Address identifies the I/O SAPIC - ** to which the signal is connected - */ - u64 dest_iosapic_addr; -}; - -#define IRT_IOSAPIC_TYPE 139 -#define IRT_IOSAPIC_LENGTH 16 - -#define IRT_VECTORED_INTR 0 - -#define IRT_PO_MASK 0x3 -#define IRT_ACTIVE_HI 1 -#define IRT_ACTIVE_LO 3 - -#define IRT_EL_MASK 0x3 -#define IRT_EL_SHIFT 2 -#define IRT_EDGE_TRIG 1 -#define IRT_LEVEL_TRIG 3 - -#define IRT_IRQ_MASK 0x3 -#define IRT_DEV_MASK 0x1f -#define IRT_DEV_SHIFT 2 - -#define IRT_IRQ_DEVNO_MASK ((IRT_DEV_MASK << IRT_DEV_SHIFT) | IRT_IRQ_MASK) - -#ifdef SUPPORT_MULTI_CELL -struct iosapic_irt { - struct iosapic_irt *irt_next; /* next routing table */ - struct irt_entry *irt_base; /* intr routing table address */ - size_t irte_count; /* number of entries in the table */ - size_t irte_size; /* size (bytes) of each entry */ -}; -#endif - -struct vector_info { - struct iosapic_info *vi_ios; /* I/O SAPIC this vector is on */ - struct irt_entry *vi_irte; /* IRT entry */ - u32 *vi_eoi_addr; /* precalculate EOI reg address */ - u32 vi_eoi_data; /* IA64: ? PA: swapped txn_data */ - u8 vi_status; /* status/flags */ - u8 vi_irqline; /* INTINn(IRQ) */ - int vi_txn_irq; /* virtual IRQ number for processor */ - ulong vi_txn_addr; /* IA64: id_eid PA: partial HPA */ - ulong vi_txn_data; /* IA64: vector PA: EIR bit */ -}; - - -struct iosapic_info { - struct iosapic_info *isi_next; /* list of I/O SAPIC */ - volatile void *isi_hpa; /* physical base address */ - struct irq_region *isi_region; /* each I/O SAPIC is one region */ - struct vector_info *isi_vector; /* IRdT (IRQ line) array */ - int isi_num_vectors; /* size of IRdT array */ - int isi_status; /* status/flags */ - unsigned int isi_version; /* DEBUG: data fr version reg */ -}; - - - -#ifdef __IA64__ -/* -** PA risc does NOT have any local sapics. IA64 does. -** PIB (Processor Interrupt Block) is handled by Astro or Dew (Stretch CEC). -** -** PA: Get id_eid from IRT and hardcode PIB to 0xfeeNNNN0 -** Emulate the data on PAT platforms. -*/ -struct local_sapic_info { - struct local_sapic_info *lsi_next; /* point to next CPU info */ - int *lsi_cpu_id; /* point to logical CPU id */ - unsigned long *lsi_id_eid; /* point to IA-64 CPU id */ - int *lsi_status; /* point to CPU status */ - void *lsi_private; /* point to special info */ -}; - -/* -** "root" data structure which ties everything together. -** Should always be able to start with sapic_root and locate -** the desired information. -*/ -struct sapic_info { - struct sapic_info *si_next; /* info is per cell */ - int si_cellid; /* cell id */ - unsigned int si_status; /* status */ - char *si_pib_base; /* intr blk base address */ - local_sapic_info_t *si_local_info; - io_sapic_info_t *si_io_info; - extint_info_t *si_extint_info;/* External Intr info */ -}; -#endif - diff -Nru a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c --- a/arch/parisc/kernel/irq.c Mon Nov 4 14:31:01 2002 +++ b/arch/parisc/kernel/irq.c Mon Nov 4 14:31:01 2002 @@ -57,7 +57,7 @@ /* Bits in EIEM correlate with cpu_irq_action[]. ** Numbered *Big Endian*! (ie bit 0 is MSB) */ -static unsigned long cpu_eiem = 0; +static volatile unsigned long cpu_eiem = 0; static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED; /* protect IRQ regions */ @@ -104,24 +104,35 @@ set_eiem(cpu_eiem); } -static struct irqaction cpu_irq_actions[IRQ_PER_REGION] = { +/* + * XXX cpu_irq_actions[] will become 2 dimensional for per CPU EIR support. + * correspond changes needed in: + * processor_probe() initialize additional action arrays + * request_irq() handle CPU IRQ region specially + * do_cpu_irq_mask() index into the matching irq_action array. + */ +struct irqaction cpu_irq_actions[IRQ_PER_REGION] = { [IRQ_OFFSET(TIMER_IRQ)] { handler: timer_interrupt, name: "timer", }, #ifdef CONFIG_SMP [IRQ_OFFSET(IPI_IRQ)] { handler: ipi_interrupt, name: "IPI", }, #endif }; -struct irq_region cpu_irq_region = { +struct irq_region_ops cpu_irq_ops = { + disable_cpu_irq, enable_cpu_irq, unmask_cpu_irq, unmask_cpu_irq +}; + +struct irq_region cpu0_irq_region = { ops: { disable_cpu_irq, enable_cpu_irq, unmask_cpu_irq, unmask_cpu_irq }, data: { dev: &cpu_data[0], - name: "PA-CPU-00", + name: "PARISC-CPU", irqbase: IRQ_FROM_REGION(CPU_IRQ_REGION), }, action: cpu_irq_actions, }; struct irq_region *irq_region[NR_IRQ_REGS] = { [ 0 ] NULL, /* reserved for EISA, else causes data page fault (aka code 15) */ - [ CPU_IRQ_REGION ] &cpu_irq_region, + [ CPU_IRQ_REGION ] &cpu0_irq_region, }; @@ -192,10 +203,10 @@ unsigned int regnr = 0; seq_puts(p, " "); -#if 0 /* def CONFIG_SMP */ - for (; regnr < smp_num_cpus; regnr++) +#ifdef CONFIG_SMP + for (regnr = 0; regnr < NR_CPUS; regnr++) #endif - seq_printf(p, " CPU%d ", regnr); + seq_printf(p, " CPU%02d ", regnr); #ifdef PARISC_IRQ_CR16_COUNTS seq_printf(p, "[min/avg/max] (CPU cycle counts)"); @@ -216,24 +227,16 @@ for (i = 0; i <= MAX_CPU_IRQ; i++) { struct irqaction *action = ®ion->action[i]; unsigned int irq_no = IRQ_FROM_REGION(regnr) + i; -#if 0 /* def CONFIG_SMP */ -/* We currently direct all Interrupts at the Monarch. - * The right way to handle SMP IRQ stats is to have one IRQ region/CPU. - */ - unsigned int j; -#endif - + int j=0; if (!action->handler) continue; seq_printf(p, "%3d: ", irq_no); -#if 1 /* ndef CONFIG_SMP */ - seq_printf(p, "%10u ", kstat_irqs(irq_no)); -#else - for (j = 0; j < smp_num_cpus; j++) - seq_printf(p, "%10u ", - kstat.irqs[cpu_logical_map(j)][irq_no]); +#ifdef CONFIG_SMP + for (; j < NR_CPUS; j++) #endif + seq_printf(p, "%10u ", kstat.irqs[j][regnr][irq_no]); + seq_printf(p, " %14s", region->data.name ? region->data.name : "N/A"); #ifndef PARISC_IRQ_CR16_COUNTS @@ -243,12 +246,12 @@ seq_printf(p, ", %s", action->name); #else for ( ;action; action = action->next) { - unsigned int i, avg, min, max; + unsigned int k, avg, min, max; min = max = action->cr16_hist[0]; - for (avg = i = 0; i < PARISC_CR16_HIST_SIZE; i++) { - int hist = action->cr16_hist[i]; + for (avg = k = 0; k < PARISC_CR16_HIST_SIZE; k++) { + int hist = action->cr16_hist[k]; if (hist) { avg += hist; @@ -259,7 +262,7 @@ if (hist < min) min = hist; } - avg /= i; + avg /= k; seq_printf(p, " %s[%d/%d/%d]", action->name, min,avg,max); } @@ -292,7 +295,7 @@ /* never return irq 0 cause that's the interval timer */ for (irq = 1; irq <= MAX_CPU_IRQ; irq++) { - if (cpu_irq_region.action[irq].handler == NULL) { + if (cpu_irq_actions[irq].handler == NULL) { return (IRQ_FROM_REGION(CPU_IRQ_REGION) + irq); } } @@ -314,14 +317,18 @@ unsigned long txn_alloc_addr(int virt_irq) { - struct cpuinfo_parisc *dev = (struct cpuinfo_parisc *) (irq_region[IRQ_REGION(virt_irq)]->data.dev); + static int next_cpu = -1; - if (!dev) { - printk(KERN_ERR "txn_alloc_addr(0x%x): CPU IRQ region? dev %p\n", - virt_irq,dev); - return 0; - } - return (dev->txn_addr); + next_cpu++; /* assign to "next" CPU we want this bugger on */ + + /* validate entry */ + while ((next_cpu < NR_CPUS) && !cpu_data[next_cpu].txn_addr) + next_cpu++; + + if (next_cpu >= NR_CPUS) + next_cpu = 0; /* nothing else, assign monarch */ + + return cpu_data[next_cpu].txn_addr; } @@ -365,7 +372,7 @@ int cpu = smp_processor_id(); irq_enter(); - ++kstat.irqs[IRQ_REGION(irq)][IRQ_OFFSET(irq)]; + ++kstat.irqs[cpu][IRQ_REGION(irq)][IRQ_OFFSET(irq)]; DBG_IRQ(irq, ("do_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq))); @@ -407,7 +414,7 @@ /* ONLY called from entry.S:intr_extint() */ -void do_cpu_irq_mask(struct irq_region *region, struct pt_regs *regs) +void do_cpu_irq_mask(struct pt_regs *regs) { unsigned long eirr_val; unsigned int i=3; /* limit time in interrupt context */ @@ -431,7 +438,7 @@ */ while ((eirr_val = (mfctl(23) & cpu_eiem)) && --i) { unsigned long bit = (1UL<>=1, irq++) + /* Work our way from MSb to LSb...same order we alloc EIRs */ + for (irq = 0; eirr_val && bit; bit>>=1, irq++) { - unsigned int irq_num; - if (!(bit&eirr_val)) + if (!(bit & eirr_val & cpu_eiem)) continue; /* clear bit in mask - can exit loop sooner */ eirr_val &= ~bit; - irq_num = region->data.irqbase + irq; - do_irq(®ion->action[irq], irq_num, regs); + do_irq(&cpu_irq_actions[irq], TIMER_IRQ+irq, regs); } } set_eiem(cpu_eiem); @@ -673,6 +679,14 @@ spin_unlock(&irq_lock); printk(KERN_ERR "Trying to free free IRQ%d\n",irq); } + + +#ifdef CONFIG_SMP +void synchronize_irq(unsigned int irqnum) +{ + while (in_irq()) ; +} +#endif /* diff -Nru a/arch/parisc/kernel/lasimap.map b/arch/parisc/kernel/lasimap.map --- a/arch/parisc/kernel/lasimap.map Mon Nov 4 14:31:02 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,322 +0,0 @@ -# HP 712 kernel keymap. This uses 7 modifier combinations. - -keymaps 0-2,4-5,8,12 -# ie, plain, Shift, AltGr, Control, Control+Shift, Alt and Control+Alt - - -# Change the above line into -# keymaps 0-2,4-6,8,12 -# in case you want the entries -# altgr control keycode 83 = Boot -# altgr control keycode 111 = Boot -# below. -# -# In fact AltGr is used very little, and one more keymap can -# be saved by mapping AltGr to Alt (and adapting a few entries): -# keycode 100 = Alt -# -keycode 1 = F9 F19 Console_21 - control keycode 1 = F9 - alt keycode 1 = Console_9 - control alt keycode 1 = Console_9 -keycode 2 = -keycode 3 = F5 F15 Console_17 - control keycode 3 = F5 - alt keycode 3 = Console_5 - control alt keycode 3 = Console_5 -keycode 4 = F3 F13 Console_15 - control keycode 4 = F3 - alt keycode 4 = Console_3 - control alt keycode 4 = Console_3 -keycode 5 = F1 F11 Console_13 - control keycode 5 = F1 - alt keycode 5 = Console_1 - control alt keycode 5 = Console_1 -keycode 6 = F2 F12 Console_14 - control keycode 6 = F2 - alt keycode 6 = Console_2 - control alt keycode 6 = Console_2 -keycode 7 = F12 F12 Console_24 - control keycode 7 = F12 - alt keycode 7 = Console_12 - control alt keycode 7 = Console_12 -keycode 8 = -keycode 9 = F10 F20 Console_22 - control keycode 9 = F10 - alt keycode 9 = Console_10 - control alt keycode 9 = Console_10 -keycode 10 = F8 F18 Console_20 - control keycode 10 = F8 - alt keycode 10 = Console_8 - control alt keycode 10 = Console_8 -keycode 11 = F6 F16 Console_18 - control keycode 11 = F6 - alt keycode 11 = Console_6 - control alt keycode 11 = Console_6 -keycode 12 = F4 F14 Console_16 - control keycode 12 = F4 - alt keycode 12 = Console_4 - control alt keycode 12 = Console_4 -keycode 13 = Tab Tab - alt keycode 13 = Meta_Tab -keycode 14 = grave asciitilde - control keycode 14 = nul - alt keycode 14 = Meta_grave -keycode 15 = -keycode 16 = -keycode 17 = Alt -keycode 18 = Shift -keycode 19 = -keycode 20 = Control -keycode 21 = q -keycode 22 = one exclam exclam -keycode 23 = -keycode 24 = -keycode 25 = -keycode 26 = z -keycode 27 = s -keycode 28 = a - altgr keycode 28 = Hex_A -keycode 29 = w -keycode 30 = two at at -keycode 31 = -keycode 32 = -keycode 33 = c - altgr keycode 46 = Hex_C -keycode 34 = x -keycode 35 = d - altgr keycode 35 = Hex_D -keycode 36 = e - altgr keycode 36 = Hex_E -keycode 37 = four dollar -keycode 38 = three numbersign -keycode 39 = -keycode 40 = -keycode 41 = -keycode 42 = v -keycode 43 = f - altgr keycode 43 = Hex_F -keycode 44 = t -keycode 45 = r -keycode 46 = five percent -keycode 47 = -keycode 48 = -keycode 49 = n -keycode 50 = b - altgr keycode 50 = Hex_B -keycode 51 = h -keycode 52 = g -keycode 53 = y -keycode 54 = six asciicircum -keycode 55 = -keycode 56 = -keycode 57 = -keycode 58 = m -keycode 59 = j -keycode 60 = u -keycode 61 = seven ampersand -keycode 62 = eight asterisk asterisk -keycode 63 = -keycode 64 = -keycode 65 = comma less - alt keycode 65 = Meta_comma -keycode 66 = k -keycode 67 = i -keycode 68 = o -keycode 69 = zero parenright bracketright -keycode 70 = nine parenleft bracketleft -keycode 71 = -keycode 72 = -keycode 73 = period greater - control keycode 73 = Compose - alt keycode 73 = Meta_period -keycode 74 = slash question - control keycode 74 = Delete - alt keycode 53 = Meta_slash -keycode 75 = l -keycode 76 = semicolon colon - alt keycode 39 = Meta_semicolon -keycode 77 = p -keycode 78 = minus underscore -keycode 79 = -keycode 80 = -keycode 81 = -keycode 82 = apostrophe quotedbl - control keycode 82 = Control_g - alt keycode 40 = Meta_apostrophe -keycode 83 = -keycode 84 = bracketleft braceleft - control keycode 84 = Escape - alt keycode 26 = Meta_bracketleft -keycode 85 = equal plus -keycode 86 = -keycode 87 = -keycode 88 = Caps_Lock -keycode 88 = -keycode 89 = -keycode 89 = -keycode 89 = -keycode 90 = Return - alt keycode 90 = Meta_Control_m -keycode 91 = bracketright braceright asciitilde - control keycode 91 = Control_bracketright - alt keycode 91 = Meta_bracketright -keycode 92 = -keycode 93 = backslash bar - control keycode 43 = Control_backslash - alt keycode 43 = Meta_backslash -keycode 94 = -keycode 95 = -keycode 96 = -keycode 97 = -keycode 98 = -keycode 99 = -keycode 100 = -keycode 101 = -keycode 102 = BackSpace -keycode 103 = -keycode 104 = -keycode 105 = KP_1 - alt keycode 105 = Ascii_1 - altgr keycode 105 = Hex_1 -keycode 106 = -keycode 107 = KP_4 - alt keycode 107 = Ascii_4 - altgr keycode 107 = Hex_4 -keycode 108 = KP_7 - alt keycode 108 = Ascii_7 - altgr keycode 108 = Hex_7 -keycode 109 = -keycode 110 = -keycode 111 = -keycode 112 = KP_0 - alt keycode 82 = Ascii_0 - altgr keycode 82 = Hex_0 -keycode 113 = KP_Period -keycode 114 = KP_2 - alt keycode 114 = Ascii_2 - altgr keycode 114 = Hex_2 -keycode 115 = KP_5 - alt keycode 115 = Ascii_5 - altgr keycode 115 = Hex_5 -keycode 116 = KP_6 - alt keycode 116 = Ascii_6 - altgr keycode 116 = Hex_6 -keycode 117 = KP_8 - alt keycode 117 = Ascii_8 - altgr keycode 117 = Hex_8 -keycode 118 = Escape -keycode 119 = -keycode 120 = F11 -keycode 121 = KP_Add -keycode 122 = KP_3 - alt keycode 122 = Ascii_3 - altgr keycode 122 = Hex_3 -keycode 123 = KP_Subtract -keycode 124 = KP_Multiply -keycode 125 = KP_9 - alt keycode 125 = Ascii_9 - altgr keycode 125 = Hex_9 -keycode 126 = -# 131!! -keycode 127 = F7 F17 Console_19 - control keycode 127 = F7 - alt keycode 127 = Console_7 - control alt keycode 127 = Console_7 - -string F1 = "\033[[A" -string F2 = "\033[[B" -string F3 = "\033[[C" -string F4 = "\033[[D" -string F5 = "\033[[E" -string F6 = "\033[17~" -string F7 = "\033[18~" -string F8 = "\033[19~" -string F9 = "\033[20~" -string F10 = "\033[21~" -string F11 = "\033[23~" -string F12 = "\033[24~" -string F13 = "\033[25~" -string F14 = "\033[26~" -string F15 = "\033[28~" -string F16 = "\033[29~" -string F17 = "\033[31~" -string F18 = "\033[32~" -string F19 = "\033[33~" -string F20 = "\033[34~" -string Find = "\033[1~" -string Insert = "\033[2~" -string Remove = "\033[3~" -string Select = "\033[4~" -string Prior = "\033[5~" -string Next = "\033[6~" -string Macro = "\033[M" -string Pause = "\033[P" -compose '`' 'A' to 'À' -compose '`' 'a' to 'à' -compose '\'' 'A' to 'Á' -compose '\'' 'a' to 'á' -compose '^' 'A' to 'Â' -compose '^' 'a' to 'â' -compose '~' 'A' to 'Ã' -compose '~' 'a' to 'ã' -compose '"' 'A' to 'Ä' -compose '"' 'a' to 'ä' -compose 'O' 'A' to 'Å' -compose 'o' 'a' to 'å' -compose '0' 'A' to 'Å' -compose '0' 'a' to 'å' -compose 'A' 'A' to 'Å' -compose 'a' 'a' to 'å' -compose 'A' 'E' to 'Æ' -compose 'a' 'e' to 'æ' -compose ',' 'C' to 'Ç' -compose ',' 'c' to 'ç' -compose '`' 'E' to 'È' -compose '`' 'e' to 'è' -compose '\'' 'E' to 'É' -compose '\'' 'e' to 'é' -compose '^' 'E' to 'Ê' -compose '^' 'e' to 'ê' -compose '"' 'E' to 'Ë' -compose '"' 'e' to 'ë' -compose '`' 'I' to 'Ì' -compose '`' 'i' to 'ì' -compose '\'' 'I' to 'Í' -compose '\'' 'i' to 'í' -compose '^' 'I' to 'Î' -compose '^' 'i' to 'î' -compose '"' 'I' to 'Ï' -compose '"' 'i' to 'ï' -compose '-' 'D' to 'Ð' -compose '-' 'd' to 'ð' -compose '~' 'N' to 'Ñ' -compose '~' 'n' to 'ñ' -compose '`' 'O' to 'Ò' -compose '`' 'o' to 'ò' -compose '\'' 'O' to 'Ó' -compose '\'' 'o' to 'ó' -compose '^' 'O' to 'Ô' -compose '^' 'o' to 'ô' -compose '~' 'O' to 'Õ' -compose '~' 'o' to 'õ' -compose '"' 'O' to 'Ö' -compose '"' 'o' to 'ö' -compose '/' 'O' to 'Ø' -compose '/' 'o' to 'ø' -compose '`' 'U' to 'Ù' -compose '`' 'u' to 'ù' -compose '\'' 'U' to 'Ú' -compose '\'' 'u' to 'ú' -compose '^' 'U' to 'Û' -compose '^' 'u' to 'û' -compose '"' 'U' to 'Ü' -compose '"' 'u' to 'ü' -compose '\'' 'Y' to 'Ý' -compose '\'' 'y' to 'ý' -compose 'T' 'H' to 'Þ' -compose 't' 'h' to 'þ' -compose 's' 's' to 'ß' -compose '"' 'y' to 'ÿ' -compose 's' 'z' to 'ß' -compose 'i' 'j' to 'ÿ' diff -Nru a/arch/parisc/kernel/lba_pci.c b/arch/parisc/kernel/lba_pci.c --- a/arch/parisc/kernel/lba_pci.c Mon Nov 4 14:31:02 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1346 +0,0 @@ -/* -** PCI Lower Bus Adapter (LBA) manager -** -** (c) Copyright 1999,2000 Grant Grundler -** (c) Copyright 1999,2000 Hewlett-Packard Company -** -** 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 module primarily provides access to PCI bus (config/IOport -** spaces) on platforms with an SBA/LBA chipset. A/B/C/J/L/N-class -** with 4 digit model numbers - eg C3000 (and A400...sigh). -** -** LBA driver isn't as simple as the Dino driver because: -** (a) this chip has substantial bug fixes between revisions -** (Only one Dino bug has a software workaround :^( ) -** (b) has more options which we don't (yet) support (DMA hints, OLARD) -** (c) IRQ support lives in the I/O SAPIC driver (not with PCI driver) -** (d) play nicely with both PAT and "Legacy" PA-RISC firmware (PDC). -** (dino only deals with "Legacy" PDC) -** -** LBA driver passes the I/O SAPIC HPA to the I/O SAPIC driver. -** (I/O SAPIC is integratd in the LBA chip). -** -** FIXME: Add support to SBA and LBA drivers for DMA hint sets -** FIXME: Add support for PCI card hot-plug (OLARD). -*/ - -#include -#include -#include -#include -#include /* for __init and __devinit */ -#include -#include -#include -#include - -#include -#include /* for struct irq_region support */ -#include -#include -#include -#include -#include - -#include /* for register_driver() stuff */ -#include /* for iosapic_register() */ -#include /* gsc_read/write stuff */ - - -#ifndef TRUE -#define TRUE (1 == 1) -#define FALSE (1 == 0) -#endif - -#undef DEBUG_LBA /* general stuff */ -#undef DEBUG_LBA_PORT /* debug I/O Port access */ -#undef DEBUG_LBA_CFG /* debug Config Space Access (ie PCI Bus walk) */ -#undef DEBUG_LBA_PAT /* debug PCI Resource Mgt code - PDC PAT only */ - -#ifdef DEBUG_LBA -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -#ifdef DEBUG_LBA_PORT -#define DBG_PORT(x...) printk(x) -#else -#define DBG_PORT(x...) -#endif - -#ifdef DEBUG_LBA_CFG -#define DBG_CFG(x...) printk(x) -#else -#define DBG_CFG(x...) -#endif - -#ifdef DEBUG_LBA_PAT -#define DBG_PAT(x...) printk(x) -#else -#define DBG_PAT(x...) -#endif - -/* -** Config accessor functions only pass in the 8-bit bus number and not -** the 8-bit "PCI Segment" number. Each LBA will be assigned a PCI bus -** number based on what firmware wrote into the scratch register. -** -** The "secondary" bus number is set to this before calling -** pci_register_ops(). If any PPB's are present, the scan will -** discover them and update the "secondary" and "subordinate" -** fields in the pci_bus structure. -** -** Changes in the configuration *may* result in a different -** bus number for each LBA depending on what firmware does. -*/ - -#define MODULE_NAME "lba" - -static int lba_driver_callback(struct hp_device *, struct pa_iodc_driver *); - - -static struct pa_iodc_driver lba_drivers_for[]= { - - {HPHW_BRIDGE, 0x782, 0x0, 0xa, 0,0, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "tbd", (void *) lba_driver_callback}, - - {0,0,0,0,0,0, - 0, - (char *) NULL, (char *) NULL, (void *) NULL} -}; - - -#define LBA_FUNC_ID 0x0000 /* function id */ -#define LBA_FCLASS 0x0008 /* function class, bist, header, rev... */ -#define LBA_CAPABLE 0x0030 /* capabilities register */ - -#define LBA_PCI_CFG_ADDR 0x0040 /* poke CFG address here */ -#define LBA_PCI_CFG_DATA 0x0048 /* read or write data here */ - -#define LBA_PMC_MTLT 0x0050 /* Firmware sets this - read only. */ -#define LBA_FW_SCRATCH 0x0058 /* Firmware writes the PCI bus number here. */ -#define LBA_ERROR_ADDR 0x0070 /* On error, address gets logged here */ - -#define LBA_ARB_MASK 0x0080 /* bit 0 enable arbitration. PAT/PDC enables */ -#define LBA_ARB_PRI 0x0088 /* firmware sets this. */ -#define LBA_ARB_MODE 0x0090 /* firmware sets this. */ -#define LBA_ARB_MTLT 0x0098 /* firmware sets this. */ - -#define LBA_MOD_ID 0x0100 /* Module ID. PDC_PAT_CELL reports 4 */ - -#define LBA_STAT_CTL 0x0108 /* Status & Control */ -#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */ - -#define LBA_LMMIO_BASE 0x0200 /* < 4GB I/O address range */ -#define LBA_LMMIO_MASK 0x0208 - -#define LBA_GMMIO_BASE 0x0210 /* > 4GB I/O address range */ -#define LBA_GMMIO_MASK 0x0218 - -#define LBA_WLMMIO_BASE 0x0220 /* All < 4GB ranges under the same *SBA* */ -#define LBA_WLMMIO_MASK 0x0228 - -#define LBA_WGMMIO_BASE 0x0230 /* All > 4GB ranges under the same *SBA* */ -#define LBA_WGMMIO_MASK 0x0238 - -#define LBA_IOS_BASE 0x0240 /* I/O port space for this LBA */ -#define LBA_IOS_MASK 0x0248 - -#define LBA_ELMMIO_BASE 0x0250 /* Extra LMMIO range */ -#define LBA_ELMMIO_MASK 0x0258 - -#define LBA_EIOS_BASE 0x0260 /* Extra I/O port space */ -#define LBA_EIOS_MASK 0x0268 - -#define LBA_DMA_CTL 0x0278 /* firmware sets this */ - -/* RESET: ignore DMA stuff until we can measure performance */ -#define LBA_IBASE 0x0300 /* DMA support */ -#define LBA_IMASK 0x0308 -#define LBA_HINT_CFG 0x0310 -#define LBA_HINT_BASE 0x0380 /* 14 registers at every 8 bytes. */ - -/* ERROR regs are needed for config cycle kluges */ -#define LBA_ERROR_CONFIG 0x0680 -#define LBA_ERROR_STATUS 0x0688 - -#define LBA_IOSAPIC_BASE 0x800 /* Offset of IRQ logic */ - -/* non-postable I/O port space, densely packed */ -#ifdef __LP64__ -#define LBA_ASTRO_PORT_BASE (0xfffffffffee00000UL) -#else -#define LBA_ASTRO_PORT_BASE (0xfee00000UL) -#endif - - -/* -** lba_device: Per instance Elroy data structure -*/ -struct lba_device { - struct pci_hba_data hba; - - spinlock_t lba_lock; - void *iosapic_obj; - -#ifdef __LP64__ - unsigned long lmmio_base; /* PA_VIEW - fixup MEM addresses */ - unsigned long gmmio_base; /* PA_VIEW - Not used (yet) */ - unsigned long iop_base; /* PA_VIEW - for IO port accessor funcs */ -#endif - - int flags; /* state/functionality enabled */ - int hw_rev; /* HW revision of chip */ -}; - - -static u32 lba_t32; - -/* -** lba "flags" -*/ -#define LBA_FLAG_NO_DMA_DURING_CFG 0x01 -#define LBA_FLAG_SKIP_PROBE 0x10 - -/* Tape Release 4 == hw_rev 5 */ -#define LBA_TR4PLUS(d) ((d)->hw_rev > 0x4) -#define LBA_DMA_DURING_CFG_DISABLED(d) ((d)->flags & LBA_FLAG_NO_DMA_DURING_CFG) -#define LBA_SKIP_PROBE(d) ((d)->flags & LBA_FLAG_SKIP_PROBE) - - -/* Looks nice and keeps the compiler happy */ -#define LBA_DEV(d) ((struct lba_device *) (d)) - - -/* -** Only allow 8 subsidiary busses per LBA -** Problem is the PCI bus numbering is globally shared. -*/ -#define LBA_MAX_NUM_BUSES 8 - -/************************************ - * LBA register read and write support - * - * BE WARNED: register writes are posted. - * (ie follow writes which must reach HW with a read) - */ -#define READ_U8(addr) gsc_readb(addr) -#define READ_U16(addr) gsc_readw((u16 *) (addr)) -#define READ_U32(addr) gsc_readl((u32 *) (addr)) -#define WRITE_U8(value, addr) gsc_writeb(value, addr) -#define WRITE_U16(value, addr) gsc_writew(value, (u16 *) (addr)) -#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr)) - -#define READ_REG8(addr) gsc_readb(addr) -#define READ_REG16(addr) le16_to_cpu(gsc_readw((u16 *) (addr))) -#define READ_REG32(addr) le32_to_cpu(gsc_readl((u32 *) (addr))) -#define WRITE_REG8(value, addr) gsc_writeb(value, addr) -#define WRITE_REG16(value, addr) gsc_writew(cpu_to_le16(value), (u16 *) (addr)) -#define WRITE_REG32(value, addr) gsc_writel(cpu_to_le32(value), (u32 *) (addr)) - - -#define LBA_CFG_TOK(bus,dfn) ((u32) ((bus)<<16 | (dfn)<<8)) -#define LBA_CFG_BUS(tok) ((u8) ((tok)>>16)) -#define LBA_CFG_DEV(tok) ((u8) ((tok)>>11) & 0x1f) -#define LBA_CFG_FUNC(tok) ((u8) ((tok)>>8 ) & 0x7) - - -#ifdef DEBUG_LBA -/* Extract LBA (Rope) number from HPA */ -#define LBA_NUM(x) ((((uintptr_t) x) >> 13) & 0xf) -#endif /* DEBUG_LBA */ - -#ifdef __LP64__ -/* PDC_PAT */ -static unsigned long pdc_result[32] __attribute__ ((aligned (8))) = {0,0,0,0}; -#endif - -/* -** One time initialization to let the world know the LBA was found. -** This is the only routine which is NOT static. -** Must be called exactly once before pci_init(). -*/ -void __init lba_init(void) -{ - register_driver(lba_drivers_for); -} - - -static void -lba_dump_res(struct resource *r, int d) -{ - int i; - - if (NULL == r) - return; - - printk("(%p)", r->parent); - for (i = d; i ; --i) printk(" "); - printk("%p [%lx,%lx]/%x\n", r, r->start, r->end, (int) r->flags); - lba_dump_res(r->child, d+2); - lba_dump_res(r->sibling, d); -} - - -/* -** LBA rev 2.0, 2.1, 2.2, and 3.0 bus walks require a complex -** workaround for cfg cycles: -** -- preserve LBA state -** -- LBA_FLAG_NO_DMA_DURING_CFG workaround -** -- turn on smart mode -** -- probe with config writes before doing config reads -** -- check ERROR_STATUS -** -- clear ERROR_STATUS -** -- restore LBA state -** -** The workaround is only used for device discovery. -*/ - -static int -lba_device_present( u8 bus, u8 dfn, struct lba_device *d) -{ - u8 first_bus = d->hba.hba_bus->secondary; - u8 last_sub_bus = d->hba.hba_bus->subordinate; -#if 0 -/* FIXME - see below in this function */ - u8 dev = PCI_SLOT(dfn); - u8 func = PCI_FUNC(dfn); -#endif - - ASSERT(bus >= first_bus); - ASSERT(bus <= last_sub_bus); - ASSERT((bus - first_bus) < LBA_MAX_NUM_BUSES); - - if ((bus < first_bus) || - (bus > last_sub_bus) || - ((bus - first_bus) >= LBA_MAX_NUM_BUSES)) - { - /* devices that fall into any of these cases won't get claimed */ - return(FALSE); - } - -#if 0 -/* -** FIXME: Need to implement code to fill the devices bitmap based -** on contents of the local pci_bus tree "data base". -** pci_register_ops() walks the bus for us and builds the tree. -** For now, always do the config cycle. -*/ - bus -= first_bus; - - return (((d->devices[bus][dev]) >> func) & 0x1); -#else - return TRUE; -#endif -} - - - -#define LBA_CFG_SETUP(d, tok) { \ - /* Save contents of error config register. */ \ - error_config = READ_REG32(d->hba.base_addr + LBA_ERROR_CONFIG); \ -\ - /* Save contents of status control register. */ \ - status_control = READ_REG32(d->hba.base_addr + LBA_STAT_CTL); \ -\ - /* For LBA rev 2.0, 2.1, 2.2, and 3.0, we must disable DMA \ - ** arbitration for full bus walks. \ - */ \ - if (LBA_DMA_DURING_CFG_DISABLED(d)) { \ - /* Save contents of arb mask register. */ \ - arb_mask = READ_REG32(d->hba.base_addr + LBA_ARB_MASK); \ -\ - /* \ - * Turn off all device arbitration bits (i.e. everything \ - * except arbitration enable bit). \ - */ \ - WRITE_REG32(0x1, d->hba.base_addr + LBA_ARB_MASK); \ - } \ -\ - /* \ - * Set the smart mode bit so that master aborts don't cause \ - * LBA to go into PCI fatal mode (required). \ - */ \ - WRITE_REG32(error_config | 0x20, d->hba.base_addr + LBA_ERROR_CONFIG); \ -} - - -#define LBA_CFG_PROBE(d, tok) { \ - /* \ - * Setup Vendor ID write and read back the address register \ - * to make sure that LBA is the bus master. \ - */ \ - WRITE_REG32(tok | PCI_VENDOR_ID, (d)->hba.base_addr + LBA_PCI_CFG_ADDR);\ - /* \ - * Read address register to ensure that LBA is the bus master, \ - * which implies that DMA traffic has stopped when DMA arb is off. \ - */ \ - lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ - /* \ - * Generate a cfg write cycle (will have no affect on \ - * Vendor ID register since read-only). \ - */ \ - WRITE_REG32(~0, (d)->hba.base_addr + LBA_PCI_CFG_DATA); \ - /* \ - * Make sure write has completed before proceeding further, \ - * i.e. before setting clear enable. \ - */ \ - lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ -} - - -/* - * HPREVISIT: - * -- Can't tell if config cycle got the error. - * - * OV bit is broken until rev 4.0, so can't use OV bit and - * LBA_ERROR_LOG_ADDR to tell if error belongs to config cycle. - * - * As of rev 4.0, no longer need the error check. - * - * -- Even if we could tell, we still want to return -1 - * for **ANY** error (not just master abort). - * - * -- Only clear non-fatal errors (we don't want to bring - * LBA out of pci-fatal mode). - * - * Actually, there is still a race in which - * we could be clearing a fatal error. We will - * live with this during our real mode bus walk - * until rev 4.0 (no driver activity during - * real mode bus walk). The real mode bus walk - * has race conditions concerning the use of - * smart mode as well. - */ - -#define LBA_MASTER_ABORT_ERROR 0xc -#define LBA_FATAL_ERROR 0x10 - -#define LBA_CFG_MASTER_ABORT_CHECK(d, base, tok, error) { \ - u32 error_status = 0; \ - /* \ - * Set clear enable (CE) bit. Unset by HW when new \ - * errors are logged -- LBA HW ERS section 14.3.3). \ - */ \ - WRITE_REG32(status_control | 0x20, base + LBA_STAT_CTL); \ - error_status = READ_REG32(base + LBA_ERROR_STATUS); \ - if ((error_status & 0x1f) != 0) { \ - /* \ - * Fail the config read request. \ - */ \ - error = 1; \ - if ((error_status & LBA_FATAL_ERROR) == 0) { \ - /* \ - * Clear error status (if fatal bit not set) by setting \ - * clear error log bit (CL). \ - */ \ - WRITE_REG32(status_control | 0x10, base + LBA_STAT_CTL); \ - } \ - } \ -} - -#define LBA_CFG_TR4_ADDR_SETUP(d, addr) \ - WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR) - -#define LBA_CFG_ADDR_SETUP(d, addr) { \ - WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ - /* \ - * HPREVISIT: \ - * -- Potentially could skip this once DMA bug fixed. \ - * \ - * Read address register to ensure that LBA is the bus master, \ - * which implies that DMA traffic has stopped when DMA arb is off. \ - */ \ - lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ -} - - -#define LBA_CFG_RESTORE(d, base) { \ - /* \ - * Restore status control register (turn off clear enable). \ - */ \ - WRITE_REG32(status_control, base + LBA_STAT_CTL); \ - /* \ - * Restore error config register (turn off smart mode). \ - */ \ - WRITE_REG32(error_config, base + LBA_ERROR_CONFIG); \ - if (LBA_DMA_DURING_CFG_DISABLED(d)) { \ - /* \ - * Restore arb mask register (reenables DMA arbitration). \ - */ \ - WRITE_REG32(arb_mask, base + LBA_ARB_MASK); \ - } \ -} - - - -static unsigned int -lba_rd_cfg( struct lba_device *d, u32 tok, u8 reg, u32 size) -{ - u32 data = ~0; - int error = 0; - u32 arb_mask = 0; /* used by LBA_CFG_SETUP/RESTORE */ - u32 error_config = 0; /* used by LBA_CFG_SETUP/RESTORE */ - u32 status_control = 0; /* used by LBA_CFG_SETUP/RESTORE */ - - ASSERT((size == sizeof(u8)) || - (size == sizeof(u16)) || - (size == sizeof(u32))); - - if ((size != sizeof(u8)) && - (size != sizeof(u16)) && - (size != sizeof(u32))) { - return(data); - } - - LBA_CFG_SETUP(d, tok); - LBA_CFG_PROBE(d, tok); - LBA_CFG_MASTER_ABORT_CHECK(d, d->hba.base_addr, tok, error); - if (!error) { - LBA_CFG_ADDR_SETUP(d, tok | reg); - switch (size) { - case sizeof(u8): - data = (u32) READ_REG8(d->hba.base_addr + LBA_PCI_CFG_DATA + (reg & 3)); - break; - case sizeof(u16): - data = (u32) READ_REG16(d->hba.base_addr + LBA_PCI_CFG_DATA + (reg & 2)); - break; - case sizeof(u32): - data = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_DATA); - break; - default: - break; /* leave data as -1 */ - } - } - LBA_CFG_RESTORE(d, d->hba.base_addr); - return(data); -} - - - -#define LBA_CFG_RD(size, mask) \ -static int lba_cfg_read##size (struct pci_dev *dev, int pos, u##size *data) \ -{ \ - struct lba_device *d = LBA_DEV(dev->bus->sysdata); \ - u32 local_bus = (dev->bus->parent == NULL) ? 0 : dev->bus->secondary; \ - u32 tok = LBA_CFG_TOK(local_bus,dev->devfn); \ - \ - if ((!LBA_TR4PLUS(d)) && (!LBA_SKIP_PROBE(d))) { \ - /* original - Generate config cycle on broken elroy \ - with risk we will miss PCI bus errors. */ \ - *data = (u##size) lba_rd_cfg(d, tok, pos, sizeof(u##size)); \ - DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, *data); \ - return(*data == (u##size) -1); \ - } \ - \ - if (LBA_SKIP_PROBE(d) && (!lba_device_present(dev->bus->secondary, dev->devfn, d))) \ - { \ - DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> -1 (b)\n", __FUNCTION__, dev->slot_name, pos, *data); \ - /* either don't want to look or know device isn't present. */ \ - *data = (u##size) -1; \ - return(0); \ - } \ - \ - /* Basic Algorithm \ - ** Should only get here on fully working LBA rev. \ - ** This is how simple the code should have been. \ - */ \ - LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); \ - *data = READ_REG##size(d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & mask));\ - DBG_CFG(KERN_DEBUG "%s(%s+%2x) -> 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, *data);\ - return(*data == (u##size) -1); \ -} - -LBA_CFG_RD( 8, 3) -LBA_CFG_RD(16, 2) -LBA_CFG_RD(32, 0) - - - -static void -lba_wr_cfg( struct lba_device *d, u32 tok, u8 reg, u32 data, u32 size) -{ - int error = 0; - u32 arb_mask = 0; - u32 error_config = 0; - u32 status_control = 0; - - ASSERT((size == sizeof(u8)) || - (size == sizeof(u16)) || - (size == sizeof(u32))); - - if ((size != sizeof(u8)) && - (size != sizeof(u16)) && - (size != sizeof(u32))) { - return; - } - - LBA_CFG_SETUP(d, tok); - LBA_CFG_ADDR_SETUP(d, tok | reg); - switch (size) { - case sizeof(u8): - WRITE_REG8((u8) data, d->hba.base_addr + LBA_PCI_CFG_DATA + (reg&3)); - break; - case sizeof(u16): - WRITE_REG16((u8) data, d->hba.base_addr + LBA_PCI_CFG_DATA +(reg&2)); - break; - case sizeof(u32): - WRITE_REG32(data, d->hba.base_addr + LBA_PCI_CFG_DATA); - break; - default: - break; - } - LBA_CFG_MASTER_ABORT_CHECK(d, d->hba.base_addr, tok, error); - LBA_CFG_RESTORE(d, d->hba.base_addr); -} - - -/* - * LBA 4.0 config write code implements non-postable semantics - * by doing a read of CONFIG ADDR after the write. - */ - -#define LBA_CFG_WR(size, mask) \ -static int lba_cfg_write##size (struct pci_dev *dev, int pos, u##size data) \ -{ \ - struct lba_device *d = LBA_DEV(dev->bus->sysdata); \ - u32 local_bus = (dev->bus->parent == NULL) ? 0 : dev->bus->secondary; \ - u32 tok = LBA_CFG_TOK(local_bus,dev->devfn); \ - \ - ASSERT((tok & 0xff) == 0); \ - ASSERT(pos < 0x100); \ - \ - if ((!LBA_TR4PLUS(d)) && (!LBA_SKIP_PROBE(d))) { \ - /* Original Workaround */ \ - lba_wr_cfg(d, tok, pos, (u32) data, sizeof(u##size)); \ - DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (a)\n", __FUNCTION__, dev->slot_name, pos, data); \ - return 0; \ - } \ - \ - if (LBA_SKIP_PROBE(d) && (!lba_device_present(dev->bus->secondary, dev->devfn, d))) { \ - DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (b)\n", __FUNCTION__, dev->slot_name, pos, data); \ - return 1; /* New Workaround */ \ - } \ - \ - DBG_CFG(KERN_DEBUG "%s(%s+%2x) = 0x%x (c)\n", __FUNCTION__, dev->slot_name, pos, data); \ - /* Basic Algorithm */ \ - LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); \ - WRITE_REG##size(data, d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & mask)); \ - lba_t32 = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_ADDR); \ - return 0; \ -} - - -LBA_CFG_WR( 8, 3) -LBA_CFG_WR(16, 2) -LBA_CFG_WR(32, 0) - -static struct pci_ops lba_cfg_ops = { - lba_cfg_read8, lba_cfg_read16, lba_cfg_read32, - lba_cfg_write8, lba_cfg_write16, lba_cfg_write32 - -}; - - - -static void -lba_bios_init(void) -{ - DBG(KERN_DEBUG MODULE_NAME ": lba_bios_init\n"); -} - - -#ifdef __LP64__ - -/* -** Determine if a device is already configured. -** If so, reserve it resources. -** -** Read PCI cfg command register and see if I/O or MMIO is enabled. -** PAT has to enable the devices it's using. -** -** Note: resources are fixed up before we try to claim them. -*/ -static void -lba_claim_dev_resources(struct pci_dev *dev) -{ - u16 cmd; - int i, srch_flags; - - (void) lba_cfg_read16(dev, PCI_COMMAND, &cmd); - - srch_flags = (cmd & PCI_COMMAND_IO) ? IORESOURCE_IO : 0; - if (cmd & PCI_COMMAND_MEMORY) - srch_flags |= IORESOURCE_MEM; - - if (!srch_flags) - return; - - for (i = 0; i <= PCI_ROM_RESOURCE; i++) { - if (dev->resource[i].flags & srch_flags) { - pci_claim_resource(dev, i); - DBG(" claimed %s %d [%lx,%lx]/%x\n", - dev->slot_name, i, - dev->resource[i].start, - dev->resource[i].end, - (int) dev->resource[i].flags - ); - } - } -} -#endif - - -/* -** The algorithm is generic code. -** But it needs to access local data structures to get the IRQ base. -** Could make this a "pci_fixup_irq(bus, region)" but not sure -** it's worth it. -** -** Called by do_pci_scan_bus() immediately after each PCI bus is walked. -** Resources aren't allocated until recursive buswalk below HBA is completed. -*/ -static void -lba_fixup_bus(struct pci_bus *bus) -{ - struct list_head *ln; - struct pci_dev *dev; - u16 fbb_enable = PCI_STATUS_FAST_BACK; - u16 status; - struct lba_device *ldev = LBA_DEV(bus->sysdata); -#ifdef __LP64__ - int i; -#endif - DBG("lba_fixup_bus(0x%p) bus %d sysdata 0x%p\n", - bus, bus->secondary, bus->sysdata); - - /* - ** Properly Setup MMIO resources for this bus. - ** pci_alloc_primary_bus() mangles this. - */ - if (NULL == bus->self) { - int err; - - DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n", - ldev->hba.io_space.name, - ldev->hba.io_space.start, - ldev->hba.io_space.end, - (int) ldev->hba.io_space.flags); - DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n", - ldev->hba.mem_space.name, - ldev->hba.mem_space.start, - ldev->hba.mem_space.end, - (int) ldev->hba.mem_space.flags); - - err = request_resource(&ioport_resource, &(ldev->hba.io_space)); - if (err < 0) { - BUG(); - lba_dump_res(&ioport_resource, 2); - } - err = request_resource(&iomem_resource, &(ldev->hba.mem_space)); - if (err < 0) { - BUG(); - lba_dump_res(&iomem_resource, 2); - } - - bus->resource[0] = &(ldev->hba.io_space); - bus->resource[1] = &(ldev->hba.mem_space); - } - - list_for_each(ln, &bus->devices) { - - dev = pci_dev_b(ln); - -#ifdef __LP64__ - /* - ** 0-5 are the "standard PCI regions" - ** (see comments near PCI_NUM_RESOURCES in include/linux/pci.h) - */ - for (i = 0; i <= PCI_ROM_RESOURCE; i++) { - struct resource *res = &(dev->resource[i]); - - if (res->flags & IORESOURCE_MEM) { - /* "Globalize" PCI address */ - res->start |= ldev->lmmio_base; - res->end |= ldev->lmmio_base; - } - } -#endif - - /* - ** If one device does not support FBB transfers, - ** No one on the bus can be allowed to use them. - */ - (void) lba_cfg_read16(dev, PCI_STATUS, &status); - fbb_enable &= status; - -#ifdef __LP64__ - if (pdc_pat) { - /* Claim resources for PDC's devices */ - lba_claim_dev_resources(dev); - } -#endif /* __LP64__ */ - - /* - ** P2PB's have no IRQs. ignore them. - */ - if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) - continue; - - /* Adjust INTERRUPT_LINE for this dev */ - iosapic_fixup_irq(LBA_DEV(bus->sysdata)->iosapic_obj, dev); - } - -#if 0 -/* FIXME/REVISIT - finish figuring out to set FBB on both -** pbus_set_ranges() clobbers PCI_BRIDGE_CONTROL. -** Can't fixup here anyway....garr... -*/ - if (fbb_enable) { - if (bus->self) { - u8 control; - /* enable on PPB */ - (void) lba_cfg_read8(bus->self, PCI_BRIDGE_CONTROL, &control); - (void) lba_cfg_write8(bus->self, PCI_BRIDGE_CONTROL, control | PCI_STATUS_FAST_BACK); - - } else { - /* enable on LBA */ - } - fbb_enable = PCI_COMMAND_FAST_BACK; - } - - /* Lastly enable FBB/PERR/SERR on all devices too */ - list_for_each(ln, &bus->devices) { - (void) lba_cfg_read16(dev, PCI_COMMAND, &status); - status |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR | fbb_enable; - (void) lba_cfg_write16(dev, PCI_COMMAND, status); - } -#endif -} - - -struct pci_bios_ops lba_bios_ops = { - lba_bios_init, - lba_fixup_bus /* void lba_fixup_bus(struct pci_bus *bus) */ -}; - - - - -/******************************************************* -** -** LBA Sprockets "I/O Port" Space Accessor Functions -** -** This set of accessor functions is intended for use with -** "legacy firmware" (ie Sprockets on Allegro/Forte boxes). -** -** Many PCI devices don't require use of I/O port space (eg Tulip, -** NCR720) since they export the same registers to both MMIO and -** I/O port space. In general I/O port space is slower than -** MMIO since drivers are designed so PIO writes can be posted. -** -********************************************************/ - -#define LBA_PORT_IN(size, mask) \ -static u##size lba_astro_in##size (struct pci_hba_data *d, u16 addr) \ -{ \ - u##size t; \ - ASSERT(bus != NULL); \ - DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x) ->", __FUNCTION__, bus, addr); \ - t = READ_REG##size(LBA_ASTRO_PORT_BASE + addr); \ - DBG_PORT(" 0x%x\n", t); \ - return (t); \ -} - -LBA_PORT_IN( 8, 3) -LBA_PORT_IN(16, 2) -LBA_PORT_IN(32, 0) - - - -/* -** BUG X4107: Ordering broken - DMA RD return can bypass PIO WR -** -** Fixed in Elroy 2.2. The READ_U32(..., LBA_FUNC_ID) below is -** guarantee non-postable completion semantics - not avoid X4107. -** The READ_U32 only guarantees the write data gets to elroy but -** out to the PCI bus. We can't read stuff from I/O port space -** since we don't know what has side-effects. Attempting to read -** from configuration space would be suicidal given the number of -** bugs in that elroy functionality. -** -** Description: -** DMA read results can improperly pass PIO writes (X4107). The -** result of this bug is that if a processor modifies a location in -** memory after having issued PIO writes, the PIO writes are not -** guaranteed to be completed before a PCI device is allowed to see -** the modified data in a DMA read. -** -** Note that IKE bug X3719 in TR1 IKEs will result in the same -** symptom. -** -** Workaround: -** The workaround for this bug is to always follow a PIO write with -** a PIO read to the same bus before starting DMA on that PCI bus. -** -*/ -#define LBA_PORT_OUT(size, mask) \ -static void lba_astro_out##size (struct pci_hba_data *d, u16 addr, u##size val) \ -{ \ - ASSERT(bus != NULL); \ - DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, d, addr, val); \ - WRITE_REG##size(val, LBA_ASTRO_PORT_BASE + addr); \ - if (LBA_DEV(d)->hw_rev < 3) \ - lba_t32 = READ_U32(d->base_addr + LBA_FUNC_ID); \ -} - -LBA_PORT_OUT( 8, 3) -LBA_PORT_OUT(16, 2) -LBA_PORT_OUT(32, 0) - - -static struct pci_port_ops lba_astro_port_ops = { - lba_astro_in8, lba_astro_in16, lba_astro_in32, - lba_astro_out8, lba_astro_out16, lba_astro_out32 -}; - - -#ifdef __LP64__ - -#define PIOP_TO_GMMIO(lba, addr) \ - ((lba)->iop_base + (((addr)&0xFFFC)<<10) + ((addr)&3)) - -/******************************************************* -** -** LBA PAT "I/O Port" Space Accessor Functions -** -** This set of accessor functions is intended for use with -** "PAT PDC" firmware (ie Prelude/Rhapsody/Piranha boxes). -** -** This uses the PIOP space located in the first 64MB of GMMIO. -** Each rope gets a full 64*KB* (ie 4 bytes per page) this way. -** bits 1:0 stay the same. bits 15:2 become 25:12. -** Then add the base and we can generate an I/O Port cycle. -********************************************************/ -#undef LBA_PORT_IN -#define LBA_PORT_IN(size, mask) \ -static u##size lba_pat_in##size (struct pci_hba_data *l, u16 addr) \ -{ \ - u##size t; \ - ASSERT(bus != NULL); \ - DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x) ->", __FUNCTION__, l, addr); \ - t = READ_REG##size(PIOP_TO_GMMIO(LBA_DEV(l), addr)); \ - DBG_PORT(" 0x%x\n", t); \ - return (t); \ -} - -LBA_PORT_IN( 8, 3) -LBA_PORT_IN(16, 2) -LBA_PORT_IN(32, 0) - - -#undef LBA_PORT_OUT -#define LBA_PORT_OUT(size, mask) \ -static void lba_pat_out##size (struct pci_hba_data *l, u16 addr, u##size val) \ -{ \ - void *where = (void *) PIOP_TO_GMMIO(LBA_DEV(l), addr); \ - ASSERT(bus != NULL); \ - DBG_PORT(KERN_DEBUG "%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, l, addr, val); \ - WRITE_REG##size(val, where); \ - /* flush the I/O down to the elroy at least */ \ - lba_t32 = READ_U32(l->base_addr + LBA_FUNC_ID); \ -} - -LBA_PORT_OUT( 8, 3) -LBA_PORT_OUT(16, 2) -LBA_PORT_OUT(32, 0) - - -static struct pci_port_ops lba_pat_port_ops = { - lba_pat_in8, lba_pat_in16, lba_pat_in32, - lba_pat_out8, lba_pat_out16, lba_pat_out32 -}; - - - -/* -** make range information from PDC available to PCI subsystem. -** We make the PDC call here in order to get the PCI bus range -** numbers. The rest will get forwarded in pcibios_fixup_bus(). -** We don't have a struct pci_bus assigned to us yet. -*/ -static void -lba_pat_resources( struct hp_device *d, struct lba_device *lba_dev) -{ - pdc_pat_cell_mod_maddr_block_t pa_pdc_cell; /* PA_VIEW */ -#ifdef DONT_NEED_THIS_FOR_ASTRO - pdc_pat_cell_mod_maddr_block_t io_pdc_cell; /* IO_VIEW */ - long io_count; -#endif - long status; /* PDC return status */ - long pa_count; - int i; - - /* return cell module (IO view) */ - status = pdc_pat_cell_module(& pdc_result, d->pcell_loc, d->mod_index, - PA_VIEW, & pa_pdc_cell); - pa_count = pa_pdc_cell.mod[1]; - -#ifdef DONT_NEED_THIS_FOR_ASTRO - status |= pdc_pat_cell_module(& pdc_result, d->pcell_loc, d->mod_index, - IO_VIEW, & io_pdc_cell); - io_count = io_pdc_cell.mod[1]; -#endif - - /* We've already done this once for device discovery...*/ - if (status != PDC_RET_OK) { - panic("pdc_pat_cell_module() call failed for LBA!\n"); - } - - if (PAT_GET_ENTITY(pa_pdc_cell.mod_info) != PAT_ENTITY_LBA) { - panic("pdc_pat_cell_module() entity returned != PAT_ENTITY_LBA!\n"); - } - - /* - ** Inspect the resources PAT tells us about - */ - for (i = 0; i < pa_count; i++) { - struct { - unsigned long type; - unsigned long start; - unsigned long end; /* aka finish */ - } *p; - struct resource *r; - - p = (void *) &(pa_pdc_cell.mod[2+i*3]); - - /* Convert the PAT range data to PCI "struct resource" */ - switch(p->type & 0xff) { - case PAT_PBNUM: - lba_dev->hba.bus_num.start = p->start; - lba_dev->hba.bus_num.end = p->end; - break; - case PAT_LMMIO: - /* used to fix up pre-initialized MEM BARs */ - lba_dev->lmmio_base = p->start; - - r = &(lba_dev->hba.mem_space); - r->name = "LBA LMMIO"; - r->start = p->start; - r->end = p->end; - r->flags = IORESOURCE_MEM; - r->parent = r->sibling = r->child = NULL; - break; - case PAT_GMMIO: - printk(KERN_WARNING MODULE_NAME - " range[%d] : ignoring GMMIO (0x%lx)\n", - i, p->start); - lba_dev->gmmio_base = p->start; - break; - case PAT_NPIOP: - printk(KERN_WARNING MODULE_NAME - " range[%d] : ignoring NPIOP (0x%lx)\n", - i, p->start); - break; - case PAT_PIOP: - /* - ** Postable I/O port space is per PCI host adapter. - */ - - /* save base of 64MB PIOP region */ - lba_dev->iop_base = p->start; - - r = &(lba_dev->hba.io_space); - r->name = "LBA I/O Port"; - r->start = lba_dev->hba.hba_num << 16; - r->end = r->start + 0xffffUL; - r->flags = IORESOURCE_IO; - r->parent = r->sibling = r->child = NULL; - break; - default: - printk(KERN_WARNING MODULE_NAME - " range[%d] : unknown pat range type (0x%lx)\n", - i, p->type & 0xff); - break; - } - } -} -#endif /* __LP64__ */ - - -static void -lba_legacy_resources( struct hp_device *d, struct lba_device *lba_dev) -{ - int lba_num; - struct resource *r; -#ifdef __LP64__ - /* - ** Used to sign extend instead BAR values are only 32-bit. - ** 64-bit BARs have the upper 32-bit's zero'd by firmware. - ** "Sprockets" PDC initializes for 32-bit OS. - */ - lba_dev->lmmio_base = 0xffffffff00000000UL; -#endif - - /* - ** With "legacy" firmware, the lowest byte of FW_SCRATCH - ** represents bus->secondary and the second byte represents - ** bus->subsidiary (i.e. highest PPB programmed by firmware). - ** PCI bus walk *should* end up with the same result. - ** FIXME: But we don't have sanity checks in PCI or LBA. - */ - lba_num = READ_REG32(d->hpa + LBA_FW_SCRATCH); - r = &(lba_dev->hba.bus_num); - r->name = "LBA PCI Busses"; - r->start = lba_num & 0xff; - r->end = (lba_num>>8) & 0xff; - - /* Set up local PCI Bus resources - we don't really need - ** them for Legacy boxes but it's nice to see in /proc. - */ - r = &(lba_dev->hba.mem_space); - r->name = "LBA PCI LMMIO"; - r->flags = IORESOURCE_MEM; - r->start = READ_REG32(d->hpa + LBA_LMMIO_BASE); - r->end = r->start + ~ (READ_REG32(d->hpa + LBA_LMMIO_MASK)); - - r = &(lba_dev->hba.io_space); - r->name = "LBA PCI I/O Ports"; - r->flags = IORESOURCE_IO; - r->start = READ_REG32(d->hpa + LBA_IOS_BASE); - r->end = r->start + (READ_REG32(d->hpa + LBA_IOS_MASK) ^ 0xffff); - - lba_num = lba_dev->hba.hba_num << 16; - r->start |= lba_num; - r->end |= lba_num; -} - - -/************************************************************************** -** -** LBA initialization code (HW and SW) -** -** o identify LBA chip itself -** o initialize LBA chip modes (HardFail) -** o FIXME: initialize DMA hints for reasonable defaults -** o enable configuration functions -** o call pci_register_ops() to discover devs (fixup/fixup_bus get invoked) -** -**************************************************************************/ - -static void -lba_hw_init(struct lba_device *d) -{ - u32 stat; - - /* Set HF mode as the default (vs. -1 mode). */ - stat = READ_REG32(d->hba.base_addr + LBA_STAT_CTL); - WRITE_REG32(stat | HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL); - - /* - ** FIXME: Hint registers are programmed with default hint - ** values by firmware. Hints should be sane even if we - ** can't reprogram them the way drivers want. - */ -} - - - -static void -lba_common_init(struct lba_device *lba_dev) -{ - pci_bios = &lba_bios_ops; - pcibios_register_hba((struct pci_hba_data *)lba_dev); - lba_dev->lba_lock = SPIN_LOCK_UNLOCKED; - - /* - ** Set flags which depend on hw_rev - */ - if (!LBA_TR4PLUS(lba_dev)) { - lba_dev->flags |= LBA_FLAG_NO_DMA_DURING_CFG; - } -} - - - -/* -** Determine if lba should claim this chip (return 0) or not (return 1). -** If so, initialize the chip and tell other partners in crime they -** have work to do. -*/ -static __init int -lba_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri) -{ - struct lba_device *lba_dev; - struct pci_bus *lba_bus; - u32 func_class; - void *tmp_obj; - - /* from drivers/pci/setup-bus.c */ - extern void __init pbus_set_ranges(struct pci_bus *, struct pbus_set_ranges_data *); - - /* Read HW Rev First */ - func_class = READ_REG32(d->hpa + LBA_FCLASS); - func_class &= 0xf; - - switch (func_class) { - case 0: dri->version = "TR1.0"; break; - case 1: dri->version = "TR2.0"; break; - case 2: dri->version = "TR2.1"; break; - case 3: dri->version = "TR2.2"; break; - case 4: dri->version = "TR3.0"; break; - case 5: dri->version = "TR4.0"; break; - default: dri->version = "TR4+"; - } - - printk("%s version %s (0x%x) found at 0x%p\n", dri->name, dri->version, func_class & 0xf, d->hpa); - - /* Just in case we find some prototypes... */ - if (func_class < 2) { - printk(KERN_WARNING "Can't support LBA older than TR2.1 " - "- continuing under adversity.\n"); - } - - /* - ** Tell I/O SAPIC driver we have a IRQ handler/region. - */ - tmp_obj = iosapic_register(d->hpa+LBA_IOSAPIC_BASE); - if (NULL == tmp_obj) { - /* iosapic may have failed. But more likely the - ** slot isn't occupied and thus has no IRT entries. - ** iosapic_register looks for this iosapic in the IRT - ** before bothering to allocating data structures - ** we don't need. - */ - DBG(KERN_WARNING MODULE_NAME ": iosapic_register says not used\n"); - return (1); - } - - lba_dev = kmalloc(sizeof(struct lba_device), GFP_KERNEL); - if (NULL == lba_dev) - { - printk("lba_init_chip - couldn't alloc lba_device\n"); - return(1); - } - - memset(lba_dev, 0, sizeof(struct lba_device)); - - - /* ---------- First : initialize data we already have --------- */ - - /* - ** Need hw_rev to adjust configuration space behavior. - ** LBA_TR4PLUS macro uses hw_rev field. - */ - lba_dev->hw_rev = func_class; - - lba_dev->hba.base_addr = d->hpa; /* faster access */ - lba_dev->iosapic_obj = tmp_obj; /* save interrupt handle */ - - /* ------------ Second : initialize common stuff ---------- */ - lba_common_init(lba_dev); - lba_hw_init(lba_dev); - - /* ---------- Third : setup I/O Port and MMIO resources --------- */ -#ifdef __LP64__ - - if (pdc_pat) { - /* PDC PAT firmware uses PIOP region of GMMIO space. */ - pci_port = &lba_pat_port_ops; - - /* Go ask PDC PAT what resources this LBA has */ - lba_pat_resources(d, lba_dev); - - } else { -#endif - /* Sprockets PDC uses NPIOP region */ - pci_port = &lba_astro_port_ops; - - /* Poke the chip a bit for /proc output */ - lba_legacy_resources(d, lba_dev); -#ifdef __LP64__ - } -#endif - - /* - ** Tell PCI support another PCI bus was found. - ** Walks PCI bus for us too. - */ - lba_bus = lba_dev->hba.hba_bus = - pci_scan_bus( lba_dev->hba.bus_num.start, &lba_cfg_ops, (void *) lba_dev); - -#ifdef __LP64__ - if (pdc_pat) { - - /* determine window sizes needed by PCI-PCI bridges */ - DBG_PAT("LBA pcibios_size_bridge()\n"); - pcibios_size_bridge(lba_bus, NULL); - - /* assign resources to un-initialized devices */ - DBG_PAT("LBA pcibios_assign_unassigned_resources()\n"); - pcibios_assign_unassigned_resources(lba_bus); - -#ifdef DEBUG_LBA_PAT - DBG_PAT("\nLBA PIOP resource tree\n"); - lba_dump_res(&lba_dev->hba.io_space, 2); - DBG_PAT("\nLBA LMMIO resource tree\n"); - lba_dump_res(&lba_dev->hba.mem_space, 2); -#endif - - /* program *all* PCI-PCI bridge range registers */ - DBG_PAT("LBA pbus_set_ranges()\n"); - pbus_set_ranges(lba_bus, NULL); - } -#endif /* __LP64__ */ - - /* - ** Once PCI register ops has walked the bus, access to config - ** space is restricted. Avoids master aborts on config cycles. - ** Early LBA revs go fatal on *any* master abort. - */ - if (!LBA_TR4PLUS(lba_dev)) { - lba_dev->flags |= LBA_FLAG_SKIP_PROBE; - } - - /* Whew! Finally done! Tell services we got this one covered. */ - return 0; -} - - -/* -** Initialize the IBASE/IMASK registers for LBA (Elroy). -** Only called from sba_iommu.c initialization sequence. -*/ -void lba_init_iregs(void *sba_hpa, u32 ibase, u32 imask) -{ - extern struct pci_hba_data *hba_list; /* arch/parisc/kernel/pci.c */ - struct pci_hba_data *lba; - - imask <<= 2; /* adjust for hints - 2 more bits */ - - ASSERT((ibase & 0x003fffff) == 0); - ASSERT((imask & 0x003fffff) == 0); - - /* FIXME: sba_hpa is intended to search some table to - ** determine which LBA's belong to the caller's SBA. - ** IS_ASTRO: just assume only one SBA for now. - */ - ASSERT(NULL != hba_list); - DBG(KERN_DEBUG "%s() ibase 0x%x imask 0x%x\n", __FUNCTION__, ibase, imask); - - for (lba = hba_list; NULL != lba; lba = lba->next) { - DBG(KERN_DEBUG "%s() base_addr %p\n", __FUNCTION__, lba->base_addr); - WRITE_REG32( imask, lba->base_addr + LBA_IMASK); - WRITE_REG32( ibase, lba->base_addr + LBA_IBASE); - } - DBG(KERN_DEBUG "%s() done\n", __FUNCTION__); -} - diff -Nru a/arch/parisc/kernel/led.c b/arch/parisc/kernel/led.c --- a/arch/parisc/kernel/led.c Mon Nov 4 14:31:01 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,451 +0,0 @@ -/* - * Chassis LCD/LED driver for HP-PARISC workstations - * - * (c) Copyright 2000 Red Hat Software - * (c) Copyright 2000 Helge Deller - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* HZ */ -#include - - -/* define to disable all LED functions */ -#undef DISABLE_LEDS - - -#define CPU_HVERSION ((boot_cpu_data.hversion >> 4) & 0x0FFF) - - -struct lcd_block { - unsigned char command; /* stores the command byte */ - unsigned char on; /* value for turning LED on */ - unsigned char off; /* value for turning LED off */ -}; - -/* Structure returned by PDC_RETURN_CHASSIS_INFO */ -struct pdc_chassis_lcd_info_ret_block { - unsigned long model:16; /* DISPLAY_MODEL_XXXX (see below) */ - unsigned long lcd_width:16; /* width of the LCD in chars (DISPLAY_MODEL_LCD only) */ - char *lcd_cmd_reg_addr; /* ptr to LCD cmd-register & data ptr for LED */ - char *lcd_data_reg_addr; /* ptr to LCD data-register (LCD only) */ - unsigned int min_cmd_delay; /* delay in uS after cmd-write (LCD only) */ - unsigned char reset_cmd1; /* command #1 for writing LCD string (LCD only) */ - unsigned char reset_cmd2; /* command #2 for writing LCD string (LCD only) */ - unsigned char act_enable; /* 0 = no activity (LCD only) */ - struct lcd_block heartbeat; - struct lcd_block disk_io; - struct lcd_block lan_rcv; - struct lcd_block lan_tx; - char _pad; -}; - -/* values for pdc_chassis_lcd_info_ret_block.model: */ -#define DISPLAY_MODEL_LCD 0 /* KittyHawk LED or LCD */ -#define DISPLAY_MODEL_NONE 1 /* no LED or LCD */ -#define DISPLAY_MODEL_LASI 2 /* LASI style 8 bit LED */ -#define DISPLAY_MODEL_OLD_ASP 0x7F /* faked: ASP style 8 x 1 bit LED (only very old ASP versions) */ - - -/* LCD_CMD and LCD_DATA for KittyHawk machines */ -#ifdef __LP64__ -#define KITTYHAWK_LCD_CMD 0xfffffffff0190000L -#else -#define KITTYHAWK_LCD_CMD 0xf0190000 -#endif -#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD + 1) - - -/* lcd_info is pre-initialized to the values needed to program KittyHawk LCD's */ -static struct pdc_chassis_lcd_info_ret_block -lcd_info __attribute__((aligned(8))) = -{ - model:DISPLAY_MODEL_LCD, - lcd_width:16, - lcd_cmd_reg_addr:(char *) KITTYHAWK_LCD_CMD, - lcd_data_reg_addr:(char *) KITTYHAWK_LCD_DATA, - min_cmd_delay:40, - reset_cmd1:0x80, - reset_cmd2:0xc0, -}; - - -/* direct access to some of the lcd_info variables */ -#define LCD_CMD_REG lcd_info.lcd_cmd_reg_addr -#define LCD_DATA_REG lcd_info.lcd_data_reg_addr -#define LED_DATA_REG lcd_info.lcd_cmd_reg_addr /* LASI & ASP only */ - - - - -/* - ** - ** led_ASP_driver() - ** - */ -#define LED_DATA 0x01 /* data to shift (0:on 1:off) */ -#define LED_STROBE 0x02 /* strobe to clock data */ -static void led_ASP_driver(unsigned char leds) -{ - int i; - - leds = ~leds; - for (i = 0; i < 8; i++) { - unsigned char value; - value = (leds & 0x80) >> 7; - gsc_writeb( value, LED_DATA_REG ); - gsc_writeb( value | LED_STROBE, LED_DATA_REG ); - leds <<= 1; - } -} - - -/* - ** - ** led_LASI_driver() - ** - */ -static void led_LASI_driver(unsigned char leds) -{ - leds = ~leds; - gsc_writeb( leds, LED_DATA_REG ); -} - - -/* - ** - ** led_LCD_driver() - ** - ** The logic of the LCD driver is, that we write at every interrupt - ** only to one of LCD_CMD_REG _or_ LCD_DATA_REG - registers. - ** That way we don't need to let this interrupt routine busywait - ** the "min_cmd_delay", since idlewaiting in an interrupt-routine is - ** allways a BAD IDEA ! - ** - ** TODO: check the value of "min_cmd_delay" against the value of HZ. - ** - */ - -static void led_LCD_driver(unsigned char leds) -{ - static int last_index; /* 0:heartbeat, 1:disk, 2:lan_in, 3:lan_out */ - static int last_was_cmd;/* 0: CMD was written last, 1: DATA was last */ - struct lcd_block *block_ptr; - int value; - - // leds = ~leds; /* needed ? */ - - switch (last_index) { - case 0: block_ptr = &lcd_info.heartbeat; - value = leds & LED_HEARTBEAT; - break; - case 1: block_ptr = &lcd_info.disk_io; - value = leds & LED_DISK_IO; - break; - case 2: block_ptr = &lcd_info.lan_rcv; - value = leds & LED_LAN_RCV; - break; - case 3: block_ptr = &lcd_info.lan_tx; - value = leds & LED_LAN_TX; - break; - default: /* should never happen: */ - BUG(); - return; - } - - if (last_was_cmd) { - /* write the value to the LCD data port */ - gsc_writeb( value ? block_ptr->on : block_ptr->off, LCD_DATA_REG ); - } else { - /* write the command-byte to the LCD command register */ - gsc_writeb( block_ptr->command, LCD_CMD_REG ); - } - - /* now update the vars for the next interrupt iteration */ - if (++last_was_cmd == 2) { - last_was_cmd = 0; - if (++last_index == 4) - last_index = 0; - } -} - - - -static char currentleds; /* stores current value of the LEDs */ - -static void (*led_func_ptr) (unsigned char); /* ptr to LCD/LED-specific function */ - -/* - ** led_interrupt_func() - ** - ** is called at every timer interrupt from time.c, - ** updates the chassis LCD/LED - */ - -#define HEARTBEAT_LEN (HZ/16) - -void led_interrupt_func(void) -{ -#ifndef DISABLE_LEDS - static int count; - static int lastleds = -1; - static int nr; - - /* exit, if not initialized */ - if (!led_func_ptr) - return; - - /* increment the local counter */ - if (count == (HZ-1)) - count = 0; - else - count++; - - /* calculate the Heartbeat */ - if ((count % (HZ/2)) < HEARTBEAT_LEN) - currentleds |= LED_HEARTBEAT; - else - currentleds &= ~LED_HEARTBEAT; - - /* roll LEDs 0..2 */ - if (count == 0) { - if (nr++ >= 2) - nr = 0; - currentleds &= ~7; - currentleds |= (1 << nr); - } - - /* now update the LEDs */ - if (currentleds != lastleds) { - led_func_ptr(currentleds); - lastleds = currentleds; - } -#endif -} - - -/* - ** register_led_driver() - ** - ** All information in lcd_info needs to be set up prior - ** calling this function. - */ - -static void __init register_led_driver(void) -{ -#ifndef DISABLE_LEDS - switch (lcd_info.model) { - case DISPLAY_MODEL_LCD: - printk(KERN_INFO "LCD display at (%p,%p)\n", - LCD_CMD_REG , LCD_DATA_REG); - led_func_ptr = led_LCD_driver; - break; - - case DISPLAY_MODEL_LASI: - printk(KERN_INFO "LED display at %p\n", - LED_DATA_REG); - led_func_ptr = led_LASI_driver; - break; - - case DISPLAY_MODEL_OLD_ASP: - printk(KERN_INFO "LED (ASP-style) display at %p\n", - LED_DATA_REG); - led_func_ptr = led_ASP_driver; - break; - - default: - printk(KERN_ERR "%s: Wrong LCD/LED model %d !\n", - __FUNCTION__, lcd_info.model); - return; - } -#endif -} - -/* - * XXX - could this move to lasi.c ?? - */ - -/* - ** lasi_led_init() - ** - ** lasi_led_init() is called from lasi.c with the base hpa - ** of the lasi controller chip. - ** Since Mirage and Electra machines use a different LED - ** address register, we need to check for these machines - ** explicitly. - */ - -#ifdef CONFIG_GSC_LASI -void __init lasi_led_init(unsigned long lasi_hpa) -{ - if (lcd_info.model != DISPLAY_MODEL_NONE || - lasi_hpa == 0) - return; - - printk("%s: CPU_HVERSION %x\n", __FUNCTION__, CPU_HVERSION); - - /* Mirage and Electra machines need special offsets */ - switch (CPU_HVERSION) { - case 0x60A: /* Mirage Jr (715/64) */ - case 0x60B: /* Mirage 100 */ - case 0x60C: /* Mirage 100+ */ - case 0x60D: /* Electra 100 */ - case 0x60E: /* Electra 120 */ - LED_DATA_REG = (char *) (lasi_hpa - 0x00020000); - break; - default: - LED_DATA_REG = (char *) (lasi_hpa + 0x0000C000); - break; - } /* switch() */ - - lcd_info.model = DISPLAY_MODEL_LASI; - register_led_driver(); -} -#endif - - -/* - ** asp_led_init() - ** - ** asp_led_init() is called from asp.c with the ptr - ** to the LED display. - */ - -#ifdef CONFIG_GSC_LASI -void __init asp_led_init(unsigned long led_ptr) -{ - if (lcd_info.model != DISPLAY_MODEL_NONE || - led_ptr == 0) - return; - - lcd_info.model = DISPLAY_MODEL_OLD_ASP; - LED_DATA_REG = (char *) led_ptr; - - register_led_driver(); -} - -#endif - - - -/* - ** register_led_regions() - ** - ** Simple function, which registers the LCD/LED regions for /procfs. - ** At bootup - where the initialisation of the LCD/LED normally happens - - ** not all internal structures of request_region() are properly set up, - ** so that we delay the registration until busdevice.c is executed. - ** - */ - -void __init register_led_regions(void) -{ - switch (lcd_info.model) { - case DISPLAY_MODEL_LCD: - request_region((unsigned long)LCD_CMD_REG, 1, "lcd_cmd"); - request_region((unsigned long)LCD_DATA_REG, 1, "lcd_data"); - break; - case DISPLAY_MODEL_LASI: - case DISPLAY_MODEL_OLD_ASP: - request_region((unsigned long)LED_DATA_REG, 1, "led_data"); - break; - } -} - - - -/* - ** led_init() - ** - ** led_init() is called very early in the bootup-process from setup.c - ** and asks the PDC for an usable chassis LCD or LED. - ** If the PDC doesn't return any info, then the LED - ** is detected by lasi.c or asp.c and registered with the - ** above functions lasi_led_init() or asp_led_init(). - ** KittyHawk machines have often a buggy PDC, so that - ** we explicitly check for those machines here. - */ - -int __init led_init(void) -{ -#ifndef DISABLE_LEDS - long pdc_result[32]; - - printk("%s: CPU_HVERSION %x\n", __FUNCTION__, CPU_HVERSION); - - /* Work around the buggy PDC of KittyHawk-machines */ - switch (CPU_HVERSION) { - case 0x580: /* KittyHawk DC2-100 (K100) */ - case 0x581: /* KittyHawk DC3-120 (K210) */ - case 0x582: /* KittyHawk DC3 100 (K400) */ - case 0x583: /* KittyHawk DC3 120 (K410) */ - case 0x58B: /* KittyHawk DC2 100 (K200) */ - printk("%s: KittyHawk-Machine found !!\n", __FUNCTION__); - goto found; /* use the preinitialized values of lcd_info */ - - default: - break; - } - - /* initialize pdc_result, so we can check the return values of pdc_chassis_info() */ - pdc_result[0] = pdc_result[1] = 0; - - if (pdc_chassis_info(&pdc_result, &lcd_info, sizeof(lcd_info)) == PDC_OK) { - printk("%s: chassis info: model %d, ret0=%d, ret1=%d\n", - __FUNCTION__, lcd_info.model, pdc_result[0], pdc_result[1]); - - /* check the results. Some machines have a buggy PDC */ - if (pdc_result[0] <= 0 || pdc_result[0] != pdc_result[1]) - goto not_found; - - switch (lcd_info.model) { - case DISPLAY_MODEL_LCD: /* LCD display */ - if (pdc_result[0] != sizeof(struct pdc_chassis_lcd_info_ret_block) - && pdc_result[0] != sizeof(struct pdc_chassis_lcd_info_ret_block) - 1) - goto not_found; - printk("%s: min_cmd_delay = %d uS\n", - __FUNCTION__, lcd_info.min_cmd_delay); - break; - - case DISPLAY_MODEL_NONE: /* no LED or LCD available */ - goto not_found; - - case DISPLAY_MODEL_LASI: /* Lasi style 8 bit LED display */ - if (pdc_result[0] != 8 && pdc_result[0] != 32) - goto not_found; - break; - - default: - printk(KERN_WARNING "Unknown LCD/LED model %d\n", - lcd_info.model); - goto not_found; - } /* switch() */ - -found: - /* register the LCD/LED driver */ - register_led_driver(); - return 0; - - } /* if() */ - -not_found: - lcd_info.model = DISPLAY_MODEL_NONE; - return 1; -#endif -} diff -Nru a/arch/parisc/kernel/pa7300lc.c b/arch/parisc/kernel/pa7300lc.c --- a/arch/parisc/kernel/pa7300lc.c Mon Nov 4 14:31:01 2002 +++ b/arch/parisc/kernel/pa7300lc.c Mon Nov 4 14:31:01 2002 @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include diff -Nru a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c --- a/arch/parisc/kernel/parisc_ksyms.c Mon Nov 4 14:31:03 2002 +++ b/arch/parisc/kernel/parisc_ksyms.c Mon Nov 4 14:31:03 2002 @@ -79,13 +79,9 @@ EXPORT_SYMBOL_NOVERS($global$); #endif -#include EXPORT_SYMBOL(register_parisc_driver); EXPORT_SYMBOL(unregister_parisc_driver); EXPORT_SYMBOL(pdc_iodc_read); -#ifdef CONFIG_GSC -EXPORT_SYMBOL(gsc_alloc_irq); -#endif #include EXPORT_SYMBOL(__ioremap); diff -Nru a/arch/parisc/kernel/pdc.c b/arch/parisc/kernel/pdc.c --- a/arch/parisc/kernel/pdc.c Mon Nov 4 14:31:03 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,217 +0,0 @@ -/* arch/parisc/kernel/pdc.c - safe pdc access routines - * - * Copyright 1999 SuSE GmbH Nuernberg (Philipp Rumpf, prumpf@tux.org) - * portions Copyright 1999 The Puffin Group, (Alex deVries, David Kennedy) - * - * only these routines should be used out of the real kernel (i.e. everything - * using virtual addresses) for obvious reasons */ - -/* I think it would be in everyone's best interest to follow this - * guidelines when writing PDC wrappers: - * - * - the name of the pdc wrapper should match one of the macros - * used for the first two arguments - * - don't use caps for random parts of the name - * - use ASSERT_ALIGN to ensure the aligment of the arguments is - * correct - * - use __pa() to convert virtual (kernel) pointers to physical - * ones. - * - the name of the struct used for pdc return values should equal - * one of the macros used for the first two arguments to the - * corresponding PDC call - * - keep the order of arguments - * - don't be smart (setting trailing NUL bytes for strings, return - * something useful even if the call failed) unless you are sure - * it's not going to affect functionality or performance - * - * Example: - * int pdc_cache_info(struct pdc_cache_info *cache_info ) - * { - * ASSERT_ALIGN(cache_info, 8); - * - * return mem_pdc_call(PDC_CACHE,PDC_CACHE_INFO,__pa(cache_info),0); - * } - * prumpf 991016 - */ - -#include -#include - -#include -#include -#include -#include - - -#define ASSERT_ALIGN(ptr, align) \ - do { if(((unsigned long)(ptr)) & (align-1)) { \ - printk("PDC: %s:%d %s() called with " \ - "unaligned argument from %p", __FILE__, __LINE__, \ - __FUNCTION__, __builtin_return_address(0)); \ - \ - return -1; \ - } } while(0) - -/* verify address can be accessed without an HPMC */ -int pdc_add_valid(void *address) -{ - ASSERT_ALIGN(address, 4); - - return mem_pdc_call(PDC_ADD_VALID, PDC_ADD_VALID_VERIFY, (unsigned long)address); -} - -#if 0 -int pdc_chassis_warn(struct pdc_chassis_warn *address) -{ - ASSERT_ALIGN(address, 4); - - return mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_WARN, __pa(address), 0); -} -#endif - -int pdc_chassis_disp(unsigned long disp) -{ - return mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_DISP, disp); -} - -int pdc_chassis_info(void *pdc_result, void *chassis_info, unsigned long len) -{ - ASSERT_ALIGN(pdc_result, 4); - ASSERT_ALIGN(chassis_info, 4); - return mem_pdc_call(PDC_CHASSIS,PDC_RETURN_CHASSIS_INFO, - __pa(pdc_result), __pa(chassis_info), len); -} - -int pdc_hpa_processor(void *address) -{ - /* We're using 0 for the last parameter just to make sure. - It's actually HVERSION dependant. And remember, life is - hard without a backspace. */ - ASSERT_ALIGN(address, 4); - - return mem_pdc_call(PDC_HPA, PDC_HPA_PROCESSOR, __pa(address),0); -} - -#if 0 -int pdc_hpa_modules(void *address) -{ - return mem_pdc_call(PDC_HPA, PDC_HPA_MODULES, address); -} -#endif - -int pdc_iodc_read(void *address, void * hpa, unsigned int index, - void * iodc_data, unsigned int iodc_data_size) -{ - ASSERT_ALIGN(address, 4); - ASSERT_ALIGN(iodc_data, 8); - return mem_pdc_call(PDC_IODC, PDC_IODC_READ, - __pa(address), hpa, index, __pa(iodc_data), iodc_data_size); -} - - -int pdc_system_map_find_mods(void *pdc_mod_info, - void *mod_path, int index) -{ - return mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE, - __pa(pdc_mod_info), __pa(mod_path), (long)index); -} - - -int pdc_model_info(struct pdc_model *model) { - ASSERT_ALIGN(model, 8); - return mem_pdc_call(PDC_MODEL,PDC_MODEL_INFO,__pa(model),0); -} - -/* get system model name from PDC ROM (e.g. 9000/715 or 9000/778/B160L) */ -int pdc_model_sysmodel(char * name) -{ - struct pdc_model_sysmodel sys_model; - int retval; - - ASSERT_ALIGN(&sys_model, 8); - ASSERT_ALIGN(name, 4); - - sys_model.mod_len = 0; - retval = mem_pdc_call(PDC_MODEL,PDC_MODEL_SYSMODEL,__pa(&sys_model), - OS_ID_HPUX,__pa(name)); - - if (retval == PDC_RET_OK) - name[sys_model.mod_len] = '\0'; /* add trailing '\0' */ - else - name[0] = 0; - - return retval; -} - -/* id: 0 = cpu revision, 1 = boot-rom-version */ -int pdc_model_versions(struct pdc_model_cpuid *cpu_id, int id) { - return mem_pdc_call(PDC_MODEL,PDC_MODEL_VERSIONS,__pa(cpu_id),id); -} - -int pdc_model_cpuid(struct pdc_model_cpuid *cpu_id) { - cpu_id->cpuid = 0; /* preset zero (call maybe not implemented!) */ - return mem_pdc_call(PDC_MODEL,6,__pa(cpu_id),0); /* 6="return CPU ID" */ -} - -int pdc_cache_info(struct pdc_cache_info *cache_info) { - ASSERT_ALIGN(cache_info, 8); - - return mem_pdc_call(PDC_CACHE,PDC_CACHE_INFO,__pa(cache_info),0); -} - -#ifndef __LP64__ -int pdc_btlb_info( struct pdc_btlb_info *btlb ) { - int status; - status = mem_pdc_call(PDC_BLOCK_TLB,PDC_BTLB_INFO,__pa(btlb),0); - if (status<0) btlb->max_size = 0; - return status; -} - -int pdc_mem_map_hpa(void *r_addr, void *mod_path) { - return mem_pdc_call(PDC_MEM_MAP,PDC_MEM_MAP_HPA, - __pa(r_addr),__pa(mod_path)); -} - -int pdc_lan_station_id(char *lan_addr, void *net_hpa) { - struct pdc_lan_station_id id; - unsigned char *addr; - - if (mem_pdc_call(PDC_LAN_STATION_ID, PDC_LAN_STATION_ID_READ, - __pa(&id), net_hpa) < 0) - addr = 0; /* FIXME: else read MAC from NVRAM */ - else - addr = id.addr; - if (addr) - memmove( lan_addr, addr, PDC_LAN_STATION_ID_SIZE); - else - memset( lan_addr, 0, PDC_LAN_STATION_ID_SIZE); - return (addr != 0); -} -#endif - - -/* Similar to PDC_PAT stuff in pdcpat.c - but added for Forte/Allegro boxes */ -int pdc_pci_irt_size(void *r_addr, void *hpa) -{ - return mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SIZE, - __pa(r_addr), hpa); - -} - -int pdc_pci_irt(void *r_addr, void *hpa, void *tbl) -{ - return mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL, - __pa(r_addr), hpa, __pa(tbl)); -} - -/* access the TOD clock */ -int pdc_tod_read(struct pdc_tod *tod) -{ - ASSERT_ALIGN(tod, 8); - return mem_pdc_call(PDC_TOD, PDC_TOD_READ, __pa(tod), 0); -} - -int pdc_tod_set(unsigned long sec, unsigned long usec) -{ - return mem_pdc_call(PDC_TOD, PDC_TOD_WRITE, sec, usec); -} diff -Nru a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c --- a/arch/parisc/kernel/perf.c Mon Nov 4 14:31:01 2002 +++ b/arch/parisc/kernel/perf.c Mon Nov 4 14:31:01 2002 @@ -49,11 +49,11 @@ #include #include -#include #include #include #include #include +#include /* for __raw_read() */ #include "perf_images.h" diff -Nru a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c --- a/arch/parisc/kernel/process.c Mon Nov 4 14:31:03 2002 +++ b/arch/parisc/kernel/process.c Mon Nov 4 14:31:03 2002 @@ -35,7 +35,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c --- a/arch/parisc/kernel/processor.c Mon Nov 4 14:31:02 2002 +++ b/arch/parisc/kernel/processor.c Mon Nov 4 14:31:02 2002 @@ -167,12 +167,24 @@ ** p->state = STATE_RENDEZVOUS; */ - /* - ** itimer and ipi IRQ handlers are statically initialized in - ** arch/parisc/kernel/irq.c. ie Don't need to register them. - */ - p->region = irq_region[IRQ_FROM_REGION(CPU_IRQ_REGION)]; +#if 0 + /* CPU 0 IRQ table is statically allocated/initialized */ + if (cpuid) { + struct irqaction actions[]; + /* + ** itimer and ipi IRQ handlers are statically initialized in + ** arch/parisc/kernel/irq.c. ie Don't need to register them. + */ + actions = kmalloc(sizeof(struct irqaction)*MAX_CPU_IRQ, GFP_ATOMIC); + if (!actions) { + /* not getting it's own table, share with monarch */ + actions = cpu_irq_actions[0]; + } + + cpu_irq_actions[cpuid] = actions; + } +#endif return 0; } diff -Nru a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c --- a/arch/parisc/kernel/ptrace.c Mon Nov 4 14:31:00 2002 +++ b/arch/parisc/kernel/ptrace.c Mon Nov 4 14:31:00 2002 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -101,6 +102,11 @@ /* are we already being traced? */ if (current->ptrace & PT_PTRACED) goto out; + + ret = security_ops->ptrace(current->parent, current); + if (ret) + goto out; + /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; ret = 0; @@ -385,7 +391,7 @@ goto out_tsk; default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); goto out_tsk; } @@ -409,7 +415,8 @@ return; if (!(current->ptrace & PT_PTRACED)) return; - current->exit_code = SIGTRAP; + current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0); current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); diff -Nru a/arch/parisc/kernel/real1.c b/arch/parisc/kernel/real1.c --- a/arch/parisc/kernel/real1.c Mon Nov 4 14:31:01 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,154 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com) - * - * most of these calls might reasonably be moved to ../kernel -PB - * - * The basic principle is to construct a stack frame in C then call - * some assembly which adopts that stack, does some rfi magic, may - * switch wide/narrow mode, and calls the routine described by the - * 'fn' parameter WHICH IS NOT A FUNCTION POINTER!!!!!!!!!!!!!!!! - */ -#include -#include -#include -#include /* for __pa() */ -#include - -static spinlock_t pdc_lock = SPIN_LOCK_UNLOCKED; - -/***************** 32-bit real-mode calls ***********/ -/* The struct below is used - * to overlay real_stack (real2.S), preparing a 32-bit call frame. - * real32_call_asm() then uses this stack in narrow real mode - */ - -struct narrow_stack { - /* use int, not long which is 64 bits */ - unsigned int arg13; - unsigned int arg12; - unsigned int arg11; - unsigned int arg10; - unsigned int arg9; - unsigned int arg8; - unsigned int arg7; - unsigned int arg6; - unsigned int arg5; - unsigned int arg4; - unsigned int arg3; - unsigned int arg2; - unsigned int arg1; - unsigned int arg0; - unsigned int frame_marker[8]; - unsigned int sp; - /* in reality, there's nearly 8k of stack after this */ -}; - -long -real32_call(unsigned long fn, ...) -{ - unsigned long r; - va_list args; - unsigned long flags; - extern struct narrow_stack real_stack; - extern unsigned long real32_call_asm(unsigned int *, - unsigned int *, unsigned int); - - va_start(args, fn); - real_stack.arg0 = va_arg(args, unsigned int); - real_stack.arg1 = va_arg(args, unsigned int); - real_stack.arg2 = va_arg(args, unsigned int); - real_stack.arg3 = va_arg(args, unsigned int); - real_stack.arg4 = va_arg(args, unsigned int); - real_stack.arg5 = va_arg(args, unsigned int); - real_stack.arg6 = va_arg(args, unsigned int); - real_stack.arg7 = va_arg(args, unsigned int); - real_stack.arg8 = va_arg(args, unsigned int); - real_stack.arg9 = va_arg(args, unsigned int); - real_stack.arg10 = va_arg(args, unsigned int); - real_stack.arg11 = va_arg(args, unsigned int); - real_stack.arg12 = va_arg(args, unsigned int); - real_stack.arg13 = va_arg(args, unsigned int); - va_end(args); - - if (fn == 0) { - /* mem_pdc call */ - fn = PAGE0->mem_pdc; - } - - spin_lock_irqsave(&pdc_lock, flags); - r = real32_call_asm(&real_stack.sp, &real_stack.arg0, fn); - spin_unlock_irqrestore(&pdc_lock, flags); - - return r; -} - -#ifdef __LP64__ -/***************** 64-bit real-mode calls ***********/ - -struct wide_stack { - unsigned long arg0; - unsigned long arg1; - unsigned long arg2; - unsigned long arg3; - unsigned long arg4; - unsigned long arg5; - unsigned long arg6; - unsigned long arg7; - unsigned long arg8; - unsigned long arg9; - unsigned long arg10; - unsigned long arg11; - unsigned long arg12; - unsigned long arg13; - unsigned long frame_marker[2]; /* rp, previous sp */ - unsigned long sp; - /* in reality, there's nearly 8k of stack after this */ -}; - -long -real64_call(unsigned long fn, ...) -{ - unsigned long r; - va_list args; - unsigned long flags; - extern struct wide_stack real_stack; - extern unsigned long real64_call_asm(unsigned long *, - unsigned long *, unsigned long); - - va_start(args, fn); - real_stack.arg0 = va_arg(args, unsigned long); - real_stack.arg1 = va_arg(args, unsigned long); - real_stack.arg2 = va_arg(args, unsigned long); - real_stack.arg3 = va_arg(args, unsigned long); - real_stack.arg4 = va_arg(args, unsigned long); - real_stack.arg5 = va_arg(args, unsigned long); - real_stack.arg6 = va_arg(args, unsigned long); - real_stack.arg7 = va_arg(args, unsigned long); - real_stack.arg8 = va_arg(args, unsigned long); - real_stack.arg9 = va_arg(args, unsigned long); - real_stack.arg10 = va_arg(args, unsigned long); - real_stack.arg11 = va_arg(args, unsigned long); - real_stack.arg12 = va_arg(args, unsigned long); - real_stack.arg13 = va_arg(args, unsigned long); - va_end(args); - - if (fn == 0) { - /* mem_pdc call */ - fn = PAGE0->mem_pdc_hi; - fn <<= 32; - fn |= PAGE0->mem_pdc; - } - - spin_lock_irqsave(&pdc_lock, flags); - r = real64_call_asm(&real_stack.sp, &real_stack.arg0, fn); - spin_unlock_irqrestore(&pdc_lock, flags); - - return r; -} - -#endif diff -Nru a/arch/parisc/kernel/sba_iommu.c b/arch/parisc/kernel/sba_iommu.c --- a/arch/parisc/kernel/sba_iommu.c Mon Nov 4 14:31:02 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1752 +0,0 @@ -/* -** System Bus Adapter (SBA) I/O MMU manager -** -** (c) Copyright 2000 Grant Grundler -** (c) Copyright 2000 Hewlett-Packard Company -** -** Portions (c) 1999 Dave S. Miller (from sparc64 I/O MMU code) -** -** 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 module initializes the IOC (I/O Controller) found on B1000/C3000/ -** J5000/J7000/N-class/L-class machines and their successors. -** -** FIXME: Multi-IOC support missing - depends on hp_device data -** FIXME: add DMA hint support programming in both sba and lba modules. -*/ - -#include -#include -#include -#include -#include -#include - -#include -#include -#define PCI_DEBUG /* for ASSERT */ -#include -#undef PCI_DEBUG - -#include -#include -#include /* for DMA_CHUNK_SIZE */ - -#include /* for register_driver() stuff */ -#include /* FIXME: for gsc_read/gsc_write */ - -#include -#include /* for proc_runway_root */ - - -#define MODULE_NAME "SBA" - -/* -** The number of debug flags is a clue - this code is fragile. -** Don't even think about messing with it unless you have -** plenty of 710's to sacrafice to the computer gods. :^) -*/ -#undef DEBUG_SBA_INIT -#undef DEBUG_SBA_RUN -#undef DEBUG_SBA_RUN_SG -#undef DEBUG_SBA_RESOURCE -#undef ASSERT_PDIR_SANITY -#undef DEBUG_LARGE_SG_ENTRIES - -#if 1 -#define SBA_INLINE -#else -#define SBA_INLINE __inline__ -#endif - -#ifdef DEBUG_SBA_INIT -#define DBG_INIT(x...) printk(x) -#else -#define DBG_INIT(x...) -#endif - -#ifdef DEBUG_SBA_RUN -#define DBG_RUN(x...) printk(x) -#else -#define DBG_RUN(x...) -#endif - -#ifdef DEBUG_SBA_RUN_SG -#define DBG_RUN_SG(x...) printk(x) -#else -#define DBG_RUN_SG(x...) -#endif - - -#ifdef DEBUG_SBA_RESOURCE -#define DBG_RES(x...) printk(x) -#else -#define DBG_RES(x...) -#endif - -/* -** The number of pdir entries to "free" before issueing -** a read to PCOM register to flush out PCOM writes. -** Interacts with allocation granularity (ie 4 or 8 entries -** allocated and free'd/purged at a time might make this -** less interesting). -*/ -#if 0 -#define DELAYED_RESOURCE_CNT 16 -#else -#undef DELAYED_RESOURCE_CNT -#endif - -#define DEFAULT_DMA_HINT_REG 0 - -#define ASTRO_RUNWAY_PORT 0x582 -#define ASTRO_ROPES_PORT 0x780 - -#define IKE_MERCED_PORT 0x803 -#define IKE_ROPES_PORT 0x781 - -int sba_driver_callback(struct hp_device *, struct pa_iodc_driver *); - -static struct pa_iodc_driver sba_drivers_for[] = { - -/* FIXME: why is SVERSION checked? */ - - {HPHW_IOA, ASTRO_RUNWAY_PORT, 0x0, 0xb, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "I/O MMU", (void *) sba_driver_callback}, - - {HPHW_BCPORT, ASTRO_ROPES_PORT, 0x0, 0xb, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "I/O MMU", (void *) sba_driver_callback}, - -#if 0 -/* FIXME : N-class! Use a different "callback"? */ - {HPHW_BCPORT, IKE_MERCED_PORT, 0x0, 0xb, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "I/O MMU", (void *) sba_driver_callback}, - - {HPHW_BCPORT, IKE_ROPES_PORT, 0x0, 0xb, 0, 0x10, - DRIVER_CHECK_HVERSION + - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - MODULE_NAME, "I/O MMU", (void *) sba_driver_callback}, -#endif - - {0,0,0,0,0,0, - 0, - (char *) NULL, (char *) NULL, (void *) NULL } -}; - - -#define SBA_FUNC_ID 0x0000 /* function id */ -#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */ - -#define IS_ASTRO(id) ( \ - (((id)->hw_type == HPHW_IOA) && ((id)->hversion == ASTRO_RUNWAY_PORT)) || \ - (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == ASTRO_ROPES_PORT)) \ -) - -#define CONFIG_FUNC_SIZE 4096 /* SBA configuration function reg set */ - -#define ASTRO_IOC_OFFSET 0x20000 -/* Ike's IOC's occupy functions 2 and 3 (not 0 and 1) */ -#define IKE_IOC_OFFSET(p) ((p+2)*CONFIG_FUNC_SIZE) - -#define IOC_CTRL 0x8 /* IOC_CTRL offset */ -#define IOC_CTRL_TE (0x1 << 0) /* TOC Enable */ -#define IOC_CTRL_RM (0x1 << 8) /* Real Mode */ -#define IOC_CTRL_NC (0x1 << 9) /* Non Coherent Mode */ - -#define MAX_IOC 2 /* per Ike. Astro only has 1 */ - - -/* -** Offsets into MBIB (Function 0 on Ike and hopefully Astro) -** Firmware programs this stuff. Don't touch it. -*/ -#define IOS_DIST_BASE 0x390 -#define IOS_DIST_MASK 0x398 -#define IOS_DIST_ROUTE 0x3A0 - -#define IOS_DIRECT_BASE 0x3C0 -#define IOS_DIRECT_MASK 0x3C8 -#define IOS_DIRECT_ROUTE 0x3D0 - -/* -** Offsets into I/O TLB (Function 2 and 3 on Ike) -*/ -#define ROPE0_CTL 0x200 /* "regbus pci0" */ -#define ROPE1_CTL 0x208 -#define ROPE2_CTL 0x210 -#define ROPE3_CTL 0x218 -#define ROPE4_CTL 0x220 -#define ROPE5_CTL 0x228 -#define ROPE6_CTL 0x230 -#define ROPE7_CTL 0x238 - -#define HF_ENABLE 0x40 - - -#define IOC_IBASE 0x300 /* IO TLB */ -#define IOC_IMASK 0x308 -#define IOC_PCOM 0x310 -#define IOC_TCNFG 0x318 -#define IOC_PDIR_BASE 0x320 - -#define IOC_IOVA_SPACE_BASE 0 /* IOVA ranges start at 0 */ - -/* -** IOC supports 4/8/16/64KB page sizes (see TCNFG register) -** It's safer (avoid memory corruption) to keep DMA page mappings -** equivalently sized to VM PAGE_SIZE. -** -** We really can't avoid generating a new mapping for each -** page since the Virtual Coherence Index has to be generated -** and updated for each page. -** -** IOVP_SIZE could only be greater than PAGE_SIZE if we are -** confident the drivers really only touch the next physical -** page iff that driver instance owns it. -*/ -#define IOVP_SIZE PAGE_SIZE -#define IOVP_SHIFT PAGE_SHIFT -#define IOVP_MASK PAGE_MASK - -#define SBA_PERF_CFG 0x708 /* Performance Counter stuff */ -#define SBA_PERF_MASK1 0x718 -#define SBA_PERF_MASK2 0x730 - - -/* -** Offsets into PCI Performance Counters (functions 12 and 13) -** Controlled by PERF registers in function 2 & 3 respectively. -*/ -#define SBA_PERF_CNT1 0x200 -#define SBA_PERF_CNT2 0x208 -#define SBA_PERF_CNT3 0x210 - - -struct ioc { - char *ioc_hpa; /* I/O MMU base address */ - char *res_map; /* resource map, bit == pdir entry */ - u64 *pdir_base; /* physical base address */ - - unsigned long *res_hint; /* next available IOVP - circular search */ - unsigned int res_bitshift; /* from the LEFT! */ - unsigned int res_size; /* size of resource map in bytes */ - unsigned int hint_shift_pdir; - spinlock_t res_lock; - unsigned long hint_mask_pdir; /* bits used for DMA hints */ -#ifdef DELAYED_RESOURCE_CNT - dma_addr_t res_delay[DELAYED_RESOURCE_CNT]; -#endif - -#ifdef CONFIG_PROC_FS -#define SBA_SEARCH_SAMPLE 0x100 - unsigned long avg_search[SBA_SEARCH_SAMPLE]; - unsigned long avg_idx; /* current index into avg_search */ - unsigned long used_pages; - unsigned long msingle_calls; - unsigned long msingle_pages; - unsigned long msg_calls; - unsigned long msg_pages; - unsigned long usingle_calls; - unsigned long usingle_pages; - unsigned long usg_calls; - unsigned long usg_pages; -#endif - - /* STUFF We don't need in performance path */ - unsigned int pdir_size; /* in bytes, determined by IOV Space size */ - unsigned long ibase; /* pdir IOV Space base - shared w/lba_pci */ - unsigned long imask; /* pdir IOV Space mask - shared w/lba_pci */ -}; - -struct sba_device { - struct sba_device *next; /* list of LBA's in system */ - struct hp_device *iodc; /* data about dev from firmware */ - char *sba_hpa; /* base address */ - spinlock_t sba_lock; - unsigned int flags; /* state/functionality enabled */ - unsigned int hw_rev; /* HW revision of chip */ - - unsigned int num_ioc; /* number of on-board IOC's */ - struct ioc ioc[MAX_IOC]; -}; - - -static struct sba_device *sba_list; -static int sba_count; - -/* Ratio of Host MEM to IOV Space size */ -static unsigned long sba_mem_ratio = 4; - -/* Looks nice and keeps the compiler happy */ -#define SBA_DEV(d) ((struct sba_device *) (d)) - - -#define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1)) - - -/************************************ -** SBA register read and write support -** -** BE WARNED: register writes are posted. -** (ie follow writes which must reach HW with a read) -*/ -#define READ_U8(addr) gsc_readb(addr) -#define READ_U16(addr) gsc_readw((u16 *) (addr)) -#define READ_U32(addr) gsc_readl((u32 *) (addr)) -#define WRITE_U8(value, addr) gsc_writeb(value, addr) -#define WRITE_U16(value, addr) gsc_writew(value, (u16 *) (addr)) -#define WRITE_U32(value, addr) gsc_writel(value, (u32 *) (addr)) - -#define READ_REG8(addr) gsc_readb(addr) -#define READ_REG16(addr) le16_to_cpu(gsc_readw((u16 *) (addr))) -#define READ_REG32(addr) le32_to_cpu(gsc_readl((u32 *) (addr))) -#define READ_REG64(addr) le64_to_cpu(gsc_readq((u64 *) (addr))) -#define WRITE_REG8(value, addr) gsc_writeb(value, addr) -#define WRITE_REG16(value, addr) gsc_writew(cpu_to_le16(value), (u16 *) (addr)) -#define WRITE_REG32(value, addr) gsc_writel(cpu_to_le32(value), (u32 *) (addr)) -#define WRITE_REG64(value, addr) gsc_writeq(cpu_to_le64(value), (u64 *) (addr)) - -#ifdef DEBUG_SBA_INIT - -static void -sba_dump_ranges(char *hpa) -{ - printk("SBA at 0x%p\n", hpa); - printk("IOS_DIST_BASE : %08x %08x\n", - READ_REG32(hpa+IOS_DIST_BASE+4), - READ_REG32(hpa+IOS_DIST_BASE)); - printk("IOS_DIST_MASK : %08x %08x\n", - READ_REG32(hpa+IOS_DIST_MASK+4), - READ_REG32(hpa+IOS_DIST_MASK)); - printk("IOS_DIST_ROUTE : %08x %08x\n", - READ_REG32(hpa+IOS_DIST_ROUTE+4), - READ_REG32(hpa+IOS_DIST_ROUTE)); - printk("\n"); - printk("IOS_DIRECT_BASE : %08x %08x\n", - READ_REG32(hpa+IOS_DIRECT_BASE+4), - READ_REG32(hpa+IOS_DIRECT_BASE)); - printk("IOS_DIRECT_MASK : %08x %08x\n", - READ_REG32(hpa+IOS_DIRECT_MASK+4), - READ_REG32(hpa+IOS_DIRECT_MASK)); - printk("IOS_DIRECT_ROUTE: %08x %08x\n", - READ_REG32(hpa+IOS_DIRECT_ROUTE+4), - READ_REG32(hpa+IOS_DIRECT_ROUTE)); -} - -static void -sba_dump_tlb(char *hpa) -{ - printk("IO TLB at 0x%p\n", hpa); - printk("IOC_IBASE : %08x %08x\n", - READ_REG32(hpa+IOC_IBASE+4), - READ_REG32(hpa+IOC_IBASE)); - printk("IOC_IMASK : %08x %08x\n", - READ_REG32(hpa+IOC_IMASK+4), - READ_REG32(hpa+IOC_IMASK)); - printk("IOC_TCNFG : %08x %08x\n", - READ_REG32(hpa+IOC_TCNFG+4), - READ_REG32(hpa+IOC_TCNFG)); - printk("IOC_PDIR_BASE: %08x %08x\n", - READ_REG32(hpa+IOC_PDIR_BASE+4), - READ_REG32(hpa+IOC_PDIR_BASE)); - printk("\n"); -} -#endif - - -#ifdef ASSERT_PDIR_SANITY - -static void -sba_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide) -{ - /* start printing from lowest pde in rval */ - u64 *ptr = &(ioc->pdir_base[pide & (~0U * BITS_PER_LONG)]); - unsigned long *rptr = (unsigned long *) &(ioc->res_map[(pide >>3) & ~(sizeof(unsigned long) - 1)]); - uint rcnt; - - printk("SBA: %s rp %p bit %d rval 0x%lx\n", - msg, - rptr, pide & (BITS_PER_LONG - 1), *rptr); - - rcnt = 0; - while (rcnt < BITS_PER_LONG) { - printk("%s %2d %p %016Lx\n", - (rcnt == (pide & (BITS_PER_LONG - 1))) - ? " -->" : " ", - rcnt, ptr, *ptr ); - rcnt++; - ptr++; - } - printk(msg); -} - - -/* Verify the resource map and pdir state is consistent */ -static int -sba_check_pdir(struct ioc *ioc, char *msg) -{ - u32 *rptr_end = (u32 *) &(ioc->res_map[ioc->res_size]); - u32 *rptr = (u32 *) ioc->res_map; /* resource map ptr */ - u64 *pptr = ioc->pdir_base; /* pdir ptr */ - uint pide = 0; - - while (rptr < rptr_end) { - u32 rval = *rptr; - int rcnt = 32; /* number of bits we might check */ - - while (rcnt) { - /* Get last byte and highest bit from that */ - u32 pde = ((u32) (((char *)pptr)[7])) << 24; - if ((rval ^ pde) & 0x80000000) - { - /* - ** BUMMER! -- res_map != pdir -- - ** Dump rval and matching pdir entries - */ - sba_dump_pdir_entry(ioc, msg, pide); - return(1); - } - rcnt--; - rval <<= 1; /* try the next bit */ - pptr++; - pide++; - } - rptr++; /* look at next word of res_map */ - } - /* It'd be nice if we always got here :^) */ - return 0; -} - - -static void -sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents) -{ - while (nents-- > 0) { - printk(" %d : %08lx/%05x %p/%05x\n", - nents, - (unsigned long) sg_dma_address(startsg), - sg_dma_len(startsg), - startsg->address, startsg->length); - startsg++; - } -} - -#endif /* ASSERT_PDIR_SANITY */ - - - -/* -** One time initialization to let the world know the LBA was found. -** This is the only routine which is NOT static. -** Must be called exactly once before pci_init(). -*/ -void __init -sba_init(void) -{ - sba_list = (struct sba_device *) NULL; - sba_count = 0; - -#ifdef DEBUG_SBA_INIT - sba_dump_ranges((char *) 0xFED00000L); -#endif - - register_driver(sba_drivers_for); -} - - - -/************************************************************** -* -* I/O Pdir Resource Management -* -* Bits set in the resource map are in use. -* Each bit can represent a number of pages. -* LSbs represent lower addresses (IOVA's). -* -***************************************************************/ -#define PAGES_PER_RANGE 1 /* could increase this to 4 or 8 if needed */ - -/* Convert from IOVP to IOVA and vice versa. */ -#define SBA_IOVA(ioc,iovp,offset,hint_reg) ((iovp) | (offset) | ((hint_reg)<<(ioc->hint_shift_pdir))) -#define SBA_IOVP(ioc,iova) ((iova) & ioc->hint_mask_pdir) - -/* FIXME : review these macros to verify correctness and usage */ -#define PDIR_INDEX(iovp) ((iovp)>>IOVP_SHIFT) -#define MKIOVP(dma_hint,pide) (dma_addr_t)((long)(dma_hint) | ((long)(pide) << IOVP_SHIFT)) -#define MKIOVA(iovp,offset) (dma_addr_t)((long)iovp | (long)offset) - -#define RESMAP_MASK(n) (~0UL << (BITS_PER_LONG - (n))) -#define RESMAP_IDX_MASK (sizeof(unsigned long) - 1) - - -/* -** Perf optimizations: -** o search for log2(size) bits at a time. -** -** Search should use register width as "stride" to search the res_map. -*/ - -static SBA_INLINE unsigned long -sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted) -{ - unsigned long *res_ptr = ioc->res_hint; - unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]); - unsigned long pide = ~0UL; - - ASSERT(((unsigned long) ioc->res_hint & (sizeof(unsigned long) - 1UL)) == 0); - ASSERT(res_ptr < res_end); - if (bits_wanted > (BITS_PER_LONG/2)) { - /* Search word at a time - no mask needed */ - for(; res_ptr < res_end; ++res_ptr) { - if (*res_ptr == 0) { - *res_ptr = RESMAP_MASK(bits_wanted); - pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); - pide <<= 3; /* convert to bit address */ - ASSERT(0 != pide); - break; - } - } - /* point to the next word on next pass */ - res_ptr++; - ioc->res_bitshift = 0; - } else { - /* - ** Search the resource bit map on well-aligned values. - ** "o" is the alignment. - ** We need the alignment to invalidate I/O TLB using - ** SBA HW features in the unmap path. - */ - unsigned long o = 1 << get_order(bits_wanted << PAGE_SHIFT); - uint bitshiftcnt = ROUNDUP(ioc->res_bitshift, o); - unsigned long mask; - - if (bitshiftcnt >= BITS_PER_LONG) { - bitshiftcnt = 0; - res_ptr++; - } - mask = RESMAP_MASK(bits_wanted) >> bitshiftcnt; - - DBG_RES("sba_search_bitmap() o %ld %p", o, res_ptr); - while(res_ptr < res_end) - { - DBG_RES(" %p %lx %lx\n", res_ptr, mask, *res_ptr); - ASSERT(0 != mask); - if(0 == ((*res_ptr) & mask)) { - *res_ptr |= mask; /* mark resources busy! */ - pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); - pide <<= 3; /* convert to bit address */ - pide += bitshiftcnt; - ASSERT(0 != pide); - break; - } - mask >>= o; - bitshiftcnt += o; - if (0 == mask) { - mask = RESMAP_MASK(bits_wanted); - bitshiftcnt=0; - res_ptr++; - } - } - /* look in the same word on the next pass */ - ioc->res_bitshift = bitshiftcnt + bits_wanted; - } - - /* wrapped ? */ - ioc->res_hint = (res_end == res_ptr) ? (unsigned long *) ioc->res_map : res_ptr; - return (pide); -} - - -static int -sba_alloc_range(struct ioc *ioc, size_t size) -{ - unsigned int pages_needed = size >> IOVP_SHIFT; -#ifdef CONFIG_PROC_FS - unsigned long cr_start = mfctl(16); -#endif - unsigned long pide; - - ASSERT(pages_needed); - ASSERT((pages_needed * IOVP_SIZE) < DMA_CHUNK_SIZE); - ASSERT(pages_needed < BITS_PER_LONG); - ASSERT(0 == (size & ~IOVP_MASK)); - - /* - ** "seek and ye shall find"...praying never hurts either... - ** ggg sacrifices another 710 to the computer gods. - */ - - pide = sba_search_bitmap(ioc, pages_needed); - if (pide >= (ioc->res_size << 3)) { - pide = sba_search_bitmap(ioc, pages_needed); - if (pide >= (ioc->res_size << 3)) - panic(__FILE__ ": I/O MMU @ %p is out of mapping resources\n", ioc->ioc_hpa); - } - -#ifdef ASSERT_PDIR_SANITY - /* verify the first enable bit is clear */ - if(0x00 != ((u8 *) ioc->pdir_base)[pide*sizeof(u64) + 7]) { - sba_dump_pdir_entry(ioc, "sba_search_bitmap() botched it?", pide); - } -#endif - - DBG_RES("sba_alloc_range(%x) %d -> %lx hint %x/%x\n", - size, pages_needed, pide, - (uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map), - ioc->res_bitshift ); - -#ifdef CONFIG_PROC_FS - { - unsigned long cr_end = mfctl(16); - unsigned long tmp = cr_end - cr_start; - /* check for roll over */ - cr_start = (cr_end < cr_start) ? -(tmp) : (tmp); - } - ioc->avg_search[ioc->avg_idx++] = cr_start; - ioc->avg_idx &= SBA_SEARCH_SAMPLE - 1; - - ioc->used_pages += pages_needed; -#endif - - return (pide); -} - - -/* -** clear bits in the ioc's resource map -*/ -static SBA_INLINE void -sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size) -{ - unsigned long iovp = SBA_IOVP(ioc, iova); - unsigned int pide = PDIR_INDEX(iovp); - unsigned int ridx = pide >> 3; /* convert bit to byte address */ - unsigned long *res_ptr = (unsigned long *) &((ioc)->res_map[ridx & ~RESMAP_IDX_MASK]); - - int bits_not_wanted = size >> IOVP_SHIFT; - - /* 3-bits "bit" address plus 2 (or 3) bits for "byte" == bit in word */ - unsigned long m = RESMAP_MASK(bits_not_wanted) >> (pide & (BITS_PER_LONG - 1)); - - DBG_RES("sba_free_range( ,%x,%x) %x/%lx %x %p %lx\n", - (uint) iova, size, - bits_not_wanted, m, pide, res_ptr, *res_ptr); - -#ifdef CONFIG_PROC_FS - ioc->used_pages -= bits_not_wanted; -#endif - - ASSERT(m != 0); - ASSERT(bits_not_wanted); - ASSERT((bits_not_wanted * IOVP_SIZE) < DMA_CHUNK_SIZE); - ASSERT(bits_not_wanted < BITS_PER_LONG); - ASSERT((*res_ptr & m) == m); /* verify same bits are set */ - *res_ptr &= ~m; -} - - -/************************************************************** -* -* "Dynamic DMA Mapping" support (aka "Coherent I/O") -* -***************************************************************/ - -#define SBA_DMA_HINT(ioc, val) ((val) << (ioc)->hint_shift_pdir) - - -typedef unsigned long space_t; -#define KERNEL_SPACE 0 - -/* -* SBA Mapping Routine -* -* Given a virtual address (vba, arg2) and space id, (sid, arg1) -* sba_io_pdir_entry() loads the I/O PDIR entry pointed to by -* pdir_ptr (arg0). Each IO Pdir entry consists of 8 bytes as -* shown below (MSB == bit 0): -* -* 0 19 51 55 63 -* +-+---------------------+----------------------------------+----+--------+ -* |V| U | PPN[43:12] | U | VI | -* +-+---------------------+----------------------------------+----+--------+ -* -* V == Valid Bit -* U == Unused -* PPN == Physical Page Number -* VI == Virtual Index (aka Coherent Index) -* -* The physical address fields are filled with the results of the LPA -* instruction. The virtual index field is filled with the results of -* of the LCI (Load Coherence Index) instruction. The 8 bits used for -* the virtual index are bits 12:19 of the value returned by LCI. -* -* We need to pre-swap the bytes since PCX-W is Big Endian. -*/ - -void SBA_INLINE -sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba) -{ - u64 pa; /* physical address */ - register unsigned ci; /* coherent index */ - - /* We currently only support kernel addresses */ - ASSERT(sid == 0); - ASSERT(((unsigned long) vba & 0xc0000000UL) == 0xc0000000UL); - - pa = virt_to_phys(vba); - pa &= ~4095ULL; /* clear out offset bits */ - - mtsp(sid,1); - asm("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba)); - pa |= (ci >> 12) & 0xff; /* move CI (8 bits) into lowest byte */ - - pa |= 0x8000000000000000ULL; /* set "valid" bit */ - *pdir_ptr = cpu_to_le64(pa); /* swap and store into I/O Pdir */ -} - - -/*********************************************************** - * The Ike PCOM (Purge Command Register) is to purge - * stale entries in the IO TLB when unmapping entries. - * - * The PCOM register supports purging of multiple pages, with a minium - * of 1 page and a maximum of 2GB. Hardware requires the address be - * aligned to the size of the range being purged. The size of the range - * must be a power of 2. - ***********************************************************/ -static SBA_INLINE void -sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) -{ - u32 iovp = (u32) SBA_IOVP(ioc,iova); - - /* Even though this is a big-endian machine, the entries - ** in the iopdir are swapped. That's why we clear the byte - ** at +7 instead of at +0. - */ - int off = PDIR_INDEX(iovp)*sizeof(u64)+7; - - /* Must be non-zero and rounded up */ - ASSERT(byte_cnt > 0); - ASSERT(0 == (byte_cnt & ~IOVP_MASK)); - -#ifdef ASSERT_PDIR_SANITY - /* Assert first pdir entry is set */ - if (0x80 != (((u8 *) ioc->pdir_base)[off])) { - sba_dump_pdir_entry(ioc,"sba_mark_invalid()", PDIR_INDEX(iovp)); - } -#endif - - if (byte_cnt <= IOVP_SIZE) - { - ASSERT( off < ioc->pdir_size); - - iovp |= IOVP_SHIFT; /* set "size" field for PCOM */ - - /* - ** clear I/O PDIR entry "valid" bit - ** Do NOT clear the rest - save it for debugging. - ** We should only clear bits that have previously - ** been enabled. - */ - ((u8 *)(ioc->pdir_base))[off] = 0; - } else { - u32 t = get_order(byte_cnt) + PAGE_SHIFT; - - iovp |= t; - ASSERT(t <= 31); /* 2GB! Max value of "size" field */ - - do { - /* verify this pdir entry is enabled */ - ASSERT(0x80 == (((u8 *) ioc->pdir_base)[off] & 0x80)); - /* clear I/O Pdir entry "valid" bit first */ - ((u8 *)(ioc->pdir_base))[off] = 0; - off += sizeof(u64); - byte_cnt -= IOVP_SIZE; - } while (byte_cnt > 0); - } - - WRITE_REG32(iovp, ioc->ioc_hpa+IOC_PCOM); -} - -static int -sba_dma_supported( struct pci_dev *dev, u64 mask) -{ - if (dev == NULL) { - printk(MODULE_NAME ": EISA/ISA/et al not supported\n"); - BUG(); - return(0); - } - - dev->dma_mask = mask; /* save it */ - - /* only support PCI devices */ - return((int) (mask >= 0xffffffff)); -} - - -/* -** map_single returns a fully formed IOVA -*/ -static dma_addr_t -sba_map_single(struct pci_dev *dev, void *addr, size_t size, int direction) -{ - struct ioc *ioc = &sba_list->ioc[0]; /* FIXME : see Multi-IOC below */ - unsigned long flags; - dma_addr_t iovp; - dma_addr_t offset; - u64 *pdir_start; - int pide; - - ASSERT(size > 0); - - /* save offset bits */ - offset = ((dma_addr_t) addr) & ~IOVP_MASK; - - /* round up to nearest IOVP_SIZE */ - size = (size + offset + ~IOVP_MASK) & IOVP_MASK; - - spin_lock_irqsave(&ioc->res_lock, flags); -#ifdef ASSERT_PDIR_SANITY - sba_check_pdir(ioc,"Check before sba_map_single()"); -#endif - -#ifdef CONFIG_PROC_FS - ioc->msingle_calls++; - ioc->msingle_pages += size >> IOVP_SHIFT; -#endif - pide = sba_alloc_range(ioc, size); - iovp = (dma_addr_t) pide << IOVP_SHIFT; - - DBG_RUN("sba_map_single() 0x%p -> 0x%lx", addr, (long) iovp | offset); - - pdir_start = &(ioc->pdir_base[pide]); - - while (size > 0) { - ASSERT(((u8 *)pdir_start)[7] == 0); /* verify availability */ - sba_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long) addr); - - DBG_RUN(" pdir 0x%p %02x%02x%02x%02x%02x%02x%02x%02x\n", - pdir_start, - (u8) (((u8 *) pdir_start)[7]), - (u8) (((u8 *) pdir_start)[6]), - (u8) (((u8 *) pdir_start)[5]), - (u8) (((u8 *) pdir_start)[4]), - (u8) (((u8 *) pdir_start)[3]), - (u8) (((u8 *) pdir_start)[2]), - (u8) (((u8 *) pdir_start)[1]), - (u8) (((u8 *) pdir_start)[0]) - ); - - addr += IOVP_SIZE; - size -= IOVP_SIZE; - pdir_start++; - } - /* form complete address */ -#ifdef ASSERT_PDIR_SANITY - sba_check_pdir(ioc,"Check after sba_map_single()"); -#endif - spin_unlock_irqrestore(&ioc->res_lock, flags); - return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG); -} - - -static void -sba_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction) -{ -#ifdef FIXME -/* Multi-IOC (ie N-class) : need to lookup IOC from dev -** o If we can't know about lba PCI data structs, that eliminates ->sysdata. -** o walking up pcidev->parent dead ends at elroy too -** o leaves hashing dev->bus->number into some lookup. -** (may only work for N-class) -** o use (struct pci_hba) and put fields in there for DMA. -** (ioc and per device dma_hint.) -** -** Last one seems the clearest and most promising. -** sba_dma_supported() fill in those fields when the driver queries -** the system for support. -*/ - struct ioc *ioc = (struct ioc *) ((struct pci_hba *) (dev->sysdata))->dma_data; -#else - struct ioc *ioc = &sba_list->ioc[0]; -#endif - - unsigned long flags; - dma_addr_t offset; - offset = iova & ~IOVP_MASK; - - DBG_RUN("%s() iovp 0x%lx/%x\n", __FUNCTION__, (long) iova, size); - - iova ^= offset; /* clear offset bits */ - size += offset; - size = ROUNDUP(size, IOVP_SIZE); - - ASSERT(0 != iova); - - spin_lock_irqsave(&ioc->res_lock, flags); -#ifdef CONFIG_PROC_FS - ioc->usingle_calls++; - ioc->usingle_pages += size >> IOVP_SHIFT; -#endif -#ifdef DELAYED_RESOURCE_CNT - if (ioc->saved_cnt < DELAYED_RESOURCE_CNT) { - ioc->saved_iova[ioc->saved_cnt] = iova; - ioc->saved_size[ioc->saved_cnt] = size; - ioc_saved_cnt++; - } else { - do { -#endif - sba_mark_invalid(ioc, iova, size); - sba_free_range(ioc, iova, size); - -#ifdef DELAYED_RESOURCE_CNT - ioc->saved_cnt--; - iova = ioc->saved_iova[ioc->saved_cnt]; - size = ioc->saved_size[ioc->saved_cnt]; - } while (ioc->saved_cnt) - - /* flush purges */ - (void) (volatile) READ_REG32(ioc->ioc_hpa+IOC_PCOM); - } -#else - /* flush purges */ - READ_REG32(ioc->ioc_hpa+IOC_PCOM); -#endif - spin_unlock_irqrestore(&ioc->res_lock, flags); -} - - -static void * -sba_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) -{ - void *ret; - - if (!hwdev) { - /* only support PCI */ - *dma_handle = 0; - return 0; - } - - ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size)); - - if (ret) { - memset(ret, 0, size); - *dma_handle = sba_map_single(hwdev, ret, size, 0); - } - - return ret; -} - - -static void -sba_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) -{ - sba_unmap_single(hwdev, dma_handle, size, 0); - free_pages((unsigned long) vaddr, get_order(size)); -} - -/* -** Two address ranges are "virtually contiguous" iff: -** 1) end of prev == start of next, or... append case -** 3) end of next == start of prev prepend case -** -** and they are DMA contiguous *iff*: -** 2) end of prev and start of next are both on a page boundry -** -** (shift left is a quick trick to mask off upper bits) -*/ -#define DMA_CONTIG(__X, __Y) \ - (((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL) - -/* -** Assumption is two transactions are mutually exclusive. -** ie both go to different parts of memory. -** If both are true, then both transaction are on the same page. -*/ -#define DMA_SAME_PAGE(s1,e1,s2,e2) \ - ( ((((s1) ^ (s2)) >> PAGE_SHIFT) == 0) \ - && ((((e1) ^ (e2)) >> PAGE_SHIFT) == 0) ) - -/* -** Since 0 is a valid pdir_base index value, can't use that -** to determine if a value is valid or not. Use a flag to indicate -** the SG list entry contains a valid pdir index. -*/ -#define PIDE_FLAG 0x80000000UL - -#ifdef DEBUG_LARGE_SG_ENTRIES -int dump_run_sg = 0; -#endif - -static SBA_INLINE int -sba_fill_pdir( - struct ioc *ioc, - struct scatterlist *startsg, - int nents) -{ - struct scatterlist *dma_sg = startsg; /* pointer to current DMA */ - int n_mappings = 0; - u64 *pdirp = 0; - unsigned long dma_offset = 0; - - dma_sg--; - while (nents-- > 0) { - int cnt = sg_dma_len(startsg); - sg_dma_len(startsg) = 0; - -#ifdef DEBUG_LARGE_SG_ENTRIES - if (dump_run_sg) - printk(" %d : %08lx/%05x %p/%05x\n", - nents, - (unsigned long) sg_dma_address(startsg), cnt, - startsg->address, startsg->length - ); -#else - DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n", - nents, - (unsigned long) sg_dma_address(startsg), cnt, - startsg->address, startsg->length - ); -#endif - /* - ** Look for the start of a new DMA stream - */ - if (sg_dma_address(startsg) & PIDE_FLAG) { - u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG; - dma_offset = (unsigned long) pide & ~IOVP_MASK; - pide >>= IOVP_SHIFT; - pdirp = &(ioc->pdir_base[pide]); - sg_dma_address(startsg) = 0; - ++dma_sg; - sg_dma_address(dma_sg) = (pide << IOVP_SHIFT) + dma_offset; - n_mappings++; - } - - /* - ** Look for a VCONTIG chunk - */ - if (cnt) { - unsigned long vaddr = (unsigned long) startsg->address; - ASSERT(pdirp); - - sg_dma_len(dma_sg) += cnt; - cnt += dma_offset; - dma_offset=0; /* only want offset on first chunk */ - cnt = ROUNDUP(cnt, IOVP_SIZE); -#ifdef CONFIG_PROC_FS - ioc->msg_pages += cnt >> IOVP_SHIFT; -#endif - do { - sba_io_pdir_entry(pdirp, KERNEL_SPACE, vaddr); - vaddr += IOVP_SIZE; - cnt -= IOVP_SIZE; - pdirp++; - } while (cnt > 0); - } - startsg++; - } -#ifdef DEBUG_LARGE_SG_ENTRIES - dump_run_sg = 0; -#endif - return(n_mappings); -} - - - -/* -** First pass is to walk the SG list and determine where the breaks are -** in the DMA stream. Allocates PDIR entries but does not fill them. -** Returns the number of DMA chunks. -** -** Doing the fill seperate from the coalescing/allocation keeps the -** code simpler. Future enhancement could make one pass through -** the sglist do both. -*/ -static SBA_INLINE int -sba_coalesce_chunks( struct ioc *ioc, - struct scatterlist *startsg, - int nents) -{ - int n_mappings = 0; - - while (nents > 0) { - struct scatterlist *dma_sg; /* next DMA stream head */ - unsigned long dma_offset, dma_len; /* start/len of DMA stream */ - struct scatterlist *chunksg; /* virtually contig chunk head */ - unsigned long chunk_addr, chunk_len; /* start/len of VCONTIG chunk */ - - /* - ** Prepare for first/next DMA stream - */ - dma_sg = chunksg = startsg; - dma_len = chunk_len = startsg->length; - chunk_addr = (unsigned long) startsg->address; - dma_offset = 0UL; - - /* - ** This loop terminates one iteration "early" since - ** it's always looking one "ahead". - */ - while (--nents > 0) { - /* ptr to coalesce prev and next */ - struct scatterlist *prev_sg = startsg; - unsigned long prev_end = (unsigned long) prev_sg->address + prev_sg->length; - unsigned long current_end; - - /* PARANOID: clear entries */ - sg_dma_address(startsg) = 0; - sg_dma_len(startsg) = 0; - - /* Now start looking ahead */ - startsg++; - current_end = (unsigned long) startsg->address + startsg->length; - - /* - ** First look for virtually contiguous blocks. - ** PARISC needs this since it's cache is virtually - ** indexed and we need the associated virtual - ** address for each I/O address we map. - ** - ** 1) can we *prepend* the next transaction? - */ - if (current_end == (unsigned long) prev_sg->address) - { - /* prepend : get new offset */ - chunksg = startsg; - chunk_addr = (unsigned long) prev_sg->address; - chunk_len += startsg->length; - dma_len += startsg->length; - continue; - } - - /* - ** 2) or append the next transaction? - */ - if (prev_end == (unsigned long) startsg->address) - { - chunk_len += startsg->length; - dma_len += startsg->length; - continue; - } - -#ifdef DEBUG_LARGE_SG_ENTRIES - dump_run_sg = (chunk_len > IOVP_SIZE); -#endif - /* - ** Not virtually contigous. - ** Terminate prev chunk. - ** Start a new chunk. - ** - ** Once we start a new VCONTIG chunk, the offset - ** can't change. And we need the offset from the first - ** chunk - not the last one. Ergo Successive chunks - ** must start on page boundaries and dove tail - ** with it's predecessor. - */ - sg_dma_len(prev_sg) = chunk_len; - - chunk_len = startsg->length; - dma_offset |= (chunk_addr & ~IOVP_MASK); - ASSERT((0 == (chunk_addr & ~IOVP_MASK)) || - (dma_offset == (chunk_addr & ~IOVP_MASK))); - -#if 0 - /* - ** 4) do the chunks end/start on page boundaries? - ** Easier than 3 since no offsets are involved. - */ - if (DMA_CONTIG(prev_end, startsg->address)) - { - /* - ** Yes. - ** Reset chunk ptr. - */ - chunksg = startsg; - chunk_addr = (unsigned long) startsg->address; - - continue; - } else -#endif - { - break; - } - } - - /* - ** End of DMA Stream - ** Terminate chunk. - ** Allocate space for DMA stream. - */ - sg_dma_len(startsg) = chunk_len; - dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK; - sg_dma_address(dma_sg) = - PIDE_FLAG - | (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT) - | dma_offset; - n_mappings++; - } - - return n_mappings; -} - - -/* -** And this algorithm still generally only ends up coalescing entries -** that happens to be on the same page due to how sglists are assembled. -*/ -static int -sba_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) -{ - struct ioc *ioc = &sba_list->ioc[0]; /* FIXME : see Multi-IOC below */ - int coalesced, filled = 0; - unsigned long flags; - - DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents); - - /* Fast path single entry scatterlists. */ - if (nents == 1) { - sg_dma_address(sglist)= sba_map_single(dev, sglist->address, - sglist->length, direction); - sg_dma_len(sglist)= sglist->length; - return 1; - } - - spin_lock_irqsave(&ioc->res_lock, flags); - -#ifdef ASSERT_PDIR_SANITY - if (sba_check_pdir(ioc,"Check before sba_map_sg()")) - { - sba_dump_sg(ioc, sglist, nents); - panic("Check before sba_map_sg()"); - } -#endif - -#ifdef CONFIG_PROC_FS - ioc->msg_calls++; -#endif - - /* - ** First coalesce the chunks and allocate I/O pdir space - ** - ** If this is one DMA stream, we can properly map using the - ** correct virtual address associated with each DMA page. - ** w/o this association, we wouldn't have coherent DMA! - ** Access to the virtual address is what forces a two pass algorithm. - */ - coalesced = sba_coalesce_chunks(ioc, sglist, nents); - - /* - ** Program the I/O Pdir - ** - ** map the virtual addresses to the I/O Pdir - ** o dma_address will contain the pdir index - ** o dma_len will contain the number of bytes to map - ** o address contains the virtual address. - */ - filled = sba_fill_pdir(ioc, sglist, nents); - -#ifdef ASSERT_PDIR_SANITY - if (sba_check_pdir(ioc,"Check after sba_map_sg()")) - { - sba_dump_sg(ioc, sglist, nents); - panic("Check after sba_map_sg()\n"); - } -#endif - - spin_unlock_irqrestore(&ioc->res_lock, flags); - - ASSERT(coalesced == filled); - DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled); - - return filled; -} - - -static void -sba_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) -{ - struct ioc *ioc = &sba_list->ioc[0]; /* FIXME : see Multi-IOC below */ -#ifdef ASSERT_PDIR_SANITY - unsigned long flags; -#endif - - DBG_RUN_SG("%s() START %d entries, %p,%x\n", - __FUNCTION__, nents, sglist->address, sglist->length); - -#ifdef CONFIG_PROC_FS - ioc->usg_calls++; -#endif - -#ifdef ASSERT_PDIR_SANITY - spin_lock_irqsave(&ioc->res_lock, flags); - sba_check_pdir(ioc,"Check before sba_unmap_sg()"); - spin_unlock_irqrestore(&ioc->res_lock, flags); -#endif - - while (sg_dma_len(sglist) && nents--) { - -#ifdef CONFIG_PROC_FS - ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT; -#endif - sba_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); - ++sglist; - } - - DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__, nents); - -#ifdef ASSERT_PDIR_SANITY - spin_lock_irqsave(&ioc->res_lock, flags); - sba_check_pdir(ioc,"Check after sba_unmap_sg()"); - spin_unlock_irqrestore(&ioc->res_lock, flags); -#endif - -} - -static struct pci_dma_ops sba_ops = { - sba_dma_supported, - sba_alloc_consistent, /* allocate cacheable host mem */ - sba_free_consistent, /* release cacheable host mem */ - sba_map_single, - sba_unmap_single, - sba_map_sg, - sba_unmap_sg, - NULL, /* dma_sync_single */ - NULL /* dma_sync_sg */ -}; - - -/************************************************************************** -** -** SBA PAT PDC support -** -** o call pdc_pat_cell_module() -** o store ranges in PCI "resource" structures -** -**************************************************************************/ - -static void -sba_get_pat_resources(struct sba_device *sba_dev) -{ -#if 0 -/* -** TODO/REVISIT/FIXME: support for directed ranges requires calls to -** PAT PDC to program the SBA/LBA directed range registers...this -** burden may fall on the LBA code since it directly supports the -** PCI subsystem. It's not clear yet. - ggg -*/ -PAT_MOD(mod)->mod_info.mod_pages = PAT_GET_MOD_PAGES(temp); - FIXME : ??? -PAT_MOD(mod)->mod_info.dvi = PAT_GET_DVI(temp); - Tells where the dvi bits are located in the address. -PAT_MOD(mod)->mod_info.ioc = PAT_GET_IOC(temp); - FIXME : ??? -#endif -} - - -/************************************************************** -* -* Initialization and claim -* -***************************************************************/ - - -static void -sba_ioc_init(struct ioc *ioc) -{ - extern unsigned long mem_max; /* arch.../setup.c */ - extern void lba_init_iregs(void *, u32, u32); /* arch.../lba_pci.c */ - - u32 iova_space_size, iova_space_mask; - void * pdir_base; - int pdir_size, iov_order; - - /* - ** Determine IOVA Space size from memory size. - ** Using "mem_max" is a kluge. - ** - ** Ideally, PCI drivers would register the maximum number - ** of DMA they can have outstanding for each device they - ** own. Next best thing would be to guess how much DMA - ** can be outstanding based on PCI Class/sub-class. Both - ** methods still require some "extra" to support PCI - ** Hot-Plug/Removal of PCI cards. (aka PCI OLARD). - ** - ** While we have 32-bits "IOVA" space, top two 2 bits are used - ** for DMA hints - ergo only 30 bits max. - */ - /* limit IOVA space size to 1MB-1GB */ - if (mem_max < (sba_mem_ratio*1024*1024)) { - iova_space_size = 1024*1024; -#ifdef __LP64__ - } else if (mem_max > (sba_mem_ratio*512*1024*1024)) { - iova_space_size = 512*1024*1024; -#endif - } else { - iova_space_size = (u32) (mem_max/sba_mem_ratio); - } - - /* - ** iova space must be log2() in size. - ** thus, pdir/res_map will also be log2(). - */ - iov_order = get_order(iova_space_size >> (IOVP_SHIFT-PAGE_SHIFT)); - ASSERT(iov_order <= (30 - IOVP_SHIFT)); /* iova_space_size <= 1GB */ - ASSERT(iov_order >= (20 - IOVP_SHIFT)); /* iova_space_size >= 1MB */ - iova_space_size = 1 << (iov_order + IOVP_SHIFT); - - ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64); - - ASSERT(pdir_size < 4*1024*1024); /* max pdir size < 4MB */ - - /* Verify it's a power of two */ - ASSERT((1 << get_order(pdir_size)) == (pdir_size >> PAGE_SHIFT)); - - DBG_INIT("%s() hpa 0x%p mem %dMBIOV %dMB (%d bits) PDIR size 0x%0x", - __FUNCTION__, ioc->ioc_hpa, (int) (mem_max>>20), - iova_space_size>>20, iov_order + PAGE_SHIFT, pdir_size); - - /* FIXME : DMA HINTs not used */ - ioc->hint_shift_pdir = iov_order + PAGE_SHIFT; - ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT)); - - ioc->pdir_base = - pdir_base = (void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size)); - if (NULL == pdir_base) - { - panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__); - } - memset(pdir_base, 0, pdir_size); - - DBG_INIT("sba_ioc_init() pdir %p size %x hint_shift_pdir %x hint_mask_pdir %lx\n", - pdir_base, pdir_size, - ioc->hint_shift_pdir, ioc->hint_mask_pdir); - - ASSERT((((unsigned long) pdir_base) & PAGE_MASK) == (unsigned long) pdir_base); - WRITE_REG64(virt_to_phys(pdir_base), (u64 *)(ioc->ioc_hpa+IOC_PDIR_BASE)); - - DBG_INIT(" base %p\n", pdir_base); - - /* build IMASK for IOC and Elroy */ - iova_space_mask = 0xffffffff; - iova_space_mask <<= (iov_order + PAGE_SHIFT); - - /* - ** On C3000 w/512MB mem, HP-UX 10.20 reports: - ** ibase=0, imask=0xFE000000, size=0x2000000. - */ - ioc->ibase = IOC_IOVA_SPACE_BASE | 1; /* bit 0 == enable bit */ - ioc->imask = iova_space_mask; /* save it */ - - DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n", __FUNCTION__, - ioc->ibase, ioc->imask); - - /* - ** FIXME: Hint registers are programmed with default hint - ** values during boot, so hints should be sane even if we - ** can't reprogram them the way drivers want. - */ - - /* - ** setup Elroy IBASE/IMASK registers as well. - */ - lba_init_iregs(ioc->ioc_hpa, ioc->ibase, ioc->imask); - - /* - ** Program the IOC's ibase and enable IOVA translation - */ - WRITE_REG32(ioc->ibase, ioc->ioc_hpa+IOC_IBASE); - WRITE_REG32(ioc->imask, ioc->ioc_hpa+IOC_IMASK); - - /* Set I/O PDIR Page size to 4K */ - WRITE_REG32(0, ioc->ioc_hpa+IOC_TCNFG); - - /* - ** Clear I/O TLB of any possible entries. - ** (Yes. This is a it paranoid...but so what) - */ - WRITE_REG32(0 | 31, ioc->ioc_hpa+IOC_PCOM); - - DBG_INIT("%s() DONE\n", __FUNCTION__); -} - - - -/************************************************************************** -** -** SBA initialization code (HW and SW) -** -** o identify SBA chip itself -** o initialize SBA chip modes (HardFail) -** o initialize SBA chip modes (HardFail) -** o FIXME: initialize DMA hints for reasonable defaults -** -**************************************************************************/ - -static void -sba_hw_init(struct sba_device *sba_dev) -{ - int i; - int num_ioc; - u32 ioc_ctl; - - ioc_ctl = READ_REG32(sba_dev->sba_hpa+IOC_CTRL); - DBG_INIT("%s() hpa 0x%p ioc_ctl 0x%x ->", __FUNCTION__, sba_dev->sba_hpa, ioc_ctl ); - ioc_ctl &= ~(IOC_CTRL_RM | IOC_CTRL_NC); - ASSERT(ioc_ctl & IOC_CTRL_TE); /* astro: firmware enables this */ - - WRITE_REG32(ioc_ctl, sba_dev->sba_hpa+IOC_CTRL); - -#ifdef SBA_DEBUG_INIT - ioc_ctl = READ_REG32(sba_dev->sba_hpa+IOC_CTRL); - DBG_INIT(" 0x%x\n", ioc_ctl ); -#endif - - if (IS_ASTRO(sba_dev->iodc)) { - /* PAT_PDC (L-class) also reports the same goofy base */ - sba_dev->ioc[0].ioc_hpa = (char *) ASTRO_IOC_OFFSET; - num_ioc = 1; - } else { - sba_dev->ioc[0].ioc_hpa = sba_dev->ioc[1].ioc_hpa = 0; - num_ioc = 2; - } - - sba_dev->num_ioc = num_ioc; - for( i = 0; i < num_ioc; i++) - { - (unsigned long) sba_dev->ioc[i].ioc_hpa += (unsigned long) sba_dev->sba_hpa + IKE_IOC_OFFSET(i); - - /* - ** Make sure the box crashes if we get any errors on a rope. - */ - WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE0_CTL); - WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE1_CTL); - WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE2_CTL); - WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE3_CTL); - WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE4_CTL); - WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE5_CTL); - WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE6_CTL); - WRITE_REG32(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE7_CTL); - - /* flush out the writes */ - READ_REG32(sba_dev->ioc[i].ioc_hpa + ROPE7_CTL); - - sba_ioc_init(&(sba_dev->ioc[i])); - } -} - -static void -sba_common_init(struct sba_device *sba_dev) -{ - int i; - - /* add this one to the head of the list (order doesn't matter) - ** This will be useful for debugging - especially if we get coredumps - */ - sba_dev->next = sba_list; - sba_list = sba_dev; - sba_count++; - - for(i=0; i< sba_dev->num_ioc; i++) { - int res_size; -#ifdef CONFIG_DMB_TRAP - extern void iterate_pages(unsigned long , unsigned long , - void (*)(pte_t * , unsigned long), - unsigned long ); - void set_data_memory_break(pte_t * , unsigned long); -#endif - /* resource map size dictated by pdir_size */ - res_size = sba_dev->ioc[i].pdir_size/sizeof(u64); /* entries */ - res_size >>= 3; /* convert bit count to byte count */ - DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, res_size); - - sba_dev->ioc[i].res_size = res_size; - sba_dev->ioc[i].res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size)); - -#ifdef CONFIG_DMB_TRAP - iterate_pages( sba_dev->ioc[i].res_map, res_size, - set_data_memory_break, 0); -#endif - - if (NULL == sba_dev->ioc[i].res_map) - { - panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__ ); - } - - memset(sba_dev->ioc[i].res_map, 0, res_size); - /* next available IOVP - circular search */ - sba_dev->ioc[i].res_hint = (unsigned long *) - &(sba_dev->ioc[i].res_map[L1_CACHE_BYTES]); - -#ifdef ASSERT_PDIR_SANITY - /* Mark first bit busy - ie no IOVA 0 */ - sba_dev->ioc[i].res_map[0] = 0x80; - sba_dev->ioc[i].pdir_base[0] = 0xeeffc0addbba0080ULL; -#endif - -#ifdef CONFIG_DMB_TRAP - iterate_pages( sba_dev->ioc[i].res_map, res_size, - set_data_memory_break, 0); - iterate_pages( sba_dev->ioc[i].pdir_base, sba_dev->ioc[i].pdir_size, - set_data_memory_break, 0); -#endif - - DBG_INIT("sba_common_init() %d res_map %x %p\n", - i, res_size, sba_dev->ioc[i].res_map); - } - - sba_dev->sba_lock = SPIN_LOCK_UNLOCKED; -} - -#ifdef CONFIG_PROC_FS -static int sba_proc_info(char *buf, char **start, off_t offset, int len) -{ - struct sba_device *sba_dev = sba_list; -/* FIXME: Multi-IOC support broken! */ - struct ioc *ioc = &sba_dev->ioc[0]; - int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */ - unsigned long i = 0, avg = 0, min, max; - - sprintf(buf, "%s rev %d.%d\n", - parisc_getHWdescription(sba_dev->iodc->hw_type, - sba_dev->iodc->hversion, sba_dev->iodc->sversion), - (sba_dev->hw_rev & 0x7) + 1, - (sba_dev->hw_rev & 0x18) >> 3 - ); - sprintf(buf, "%sIO PDIR size : %d bytes (%d entries)\n", - buf, - ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits per byte */ - total_pages); /* 8 bits per byte */ - - sprintf(buf, "%sIO PDIR entries : %ld free %ld used (%d%%)\n", buf, - total_pages - ioc->used_pages, ioc->used_pages, - (int) (ioc->used_pages * 100 / total_pages)); - - sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", - buf, ioc->res_size, ioc->res_size << 3); /* 8 bits per byte */ - - min = max = ioc->avg_search[0]; - for (i = 0; i < SBA_SEARCH_SAMPLE; i++) { - avg += ioc->avg_search[i]; - if (ioc->avg_search[i] > max) max = ioc->avg_search[i]; - if (ioc->avg_search[i] < min) min = ioc->avg_search[i]; - } - avg /= SBA_SEARCH_SAMPLE; - sprintf(buf, "%s Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n", - buf, min, avg, max); - - sprintf(buf, "%spci_map_single(): %8ld calls %8ld pages (avg %d/1000)\n", - buf, ioc->msingle_calls, ioc->msingle_pages, - (int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls)); - - /* KLUGE - unmap_sg calls unmap_single for each mapped page */ - min = ioc->usingle_calls - ioc->usg_calls; - max = ioc->usingle_pages - ioc->usg_pages; - sprintf(buf, "%spci_unmap_single: %8ld calls %8ld pages (avg %d/1000)\n", - buf, min, max, - (int) ((max * 1000)/min)); - - sprintf(buf, "%spci_map_sg() : %8ld calls %8ld pages (avg %d/1000)\n", - buf, ioc->msg_calls, ioc->msg_pages, - (int) ((ioc->msg_pages * 1000)/ioc->msg_calls)); - - sprintf(buf, "%spci_unmap_sg() : %8ld calls %8ld pages (avg %d/1000)\n", - buf, ioc->usg_calls, ioc->usg_pages, - (int) ((ioc->usg_pages * 1000)/ioc->usg_calls)); - - return strlen(buf); -} - -static int -sba_resource_map(char *buf, char **start, off_t offset, int len) -{ - struct sba_device *sba_dev = sba_list; - struct ioc *ioc = &sba_dev->ioc[0]; - unsigned long *res_ptr = (unsigned long *)ioc->res_map; - int i; - - for(i = 0; i < (ioc->res_size / sizeof(unsigned long)); ++i, ++res_ptr) { - if ((i & 7) == 0) - strcat(buf,"\n "); - sprintf(buf, "%s %08lx", buf, *res_ptr); - } - strcat(buf, "\n"); - - return strlen(buf); -} -#endif - -/* -** Determine if lba should claim this chip (return 0) or not (return 1). -** If so, initialize the chip and tell other partners in crime they -** have work to do. -*/ -int -sba_driver_callback(struct hp_device *d, struct pa_iodc_driver *dri) -{ - struct sba_device *sba_dev; - u32 func_class; - int i; - - if (IS_ASTRO(d)) { - static char astro_rev[]="Astro ?.?"; - - /* Read HW Rev First */ - func_class = READ_REG32(d->hpa); - - astro_rev[6] = '1' + (char) (func_class & 0x7); - astro_rev[8] = '0' + (char) ((func_class & 0x18) >> 3); - dri->version = astro_rev; - } else { - static char ike_rev[]="Ike rev ?"; - - /* Read HW Rev First */ - func_class = READ_REG32(d->hpa + SBA_FCLASS); - - ike_rev[8] = '0' + (char) (func_class & 0xff); - dri->version = ike_rev; - } - - printk("%s found %s at 0x%p\n", dri->name, dri->version, d->hpa); - - sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL); - if (NULL == sba_dev) - { - printk(MODULE_NAME " - couldn't alloc sba_device\n"); - return(1); - } - memset(sba_dev, 0, sizeof(struct sba_device)); - for(i=0; iioc[i].res_lock)); - - - sba_dev->hw_rev = func_class; - sba_dev->iodc = d; - sba_dev->sba_hpa = d->hpa; /* faster access */ - - sba_get_pat_resources(sba_dev); - sba_hw_init(sba_dev); - sba_common_init(sba_dev); - - hppa_dma_ops = &sba_ops; - -#ifdef CONFIG_PROC_FS - if (IS_ASTRO(d)) { - create_proc_info_entry("Astro", 0, proc_runway_root, sba_proc_info); - } else { - create_proc_info_entry("Ike", 0, proc_runway_root, sba_proc_info); - } - create_proc_info_entry("bitmap", 0, proc_runway_root, sba_resource_map); -#endif - return 0; -} diff -Nru a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c --- a/arch/parisc/kernel/setup.c Mon Nov 4 14:31:02 2002 +++ b/arch/parisc/kernel/setup.c Mon Nov 4 14:31:02 2002 @@ -143,10 +143,8 @@ dma_ops_init(); #endif -#ifdef CONFIG_VT -# if defined(CONFIG_STI_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) +#ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; /* we use take_over_console() later ! */ -# endif #endif } diff -Nru a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c --- a/arch/parisc/kernel/sys_parisc.c Mon Nov 4 14:31:02 2002 +++ b/arch/parisc/kernel/sys_parisc.c Mon Nov 4 14:31:02 2002 @@ -147,6 +147,40 @@ } +/* Fucking broken ABI */ + +extern asmlinkage long sys_truncate64(const char *, loff_t); +extern asmlinkage long sys_ftruncate64(unsigned int, loff_t); +extern asmlinkage ssize_t sys_pread64(unsigned int fd, char *buf, + size_t count, loff_t pos); +extern asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char *buf, + size_t count, loff_t pos); + +asmlinkage long parisc_truncate64(const char * path, + unsigned int high, unsigned int low) +{ + return sys_truncate(path, (loff_t)high << 32 | low); +} + +asmlinkage long parisc_ftruncate64(unsigned int fd, + unsigned int high, unsigned int low) +{ + return sys_ftruncate(fd, (loff_t)high << 32 | low); +} + +asmlinkage ssize_t parisc_pread64(unsigned int fd, char *buf, size_t count, + unsigned int high, unsigned int low) +{ + return sys_pread64(fd, buf, count, (loff_t)high << 32 | low); +} + +asmlinkage ssize_t parisc_pwrite64(unsigned int fd, const char *buf, + size_t count, unsigned int high, unsigned int low) +{ + return sys_pwrite64(fd, buf, count, (loff_t)high << 32 | low); +} + + /* * FIXME, please remove this crap as soon as possible * diff -Nru a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c --- a/arch/parisc/kernel/sys_parisc32.c Mon Nov 4 14:31:01 2002 +++ b/arch/parisc/kernel/sys_parisc32.c Mon Nov 4 14:31:01 2002 @@ -2743,19 +2743,7 @@ /* LFS */ -extern asmlinkage long sys_truncate(const char *, loff_t); -extern asmlinkage long sys_ftruncate(unsigned int, loff_t); extern asmlinkage long sys_fcntl(unsigned int, unsigned int, unsigned long); - -asmlinkage long sys32_truncate64(const char * path, unsigned int high, unsigned int low) -{ - return sys_truncate(path, (loff_t)high << 32 | low); -} - -asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned int high, unsigned int low) -{ - return sys_ftruncate(fd, (loff_t)high << 32 | low); -} asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) { diff -Nru a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S --- a/arch/parisc/kernel/syscall.S Mon Nov 4 14:31:03 2002 +++ b/arch/parisc/kernel/syscall.S Mon Nov 4 14:31:03 2002 @@ -331,10 +331,12 @@ #define ENTRY_SAME(_name_) .dword sys_##_name_ #define ENTRY_DIFF(_name_) .dword sys32_##_name_ #define ENTRY_UHOH(_name_) .dword sys32_##unimplemented +#define ENTRY_OURS(_name_) .dword parisc_##_name_ #else #define ENTRY_SAME(_name_) .word sys_##_name_ #define ENTRY_DIFF(_name_) .word sys_##_name_ #define ENTRY_UHOH(_name_) .word sys_##_name_ +#define ENTRY_OURS(_name_) .word parisc_##_name_ #endif .align 8 @@ -398,7 +400,7 @@ /* struct sockaddr... */ ENTRY_SAME(getsockname) /* it seems possible brk() could return a >4G pointer... */ - ENTRY_SAME(brk) /* 45 */ + ENTRY_SAME(brk) /* 45 */ ENTRY_SAME(setgid) ENTRY_SAME(getgid) ENTRY_SAME(signal) @@ -476,8 +478,8 @@ ENTRY_DIFF(getitimer) /* 105 */ ENTRY_SAME(capget) ENTRY_SAME(capset) - ENTRY_SAME(pread64) - ENTRY_SAME(pwrite64) + ENTRY_OURS(pread64) + ENTRY_OURS(pwrite64) ENTRY_SAME(getcwd) /* 110 */ ENTRY_SAME(vhangup) ENTRY_SAME(fstat64) @@ -592,18 +594,18 @@ ENTRY_SAME(shmat_wrapper) ENTRY_SAME(shmdt) ENTRY_SAME(shmget) - ENTRY_SAME(shmctl_broken) /* 195 */ + ENTRY_SAME(shmctl_broken) /* 195 */ ENTRY_SAME(ni_syscall) /* streams1 */ ENTRY_SAME(ni_syscall) /* streams2 */ ENTRY_SAME(lstat64) - ENTRY_DIFF(truncate64) - ENTRY_DIFF(ftruncate64) /* 200 */ + ENTRY_OURS(truncate64) + ENTRY_OURS(ftruncate64) /* 200 */ ENTRY_SAME(getdents64) ENTRY_DIFF(fcntl64) #ifdef CONFIG_XFS_FS ENTRY_SAME(attrctl) ENTRY_SAME(acl_get) - ENTRY_SAME(acl_set) /* 205 */ + ENTRY_SAME(acl_set) /* 205 */ #else ENTRY_SAME(ni_syscall) ENTRY_SAME(ni_syscall) diff -Nru a/arch/parisc/lib/Makefile b/arch/parisc/lib/Makefile --- a/arch/parisc/lib/Makefile Mon Nov 4 14:31:02 2002 +++ b/arch/parisc/lib/Makefile Mon Nov 4 14:31:02 2002 @@ -1,9 +1,5 @@ # -# Makefile for parisc-specific library files.. +# Makefile for parisc-specific library files # - -L_TARGET = lib.a obj-y := lusercopy.o bitops.o checksum.o io.o memset.o - -include $(TOPDIR)/Rules.make diff -Nru a/arch/parisc/math-emu/Makefile b/arch/parisc/math-emu/Makefile --- a/arch/parisc/math-emu/Makefile Mon Nov 4 14:31:01 2002 +++ b/arch/parisc/math-emu/Makefile Mon Nov 4 14:31:01 2002 @@ -1,11 +1,6 @@ # # Makefile for the linux/parisc floating point code # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# Note 2! The CFLAGS definition is now in the main makefile... obj-y := frnd.o driver.o decode_exc.o fpudispatch.o denormal.o \ dfmpy.o sfmpy.o sfsqrt.o dfsqrt.o dfadd.o fmpyfadd.o \ @@ -16,6 +11,4 @@ # Math emulation code beyond the FRND is required for 712/80i and # other very old or stripped-down PA-RISC CPUs -- not currently supported -obj-$CONFIG_MATH_EMULATION += unimplemented-math-emulation.o - -include $(TOPDIR)/Rules.make +obj-$(CONFIG_MATH_EMULATION) += unimplemented-math-emulation.o diff -Nru a/arch/parisc/mm/Makefile b/arch/parisc/mm/Makefile --- a/arch/parisc/mm/Makefile Mon Nov 4 14:31:02 2002 +++ b/arch/parisc/mm/Makefile Mon Nov 4 14:31:02 2002 @@ -1,7 +1,5 @@ # -# Makefile for the linux parisc-specific parts of the memory manager. +# Makefile for arch/parisc/mm # obj-y := init.o fault.o extable.o ioremap.o - -include $(TOPDIR)/Rules.make diff -Nru a/arch/ppc/Kconfig b/arch/ppc/Kconfig --- a/arch/ppc/Kconfig Mon Nov 4 14:31:02 2002 +++ b/arch/ppc/Kconfig Mon Nov 4 14:31:03 2002 @@ -1,6 +1,15 @@ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # + +config MMU + bool + default y + +config SWAP + bool + default y + config UID16 bool diff -Nru a/arch/ppc/amiga/amiints.c b/arch/ppc/amiga/amiints.c --- a/arch/ppc/amiga/amiints.c Mon Nov 4 14:31:00 2002 +++ b/arch/ppc/amiga/amiints.c Mon Nov 4 14:31:00 2002 @@ -189,7 +189,7 @@ irq_desc_t *desc = irq_desc + irq; struct irqaction *action = desc->action; - kstat.irqs[0][irq]++; + kstat_cpu(0).irqs[irq]++; action->handler(irq, action->dev_id, fp); } @@ -198,7 +198,7 @@ irq_desc_t *desc = irq_desc + irq; struct irqaction *action; - kstat.irqs[0][irq]++; + kstat_cpu(0).irqs[irq]++; custom.intreq = ami_intena_vals[irq]; diff -Nru a/arch/ppc/amiga/cia.c b/arch/ppc/amiga/cia.c --- a/arch/ppc/amiga/cia.c Mon Nov 4 14:31:01 2002 +++ b/arch/ppc/amiga/cia.c Mon Nov 4 14:31:01 2002 @@ -148,7 +148,7 @@ custom.intreq = base->int_mask; for (i = 0; i < CIA_IRQS; i++, irq++) { if (ints & 1) { - kstat.irqs[0][irq]++; + kstat_cpu(0).irqs[irq]++; action = desc->action; action->handler(irq, action->dev_id, fp); } diff -Nru a/arch/ppc/amiga/ints.c b/arch/ppc/amiga/ints.c --- a/arch/ppc/amiga/ints.c Mon Nov 4 14:31:00 2002 +++ b/arch/ppc/amiga/ints.c Mon Nov 4 14:31:00 2002 @@ -130,7 +130,7 @@ { if (vec >= VEC_INT1 && vec <= VEC_INT7 && !MACH_IS_BVME6000) { vec -= VEC_SPUR; - kstat.irqs[0][vec]++; + kstat_cpu(0).irqs[vec]++; irq_list[vec].handler(vec, irq_list[vec].dev_id, fp); } else { if (mach_process_int) @@ -149,7 +149,7 @@ if (mach_default_handler) { for (i = 0; i < SYS_IRQS; i++) { seq_printf(p, "auto %2d: %10u ", i, - i ? kstat.irqs[0][i] : num_spurious); + i ? kstat_cpu(0).irqs[i] : num_spurious); seq_puts(p, " "); seq_printf(p, "%s\n", irq_list[i].devname); } diff -Nru a/arch/ppc/configs/apus_defconfig b/arch/ppc/configs/apus_defconfig --- a/arch/ppc/configs/apus_defconfig Mon Nov 4 14:31:02 2002 +++ b/arch/ppc/configs/apus_defconfig Mon Nov 4 14:31:02 2002 @@ -73,7 +73,6 @@ CONFIG_FB_CONSOLE=y CONFIG_AMIGA=y CONFIG_ZORRO=y -CONFIG_AMIGAMOUSE=y CONFIG_ABSTRACT_CONSOLE=y CONFIG_FB=y CONFIG_MOUSE=y diff -Nru a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c --- a/arch/ppc/kernel/irq.c Mon Nov 4 14:31:02 2002 +++ b/arch/ppc/kernel/irq.c Mon Nov 4 14:31:02 2002 @@ -362,7 +362,7 @@ for (j = 0; j < NR_CPUS; j++) if (cpu_online(j)) seq_printf(p, "%10u ", - kstat.irqs[j][i]); + kstat_cpu(j).irqs[i]); #else seq_printf(p, "%10u ", kstat_irqs(i)); #endif /* CONFIG_SMP */ @@ -423,7 +423,7 @@ int cpu = smp_processor_id(); irq_desc_t *desc = irq_desc + irq; - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; spin_lock(&desc->lock); ack_irq(irq); /* diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S --- a/arch/ppc/kernel/misc.S Mon Nov 4 14:31:02 2002 +++ b/arch/ppc/kernel/misc.S Mon Nov 4 14:31:02 2002 @@ -1005,6 +1005,7 @@ mr r30,r3 /* function */ mr r31,r4 /* argument */ ori r3,r5,CLONE_VM /* flags */ + oris r3,r3,CLONE_UNTRACED>>16 li r0,__NR_clone sc cmpi 0,r3,0 /* parent or child? */ diff -Nru a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c --- a/arch/ppc/kernel/ptrace.c Mon Nov 4 14:31:01 2002 +++ b/arch/ppc/kernel/ptrace.c Mon Nov 4 14:31:01 2002 @@ -339,7 +339,7 @@ #endif default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); break; } out_tsk: @@ -354,7 +354,8 @@ if (!test_thread_flag(TIF_SYSCALL_TRACE) || !(current->ptrace & PT_PTRACED)) return; - current->exit_code = SIGTRAP; + current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0); current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); diff -Nru a/arch/ppc/platforms/mcpn765_setup.c b/arch/ppc/platforms/mcpn765_setup.c --- a/arch/ppc/platforms/mcpn765_setup.c Mon Nov 4 14:31:02 2002 +++ b/arch/ppc/platforms/mcpn765_setup.c Mon Nov 4 14:31:02 2002 @@ -154,9 +154,9 @@ * PPCBug doesn't set the enable bits for the IDE device. * Turn them on now. */ - pcibios_read_config_byte(dev->bus->number, dev->devfn, 0x40, &c); + pci_read_config_byte(dev, 0x40, &c); c |= 0x03; - pcibios_write_config_byte(dev->bus->number, dev->devfn, 0x40, c); + pci_write_config_byte(dev, 0x40, c); return; } diff -Nru a/arch/ppc/platforms/prep_pci.c b/arch/ppc/platforms/prep_pci.c --- a/arch/ppc/platforms/prep_pci.c Mon Nov 4 14:31:02 2002 +++ b/arch/ppc/platforms/prep_pci.c Mon Nov 4 14:31:02 2002 @@ -1089,8 +1089,7 @@ devnum = PCI_SLOT(tdev->devfn); /* Read the interrupt pin of the device and adjust for indexing */ - pcibios_read_config_byte(dev->bus->number, dev->devfn, - PCI_INTERRUPT_PIN, &intpin); + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &intpin); /* If device doesn't request an interrupt, return */ if ( (intpin < 1) || (intpin > 4) ) @@ -1162,7 +1161,7 @@ pci_for_each_dev(dev) { if (dev->bus->number == 0) { dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]); - pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_LINE, dev->irq); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); } else { if (Motherboard_non0 != NULL) Motherboard_non0(dev); diff -Nru a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig --- a/arch/ppc64/Kconfig Mon Nov 4 14:31:02 2002 +++ b/arch/ppc64/Kconfig Mon Nov 4 14:31:02 2002 @@ -2,6 +2,15 @@ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # + +config MMU + bool + default y + +config SWAP + bool + default y + config UID16 bool diff -Nru a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c --- a/arch/ppc64/kernel/asm-offsets.c Mon Nov 4 14:31:02 2002 +++ b/arch/ppc64/kernel/asm-offsets.c Mon Nov 4 14:31:02 2002 @@ -157,6 +157,7 @@ DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8); DEFINE(CLONE_VM, CLONE_VM); + DEFINE(CLONE_UNTRACED, CLONE_UNTRACED); return 0; } diff -Nru a/arch/ppc64/kernel/ioctl32.c b/arch/ppc64/kernel/ioctl32.c --- a/arch/ppc64/kernel/ioctl32.c Mon Nov 4 14:31:03 2002 +++ b/arch/ppc64/kernel/ioctl32.c Mon Nov 4 14:31:03 2002 @@ -66,6 +66,7 @@ #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) #include #endif /* LVM */ +#include #include /* Ugly hack. */ @@ -4402,6 +4403,18 @@ COMPATIBLE_IOCTL(NBD_PRINT_DEBUG), COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS), COMPATIBLE_IOCTL(NBD_DISCONNECT), +/* device-mapper */ +COMPATIBLE_IOCTL(DM_VERSION), +COMPATIBLE_IOCTL(DM_REMOVE_ALL), +COMPATIBLE_IOCTL(DM_DEV_CREATE), +COMPATIBLE_IOCTL(DM_DEV_REMOVE), +COMPATIBLE_IOCTL(DM_DEV_RELOAD), +COMPATIBLE_IOCTL(DM_DEV_SUSPEND), +COMPATIBLE_IOCTL(DM_DEV_RENAME), +COMPATIBLE_IOCTL(DM_DEV_DEPS), +COMPATIBLE_IOCTL(DM_DEV_STATUS), +COMPATIBLE_IOCTL(DM_TARGET_STATUS), +COMPATIBLE_IOCTL(DM_TARGET_WAIT), /* And these ioctls need translation */ HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob), HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob), diff -Nru a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c --- a/arch/ppc64/kernel/irq.c Mon Nov 4 14:31:01 2002 +++ b/arch/ppc64/kernel/irq.c Mon Nov 4 14:31:01 2002 @@ -357,7 +357,7 @@ #ifdef CONFIG_SMP for (j = 0; j < NR_CPUS; j++) { if (cpu_online(j)) - seq_printf(p, "%10u ", kstat.irqs[j][i]); + seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); } #else seq_printf(p, "%10u ", kstat_irqs(i)); @@ -484,7 +484,7 @@ if (naca->interrupt_controller == IC_OPEN_PIC) balance_irq(irq); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; spin_lock(&desc->lock); ack_irq(irq); /* diff -Nru a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S --- a/arch/ppc64/kernel/misc.S Mon Nov 4 14:31:01 2002 +++ b/arch/ppc64/kernel/misc.S Mon Nov 4 14:31:01 2002 @@ -486,6 +486,7 @@ /* XXX fix this when we optimise syscall entry to not save volatiles */ mr r6,r3 /* function */ ori r3,r5,CLONE_VM /* flags */ + oris r3,r3,(CLONE_UNTRACED>>16) li r0,__NR_clone sc cmpi 0,r3,0 /* parent or child? */ diff -Nru a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c --- a/arch/ppc64/kernel/ptrace.c Mon Nov 4 14:31:01 2002 +++ b/arch/ppc64/kernel/ptrace.c Mon Nov 4 14:31:01 2002 @@ -276,7 +276,7 @@ } default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); break; } out_tsk: @@ -292,7 +292,8 @@ return; if (!(current->ptrace & PT_PTRACED)) return; - current->exit_code = SIGTRAP; + current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0); current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); diff -Nru a/arch/ppc64/kernel/ptrace32.c b/arch/ppc64/kernel/ptrace32.c --- a/arch/ppc64/kernel/ptrace32.c Mon Nov 4 14:31:02 2002 +++ b/arch/ppc64/kernel/ptrace32.c Mon Nov 4 14:31:02 2002 @@ -413,7 +413,7 @@ default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); break; } out_tsk: diff -Nru a/arch/s390/Kconfig b/arch/s390/Kconfig --- a/arch/s390/Kconfig Mon Nov 4 14:31:01 2002 +++ b/arch/s390/Kconfig Mon Nov 4 14:31:01 2002 @@ -2,6 +2,15 @@ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # + +config MMU + bool + default y + +config SWAP + bool + default y + config ISA bool help diff -Nru a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c --- a/arch/s390/kernel/process.c Mon Nov 4 14:31:02 2002 +++ b/arch/s390/kernel/process.c Mon Nov 4 14:31:02 2002 @@ -146,7 +146,7 @@ regs.orig_gpr2 = -1; /* Ok, create the new process.. */ - p = do_fork(flags | CLONE_VM, 0, ®s, 0, NULL); + p = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } diff -Nru a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c --- a/arch/s390/kernel/ptrace.c Mon Nov 4 14:31:02 2002 +++ b/arch/s390/kernel/ptrace.c Mon Nov 4 14:31:02 2002 @@ -307,15 +307,8 @@ copied += sizeof(unsigned long); } return 0; - - case PTRACE_SETOPTIONS: - if (data & PTRACE_O_TRACESYSGOOD) - child->ptrace |= PT_TRACESYSGOOD; - else - child->ptrace &= ~PT_TRACESYSGOOD; - return 0; } - return -EIO; + return ptrace_request(child, request, addr, data); } asmlinkage int sys_ptrace(long request, long pid, long addr, long data) diff -Nru a/arch/s390x/Kconfig b/arch/s390x/Kconfig --- a/arch/s390x/Kconfig Mon Nov 4 14:31:02 2002 +++ b/arch/s390x/Kconfig Mon Nov 4 14:31:02 2002 @@ -2,6 +2,15 @@ # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. # + +config MMU + bool + default y + +config SWAP + bool + default y + config ISA bool help diff -Nru a/arch/s390x/kernel/ioctl32.c b/arch/s390x/kernel/ioctl32.c --- a/arch/s390x/kernel/ioctl32.c Mon Nov 4 14:31:02 2002 +++ b/arch/s390x/kernel/ioctl32.c Mon Nov 4 14:31:02 2002 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -896,6 +897,18 @@ IOCTL32_DEFAULT(VT_UNLOCKSWITCH), IOCTL32_DEFAULT(SIOCGSTAMP), + + IOCTL32_DEFAULT(DM_VERSION), + IOCTL32_DEFAULT(DM_REMOVE_ALL), + IOCTL32_DEFAULT(DM_DEV_CREATE), + IOCTL32_DEFAULT(DM_DEV_REMOVE), + IOCTL32_DEFAULT(DM_DEV_RELOAD), + IOCTL32_DEFAULT(DM_DEV_SUSPEND), + IOCTL32_DEFAULT(DM_DEV_RENAME), + IOCTL32_DEFAULT(DM_DEV_DEPS), + IOCTL32_DEFAULT(DM_DEV_STATUS), + IOCTL32_DEFAULT(DM_TARGET_STATUS), + IOCTL32_DEFAULT(DM_TARGET_WAIT), IOCTL32_DEFAULT(LOOP_SET_FD), IOCTL32_DEFAULT(LOOP_CLR_FD), diff -Nru a/arch/s390x/kernel/process.c b/arch/s390x/kernel/process.c --- a/arch/s390x/kernel/process.c Mon Nov 4 14:31:02 2002 +++ b/arch/s390x/kernel/process.c Mon Nov 4 14:31:02 2002 @@ -143,7 +143,7 @@ regs.orig_gpr2 = -1; /* Ok, create the new process.. */ - p = do_fork(flags | CLONE_VM, 0, ®s, 0, NULL); + p = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } diff -Nru a/arch/s390x/kernel/ptrace.c b/arch/s390x/kernel/ptrace.c --- a/arch/s390x/kernel/ptrace.c Mon Nov 4 14:31:00 2002 +++ b/arch/s390x/kernel/ptrace.c Mon Nov 4 14:31:00 2002 @@ -261,7 +261,7 @@ } return 0; } - return -EIO; + return ptrace_request(child, request, addr, data); } #ifdef CONFIG_S390_SUPPORT @@ -469,7 +469,7 @@ } return 0; } - return -EIO; + return ptrace_request(child, request, addr, data); } #endif @@ -538,12 +538,6 @@ /* detach a process that was attached. */ return ptrace_detach(child, data); - case PTRACE_SETOPTIONS: - if (data & PTRACE_O_TRACESYSGOOD) - child->ptrace |= PT_TRACESYSGOOD; - else - child->ptrace &= ~PT_TRACESYSGOOD; - return 0; /* Do requests that differ for 31/64 bit */ default: #ifdef CONFIG_S390_SUPPORT @@ -551,8 +545,8 @@ return do_ptrace_emu31(child, request, addr, data); #endif return do_ptrace_normal(child, request, addr, data); - } + /* Not reached. */ return -EIO; } diff -Nru a/arch/sh/Kconfig b/arch/sh/Kconfig --- a/arch/sh/Kconfig Mon Nov 4 14:31:03 2002 +++ b/arch/sh/Kconfig Mon Nov 4 14:31:03 2002 @@ -14,6 +14,14 @@ gaming console. The SuperH port has a home page at . +config MMU + bool + default y + +config SWAP + bool + default y + config UID16 bool default y diff -Nru a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c --- a/arch/sh/kernel/irq.c Mon Nov 4 14:31:01 2002 +++ b/arch/sh/kernel/irq.c Mon Nov 4 14:31:01 2002 @@ -239,7 +239,7 @@ :"=z" (irq)); irq = irq_demux(irq); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; desc = irq_desc + irq; spin_lock(&desc->lock); desc->handler->ack(irq); diff -Nru a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c --- a/arch/sh/kernel/process.c Mon Nov 4 14:31:02 2002 +++ b/arch/sh/kernel/process.c Mon Nov 4 14:31:02 2002 @@ -120,7 +120,7 @@ { /* Don't use this in BL=1(cli). Or else, CPU resets! */ register unsigned long __sc0 __asm__ ("r0"); register unsigned long __sc3 __asm__ ("r3") = __NR_clone; - register unsigned long __sc4 __asm__ ("r4") = (long) flags | CLONE_VM; + register unsigned long __sc4 __asm__ ("r4") = (long) flags | CLONE_VM | CLONE_UNTRACED; register unsigned long __sc5 __asm__ ("r5") = 0; register unsigned long __sc8 __asm__ ("r8") = (long) arg; register unsigned long __sc9 __asm__ ("r9") = (long) fn; diff -Nru a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c --- a/arch/sh/kernel/ptrace.c Mon Nov 4 14:31:00 2002 +++ b/arch/sh/kernel/ptrace.c Mon Nov 4 14:31:00 2002 @@ -356,17 +356,8 @@ ret = ptrace_detach(child, data); break; - case PTRACE_SETOPTIONS: { - if (data & PTRACE_O_TRACESYSGOOD) - child->ptrace |= PT_TRACESYSGOOD; - else - child->ptrace &= ~PT_TRACESYSGOOD; - ret = 0; - break; - } - default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); break; } out_tsk: diff -Nru a/arch/sparc/Kconfig b/arch/sparc/Kconfig --- a/arch/sparc/Kconfig Mon Nov 4 14:31:00 2002 +++ b/arch/sparc/Kconfig Mon Nov 4 14:31:00 2002 @@ -5,6 +5,14 @@ mainmenu "Linux/SPARC Kernel Configuration" +config MMU + bool + default y + +config SWAP + bool + default y + config UID16 bool default y diff -Nru a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c --- a/arch/sparc/kernel/irq.c Mon Nov 4 14:31:00 2002 +++ b/arch/sparc/kernel/irq.c Mon Nov 4 14:31:00 2002 @@ -124,7 +124,7 @@ for (j = 0; j < NR_CPUS; j++) { if (cpu_online(j)) seq_printf(p, "%10u ", - kstat.irqs[cpu_logical_map(j)][i]); + kstat_cpu(cpu_logical_map(j)).irqs[i]); } #endif seq_printf(p, " %c %s", @@ -424,7 +424,7 @@ smp4m_irq_rotate(cpu); #endif action = *(irq + irq_action); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; do { if (!action || !action->handler) unexpected_irq(irq, 0, regs); @@ -444,7 +444,7 @@ disable_pil_irq(irq); irq_enter(); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; floppy_interrupt(irq, dev_id, regs); irq_exit(); enable_pil_irq(irq); diff -Nru a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c --- a/arch/sparc/kernel/process.c Mon Nov 4 14:31:01 2002 +++ b/arch/sparc/kernel/process.c Mon Nov 4 14:31:01 2002 @@ -726,7 +726,7 @@ /* Notreached by child. */ "1: mov %%o0, %0\n\t" : "=r" (retval) : - "i" (__NR_clone), "r" (flags | CLONE_VM), + "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED), "i" (__NR_exit), "r" (fn), "r" (arg) : "g1", "g2", "g3", "o0", "o1", "memory", "cc"); return retval; diff -Nru a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c --- a/arch/sparc/kernel/ptrace.c Mon Nov 4 14:31:03 2002 +++ b/arch/sparc/kernel/ptrace.c Mon Nov 4 14:31:03 2002 @@ -584,10 +584,15 @@ /* PTRACE_DUMPCORE unsupported... */ - default: - pt_error_return(regs, EIO); + default: { + int err = ptrace_request(child, request, addr, data); + if (err) + pt_error_return(regs, -err); + else + pt_succ_return(regs, 0); goto out_tsk; } + } out_tsk: if (child) put_task_struct(child); @@ -604,7 +609,8 @@ return; if (!(current->ptrace & PT_PTRACED)) return; - current->exit_code = SIGTRAP; + current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0); current->state = TASK_STOPPED; current->thread.flags ^= MAGIC_CONSTANT; notify_parent(current, SIGCHLD); diff -Nru a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c --- a/arch/sparc/kernel/sun4d_irq.c Mon Nov 4 14:31:00 2002 +++ b/arch/sparc/kernel/sun4d_irq.c Mon Nov 4 14:31:00 2002 @@ -102,7 +102,7 @@ for (x = 0; x < NR_CPUS; x++) { if (cpu_online) seq_printf(p, "%10u ", - kstat.irqs[cpu_logical_map(x)][i]); + kstat_cpu(cpu_logical_map(x)).irqs[i]); } #endif seq_printf(p, "%c %s", @@ -199,7 +199,7 @@ cc_set_iclr(1 << irq); irq_enter(); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; if (!sbusl) { action = *(irq + irq_action); if (!action) diff -Nru a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig --- a/arch/sparc64/Kconfig Mon Nov 4 14:31:01 2002 +++ b/arch/sparc64/Kconfig Mon Nov 4 14:31:01 2002 @@ -5,6 +5,14 @@ mainmenu "Linux/UltraSPARC Kernel Configuration" +config MMU + bool + default y + +config SWAP + bool + default y + source "init/Kconfig" diff -Nru a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c --- a/arch/sparc64/kernel/irq.c Mon Nov 4 14:31:02 2002 +++ b/arch/sparc64/kernel/irq.c Mon Nov 4 14:31:02 2002 @@ -135,7 +135,7 @@ if (!cpu_online(j)) continue; seq_printf(p, "%10u ", - kstat.irqs[j][i]); + kstat_cpu(j).irqs[i]); } #endif seq_printf(p, " %s:%lx", action->name, @@ -738,7 +738,7 @@ #endif irq_enter(); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; if (irq == 9) kbd_pt_regs = regs; @@ -813,7 +813,7 @@ int cpu = smp_processor_id(); irq_enter(); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; *(irq_work(cpu, irq)) = 0; bucket = get_ino_in_irqaction(action) + ivector_table; diff -Nru a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c --- a/arch/sparc64/kernel/process.c Mon Nov 4 14:31:01 2002 +++ b/arch/sparc64/kernel/process.c Mon Nov 4 14:31:01 2002 @@ -694,7 +694,7 @@ /* Notreached by child. */ "1:" : "=r" (retval) : - "i" (__NR_clone), "r" (flags | CLONE_VM), + "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED), "i" (__NR_exit), "r" (fn), "r" (arg) : "g1", "g2", "g3", "o0", "o1", "memory", "cc"); return retval; diff -Nru a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c --- a/arch/sparc64/kernel/ptrace.c Mon Nov 4 14:31:02 2002 +++ b/arch/sparc64/kernel/ptrace.c Mon Nov 4 14:31:02 2002 @@ -571,10 +571,15 @@ /* PTRACE_DUMPCORE unsupported... */ - default: - pt_error_return(regs, EIO); + default: { + int err = ptrace_request(child, request, addr, data); + if (err) + pt_error_return(regs, -err); + else + pt_succ_return(regs, 0); goto out_tsk; } + } flush_and_out: { unsigned long va; @@ -612,7 +617,8 @@ return; if (!(current->ptrace & PT_PTRACED)) return; - current->exit_code = SIGTRAP; + current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0); current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); diff -Nru a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c --- a/arch/sparc64/kernel/smp.c Mon Nov 4 14:31:00 2002 +++ b/arch/sparc64/kernel/smp.c Mon Nov 4 14:31:00 2002 @@ -967,7 +967,7 @@ if (cpu == boot_cpu_id) { irq_enter(); - kstat.irqs[cpu][0]++; + kstat_cpu(cpu).irqs[0]++; timer_tick_interrupt(regs); irq_exit(); diff -Nru a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c --- a/arch/sparc64/kernel/sys_sparc.c Mon Nov 4 14:31:02 2002 +++ b/arch/sparc64/kernel/sys_sparc.c Mon Nov 4 14:31:02 2002 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff -Nru a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c --- a/arch/sparc64/mm/hugetlbpage.c Mon Nov 4 14:31:02 2002 +++ b/arch/sparc64/mm/hugetlbpage.c Mon Nov 4 14:31:02 2002 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff -Nru a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c --- a/arch/sparc64/mm/init.c Mon Nov 4 14:31:01 2002 +++ b/arch/sparc64/mm/init.c Mon Nov 4 14:31:01 2002 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff -Nru a/arch/um/Kconfig b/arch/um/Kconfig --- a/arch/um/Kconfig Mon Nov 4 14:31:01 2002 +++ b/arch/um/Kconfig Mon Nov 4 14:31:01 2002 @@ -2,6 +2,14 @@ bool default y +# XXX: does UM have a mmu/swap? +config MMU + bool + default y + +config SWAP + bool + default y mainmenu "Linux/Usermode Kernel Configuration" diff -Nru a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c --- a/arch/um/kernel/irq.c Mon Nov 4 14:31:02 2002 +++ b/arch/um/kernel/irq.c Mon Nov 4 14:31:02 2002 @@ -108,7 +108,7 @@ #else for (j = 0; j < num_online_cpus(); j++) p += sprintf(p, "%10u ", - kstat.irqs[cpu_logical_map(j)][i]); + kstat_cpu(cpu_logical_map(j)).irqs[i]); #endif p += sprintf(p, " %14s", irq_desc[i].handler->typename); p += sprintf(p, " %s", action->name); @@ -283,7 +283,7 @@ unsigned int status; irq_enter(); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; spin_lock(&desc->lock); desc->handler->ack(irq); /* diff -Nru a/arch/v850/Kconfig b/arch/v850/Kconfig --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/Kconfig Mon Nov 4 14:31:04 2002 @@ -0,0 +1,488 @@ +############################################################################# +# +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/config-language.txt. +# +############################################################################# + +mainmenu "uClinux/v850 (w/o MMU) Kernel Configuration" + +config MMU + bool + default n +config SWAP + bool + default n +config UID16 + bool + default n +config RWSEM_GENERIC_SPINLOCK + bool + default y +config RWSEM_XCHGADD_ALGORITHM + bool + default n + +# Turn off some random 386 crap that can affect device config +config ISA + bool + default n +config ISAPNP + bool + default n +config EISA + bool + default n +config MCA + bool + default n + + +############################################################################# +#### v850-specific config + +# Define the architecture +config V850 + bool + default y + +menu "Processor type and features" + + choice + prompt "Platform" + default GDB + config RTE_CB_MA1 + bool "RTE-V850E/MA1-CB" + config RTE_CB_NB85E + bool "RTE-V850E/NB85E-CB" + config V850E_SIM + bool "GDB" + config V850E2_SIM85E2C + bool "sim85e2c" + config V850E2_FPGA85E2C + bool "NA85E2C-FPGA" + config V850E2_ANNA + bool "Anna" + endchoice + + + #### V850E processor-specific config + + # All CPUs currently supported use the v850e architecture + config V850E + bool + default y + + # The RTE-V850E/MA1-CB is the only type of V850E/MA1 platform we + # currently support + config V850E_MA1 + bool + depends RTE_CB_MA1 + default y + # Similarly for the RTE-V850E/MA1-CB - V850E/TEG + config V850E_TEG + bool + depends RTE_CB_NB85E + default y + + # NB85E processor core + config V850E_NB85E + bool + depends V850E_MA1 || V850E_TEG + default y + + config V850E_MA1_HIGHRES_TIMER + bool "High resolution timer support" + depends V850E_MA1 + + + #### V850E2 processor-specific config + + # V850E2 processors + config V850E2 + bool + depends V850E2_SIM85E2C || V850E2_FPGA85E2C || V850E2_ANNA + default y + + # Processors based on the NA85E2A core + config V850E2_NA85E2A + bool + depends V850E2_ANNA + default y + + # Processors based on the NA85E2C core + config V850E2_NA85E2C + bool + depends V850E2_SIM85E2C || V850E2_FPGA85E2C + default y + + + #### RTE-CB platform-specific config + + # Boards in the RTE-x-CB series + config RTE_CB + bool + depends RTE_CB_MA1 || RTE_CB_NB85E + default y + + # Currently, we only support RTE-CB boards using the Multi debugger + config RTE_CB_MULTI + bool + depends RTE_CB + default y + + config RTE_CB_MA1_KSRAM + bool "Kernel in SRAM (limits size of kernel)" + depends RTE_CB_MA1 && RTE_CB_MULTI + default n + + config RTE_MB_A_PCI + bool "Mother-A PCI support" + depends RTE_CB + default y + + # The GBUS is used to talk to the RTE-MOTHER-A board + config RTE_GBUS_INT + bool + depends RTE_MB_A_PCI + default y + + # The only PCI bus we support is on the RTE-MOTHER-A board + config PCI + bool + default y if RTE_MB_A_PCI + + + #### Misc config + + config ROM_KERNEL + bool "Kernel in ROM" + depends V850E2_ANNA || (RTE_CB && !RTE_CB_MULTI) + + # Some platforms pre-zero memory, in which case the kernel doesn't need to + config ZERO_BSS + bool + depends !V850E2_SIM85E2C + default y + + # The crappy-ass zone allocator requires that the start of allocatable + # memory be aligned to the largest possible allocation. + config FORCE_MAX_ZONEORDER + int + default 8 if V850E2_SIM85E2C || V850E2_FPGA85E2C + + config TIME_BOOTUP + bool "Time bootup" + depends V850E_MA1_HIGHRES_TIMER + + config RESET_GUARD + bool "Reset Guard" + + config LARGE_ALLOCS + bool "Allow allocating large blocks (> 1MB) of memory" + help + Allow the slab memory allocator to keep chains for very large + memory sizes - upto 32MB. You may need this if your system has + a lot of RAM, and you need to able to allocate very large + contiguous chunks. If unsure, say N. + +endmenu + + +############################################################################# + +source init/Kconfig + +############################################################################# + +menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)" + +# config PCI +# bool "PCI support" +# help +# Support for PCI bus. + +source "drivers/pci/Kconfig" + +config HOTPLUG + bool "Support for hot-pluggable device" + ---help--- + Say Y here if you want to plug devices into your computer while + the system is running, and be able to use them quickly. In many + cases, the devices can likewise be unplugged at any time too. + + One well known example of this is PCMCIA- or PC-cards, credit-card + size devices such as network cards, modems or hard drives which are + plugged into slots found on all modern laptop computers. Another + example, used on modern desktops as well as laptops, is USB. + + Enable HOTPLUG and KMOD, and build a modular kernel. Get agent + software (at ) and install it. + Then your kernel will automatically call out to a user mode "policy + agent" (/sbin/hotplug) to load modules and set up software needed + to use devices as you hotplug them. + +source "drivers/pcmcia/Kconfig" + +source "drivers/hotplug/Kconfig" + +endmenu + +menu "Executable file formats" + +config KCORE_AOUT + bool + default y + +config KCORE_ELF + default y + +config BINFMT_FLAT + tristate "Kernel support for flat binaries" + help + Support uClinux FLAT format binaries. + +config BINFMT_ZFLAT + bool " Enable ZFLAT support" + depends on BINFMT_FLAT + help + Support FLAT format compressed binaries + +endmenu + +############################################################################# + +source drivers/mtd/Kconfig + +source drivers/parport/Kconfig + +#source drivers/pnp/Kconfig + +source drivers/block/Kconfig + +############################################################################# + +menu "Disk device support" + +config IDE + tristate "ATA/ATAPI/MFM/RLL device support" + ---help--- + If you say Y here, your kernel will be able to manage low cost mass + storage units such as ATA/(E)IDE and ATAPI units. The most common + cases are IDE hard drives and ATAPI CD-ROM drives. + + It only makes sense to choose this option if your board actually + has an IDE interface. If unsure, say N. + +source "drivers/ide/Kconfig" + +config SCSI + tristate "SCSI device support" + help + If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or + any other SCSI device under Linux, say Y and make sure that you know + the name of your SCSI host adapter (the card inside your computer + that "speaks" the SCSI protocol, also called SCSI controller), + because you will be asked for it. + +source "drivers/scsi/Kconfig" + +endmenu + +############################################################################# + + +source "drivers/md/Kconfig" + +source "drivers/message/fusion/Kconfig" + +source "drivers/ieee1394/Kconfig" + +source "drivers/message/i2o/Kconfig" + +source "net/Kconfig" + + +menu "Network device support" + depends on NET + +config NETDEVICES + bool "Network device support" + ---help--- + You can say N here if you don't intend to connect your Linux box to + any other computer at all or if all your connections will be over a + telephone line with a modem either via UUCP (UUCP is a protocol to + forward mail and news between unix hosts over telephone lines; read + the UUCP-HOWTO, available from + ) or dialing up a shell + account or a BBS, even using term (term is a program which gives you + almost full Internet connectivity if you have a regular dial up + shell account on some Internet connected Unix computer. Read + ). + + You'll have to say Y if your computer contains a network card that + you want to use under Linux (make sure you know its name because you + will be asked for it and read the Ethernet-HOWTO (especially if you + plan to use more than one network card under Linux)) or if you want + to use SLIP (Serial Line Internet Protocol is the protocol used to + send Internet traffic over telephone lines or null modem cables) or + CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better + and newer replacement for SLIP) or PLIP (Parallel Line Internet + Protocol is mainly used to create a mini network by connecting the + parallel ports of two local machines) or AX.25/KISS (protocol for + sending Internet traffic over amateur radio links). + + Make sure to read the NET-3-HOWTO. Eventually, you will have to read + Olaf Kirch's excellent and free book "Network Administrator's + Guide", to be found in . If + unsure, say Y. + +source "drivers/net/Kconfig" + +source "drivers/atm/Kconfig" + +endmenu + +source "net/ax25/Kconfig" + +source "net/irda/Kconfig" + +source "drivers/isdn/Kconfig" + +#source "drivers/telephony/Kconfig" + +# +# input before char - char/joystick depends on it. As does USB. +# +source "drivers/input/Kconfig" + +source "drivers/char/Kconfig" + +#source drivers/misc/Config.in +source "drivers/media/Kconfig" + +source "fs/Kconfig" + + +menu "Console drivers" + depends on VT + +config VGA_CONSOLE + bool "VGA text console" + help + Saying Y here will allow you to use Linux in text mode through a + display that complies with the generic VGA standard. Virtually + everyone wants that. + + The program SVGATextMode can be used to utilize SVGA video cards to + their full potential in text mode. Download it from + . + + If unsure, say N. + +config VIDEO_SELECT + bool "Video mode selection support" + ---help--- + This enables support for text mode selection on kernel startup. If + you want to take advantage of some high-resolution text mode your + card's BIOS offers, but the traditional Linux utilities like + SVGATextMode don't, you can say Y here and set the mode using the + "vga=" option from your boot loader (lilo or loadlin) or set + "vga=ask" which brings up a video mode menu on kernel startup. (Try + "man bootparam" or see the documentation of your boot loader about + how to pass options to the kernel.) + + Read the file for more information + about the Video mode selection support. If unsure, say N. + +source "drivers/video/Kconfig" + +endmenu + + +menu "Sound" + +config SOUND + tristate "Sound card support" + ---help--- + If you have a sound card in your computer, i.e. if it can say more + than an occasional beep, say Y. Be sure to have all the information + about your sound card and its configuration down (I/O port, + interrupt and DMA channel), because you will be asked for it. + + You want to read the Sound-HOWTO, available from + . General information about + the modular sound system is contained in the files + . The file + contains some slightly + outdated but still useful information as well. + + If you have a PnP sound card and you want to configure it at boot + time using the ISA PnP tools (read + ), then you need to + compile the sound card support as a module ( = code which can be + inserted in and removed from the running kernel whenever you want) + and load that module after the PnP configuration is finished. To do + this, say M here and read as well + as ; the module will be + called soundcore.o. + + I'm told that even without a sound card, you can make your computer + say more than an occasional beep, by programming the PC speaker. + Kernel patches and supporting utilities to do that are in the pcsp + package, available at . + +source "sound/Kconfig" + +endmenu + +source "drivers/usb/Kconfig" + +source "net/bluetooth/Kconfig" + + +menu "Kernel hacking" + +config FULLDEBUG + bool "Full Symbolic/Source Debugging support" + help + Enable debuging symbols on kernel build. + +config MAGIC_SYSRQ + bool "Magic SysRq key" + help + Enables console device to interprent special characters as + commands to dump state information. + +config HIGHPROFILE + bool "Use fast second timer for profiling" + help + Use a fast secondary clock to produce profiling information. + +config DUMPTOFLASH + bool "Panic/Dump to FLASH" + depends on COLDFIRE + help + Dump any panic of trap output into a flash memory segment + for later analysis. + +config NO_KERNEL_MSG + bool "Suppress Kernel BUG Messages" + help + Do not output any debug BUG messages within the kernel. + +config BDM_DISABLE + bool "Disable BDM signals" + depends on (EXPERIMENTAL && COLDFIRE) + help + Disable the CPU's BDM signals. + +endmenu + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" + +############################################################################# diff -Nru a/arch/v850/Makefile b/arch/v850/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/Makefile Mon Nov 4 14:31:04 2002 @@ -0,0 +1,65 @@ +# +# arch/v850/Makefile +# +# Copyright (C) 2001,02 NEC Corporation +# Copyright (C) 2001,02 Miles Bader +# +# This file is included by the global makefile so that you can add your own +# architecture-specific flags and dependencies. Remember to do have actions +# for "archclean" and "archdep" for cleaning up and making dependencies for +# this architecture +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# + +arch_dir = arch/v850 + +CFLAGS += -mv850e +# r16 is a fixed pointer to the current task +CFLAGS += -ffixed-r16 -mno-prolog-function +CFLAGS += -fno-builtin +CFLAGS += -D__linux__ -DUTS_SYSNAME=\"uClinux\" + + +HEAD := $(arch_dir)/kernel/head.o $(arch_dir)/kernel/init_task.o +core-y += $(arch_dir)/kernel/ +libs-y += $(arch_dir)/lib/ + + +include $(TOPDIR)/Rules.make + + +# Deal with the initial contents of the root device +ifdef ROOT_FS_IMAGE +core-y += root_fs_image.o + +# Because the kernel build-system erases all explicit .o build rules, we +# have to use an intermediate target to fool it into building for us. +# This results in it being built anew each time, but that's alright. +root_fs_image.o: root_fs_image_force + +# Note that we use the build-system's objcopy, as the v850 tools are fairly +# old, and don't have the --rename-section option. +root_fs_image_force: $(ROOT_FS_IMAGE) + objcopy -I binary -O elf32-little -B i386 --rename-section .data=.root,alloc,load,readonly,data,contents $< root_fs_image.o +endif + + +prepare: include/asm-$(ARCH)/asm-consts.h + +# Generate constants from C code for use by asm files +arch/$(ARCH)/kernel/asm-consts.s: include/asm include/linux/version.h \ + include/config/MARKER +include/asm-$(ARCH)/asm-consts.h.tmp: arch/$(ARCH)/kernel/asm-consts.s + @$(generate-asm-offsets.h) < $< > $@ +include/asm-$(ARCH)/asm-consts.h: include/asm-$(ARCH)/asm-consts.h.tmp + @echo -n ' Generating $@' + @$(update-if-changed) + + +CLEAN_FILES += include/asm-$(ARCH)/asm-consts.h.tmp \ + include/asm-$(ARCH)/asm-consts.h \ + arch/$(ARCH)/kernel/asm-consts.s \ + root_fs_image.o diff -Nru a/arch/v850/README b/arch/v850/README --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/README Mon Nov 4 14:31:04 2002 @@ -0,0 +1,23 @@ +This port to the NEC V850E processor supports the following platforms: + + + The gdb v850e simulator (CONFIG_V850E_SIM); see the subdirectory `sim' + for some more support files for this. + + + The Midas labs RTE-V850E/MA1-CB evaluation board (CONFIG_RTE_CB_MA1), + with untested support for the RTE-V850E/NB85E-CB board + (CONFIG_RTE_CB_NB85E). This support has only been tested when running + with the Multi-debugger monitor ROM (for the Green Hills Multi debugger). + The optional NEC Solution Gear RTE-MOTHER-A motherboard is also + supported, which allows PCI boards to be used (CONFIG_RTE_MB_A_PCI). + + + The sim85e2c simulator, which is a verilog simulation of the V850E2 + NA85E2C cpu core (CONFIG_V850E2_SIM85E2C). + + + A FPGA implementation of the V850E2 NA85E2C cpu core + (CONFIG_V850E2_FPGA85E2C). + + + The `Anna' (board/chip) implementation of the V850E2 processor. + +Porting to anything with a V850E/MA1 or MA2 processor should be simple. +See the file and the files it includes for an example of +how to add platform/chip-specific support. diff -Nru a/arch/v850/anna-rom.ld b/arch/v850/anna-rom.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/anna-rom.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,127 @@ +/* Linker script for the Midas labs Anna V850E2 evaluation board + (CONFIG_V850E2_ANNA), with kernel in ROM (CONFIG_ROM_KERNEL). */ + +/* Note, all symbols are prefixed with an extra `_' for compatibility with + the existing linux sources. */ + +_jiffies = _jiffies_64 ; + +MEMORY { + /* 8MB of flash ROM. */ + ROM : ORIGIN = 0, LENGTH = 0x00800000 + + /* 1MB of static RAM. This memory is mirrored 64 times. */ + SRAM : ORIGIN = 0x04000000, LENGTH = 0x00100000 + /* 64MB of DRAM. */ + SDRAM : ORIGIN = 0x08000000, LENGTH = 0x04000000 +} + +SECTIONS { + .intv : { + __intv_start = . ; + *(.intv.reset) /* Reset vector */ + *(.intv.common) /* Vectors common to all v850e proc. */ + *(.intv.mach) /* Machine-specific int. vectors. */ + __intv_end = . ; + } > ROM + + .text ALIGN (0x10) : { + __stext = . ; + *(.text) + *(.exit.text) /* 2.5 convention */ + *(.text.exit) /* 2.4 convention */ + *(.text.lock) + *(.exitcall.exit) + __real_etext = . ; /* There may be data after here. */ + *(.rodata) + + . = ALIGN (0x4) ; + *(.kstrtab) + + . = ALIGN (4) ; + *(.call_table_data) + *(.call_table_text) + + . = ALIGN (16) ; /* Exception table. */ + ___start___ex_table = . ; + *(__ex_table) + ___stop___ex_table = . ; + + ___start___ksymtab = . ;/* Kernel symbol table. */ + *(__ksymtab) + ___stop___ksymtab = . ; + . = ALIGN (4) ; + __etext = . ; + } > ROM + + .init_text ALIGN (4096) : { + *(.init.text) /* 2.5 convention */ + *(.text.init) /* 2.4 convention */ + . = ALIGN (16) ; + ___setup_start = . ; + *(.init.setup) /* 2.5 convention */ + *(.setup.init) /* 2.4 convention */ + ___setup_end = . ; + ___initcall_start = . ; + *(.initcall.init) + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + . = ALIGN (4) ; + ___initcall_end = . ; + } > ROM + + /* Device contents for the root filesystem. */ + .root ALIGN (4096) : { + __root_fs_image_start = . ; + *(.root) + __root_fs_image_end = . ; + } > ROM + + __rom_copy_src_start = . ; + + .data : { + __kram_start = . ; + __rom_copy_dst_start = . ; + + __sdata = . ; + ___data_start = . ; + *(.data) + *(.exit.data) /* 2.5 convention */ + *(.data.exit) /* 2.4 convention */ + . = ALIGN (16) ; + *(.data.cacheline_aligned) + . = ALIGN (0x2000) ; + *(.data.init_task) + . = ALIGN (0x2000) ; + __edata = . ; + } > SRAM AT> ROM + + .init_data ALIGN (4096) : { + __init_start = . ; + *(.init.data) /* 2.5 convention */ + *(.data.init) /* 2.4 convention */ + __init_end = . ; + __rom_copy_dst_end = . ; + } > SRAM AT> ROM + + .bss ALIGN (4096) : { + __sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN (4) ; + __init_stack_end = . ; + __ebss = . ; + + __kram_end = . ; + } > SRAM + + .bootmap ALIGN (4096) : { + __bootmap = . ; + . = . + 4096 ; /* enough for 128MB. */ + } > SRAM +} diff -Nru a/arch/v850/anna.ld b/arch/v850/anna.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/anna.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,122 @@ +/* Linker script for the Midas labs Anna V850E2 evaluation board + (CONFIG_V850E2_ANNA). */ + +/* Note, all symbols are prefixed with an extra `_' for compatibility with + the existing linux sources. */ + +_jiffies = _jiffies_64 ; + +MEMORY { + /* 256KB of internal memory (followed by one mirror). */ + iMEM0 : ORIGIN = 0, LENGTH = 0x00040000 + /* 256KB of internal memory (followed by one mirror). */ + iMEM1 : ORIGIN = 0x00040000, LENGTH = 0x00040000 + + /* 1MB of static RAM. This memory is mirrored 64 times. */ + SRAM : ORIGIN = 0x04000000, LENGTH = 0x00100000 + /* 64MB of DRAM. */ + SDRAM : ORIGIN = 0x08000000, LENGTH = 0x04000000 +} + +SECTIONS { + .intv : { + __intv_start = . ; + *(.intv.reset) /* Reset vector */ + *(.intv.common) /* Vectors common to all v850e proc. */ + *(.intv.mach) /* Machine-specific int. vectors. */ + __intv_end = . ; + } > iMEM0 + + .text : { + __kram_start = . ; + + __stext = . ; + *(.text) + *(.exit.text) /* 2.5 convention */ + *(.text.exit) /* 2.4 convention */ + *(.text.lock) + *(.exitcall.exit) + __real_etext = . ; /* There may be data after here. */ + *(.rodata) + + . = ALIGN (0x4) ; + *(.kstrtab) + + . = ALIGN (4) ; + *(.call_table_data) + *(.call_table_text) + + . = ALIGN (16) ; /* Exception table. */ + ___start___ex_table = . ; + *(__ex_table) + ___stop___ex_table = . ; + + ___start___ksymtab = . ;/* Kernel symbol table. */ + *(__ksymtab) + ___stop___ksymtab = . ; + . = ALIGN (4) ; + __etext = . ; + } > SRAM + + .data ALIGN (0x4) : { + __sdata = . ; + ___data_start = . ; + *(.data) + *(.exit.data) /* 2.5 convention */ + *(.data.exit) /* 2.4 convention */ + . = ALIGN (16) ; + *(.data.cacheline_aligned) + . = ALIGN (0x2000) ; + *(.data.init_task) + . = ALIGN (0x2000) ; + __edata = . ; + } > SRAM + + .bss ALIGN (0x4) : { + __sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN (4) ; + __init_stack_end = . ; + __ebss = . ; + } > SRAM + + .init ALIGN (4096) : { + __init_start = . ; + *(.init.text) /* 2.5 convention */ + *(.init.data) + *(.text.init) /* 2.4 convention */ + *(.data.init) + . = ALIGN (16) ; + ___setup_start = . ; + *(.init.setup) /* 2.5 convention */ + *(.setup.init) /* 2.4 convention */ + ___setup_end = . ; + ___initcall_start = . ; + *(.initcall.init) + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + . = ALIGN (4) ; + ___initcall_end = . ; + __init_end = . ; + + __kram_end = . ; + } > SRAM + + .bootmap ALIGN (4096) : { + __bootmap = . ; + . = . + 4096 ; /* enough for 128MB. */ + } > SRAM + + /* Device contents for the root filesystem. */ + .root : { + __root_fs_image_start = . ; + *(.root) + __root_fs_image_end = . ; + } > SDRAM +} diff -Nru a/arch/v850/fpga85e2c.ld b/arch/v850/fpga85e2c.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/fpga85e2c.ld Mon Nov 4 14:31:03 2002 @@ -0,0 +1,144 @@ +/* Linker script for the FPGA implementation of the V850E2 NA85E2C cpu core + (CONFIG_V850E2_FPGA85E2C). */ + +/* Note, all symbols are prefixed with an extra `_' for compatibility with + the existing linux sources. */ + +_jiffies = _jiffies_64 ; + +MEMORY { + /* Reset vector. */ + RESET : ORIGIN = 0, LENGTH = 0x10 + /* Interrupt vectors. */ + INTV : ORIGIN = 0x10, LENGTH = 0x470 + /* The `window' in RAM were we're allowed to load stuff. */ + RAM_LOW : ORIGIN = 0x480, LENGTH = 0x0005FB80 + /* Some more ram above the window were we can put bss &c. */ + RAM_HIGH : ORIGIN = 0x00060000, LENGTH = 0x000A0000 + /* This is the area visible from the outside world (we can use + this only for uninitialized data). */ + VISIBLE : ORIGIN = 0x00200000, LENGTH = 0x00060000 +} + +SECTIONS { + .reset : { + __kram_start = . ; + __intv_start = . ; + *(.intv.reset) /* Reset vector */ + } > RESET + + .r0_ram : { + __r0_ram = . ; + . = . + 32 ; + } > RAM_LOW + + .text : { + __stext = . ; + *(.text) + *(.exit.text) /* 2.5 convention */ + *(.text.exit) /* 2.4 convention */ + *(.text.lock) + *(.exitcall.exit) + __real_etext = . ; /* There may be data after here. */ + *(.rodata) + . = ALIGN (0x4) ; + *(.kstrtab) + + . = ALIGN (4) ; + *(.call_table_data) + *(.call_table_text) + + . = ALIGN (16) ; /* Exception table. */ + ___start___ex_table = . ; + *(__ex_table) + ___stop___ex_table = . ; + + ___start___ksymtab = . ;/* Kernel symbol table. */ + *(__ksymtab) + ___stop___ksymtab = . ; + . = ALIGN (4) ; + __etext = . ; + } > RAM_LOW + + .data : { + __sdata = . ; + *(.data) + *(.exit.data) /* 2.5 convention */ + *(.data.exit) /* 2.4 convention */ + . = ALIGN (16) ; + *(.data.cacheline_aligned) + . = ALIGN (0x2000) ; + *(.data.init_task) + . = ALIGN (0x2000) ; + __edata = . ; + } > RAM_LOW + + /* Device contents for the root filesystem. */ + .root : { + . = ALIGN (4096) ; + __root_fs_image_start = . ; + *(.root) + __root_fs_image_end = . ; + } > RAM_LOW + + .init ALIGN (4096) : { + __init_start = . ; + *(.init.text) /* 2.5 convention */ + *(.init.data) + *(.text.init) /* 2.4 convention */ + *(.data.init) + . = ALIGN (16) ; + ___setup_start = . ; + *(.init.setup) /* 2.5 convention */ + *(.setup.init) /* 2.4 convention */ + ___setup_end = . ; + ___initcall_start = . ; + *(.initcall.init) + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + . = ALIGN (4) ; + ___initcall_end = . ; + } > RAM_LOW + + /* Where the interrupt vectors are initially loaded. */ + __intv_load_start = . ; + + .intv : { + *(.intv.common) /* Vectors common to all v850e proc. */ + *(.intv.mach) /* Machine-specific int. vectors. */ + __intv_end = . ; + } > INTV AT> RAM_LOW + + .bss : { + /* This is here so that when we free init memory the + load-time copy of the interrupt vectors and any empty + space at the end of the `RAM_LOW' area is freed too. */ + . = ALIGN (4096); + __init_end = . ; + + __sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN (4) ; + __init_stack_end = . ; + __ebss = . ; + + __kram_end = . ; + } > RAM_HIGH + + .bootmap ALIGN (4096) : { + __bootmap = . ; + . = . + 4096 ; /* enough for 128MB. */ + } > RAM_HIGH + + .visible : { + _memcons_output = . ; + . = . + 0x8000 ; + _memcons_output_end = . ; + } > VISIBLE +} diff -Nru a/arch/v850/kernel/Makefile b/arch/v850/kernel/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/Makefile Mon Nov 4 14:31:04 2002 @@ -0,0 +1,38 @@ +# +# arch/v850/kernel/Makefile +# +# Copyright (C) 2001,02 NEC Corporation +# Copyright (C) 2001,02 Miles Bader +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# + +EXTRA_TARGETS := head.o init_task.o + +obj-y += intv.o entry.o process.o syscalls.o time.o semaphore.o setup.o \ + signal.o irq.o mach.o ptrace.o bug.o +export-objs += v850_ksyms.o rte_mb_a_pci.o + +obj-$(CONFIG_MODULES) += v850_ksyms.o +# chip-specific code +obj-$(CONFIG_V850E_MA1) += ma.o nb85e_utils.o nb85e_timer_d.o +obj-$(CONFIG_V850E_NB85E) += nb85e_intc.o +obj-$(CONFIG_V850E2_ANNA) += anna.o nb85e_intc.o nb85e_utils.o nb85e_timer_d.o +# platform-specific code +obj-$(CONFIG_V850E_SIM) += sim.o simcons.o +obj-$(CONFIG_V850E2_SIM85E2C) += sim85e2c.o nb85e_intc.o memcons.o +obj-$(CONFIG_V850E2_FPGA85E2C) += fpga85e2c.o nb85e_intc.o memcons.o +obj-$(CONFIG_RTE_CB) += rte_cb.o rte_cb_leds.o +obj-$(CONFIG_RTE_CB_MA1) += rte_ma1_cb.o +obj-$(CONFIG_RTE_CB_NB85E) += rte_nb85e_cb.o +obj-$(CONFIG_RTE_CB_MULTI) += rte_cb_multi.o +obj-$(CONFIG_RTE_MB_A_PCI) += rte_mb_a_pci.o +obj-$(CONFIG_RTE_GBUS_INT) += gbus_int.o +# feature-specific code +obj-$(CONFIG_V850E_MA1_HIGHRES_TIMER) += highres_timer.o +obj-$(CONFIG_PROC_FS) += procfs.o + + +include $(TOPDIR)/Rules.make diff -Nru a/arch/v850/kernel/anna.c b/arch/v850/kernel/anna.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/anna.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,202 @@ +/* + * arch/v850/kernel/anna.c -- Anna V850E2 evaluation chip/board + * + * Copyright (C) 2002 NEC Corporation + * Copyright (C) 2002 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "mach.h" + + +/* SRAM and SDRAM are vaguely contiguous (with a hole in between; see + mach_reserve_bootmem for details), so just use both as one big area. */ +#define RAM_START SRAM_ADDR +#define RAM_END (SDRAM_ADDR + SDRAM_SIZE) + + +static void anna_led_tick (void); + + +void __init mach_early_init (void) +{ + ANNA_ILBEN = 0; + ANNA_CSC(0) = 0x402F; + ANNA_CSC(1) = 0x4000; + ANNA_BPC = 0; + ANNA_BSC = 0xAAAA; + ANNA_BEC = 0; + ANNA_BHC = 0x00FF; /* icache all memory, dcache none */ + ANNA_BCT(0) = 0xB088; + ANNA_BCT(1) = 0x0008; + ANNA_DWC(0) = 0x0027; + ANNA_DWC(1) = 0; + ANNA_BCC = 0x0006; + ANNA_ASC = 0; + ANNA_LBS = 0x0089; + ANNA_SCR3 = 0x21A9; + ANNA_RFS3 = 0x8121; + + nb85e_intc_disable_irqs (); +} + +void __init mach_setup (char **cmdline) +{ + printk (KERN_INFO + "CPU: %s\n" + "Platform: %s\n", + CPU_MODEL_LONG, + PLATFORM_LONG); + +#ifdef CONFIG_V850E_NB85E_UART_CONSOLE + nb85e_uart_cons_init (1); +#endif + + ANNA_PORT_PM (0) = 0; /* Make all LED pins output pins. */ + mach_tick = anna_led_tick; +} + +void __init mach_get_physical_ram (unsigned long *ram_start, + unsigned long *ram_len) +{ + *ram_start = RAM_START; + *ram_len = RAM_END - RAM_START; +} + +void __init mach_reserve_bootmem () +{ + /* The space between SRAM and SDRAM is filled with duplicate + images of SRAM. Prevent the kernel from using them. */ + reserve_bootmem (SRAM_ADDR + SRAM_SIZE, + SDRAM_ADDR - (SRAM_ADDR + SRAM_SIZE)); +} + +void mach_gettimeofday (struct timespec *tv) +{ + tv->tv_sec = 0; + tv->tv_nsec = 0; +} + +void __init mach_sched_init (struct irqaction *timer_action) +{ + /* Start hardware timer. */ + nb85e_timer_d_configure (0, HZ); + /* Install timer interrupt handler. */ + setup_irq (IRQ_INTCMD(0), timer_action); +} + +static struct nb85e_intc_irq_init irq_inits[] = { + { "IRQ", 0, NUM_MACH_IRQS, 1, 7 }, + { "PIN", IRQ_INTP(0), IRQ_INTP_NUM, 1, 4 }, + { "CCC", IRQ_INTCCC(0), IRQ_INTCCC_NUM, 1, 5 }, + { "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM, 1, 5 }, + { "DMA", IRQ_INTDMA(0), IRQ_INTDMA_NUM, 1, 2 }, + { "DMXER", IRQ_INTDMXER,1, 1, 2 }, + { "SRE", IRQ_INTSRE(0), IRQ_INTSRE_NUM, 3, 3 }, + { "SR", IRQ_INTSR(0), IRQ_INTSR_NUM, 3, 4 }, + { "ST", IRQ_INTST(0), IRQ_INTST_NUM, 3, 5 }, + { 0 } +}; +#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1) + +static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS]; + +void __init mach_init_irqs (void) +{ + nb85e_intc_init_irq_types (irq_inits, hw_itypes); +} + +void machine_restart (char *__unused) +{ +#ifdef CONFIG_RESET_GUARD + disable_reset_guard (); +#endif + asm ("jmp r0"); /* Jump to the reset vector. */ +} + +void machine_halt (void) +{ +#ifdef CONFIG_RESET_GUARD + disable_reset_guard (); +#endif + local_irq_disable (); /* Ignore all interrupts. */ + ANNA_PORT_IO(0) = 0xAA; /* Note that we halted. */ + for (;;) + asm ("halt; nop; nop; nop; nop; nop"); +} + +void machine_power_off (void) +{ + machine_halt (); +} + +/* Called before configuring an on-chip UART. */ +void anna_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud) +{ + /* The Anna connects some general-purpose I/O pins on the CPU to + the RTS/CTS lines of UART 1's serial connection. I/O pins P07 + and P37 are RTS and CTS respectively. */ + if (chan == 1) { + ANNA_PORT_PM(0) &= ~0x80; /* P07 in output mode */ + ANNA_PORT_PM(3) |= 0x80; /* P37 in input mode */ + } +} + +/* Minimum and maximum bounds for the moving upper LED boundary in the + clock tick display. We can't use the last bit because it's used for + UART0's CTS output. */ +#define MIN_MAX_POS 0 +#define MAX_MAX_POS 6 + +/* There are MAX_MAX_POS^2 - MIN_MAX_POS^2 cycles in the animation, so if + we pick 6 and 0 as above, we get 49 cycles, which is when divided into + the standard 100 value for HZ, gives us an almost 1s total time. */ +#define TICKS_PER_FRAME \ + (HZ / (MAX_MAX_POS * MAX_MAX_POS - MIN_MAX_POS * MIN_MAX_POS)) + +static void anna_led_tick () +{ + static unsigned counter = 0; + + if (++counter == TICKS_PER_FRAME) { + static int pos = 0, max_pos = MAX_MAX_POS, dir = 1; + + if (dir > 0 && pos == max_pos) { + dir = -1; + if (max_pos == MIN_MAX_POS) + max_pos = MAX_MAX_POS; + else + max_pos--; + } else { + if (dir < 0 && pos == 0) + dir = 1; + + if (pos + dir <= max_pos) { + /* Each bit of port 0 has a LED. */ + clear_bit (pos, &ANNA_PORT_IO(0)); + pos += dir; + set_bit (pos, &ANNA_PORT_IO(0)); + } + } + + counter = 0; + } +} diff -Nru a/arch/v850/kernel/asm-consts.c b/arch/v850/kernel/asm-consts.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/asm-consts.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,60 @@ +/* + * This program is used to generate definitions needed by + * assembly language modules. + * + * We use the technique used in the OSF Mach kernel code: + * generate asm statements containing #defines, + * compile this file to assembler, and then extract the + * #defines from the assembly-language output. + */ + +#include +#include +#include +#include +#include +#include + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +int main (void) +{ + /* offsets into the task struct */ + DEFINE (TASK_STATE, offsetof (struct task_struct, state)); + DEFINE (TASK_FLAGS, offsetof (struct task_struct, flags)); + DEFINE (TASK_PTRACE, offsetof (struct task_struct, ptrace)); + DEFINE (TASK_BLOCKED, offsetof (struct task_struct, blocked)); + DEFINE (TASK_THREAD, offsetof (struct task_struct, thread)); + DEFINE (TASK_THREAD_INFO, offsetof (struct task_struct, thread_info)); + DEFINE (TASK_MM, offsetof (struct task_struct, mm)); + DEFINE (TASK_ACTIVE_MM, offsetof (struct task_struct, active_mm)); + DEFINE (TASK_PID, offsetof (struct task_struct, pid)); + + /* offsets into the kernel_stat struct */ + DEFINE (STAT_IRQ, offsetof (struct kernel_stat, irqs)); + + + /* signal defines */ + DEFINE (SIGSEGV, SIGSEGV); + DEFINE (SEGV_MAPERR, SEGV_MAPERR); + DEFINE (SIGTRAP, SIGTRAP); + DEFINE (SIGCHLD, SIGCHLD); + DEFINE (SIGILL, SIGILL); + DEFINE (TRAP_TRACE, TRAP_TRACE); + + /* ptrace flag bits */ + DEFINE (PT_PTRACED, PT_PTRACED); + DEFINE (PT_DTRACE, PT_DTRACE); + + /* error values */ + DEFINE (ENOSYS, ENOSYS); + + /* clone flag bits */ + DEFINE (CLONE_VFORK, CLONE_VFORK); + DEFINE (CLONE_VM, CLONE_VM); + + return 0; +} diff -Nru a/arch/v850/kernel/bug.c b/arch/v850/kernel/bug.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/bug.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,62 @@ +/* + * arch/v850/kernel/bug.c -- Bug reporting functions + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include + +#include +#include +#include + +/* We should use __builtin_return_address, but it doesn't work in gcc-2.90 + (which is currently our standard compiler on the v850). */ +#define ret_addr() ({ register u32 lp asm ("lp"); lp; }) +#define stack_addr() ({ register u32 sp asm ("sp"); sp; }) + +void __bug () +{ + printk (KERN_CRIT "kernel BUG at PC 0x%x (SP ~0x%x)!\n", + ret_addr() - 4, /* - 4 for `jarl' */ + stack_addr()); + machine_halt (); +} + +int bad_trap (int trap_num, struct pt_regs *regs) +{ + printk (KERN_CRIT + "unimplemented trap %d called at 0x%08lx, pid %d!\n", + trap_num, regs->pc, current->pid); + return -ENOSYS; +} + +int debug_trap (struct pt_regs *regs) +{ + printk (KERN_CRIT "debug trap at 0x%08lx!\n", regs->pc); + return -ENOSYS; +} + +#ifdef CONFIG_RESET_GUARD +void unexpected_reset (unsigned long ret_addr, unsigned long kmode, + struct task_struct *task, unsigned long sp) +{ + printk (KERN_CRIT + "unexpected reset in %s mode, pid %d" + " (ret_addr = 0x%lx, sp = 0x%lx)\n", + kmode ? "kernel" : "user", + task ? task->pid : -1, + ret_addr, sp); + + machine_halt (); +} +#endif /* CONFIG_RESET_GUARD */ diff -Nru a/arch/v850/kernel/entry.S b/arch/v850/kernel/entry.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/entry.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,1005 @@ +/* + * arch/v850/kernel/entry.S -- Low-level system-call handling, trap handlers, + * and context-switching + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + + +/* Make a slightly more convenient alias for C_SYMBOL_NAME. */ +#define CSYM C_SYMBOL_NAME + + +/* The offset of the struct pt_regs in a `state save frame' on the stack. */ +#define PTO STATE_SAVE_PT_OFFSET + + +/* Save argument registers to the struct pt_regs pointed to by EP. */ +#define SAVE_ARG_REGS \ + sst.w r6, PTO+PT_GPR(6)[ep]; \ + sst.w r7, PTO+PT_GPR(7)[ep]; \ + sst.w r8, PTO+PT_GPR(8)[ep]; \ + sst.w r9, PTO+PT_GPR(9)[ep]; +/* Restore argument registers from the struct pt_regs pointed to by EP. */ +#define RESTORE_ARG_REGS \ + sld.w PTO+PT_GPR(6)[ep], r6; \ + sld.w PTO+PT_GPR(7)[ep], r7; \ + sld.w PTO+PT_GPR(8)[ep], r8; \ + sld.w PTO+PT_GPR(9)[ep], r9; + +/* Save value return registers to the struct pt_regs pointed to by EP. */ +#define SAVE_RVAL_REGS \ + sst.w r10, PTO+PT_GPR(10)[ep]; \ + sst.w r11, PTO+PT_GPR(11)[ep]; +/* Restore value return registers from the struct pt_regs pointed to by EP. */ +#define RESTORE_RVAL_REGS \ + sld.w PTO+PT_GPR(10)[ep], r10; \ + sld.w PTO+PT_GPR(11)[ep], r11; + + +#define SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS \ + sst.w r1, PTO+PT_GPR(1)[ep]; \ + sst.w r5, PTO+PT_GPR(5)[ep]; +#define SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL \ + sst.w r12, PTO+PT_GPR(12)[ep]; \ + sst.w r13, PTO+PT_GPR(13)[ep]; \ + sst.w r14, PTO+PT_GPR(14)[ep]; \ + sst.w r15, PTO+PT_GPR(15)[ep]; \ + sst.w r16, PTO+PT_GPR(16)[ep]; \ + sst.w r17, PTO+PT_GPR(17)[ep]; \ + sst.w r18, PTO+PT_GPR(18)[ep]; \ + sst.w r19, PTO+PT_GPR(19)[ep]; +#define RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS \ + sld.w PTO+PT_GPR(1)[ep], r1; \ + sld.w PTO+PT_GPR(5)[ep], r5; +#define RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL \ + sld.w PTO+PT_GPR(12)[ep], r12; \ + sld.w PTO+PT_GPR(13)[ep], r13; \ + sld.w PTO+PT_GPR(14)[ep], r14; \ + sld.w PTO+PT_GPR(15)[ep], r15; \ + sld.w PTO+PT_GPR(16)[ep], r16; \ + sld.w PTO+PT_GPR(17)[ep], r17; \ + sld.w PTO+PT_GPR(18)[ep], r18; \ + sld.w PTO+PT_GPR(19)[ep], r19; + +/* Save `call clobbered' registers to the struct pt_regs pointed to by EP. */ +#define SAVE_CALL_CLOBBERED_REGS \ + SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ + SAVE_ARG_REGS; \ + SAVE_RVAL_REGS; \ + SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL; +/* Restore `call clobbered' registers from the struct pt_regs pointed to + by EP. */ +#define RESTORE_CALL_CLOBBERED_REGS \ + RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ + RESTORE_ARG_REGS; \ + RESTORE_RVAL_REGS; \ + RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL; + +/* Save `call clobbered' registers except for the return-value registers + to the struct pt_regs pointed to by EP. */ +#define SAVE_CALL_CLOBBERED_REGS_NO_RVAL \ + SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ + SAVE_ARG_REGS; \ + SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL; +/* Restore `call clobbered' registers except for the return-value registers + from the struct pt_regs pointed to by EP. */ +#define RESTORE_CALL_CLOBBERED_REGS_NO_RVAL \ + RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ + RESTORE_ARG_REGS; \ + RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL; + +/* Zero `call clobbered' registers except for the return-value registers. */ +#define ZERO_CALL_CLOBBERED_REGS_NO_RVAL \ + mov r0, r1; mov r0, r5; \ + mov r0, r12; mov r0, r13; mov r0, r14; mov r0, r15; \ + mov r0, r16; mov r0, r17; mov r0, r18; mov r0, r19; + +/* Save `call saved' registers to the struct pt_regs pointed to by EP. */ +#define SAVE_CALL_SAVED_REGS \ + sst.w r2, PTO+PT_GPR(2)[ep]; \ + sst.w r20, PTO+PT_GPR(20)[ep]; \ + sst.w r21, PTO+PT_GPR(21)[ep]; \ + sst.w r22, PTO+PT_GPR(22)[ep]; \ + sst.w r23, PTO+PT_GPR(23)[ep]; \ + sst.w r24, PTO+PT_GPR(24)[ep]; \ + sst.w r25, PTO+PT_GPR(25)[ep]; \ + sst.w r26, PTO+PT_GPR(26)[ep]; \ + sst.w r27, PTO+PT_GPR(27)[ep]; \ + sst.w r28, PTO+PT_GPR(28)[ep]; \ + sst.w r29, PTO+PT_GPR(29)[ep]; +/* Restore `call saved' registers from the struct pt_regs pointed to by EP. */ +#define RESTORE_CALL_SAVED_REGS \ + sld.w PTO+PT_GPR(2)[ep], r2; \ + sld.w PTO+PT_GPR(20)[ep], r20; \ + sld.w PTO+PT_GPR(21)[ep], r21; \ + sld.w PTO+PT_GPR(22)[ep], r22; \ + sld.w PTO+PT_GPR(23)[ep], r23; \ + sld.w PTO+PT_GPR(24)[ep], r24; \ + sld.w PTO+PT_GPR(25)[ep], r25; \ + sld.w PTO+PT_GPR(26)[ep], r26; \ + sld.w PTO+PT_GPR(27)[ep], r27; \ + sld.w PTO+PT_GPR(28)[ep], r28; \ + sld.w PTO+PT_GPR(29)[ep], r29; + + +/* Save system registers to the struct pt_regs pointed to by REG. + r19 is clobbered. */ +#define SAVE_SYS_REGS \ + stsr SR_EIPC, r19; /* user's PC, before interrupt */ \ + sst.w r19, PTO+PT_PC[ep]; \ + stsr SR_EIPSW, r19; /* & PSW (XXX save this?) */ \ + sst.w r19, PTO+PT_PSW[ep]; \ + stsr SR_CTPC, r19; /* (XXX maybe not used in kernel?) */ \ + sst.w r19, PTO+PT_CTPC[ep]; \ + stsr SR_CTPSW, r19; /* " */ \ + sst.w r19, PTO+PT_CTPSW[ep]; \ + stsr SR_CTBP, r19; /* " */ \ + sst.w r19, PTO+PT_CTBP[ep]; +/* Restore system registers from the struct pt_regs pointed to by EP. + LP is clobbered (it is used as a scratch register because the POP_STATE + macro restores it, and this macro is usually used inside POP_STATE). */ +#define RESTORE_SYS_REGS \ + sld.w PTO+PT_PC[ep], lp; \ + ldsr lp, SR_EIPC; /* user's PC, before interrupt */ \ + sld.w PTO+PT_PSW[ep], lp; \ + ldsr lp, SR_EIPSW; /* & PSW (XXX save this?) */ \ + sld.w PTO+PT_CTPC[ep], lp; \ + ldsr lp, SR_CTPC; /* (XXX maybe not used in kernel?) */ \ + sld.w PTO+PT_CTPSW[ep], lp; \ + ldsr lp, SR_CTPSW; /* " */ \ + sld.w PTO+PT_CTBP[ep], lp; \ + ldsr lp, SR_CTBP; /* " */ + + +/* Save system registers to the struct pt_regs pointed to by REG. This is a + NMI-specific version, because NMIs save the PC/PSW in a different place + than other interrupt requests. r19 is clobbered. */ +#define SAVE_SYS_REGS_FOR_NMI \ + stsr SR_FEPC, r19; /* user's PC, before NMI */ \ + sst.w r19, PTO+PT_PC[ep]; \ + stsr SR_FEPSW, r19; /* & PSW (XXX save this?) */ \ + sst.w r19, PTO+PT_PSW[ep]; \ + stsr SR_CTPC, r19; /* (XXX maybe not used in kernel?) */ \ + sst.w r19, PTO+PT_CTPC[ep]; \ + stsr SR_CTPSW, r19; /* " */ \ + sst.w r19, PTO+PT_CTPSW[ep]; \ + stsr SR_CTBP, r19; /* " */ \ + sst.w r19, PTO+PT_CTBP[ep]; +/* Restore system registers from the struct pt_regs pointed to by EP. This is + a NMI-specific version, because NMIs save the PC/PSW in a different place + than other interrupt requests. LP is clobbered (it is used as a scratch + register because the POP_STATE macro restores it, and this macro is usually + used inside POP_STATE). */ +#define RESTORE_SYS_REGS_FOR_NMI \ + ldsr lp, SR_FEPC; /* user's PC, before NMI */ \ + sld.w PTO+PT_PC[ep], lp; \ + ldsr lp, SR_FEPSW; /* & PSW (XXX save this?) */ \ + sld.w PTO+PT_PSW[ep], lp; \ + ldsr lp, SR_CTPC; /* (XXX maybe not used in kernel?) */ \ + sld.w PTO+PT_CTPC[ep], lp; \ + ldsr lp, SR_CTPSW; /* " */ \ + sld.w PTO+PT_CTPSW[ep], lp; \ + ldsr lp, SR_CTBP; /* " */ \ + sld.w PTO+PT_CTBP[ep], lp; + + +/* Push register state, except for the stack pointer, on the stack in the form + of a struct pt_regs, in preparation for a system call. This macro makes + sure that `special' registers, system registers; TYPE identifies the set of + extra registers to be saved as well. EP is clobbered. */ +#define PUSH_STATE(type) \ + addi -STATE_SAVE_SIZE, sp, sp; /* Make room on the stack. */ \ + st.w ep, PTO+PT_GPR(GPR_EP)[sp]; \ + mov sp, ep; \ + sst.w gp, PTO+PT_GPR(GPR_GP)[ep]; \ + sst.w lp, PTO+PT_GPR(GPR_LP)[ep]; \ + type ## _STATE_SAVER; +/* Pop a register state, except for the stack pointer, from the struct pt_regs + on the stack. */ +#define POP_STATE(type) \ + mov sp, ep; \ + type ## _STATE_RESTORER; \ + sld.w PTO+PT_GPR(GPR_GP)[ep], gp; \ + sld.w PTO+PT_GPR(GPR_LP)[ep], lp; \ + sld.w PTO+PT_GPR(GPR_EP)[ep], ep; \ + addi STATE_SAVE_SIZE, sp, sp; /* Clean up our stack space. */ + + +/* Switch to the kernel stack if necessary, and push register state on + the stack in the form of a struct pt_regs. Also load the current + task pointer if switching from user mode. The stack-pointer (r3) + should have already been saved to the memory location SP_SAVE_LOC + (the reason for this is that the interrupt vectors may be beyond a + 22-bit signed offset jump from the actual interrupt handler, and this + allows them to save the stack-pointer and use that register to do an + indirect jump). This macro makes sure that `special' registers, + system registers, and the stack pointer are saved; TYPE identifies + the set of extra registers to be saved as well. SYSCALL_NUM is the + register in which the system-call number this state is for is stored + (r0 if this isn't a system call). Interrupts should already be + disabled when calling this. */ +#define SAVE_STATE(type, syscall_num, sp_save_loc) \ + tst1 0, KM; /* See if already in kernel mode. */ \ + bz 1f; \ + /* Kernel-mode state save. */ \ + ld.w sp_save_loc, sp; /* Reload kernel stack-pointer. */ \ + st.w sp, (PT_GPR(GPR_SP)-PT_SIZE)[sp]; /* Save original SP. */ \ + PUSH_STATE(type); \ + mov 1, r19; /* Was in kernel-mode. */ \ + sst.w r19, PTO+PT_KERNEL_MODE[ep]; /* [ep is set by PUSH_STATE] */ \ + br 2f; \ +1: /* User-mode state save. */ \ + ld.w KSP, sp; /* Switch to kernel stack. */ \ + PUSH_STATE(type); \ + sst.w r0, PTO+PT_KERNEL_MODE[ep]; /* Was in user-mode. */ \ + ld.w sp_save_loc, r19; \ + sst.w r19, PTO+PT_GPR(GPR_SP)[ep]; /* Store user SP. */ \ + mov 1, r19; \ + st.b r19, KM; /* Now we're in kernel-mode. */ \ + GET_CURRENT_TASK(CURRENT_TASK); /* Fetch the current task pointer. */ \ +2: /* Save away the syscall number. */ \ + sst.w syscall_num, PTO+PT_SYSCALL[ep] + + +/* Save register state not normally saved by PUSH_STATE for TYPE. */ +#define SAVE_EXTRA_STATE(type) \ + mov sp, ep; \ + type ## _EXTRA_STATE_SAVER; +/* Restore register state not normally restored by POP_STATE for TYPE. */ +#define RESTORE_EXTRA_STATE(type) \ + mov sp, ep; \ + type ## _EXTRA_STATE_RESTORER; + +/* Save any call-clobbered registers not normally saved by PUSH_STATE + for TYPE. */ +#define SAVE_EXTRA_STATE_FOR_FUNCALL(type) \ + mov sp, ep; \ + type ## _FUNCALL_EXTRA_STATE_SAVER; +/* Restore any call-clobbered registers not normally restored by POP_STATE for + TYPE. */ +#define RESTORE_EXTRA_STATE_FOR_FUNCALL(type) \ + mov sp, ep; \ + type ## _FUNCALL_EXTRA_STATE_RESTORER; + + +/* These are extra_state_saver/restorer values for a user trap. Note that we + save the argument registers so that restarted syscalls will function + properly (otherwise it wouldn't be necessary), and we must _not_ restore + the return-value registers (so that traps can return a value!), but there + are various options for what happens to other call-clobbered registers, + selected by preprocessor conditionals. */ + +#if TRAPS_PRESERVE_CALL_CLOBBERED_REGS + +/* Traps save/restore all call-clobbered registers (except for rval regs). */ +#define TRAP_STATE_SAVER \ + SAVE_CALL_CLOBBERED_REGS_NO_RVAL; \ + SAVE_SYS_REGS +#define TRAP_STATE_RESTORER \ + RESTORE_CALL_CLOBBERED_REGS_NO_RVAL; \ + RESTORE_SYS_REGS + +#else /* !TRAPS_PRESERVE_CALL_CLOBBERED_REGS */ + +/* Traps don't save call-clobbered registers (but do still save arg regs). */ +#define TRAP_STATE_SAVER \ + SAVE_ARG_REGS; \ + SAVE_SYS_REGS + +#if TRAPS_ZERO_CALL_CLOBBERED_REGS + +/* Traps zero call-clobbered registers (except for arg/rval regs) before + returning from a system call, to avoid any internal values from leaking out + of the kernel. */ +#define TRAP_STATE_RESTORER \ + ZERO_CALL_CLOBBERED_REGS_NO_ARGS_NO_RVAL; \ + RESTORE_ARG_REGS; \ + RESTORE_SYS_REGS + +#else /* !TRAPS_ZERO_CALL_CLOBBERED_REGS */ + +/* When traps return, they just leave call-clobbered registers (except for arg + regs) with whatever value they have from the kernel. */ +#define TRAP_STATE_RESTORER \ + RESTORE_ARG_REGS; \ + RESTORE_SYS_REGS + +#endif /* TRAPS_ZERO_CALL_CLOBBERED_REGS */ +#endif /* TRAPS_PRESERVE_CALL_CLOBBERED_REGS */ + +/* Save registers not normally saved by traps. */ +#define TRAP_EXTRA_STATE_SAVER \ + SAVE_RVAL_REGS; \ + SAVE_CALL_SAVED_REGS +#define TRAP_EXTRA_STATE_RESTORER \ + RESTORE_RVAL_REGS; \ + RESTORE_CALL_SAVED_REGS +#define TRAP_FUNCALL_EXTRA_STATE_SAVER \ + SAVE_RVAL_REGS +#define TRAP_FUNCALL_EXTRA_STATE_RESTORER \ + RESTORE_RVAL_REGS + + +/* Register saving/restoring for maskable interrupts. */ +#define IRQ_STATE_SAVER \ + SAVE_CALL_CLOBBERED_REGS; \ + SAVE_SYS_REGS +#define IRQ_STATE_RESTORER \ + RESTORE_CALL_CLOBBERED_REGS; \ + RESTORE_SYS_REGS +#define IRQ_EXTRA_STATE_SAVER \ + SAVE_CALL_SAVED_REGS +#define IRQ_EXTRA_STATE_RESTORER \ + RESTORE_CALL_SAVED_REGS +#define IRQ_FUNCALL_EXTRA_STATE_SAVER /* nothing */ +#define IRQ_FUNCALL_EXTRA_STATE_RESTORER /* nothing */ + +/* Register saving/restoring for non-maskable interrupts. */ +#define NMI_STATE_SAVER \ + SAVE_CALL_CLOBBERED_REGS; \ + SAVE_SYS_REGS_FOR_NMI +#define NMI_STATE_RESTORER \ + RESTORE_CALL_CLOBBERED_REGS; \ + RESTORE_SYS_REGS_FOR_NMI +#define NMI_EXTRA_STATE_SAVER \ + SAVE_CALL_SAVED_REGS +#define NMI_EXTRA_STATE_RESTORER \ + RESTORE_CALL_SAVED_REGS +#define NMI_FUNCALL_EXTRA_STATE_SAVER /* nothing */ +#define NMI_FUNCALL_EXTRA_STATE_RESTORER /* nothing */ + +/* Register saving/restoring for a context switch. We don't need to save too + many registers, because context-switching looks like a function call (via + the function `switch_thread'), so callers will save any call-clobbered + registers themselves. The stack pointer and return value are handled by + switch_thread itself. */ +#define SWITCH_STATE_SAVER \ + SAVE_CALL_SAVED_REGS +#define SWITCH_STATE_RESTORER \ + RESTORE_CALL_SAVED_REGS + + +/* Restore register state from the struct pt_regs on the stack, switch back + to the user stack if necessary, and return from the trap/interrupt. + EXTRA_STATE_RESTORER is a sequence of assembly language statements to + restore anything not restored by this macro. Only registers not saved by + the C compiler are restored (that is, R3(sp), R4(gp), R31(lp), and + anything restored by EXTRA_STATE_RESTORER). */ +#define RETURN(type) \ + ld.b PTO+PT_KERNEL_MODE[sp], r19; \ + di; /* Disable interrupts */ \ + cmp r19, r0; /* See if returning to kernel mode, */\ + bne 2f; /* ... if so, skip resched &c. */ \ + \ + /* We're returning to user mode, so check for various conditions that \ + trigger rescheduling. */ \ + GET_CURRENT_THREAD(r18); \ + ld.w TI_FLAGS[r18], r19; \ + andi _TIF_NEED_RESCHED, r19, r0; \ + bnz 3f; /* Call the scheduler. */ \ + andi _TIF_SIGPENDING, r19, r0; \ + bnz 4f; /* Signals to handle, handle them */ \ + \ +/* Finally, return to user state. */ \ +1: st.b r0, KM; /* Now officially in user state. */ \ + POP_STATE(type); \ + st.w sp, KSP; /* Save the kernel stack pointer. */ \ + ld.w PT_GPR(GPR_SP)-PT_SIZE[sp], sp; \ + /* Restore user stack pointer. */ \ + reti; \ + \ +/* Return to kernel state. */ \ +2: POP_STATE(type); \ + reti; \ + \ +/* Call the scheduler before returning from a syscall/trap. */ \ +3: SAVE_EXTRA_STATE_FOR_FUNCALL(type); /* Prepare for funcall. */ \ + jarl CSYM(schedule), lp; /* Call scheduler */ \ + di; /* The scheduler enables interrupts */\ + RESTORE_EXTRA_STATE_FOR_FUNCALL(type); \ + br 1b; \ + \ +/* Handle a signal return. */ \ +4: /* Not all registers are saved by the normal trap/interrupt entry \ + points (for instance, call-saved registers (because the normal \ + C-compiler calling sequence in the kernel makes sure they're \ + preserved), and call-clobbered registers in the case of \ + traps), but signal handlers may want to examine or change the \ + complete register state. Here we save anything not saved by \ + the normal entry sequence, so that it may be safely restored \ + (in a possibly modified form) after do_signal returns. */ \ + SAVE_EXTRA_STATE(type) /* Save state not saved by entry. */ \ + movea PTO, sp, r6; /* Arg 1: struct pt_regs *regs */ \ + mov r0, r7; /* Arg 2: sigset_t *oldset */ \ + jarl CSYM(do_signal), lp; /* Handle any signals */ \ + di; /* sig handling enables interrupts */ \ + RESTORE_EXTRA_STATE(type); /* Restore extra regs. */ \ + br 1b; + + +/* Jump to the appropriate function for the system call number in r12 + (r12 is not preserved), or return an error if r12 is not valid. The + LP register should point to the location where the called function + should return. [note that MAKE_SYS_CALL uses label 1] */ +#define MAKE_SYS_CALL \ + /* See if the system call number is valid. */ \ + addi -NR_syscalls, r12, r0; \ + bnh 1f; \ + /* Figure out which function to use for this system call. */ \ + shl 2, r12; \ + mov hilo(CSYM(sys_call_table)), r19; \ + add r19, r12; \ + ld.w 0[r12], r12; \ + /* Make the system call. */ \ + jmp [r12]; \ + /* The syscall number is invalid, return an error. */ \ +1: addi -ENOSYS, r0, r10; \ + jmp [lp]; + + + .text + +/* + * User trap. + * + * Trap 0 system calls are also handled here. + * + * The stack-pointer (r3) should have already been saved to the memory + * location ENTRY_SP (the reason for this is that the interrupt vectors may be + * beyond a 22-bit signed offset jump from the actual interrupt handler, and + * this allows them to save the stack-pointer and use that register to do an + * indirect jump). + * + * Syscall protocol: + * Syscall number in r12, args in r6-r9 + * Return value in r10 + */ +G_ENTRY(trap): + SAVE_STATE (TRAP, r12, ENTRY_SP) // Save registers. + stsr SR_ECR, r19 // Find out which trap it was. + ei // Enable interrupts. + mov hilo(ret_from_trap), lp // where the trap should return + + // The following two shifts (1) clear out extraneous NMI data in the + // upper 16-bits, (2) convert the 0x40 - 0x5f range of trap ECR + // numbers into the (0-31) << 2 range we want, (3) set the flags. + shl 27, r19 // chop off all high bits + shr 25, r19 // scale back down and then << 2 + bnz 2f // See if not trap 0. + + // Trap 0 is a `short' system call, skip general trap table. + MAKE_SYS_CALL // Jump to the syscall function. + +2: // For other traps, use a table lookup. + mov hilo(CSYM(trap_table)), r18 + add r19, r18 + ld.w 0[r18], r18 + jmp [r18] // Jump to the trap handler. +END(trap) + +/* This is just like ret_from_trap, but first restores extra registers + saved by some wrappers. */ +L_ENTRY(restore_extra_regs_and_ret_from_trap): + RESTORE_EXTRA_STATE(TRAP) + // fall through +END(restore_extra_regs_and_ret_from_trap) + +/* Entry point used to return from a syscall/trap. */ +L_ENTRY(ret_from_trap): + RETURN(TRAP) +END(ret_from_trap) + +/* This the initial entry point for a new child thread, with an appropriate + stack in place that makes it look the the child is in the middle of an + syscall. This function is actually `returned to' from switch_thread + (copy_thread makes ret_from_fork the return address in each new thread's + saved context). */ +C_ENTRY(ret_from_fork): +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) + mov r10, r6 // switch_thread returns the prev task. + jarl CSYM(schedule_tail), lp // ...which is schedule_tail's arg +#endif + mov r0, r10 // Child's fork call should return 0. + br ret_from_trap // Do normal trap return. +C_END(ret_from_fork) + + +/* + * Trap 1: `long' system calls + * `Long' syscall protocol: + * Syscall number in r12, args in r6-r9, r13-r14 + * Return value in r10 + */ +L_ENTRY(syscall_long): + // Push extra arguments on the stack. Note that by default, the trap + // handler reserves enough stack space for 6 arguments, so we don't + // have to make any additional room. + st.w r13, 16[sp] // arg 5 + st.w r14, 20[sp] // arg 6 + +#if !TRAPS_PRESERVE_CALL_CLOBBERED_REGS + // Make sure r13 and r14 are preserved, in case we have to restart a + // system call because of a signal (ep has already been set by caller). + st.w r13, PTO+PT_GPR(13)[sp] + st.w r14, PTO+PT_GPR(13)[sp] + mov hilo(ret_from_long_syscall), lp +#endif /* !TRAPS_PRESERVE_CALL_CLOBBERED_REGS */ + + MAKE_SYS_CALL // Jump to the syscall function. +END(syscall_long) + +#if !TRAPS_PRESERVE_CALL_CLOBBERED_REGS +/* Entry point used to return from a long syscall. Only needed to restore + r13/r14 if the general trap mechanism doesnt' do so. */ +L_ENTRY(ret_from_long_syscall): + ld.w PTO+PT_GPR(13)[sp], r13 // Restore the extra registers + ld.w PTO+PT_GPR(13)[sp], r14 + br ret_from_trap // The rest is the same as other traps +END(ret_from_long_syscall) +#endif /* !TRAPS_PRESERVE_CALL_CLOBBERED_REGS */ + + +/* These syscalls need access to the struct pt_regs on the stack, so we + implement them in assembly (they're basically all wrappers anyway). */ + +L_ENTRY(sys_fork_wrapper): +#ifdef CONFIG_MMU + // Save state not saved by entry. This is actually slight overkill; + // it's actually only necessary to save any state restored by + // switch_thread that's not saved by the trap entry. + SAVE_EXTRA_STATE(TRAP) // Save state not saved by entry. + addi SIGCHLD, r0, r6 // Arg 0: flags + ld.w PTO+PT_GPR(GPR_SP)[sp], r7 // Arg 1: child SP (use parent's) + movea PTO, sp, r8 // Arg 2: parent context + jr CSYM(fork_common) // Do real work (tail-call). +#else + // fork almost works, enough to trick you into looking elsewhere :-( + addi -EINVAL, r0, r10 + jmp [lp] +#endif +END(sys_fork_wrapper) + +L_ENTRY(sys_vfork_wrapper): + // Save state not saved by entry. This is actually slight overkill; + // it's actually only necessary to save any state restored by + // switch_thread that's not saved by the trap entry. + SAVE_EXTRA_STATE(TRAP) // Save state not saved by entry. + addi CLONE_VFORK | CLONE_VM | SIGCHLD, r0, r6 // Arg 0: flags + ld.w PTO+PT_GPR(GPR_SP)[sp], r7 // Arg 1: child SP (use parent's) + movea PTO, sp, r8 // Arg 2: parent context + jr CSYM(fork_common) // Do real work (tail-call). +END(sys_vfork_wrapper) + +L_ENTRY(sys_clone_wrapper): + // Save state not saved by entry. This is actually slight overkill; + // it's actually only necessary to save any state restored by + // switch_thread that's not saved by the trap entry. + SAVE_EXTRA_STATE(TRAP) // Save state not saved by entry. + ld.w PTO+PT_GPR(GPR_SP)[sp], r19 // parent's stack pointer + cmp r7, r0 // See if child SP arg (arg 1) is 0. + cmov z, r19, r7, r7 // ... and use the parent's if so. + movea PTO, sp, r8 // Arg 2: parent context + jr CSYM(fork_common) // Do real work (tail-call). +END(sys_clone_wrapper) + +L_ENTRY(sys_execve_wrapper): + movea PTO, sp, r9 // add user context as 4th arg + jr CSYM(sys_execve) // Do real work (tail-call). +END(sys_execve_wrapper) + +L_ENTRY(sys_sigsuspend_wrapper): + SAVE_EXTRA_STATE(TRAP) // Save state not saved by entry. + movea PTO, sp, r7 // add user context as 2nd arg + jarl CSYM(sys_sigsuspend), lp// Do real work. + br restore_extra_regs_and_ret_from_trap +END(sys_sigsuspend_wrapper) +L_ENTRY(sys_rt_sigsuspend_wrapper): + SAVE_EXTRA_STATE(TRAP) // Save state not saved by entry. + movea PTO, sp, r8 // add user context as 3rd arg + jarl CSYM(sys_rt_sigsuspend), lp // Do real work. + br restore_extra_regs_and_ret_from_trap +END(sys_rt_sigsuspend_wrapper) + +L_ENTRY(sys_sigreturn_wrapper): + SAVE_EXTRA_STATE(TRAP) // Save state not saved by entry. + movea PTO, sp, r6 // add user context as 1st arg + jarl CSYM(sys_sigreturn), lp // Do real work. + br restore_extra_regs_and_ret_from_trap +END(sys_sigreturn_wrapper) +L_ENTRY(sys_rt_sigreturn_wrapper): + SAVE_EXTRA_STATE(TRAP) // Save state not saved by entry. + movea PTO, sp, r6 // add user context as 1st arg + jarl CSYM(sys_rt_sigreturn), lp // Do real work. + br restore_extra_regs_and_ret_from_trap +END(sys_rt_sigreturn_wrapper) + + +/* + * Hardware maskable interrupts. + * + * The stack-pointer (r3) should have already been saved to the memory + * location ENTRY_SP (the reason for this is that the interrupt vectors may be + * beyond a 22-bit signed offset jump from the actual interrupt handler, and + * this allows them to save the stack-pointer and use that register to do an + * indirect jump). + */ +G_ENTRY(irq): + SAVE_STATE (IRQ, r0, ENTRY_SP) // Save registers. + + stsr SR_ECR, r6 // Find out which interrupt it was. + movea PTO, sp, r7 // User regs are arg2 + + // All v850 implementations I know about encode their interrupts as + // multiples of 0x10, starting at 0x80 (after NMIs and software + // interrupts). Convert this number into a simple IRQ index for the + // rest of the kernel. We also clear the upper 16 bits, which hold + // NMI info, and don't appear to be cleared when a NMI returns. + shl 16, r6 // clear upper 16 bits + shr 20, r6 // shift back, and remove lower nibble + add -8, r6 // remove bias for irqs + // Call the high-level interrupt handling code. + jarl CSYM(handle_irq), lp + // fall through + +/* Entry point used to return from an interrupt (also used by exception + handlers, below). */ +ret_from_irq: + RETURN(IRQ) +END(irq) + + +/* + * Hardware non-maskable interrupts. + * + * The stack-pointer (r3) should have already been saved to the memory + * location ENTRY_SP (the reason for this is that the interrupt vectors may be + * beyond a 22-bit signed offset jump from the actual interrupt handler, and + * this allows them to save the stack-pointer and use that register to do an + * indirect jump). + */ +G_ENTRY(nmi): + SAVE_STATE (NMI, r0, NMI_ENTRY_SP); /* Save registers. */ + + stsr SR_ECR, r6; /* Find out which nmi it was. */ + shr 20, r6; /* Extract NMI code in bits 20-24. */ + movea PTO, sp, r7; /* User regs are arg2. */ + + /* Non-maskable interrupts always lie right after maskable interrupts. + Call the generic IRQ handler, with two arguments, the IRQ number, + and a pointer to the user registers, to handle the specifics. + (we subtract one because the first NMI has code 1). */ + addi FIRST_NMI - 1, r6, r6; + jarl CSYM(handle_irq), lp + + RETURN(NMI) +END(nmi0) + + +/* + * Illegal instruction trap. + * + * The stack-pointer (r3) should have already been saved to the memory + * location ENTRY_SP (the reason for this is that the interrupt vectors may be + * beyond a 22-bit signed offset jump from the actual interrupt handler, and + * this allows them to save the stack-pointer and use that register to do an + * indirect jump). + */ +G_ENTRY(illegal_instruction): + SAVE_STATE (IRQ, r0, ENTRY_SP) // Save registers. + ei + addi SIGILL, r0, r6 // Arg 0: signal number + mov CURRENT_TASK, r7 // Arg 1: task + mov hilo(ret_from_irq), lp // where the handler should return + jr CSYM(force_sig) +END(illegal_instruction) + + +/* + * `Debug' trap + * + * The stack-pointer (r3) should have already been saved to the memory + * location ENTRY_SP (the reason for this is that the interrupt vectors may be + * beyond a 22-bit signed offset jump from the actual interrupt handler, and + * this allows them to save the stack-pointer and use that register to do an + * indirect jump). + */ +G_ENTRY(dbtrap): + SAVE_STATE (IRQ, r0, ENTRY_SP) // Save registers. + ei + movea PTO, sp, r6 // Arg 0: user regs + mov hilo(ret_from_irq), lp // where the handler should return + jr CSYM(debug_trap) +END(dbtrap) + + +/* + * Trap with no handler + */ +L_ENTRY(bad_trap_wrapper): + mov r19, r6 // Arg 0: trap number + movea PTO, sp, r7 // Arg 1: user regs + jr CSYM(bad_trap) // tail call handler +END(bad_trap_wrapper) + + +/* + * This is where we switch between two threads. The arguments are: + * r6 -- pointer to the struct thread for the `current' process + * r7 -- pointer to the struct thread for the `new' process. + * when this function returns, it will return to the new thread. + */ +C_ENTRY(switch_thread): + // Return the previous task (r10 is not clobbered by restore below) + mov CURRENT_TASK, r10 + // First, push the current processor state on the stack + PUSH_STATE(SWITCH) + // Now save the location of the kernel stack pointer for this thread; + // since we've pushed all other state on the stack, this is enough to + // restore it all later. + st.w sp, THREAD_KSP[r6] + // Now restore the stack pointer from the new process + ld.w THREAD_KSP[r7], sp + // ... and restore all state from that + POP_STATE(SWITCH) + // Update the current task pointer + GET_CURRENT_TASK(CURRENT_TASK) + // Now return into the new thread + jmp [lp] +C_END(switch_thread) + + + .data + + .align 4 + .globl CSYM(trap_table) +CSYM(trap_table): + .long bad_trap_wrapper // trap 0, doesn't use trap table. + .long syscall_long // trap 1, `long' syscall. + .long bad_trap_wrapper + .long bad_trap_wrapper + .long bad_trap_wrapper + .long bad_trap_wrapper + .long bad_trap_wrapper + .long bad_trap_wrapper + .long bad_trap_wrapper + .long bad_trap_wrapper + .long bad_trap_wrapper + .long bad_trap_wrapper + .long bad_trap_wrapper + .long bad_trap_wrapper + .long bad_trap_wrapper + .long bad_trap_wrapper + + + .section .rodata + + .align 4 + .globl CSYM(sys_call_table) +CSYM(sys_call_table): + .long CSYM(sys_ni_syscall) // 0 - old "setup()" system call + .long CSYM(sys_exit) + .long sys_fork_wrapper + .long CSYM(sys_read) + .long CSYM(sys_write) + .long CSYM(sys_open) // 5 + .long CSYM(sys_close) + .long CSYM(sys_waitpid) + .long CSYM(sys_creat) + .long CSYM(sys_link) + .long CSYM(sys_unlink) // 10 + .long sys_execve_wrapper + .long CSYM(sys_chdir) + .long CSYM(sys_time) + .long CSYM(sys_mknod) + .long CSYM(sys_chmod) // 15 + .long CSYM(sys_chown) + .long CSYM(sys_ni_syscall) // was: break + .long CSYM(sys_ni_syscall) // was: oldstat (aka stat) + .long CSYM(sys_lseek) + .long CSYM(sys_getpid) // 20 + .long CSYM(sys_mount) + .long CSYM(sys_oldumount) + .long CSYM(sys_setuid) + .long CSYM(sys_getuid) + .long CSYM(sys_stime) // 25 + .long CSYM(sys_ptrace) + .long CSYM(sys_alarm) + .long CSYM(sys_ni_syscall) // was: oldfstat (aka fstat) + .long CSYM(sys_pause) + .long CSYM(sys_utime) // 30 + .long CSYM(sys_ni_syscall) // was: stty + .long CSYM(sys_ni_syscall) // was: gtty + .long CSYM(sys_access) + .long CSYM(sys_nice) + .long CSYM(sys_ni_syscall) // 35, was: ftime + .long CSYM(sys_sync) + .long CSYM(sys_kill) + .long CSYM(sys_rename) + .long CSYM(sys_mkdir) + .long CSYM(sys_rmdir) // 40 + .long CSYM(sys_dup) + .long CSYM(sys_pipe) + .long CSYM(sys_times) + .long CSYM(sys_ni_syscall) // was: prof + .long CSYM(sys_brk) // 45 + .long CSYM(sys_setgid) + .long CSYM(sys_getgid) + .long CSYM(sys_signal) + .long CSYM(sys_geteuid) + .long CSYM(sys_getegid) // 50 + .long CSYM(sys_acct) + .long CSYM(sys_umount) // recycled never used phys() + .long CSYM(sys_ni_syscall) // was: lock + .long CSYM(sys_ioctl) + .long CSYM(sys_fcntl) // 55 + .long CSYM(sys_ni_syscall) // was: mpx + .long CSYM(sys_setpgid) + .long CSYM(sys_ni_syscall) // was: ulimit + .long CSYM(sys_ni_syscall) + .long CSYM(sys_umask) // 60 + .long CSYM(sys_chroot) + .long CSYM(sys_ustat) + .long CSYM(sys_dup2) + .long CSYM(sys_getppid) + .long CSYM(sys_getpgrp) // 65 + .long CSYM(sys_setsid) + .long CSYM(sys_sigaction) + .long CSYM(sys_sgetmask) + .long CSYM(sys_ssetmask) + .long CSYM(sys_setreuid) // 70 + .long CSYM(sys_setregid) + .long sys_sigsuspend_wrapper + .long CSYM(sys_sigpending) + .long CSYM(sys_sethostname) + .long CSYM(sys_setrlimit) // 75 + .long CSYM(sys_getrlimit) + .long CSYM(sys_getrusage) + .long CSYM(sys_gettimeofday) + .long CSYM(sys_settimeofday) + .long CSYM(sys_getgroups) // 80 + .long CSYM(sys_setgroups) + .long CSYM(sys_select) + .long CSYM(sys_symlink) + .long CSYM(sys_ni_syscall) // was: oldlstat (aka lstat) + .long CSYM(sys_readlink) // 85 + .long CSYM(sys_uselib) + .long CSYM(sys_swapon) + .long CSYM(sys_reboot) + .long CSYM(old_readdir) + .long CSYM(sys_mmap) // 90 + .long CSYM(sys_munmap) + .long CSYM(sys_truncate) + .long CSYM(sys_ftruncate) + .long CSYM(sys_fchmod) + .long CSYM(sys_fchown) // 95 + .long CSYM(sys_getpriority) + .long CSYM(sys_setpriority) + .long CSYM(sys_ni_syscall) // was: profil + .long CSYM(sys_statfs) + .long CSYM(sys_fstatfs) // 100 + .long CSYM(sys_ni_syscall) // i386: ioperm + .long CSYM(sys_socketcall) + .long CSYM(sys_syslog) + .long CSYM(sys_setitimer) + .long CSYM(sys_getitimer) // 105 + .long CSYM(sys_newstat) + .long CSYM(sys_newlstat) + .long CSYM(sys_newfstat) + .long CSYM(sys_ni_syscall) // was: olduname (aka uname) + .long CSYM(sys_ni_syscall) // 110, i386: iopl + .long CSYM(sys_vhangup) + .long CSYM(sys_ni_syscall) // was: idle + .long CSYM(sys_ni_syscall) // i386: vm86old + .long CSYM(sys_wait4) + .long CSYM(sys_swapoff) // 115 + .long CSYM(sys_sysinfo) + .long CSYM(sys_ipc) + .long CSYM(sys_fsync) + .long sys_sigreturn_wrapper + .long sys_clone_wrapper // 120 + .long CSYM(sys_setdomainname) + .long CSYM(sys_newuname) + .long CSYM(sys_ni_syscall) // i386: modify_ldt, m68k: cacheflush + .long CSYM(sys_adjtimex) + .long CSYM(sys_ni_syscall) // 125 - sys_mprotect + .long CSYM(sys_sigprocmask) + .long CSYM(sys_create_module) + .long CSYM(sys_init_module) + .long CSYM(sys_delete_module) + .long CSYM(sys_get_kernel_syms) // 130 + .long CSYM(sys_quotactl) + .long CSYM(sys_getpgid) + .long CSYM(sys_fchdir) + .long CSYM(sys_bdflush) + .long CSYM(sys_sysfs) // 135 + .long CSYM(sys_personality) + .long CSYM(sys_ni_syscall) // for afs_syscall + .long CSYM(sys_setfsuid) + .long CSYM(sys_setfsgid) + .long CSYM(sys_llseek) // 140 + .long CSYM(sys_getdents) + .long CSYM(sys_select) // for backward compat; remove someday + .long CSYM(sys_flock) + .long CSYM(sys_ni_syscall) // sys_msync + .long CSYM(sys_readv) // 145 + .long CSYM(sys_writev) + .long CSYM(sys_getsid) + .long CSYM(sys_fdatasync) + .long CSYM(sys_sysctl) + .long CSYM(sys_ni_syscall) // 150 - sys_mlock + .long CSYM(sys_ni_syscall) // sys_munlock + .long CSYM(sys_ni_syscall) // sys_mlockall + .long CSYM(sys_ni_syscall) // sys_munlockall + .long CSYM(sys_sched_setparam) + .long CSYM(sys_sched_getparam) // 155 + .long CSYM(sys_sched_setscheduler) + .long CSYM(sys_sched_getscheduler) + .long CSYM(sys_sched_yield) + .long CSYM(sys_sched_get_priority_max) + .long CSYM(sys_sched_get_priority_min) // 160 + .long CSYM(sys_sched_rr_get_interval) + .long CSYM(sys_nanosleep) + .long CSYM(sys_ni_syscall) // sys_mremap + .long CSYM(sys_setresuid) + .long CSYM(sys_getresuid) // 165 + .long CSYM(sys_ni_syscall) // for vm86 + .long CSYM(sys_query_module) + .long CSYM(sys_poll) + .long CSYM(sys_nfsservctl) + .long CSYM(sys_setresgid) // 170 + .long CSYM(sys_getresgid) + .long CSYM(sys_prctl) + .long sys_rt_sigreturn_wrapper + .long CSYM(sys_rt_sigaction) + .long CSYM(sys_rt_sigprocmask) // 175 + .long CSYM(sys_rt_sigpending) + .long CSYM(sys_rt_sigtimedwait) + .long CSYM(sys_rt_sigqueueinfo) + .long sys_rt_sigsuspend_wrapper + .long CSYM(sys_pread64) // 180 + .long CSYM(sys_pwrite64) + .long CSYM(sys_lchown) + .long CSYM(sys_getcwd) + .long CSYM(sys_capget) + .long CSYM(sys_capset) // 185 + .long CSYM(sys_sigaltstack) + .long CSYM(sys_sendfile) + .long CSYM(sys_ni_syscall) // streams1 + .long CSYM(sys_ni_syscall) // streams2 + .long sys_vfork_wrapper // 190 + .long CSYM(sys_ni_syscall) + .long CSYM(sys_mmap2) + .long CSYM(sys_truncate64) + .long CSYM(sys_ftruncate64) + .long CSYM(sys_stat64) // 195 + .long CSYM(sys_lstat64) + .long CSYM(sys_fstat64) + .long CSYM(sys_fcntl64) + .long CSYM(sys_getdents64) + .long CSYM(sys_pivot_root) // 200 + .long CSYM(sys_gettid) + .long CSYM(sys_tkill) + .long CSYM(sys_ni_syscall) // sys_mincore + .long CSYM(sys_ni_syscall) // sys_madvise + + .space (NR_syscalls-205)*4 diff -Nru a/arch/v850/kernel/fpga85e2c.c b/arch/v850/kernel/fpga85e2c.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/fpga85e2c.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,167 @@ +/* + * arch/v850/kernel/fpga85e2c.h -- Machine-dependent defs for + * FPGA implementation of V850E2/NA85E2C + * + * Copyright (C) 2002 NEC Corporation + * Copyright (C) 2002 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "mach.h" + +extern void memcons_setup (void); + + +#define REG_DUMP_ADDR 0x220000 + + +extern struct irqaction reg_snap_action; /* fwd decl */ + + +void __init mach_early_init (void) +{ + int i; + const u32 *src; + register u32 *dst asm ("ep"); + extern int panic_timeout; + extern u32 _intv_end, _intv_load_start; + + /* Set bus sizes: CS0 32-bit, CS1 16-bit, CS7 8-bit, + everything else 32-bit. */ + BSC = 0x2AA6; + for (i = 2; i <= 6; i++) + CSDEV(i) = 0; /* 32 bit */ + + /* Ensure that the simulator halts on a panic, instead of going + into an infinite loop inside the panic function. */ + panic_timeout = -1; + + /* Move the interrupt vectors into their real location. Note that + any relocations there are relative to the real location, so we + don't have to fix anything up. We use a loop instead of calling + memcpy to keep this a leaf function (to avoid a function + prologue being generated). */ + dst = 0x10; /* &_intv_start + 0x10. */ + src = &_intv_load_start; + do { + u32 t0 = src[0], t1 = src[1], t2 = src[2], t3 = src[3]; + u32 t4 = src[4], t5 = src[5], t6 = src[6], t7 = src[7]; + dst[0] = t0; dst[1] = t1; dst[2] = t2; dst[3] = t3; + dst[4] = t4; dst[5] = t5; dst[6] = t6; dst[7] = t7; + dst += 8; + src += 8; + } while (dst < &_intv_end); +} + +void __init mach_setup (char **cmdline) +{ + printk (KERN_INFO "CPU: NEC V850E2 (NA85E2C FPGA implementation)\n"); + + memcons_setup (); + + /* Setup up NMI0 to copy the registers to a known memory location. + The FGPA board has a button that produces NMI0 when pressed, so + this allows us to push the button, and then look at memory to see + what's in the registers (there's no other way to easily do so). + We have to use `setup_irq' instead of `request_irq' because it's + still too early to do memory allocation. */ + setup_irq (IRQ_NMI (0), ®_snap_action); +} + +void mach_get_physical_ram (unsigned long *ram_start, unsigned long *ram_len) +{ + *ram_start = ERAM_ADDR; + *ram_len = ERAM_SIZE; +} + +void __init mach_sched_init (struct irqaction *timer_action) +{ + /* Setup up the timer interrupt. The FPGA peripheral control + registers _only_ work with single-bit writes (set1/clr1)! */ + __clear_bit (RPU_GTMC_CE_BIT, &RPU_GTMC); + __clear_bit (RPU_GTMC_CLK_BIT, &RPU_GTMC); + __set_bit (RPU_GTMC_CE_BIT, &RPU_GTMC); + + /* We use the first RPU interrupt, which occurs every 8.192ms. */ + setup_irq (IRQ_RPU (0), timer_action); +} + + +void mach_gettimeofday (struct timespec *tv) +{ + tv->tv_sec = 0; + tv->tv_nsec = 0; +} + +void machine_halt (void) __attribute__ ((noreturn)); +void machine_halt (void) +{ + for (;;) { + DWC(0) = 0x7777; + DWC(1) = 0x7777; + ASC = 0xffff; + FLGREG(0) = 1; /* Halt immediately. */ + asm ("di; halt; nop; nop; nop; nop; nop"); + } +} + +void machine_restart (char *__unused) +{ + machine_halt (); +} + +void machine_power_off (void) +{ + machine_halt (); +} + + +/* Interrupts */ + +struct nb85e_intc_irq_init irq_inits[] = { + { "IRQ", 0, NUM_MACH_IRQS, 1, 7 }, + { "RPU", IRQ_RPU(0), IRQ_RPU_NUM, 1, 6 }, + { 0 } +}; +#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1) + +struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS]; + +/* Initialize interrupts. */ +void __init mach_init_irqs (void) +{ + nb85e_intc_init_irq_types (irq_inits, hw_itypes); +} + + +/* An interrupt handler that copies the registers to a known memory location, + for debugging purposes. */ + +static void make_reg_snap (int irq, void *dummy, struct pt_regs *regs) +{ + (*(unsigned *)REG_DUMP_ADDR)++; + (*(struct pt_regs *)(REG_DUMP_ADDR + sizeof (unsigned))) = *regs; +} + +static int reg_snap_dev_id; +static struct irqaction reg_snap_action = { + make_reg_snap, 0, 0, "reg_snap", ®_snap_dev_id, 0 +}; diff -Nru a/arch/v850/kernel/gbus_int.c b/arch/v850/kernel/gbus_int.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/gbus_int.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,267 @@ +/* + * arch/v850/kernel/gbus_int.c -- Midas labs GBUS interrupt support + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include /* For some unfathomable reason, + request_irq/free_irq are declared here. */ + +#include +#include + + +/* The number of shared GINT interrupts. */ +#define NUM_GINTS 4 + +/* For each GINT interrupt, how many GBUS interrupts are using it. */ +static unsigned gint_num_active_irqs[NUM_GINTS] = { 0 }; + +/* A table of GINTn interrupts we actually use. */ +struct used_gint { + unsigned gint; + unsigned priority; +} used_gint[] = { + { 1, GBUS_INT_PRIORITY_HIGH }, + { 3, GBUS_INT_PRIORITY_LOW } +}; +#define NUM_USED_GINTS (sizeof used_gint / sizeof used_gint[0]) + +/* A table of which GINT is used by each GBUS interrupts (they are + assigned based on priority). */ +static unsigned char gbus_int_gint[IRQ_GBUS_INT_NUM]; + + +/* Interrupt enabling/disabling. */ + +/* Enable interrupt handling for interrupt IRQ. */ +void gbus_int_enable_irq (unsigned irq) +{ + unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ]; + GBUS_INT_ENABLE (GBUS_INT_IRQ_WORD(irq), gint) + |= GBUS_INT_IRQ_MASK (irq); +} + +/* Disable interrupt handling for interrupt IRQ. Note that any + interrupts received while disabled will be delivered once the + interrupt is enabled again, unless they are explicitly cleared using + `gbus_int_clear_pending_irq'. */ +void gbus_int_disable_irq (unsigned irq) +{ + unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ]; + GBUS_INT_ENABLE (GBUS_INT_IRQ_WORD(irq), gint) + &= ~GBUS_INT_IRQ_MASK (irq); +} + +/* Return true if interrupt handling for interrupt IRQ is enabled. */ +int gbus_int_irq_enabled (unsigned irq) +{ + unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ]; + return (GBUS_INT_ENABLE (GBUS_INT_IRQ_WORD(irq), gint) + & GBUS_INT_IRQ_MASK(irq)); +} + +/* Disable all GBUS irqs. */ +int gbus_int_disable_irqs () +{ + unsigned w, n; + for (w = 0; w < GBUS_INT_NUM_WORDS; w++) + for (n = 0; n < IRQ_GINT_NUM; n++) + GBUS_INT_ENABLE (w, n) = 0; +} + +/* Clear any pending interrupts for IRQ. */ +void gbus_int_clear_pending_irq (unsigned irq) +{ + GBUS_INT_CLEAR (GBUS_INT_IRQ_WORD(irq)) = GBUS_INT_IRQ_MASK (irq); +} + +/* Return true if interrupt IRQ is pending (but disabled). */ +int gbus_int_irq_pending (unsigned irq) +{ + return (GBUS_INT_STATUS (GBUS_INT_IRQ_WORD(irq)) + & GBUS_INT_IRQ_MASK(irq)); +} + + +/* Delegating interrupts. */ + +/* Handle a shared GINT interrupt by passing to the appropriate GBUS + interrupt handler. */ +static void gbus_int_handle_irq (int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned w; + unsigned gint = irq - IRQ_GINT (0); + + for (w = 0; w < GBUS_INT_NUM_WORDS; w++) { + unsigned status = GBUS_INT_STATUS (w); + unsigned enable = GBUS_INT_ENABLE (w, gint); + + /* Only pay attention to enabled interrupts. */ + status &= enable; + if (status) { + unsigned base_irq + = IRQ_GBUS_INT (w * GBUS_INT_BITS_PER_WORD); + irq = base_irq; + do { + /* There's an active interrupt in word + W, find out which one, and call its + handler. */ + + while (! (status & 0x1)) { + irq++; + status >>= 1; + } + status &= ~0x1; + + /* Recursively call handle_irq to handle it. */ + handle_irq (irq, regs); + } while (status); + } + } + + /* Toggle the `all enable' bit back and forth, which should cause + another edge transition if there are any other interrupts + still pending, and so result in another CPU interrupt. */ + GBUS_INT_ENABLE (0, gint) &= ~0x1; + GBUS_INT_ENABLE (0, gint) |= 0x1; +} + + +/* Initialize GBUS interrupt sources. */ + +static void irq_nop (unsigned irq) { } + +static unsigned gbus_int_startup_irq (unsigned irq) +{ + unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ]; + + if (gint_num_active_irqs[gint] == 0) { + /* First enable the CPU interrupt. */ + int rval = + request_irq (IRQ_GINT(gint), gbus_int_handle_irq, + SA_INTERRUPT, + "gbus_int_handler", + &gint_num_active_irqs[gint]); + if (rval != 0) + return rval; + } + + gint_num_active_irqs[gint]++; + + gbus_int_clear_pending_irq (irq); + gbus_int_enable_irq (irq); + + return 0; +} + +static void gbus_int_shutdown_irq (unsigned irq) +{ + unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ]; + + gbus_int_disable_irq (irq); + + if (--gint_num_active_irqs[gint] == 0) + /* Disable the CPU interrupt. */ + free_irq (IRQ_GINT(gint), &gint_num_active_irqs[gint]); +} + +/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array + INITS (which is terminated by an entry with the name field == 0). */ +void __init gbus_int_init_irq_types (struct gbus_int_irq_init *inits, + struct hw_interrupt_type *hw_irq_types) +{ + struct gbus_int_irq_init *init; + for (init = inits; init->name; init++) { + int i; + struct hw_interrupt_type *hwit = hw_irq_types++; + + hwit->typename = init->name; + + hwit->startup = gbus_int_startup_irq; + hwit->shutdown = gbus_int_shutdown_irq; + hwit->enable = gbus_int_enable_irq; + hwit->disable = gbus_int_disable_irq; + hwit->ack = irq_nop; + hwit->end = irq_nop; + + /* Initialize kernel IRQ infrastructure for this interrupt. */ + init_irq_handlers(init->base, init->num, init->interval, hwit); + + /* Set the interrupt priorities. */ + for (i = 0; i < init->num; i++) { + int j; + for (j = 0; j < NUM_USED_GINTS; j++) + if (used_gint[j].priority > init->priority) + break; + /* Wherever we stopped looking is one past the + GINT we want. */ + gbus_int_gint[init->base + i * init->interval + - GBUS_INT_BASE_IRQ] + = used_gint[j > 0 ? j - 1 : 0].gint; + } + } +} + + +/* Initialize IRQS. */ + +/* Chip interrupts (GINTn) shared among GBUS interrupts. */ +static struct hw_interrupt_type gint_hw_itypes[NUM_USED_GINTS]; + + +/* GBUS interrupts themselves. */ + +__init struct gbus_int_irq_init gbus_irq_inits[] = { + /* First set defaults. */ + { "GBUS_INT", IRQ_GBUS_INT(0), IRQ_GBUS_INT_NUM, 1, 6}, + { 0 } +}; +#define NUM_GBUS_IRQ_INITS \ + ((sizeof gbus_irq_inits / sizeof gbus_irq_inits[0]) - 1) + +static struct hw_interrupt_type gbus_hw_itypes[NUM_GBUS_IRQ_INITS]; + + +/* Initialize GBUS interrupts. */ +void __init gbus_int_init_irqs (void) +{ + int i; + + /* First initialize the shared gint interrupts. */ + for (i = 0; i < NUM_USED_GINTS; i++) { + unsigned gint = used_gint[i].gint; + struct nb85e_intc_irq_init gint_irq_init[2]; + + /* We initialize one GINT interrupt at a time. */ + gint_irq_init[0].name = "GINT"; + gint_irq_init[0].base = IRQ_GINT (gint); + gint_irq_init[0].num = 1; + gint_irq_init[0].interval = 1; + gint_irq_init[0].priority = used_gint[i].priority; + + gint_irq_init[1].name = 0; /* Terminate the vector. */ + + nb85e_intc_init_irq_types (gint_irq_init, gint_hw_itypes); + } + + /* Then the GBUS interrupts. */ + gbus_int_disable_irqs (); + gbus_int_init_irq_types (gbus_irq_inits, gbus_hw_itypes); + /* Turn on the `all enable' bits, which are ANDed with + individual interrupt enable bits; we only want to bother with + the latter. They are the first bit in the first word of each + interrupt-enable area. */ + for (i = 0; i < NUM_USED_GINTS; i++) + GBUS_INT_ENABLE (0, used_gint[i].gint) = 0x1; +} diff -Nru a/arch/v850/kernel/head.S b/arch/v850/kernel/head.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/head.S Mon Nov 4 14:31:03 2002 @@ -0,0 +1,121 @@ +/* + * arch/v850/kernel/head.S -- Lowest-level startup code + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include + + +/* Make a slightly more convenient alias for C_SYMBOL_NAME. */ +#define CSYM C_SYMBOL_NAME + + + .text + + // Define `mach_early_init' as a weak symbol + .global CSYM(mach_early_init) + .weak CSYM(mach_early_init) + +C_ENTRY(start): + // Make sure interrupts are turned off, just in case + di + +#ifdef CONFIG_RESET_GUARD + // See if we got here via an unexpected reset + ld.w RESET_GUARD, r19 // Check current value of reset guard + mov RESET_GUARD_ACTIVE, r20 + cmp r19, r20 + bne 1f // Guard was not active + + // If we get here, the reset guard was active. Load up some + // interesting values as arguments, and jump to the handler. + st.w r0, RESET_GUARD // Allow further resets to succeed + mov lp, r6 // Arg 0: return address + ld.b KM, r7 // Arg 1: kernel mode + mov sp, r9 // Arg 3: stack pointer + ld.w KSP, r19 // maybe switch to kernel stack + cmp r7, r0 // see if already in kernel mode + cmov z, r19, sp, sp // and switch to kernel stack if not + GET_CURRENT_TASK(r8) // Arg 2: task pointer + jr CSYM(unexpected_reset) + +1: st.w r20, RESET_GUARD // Turn on reset guard +#endif /* CONFIG_RESET_GUARD */ + + // Setup a temporary stack for doing pre-initialization function calls. + // + // We can't use the initial kernel stack, because (1) it may be + // located in memory we're not allowed to touch, and (2) since + // it's in the data segment, calling memcpy to initialize that + // area from ROM will overwrite memcpy's return address. + mov hilo(CSYM(_init_stack_end) - 4), sp + + // See if there's a platform-specific early-initialization routine + // defined; it's a weak symbol, so it will have an address of zero if + // there's not. + mov hilo(CSYM(mach_early_init)), r6 + cmp r6, r0 + bz 3f + + // There is one, so call it. If this function is written in C, it + // should be very careful -- the stack pointer is valid, but very + // little else is (e.g., bss is not zeroed yet, and initialized data + // hasn't been). + jarl 2f, lp // first figure out return address +2: add 3f - ., lp + jmp [r6] // do call +3: + +#ifdef CONFIG_ROM_KERNEL + // Copy the data area from ROM to RAM + mov hilo(CSYM(_rom_copy_dst_start)), r6 + mov hilo(CSYM(_rom_copy_src_start)), r7 + mov hilo(CSYM(_rom_copy_dst_end)), r8 + sub r6, r8 + jarl CSYM(memcpy), lp +#endif + + // Load the initial thread's stack, and current task pointer (in r16) + mov hilo(CSYM(init_thread_union)), r19 + movea THREAD_SIZE, r19, sp + ld.w TI_TASK[r19], CURRENT_TASK + +#ifdef CONFIG_TIME_BOOTUP + /* This stuff must come after mach_early_init, because interrupts may + not work until after its been called. */ + jarl CSYM(highres_timer_reset), lp + jarl CSYM(highres_timer_start), lp +#endif + + // Kernel stack pointer save location + st.w sp, KSP + + // Assert that we're in `kernel mode' + mov 1, r19 + st.w r19, KM + +#ifdef CONFIG_ZERO_BSS + // Zero bss area, since we can't rely upon any loader to do so + mov hilo(CSYM(_sbss)), r6 + mov r0, r7 + mov hilo(CSYM(_ebss)), r8 + sub r6, r8 + jarl CSYM(memset), lp +#endif + + // Start Linux kernel. + mov hilo(CSYM(machine_halt)), lp + jr CSYM(start_kernel) +END(start) diff -Nru a/arch/v850/kernel/highres_timer.c b/arch/v850/kernel/highres_timer.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/highres_timer.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,132 @@ +/* + * arch/v850/kernel/highres_timer.c -- High resolution timing routines + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include + +#define HIGHRES_TIMER_USEC_SHIFT 12 + +/* Pre-calculated constant used for converting ticks to real time + units. We initialize it to prevent it being put into BSS. */ +static u32 highres_timer_usec_prescale = 1; + +void highres_timer_slow_tick_irq (void) __attribute__ ((noreturn)); +void highres_timer_slow_tick_irq (void) +{ + /* This is an interrupt handler, so it must be very careful to + not to trash any registers. At this point, the stack-pointer + (r3) has been saved in the chip ram location ENTRY_SP by the + interrupt vector, so we can use it as a scratch register; we + must also restore it before returning. */ + asm ("ld.w %0[r0], sp;" + "add 1, sp;" + "st.w sp, %0[r0];" + "ld.w %1[r0], sp;" /* restore pre-irq stack-pointer */ + "reti" + :: + "i" (HIGHRES_TIMER_SLOW_TICKS_ADDR), + "i" (ENTRY_SP_ADDR) + : "memory"); +} + +void highres_timer_reset (void) +{ + NB85E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT) = 0; + HIGHRES_TIMER_SLOW_TICKS = 0; +} + +void highres_timer_start (void) +{ + u32 fast_tick_rate; + + /* Start hardware timer. */ + nb85e_timer_d_configure (HIGHRES_TIMER_TIMER_D_UNIT, + HIGHRES_TIMER_SLOW_TICK_RATE); + + fast_tick_rate = + (NB85E_TIMER_D_BASE_FREQ + >> NB85E_TIMER_D_DIVLOG2 (HIGHRES_TIMER_TIMER_D_UNIT)); + + /* The obvious way of calculating microseconds from fast ticks + is to do: + + usec = fast_ticks * 10^6 / fast_tick_rate + + However, divisions are much slower than multiplications, and + the above calculation can overflow, so we do this instead: + + usec = fast_ticks * (10^6 * 2^12 / fast_tick_rate) / 2^12 + + since we can pre-calculate (10^6 * (2^12 / fast_tick_rate)) + and use a shift for dividing by 2^12, this avoids division, + and is almost as accurate (it differs by about 2 microseconds + at the extreme value of the fast-tick counter's ranger). */ + highres_timer_usec_prescale = ((1000000 << HIGHRES_TIMER_USEC_SHIFT) + / fast_tick_rate); + + /* Enable the interrupt (which is hardwired to this use), and + give it the highest priority. */ + NB85E_INTC_IC (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT)) = 0; +} + +void highres_timer_stop (void) +{ + /* Stop the timer. */ + NB85E_TIMER_D_TMCD (HIGHRES_TIMER_TIMER_D_UNIT) = + NB85E_TIMER_D_TMCD_CAE; + /* Disable its interrupt, just in case. */ + nb85e_intc_disable_irq (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT)); +} + +inline void highres_timer_read_ticks (u32 *slow_ticks, u32 *fast_ticks) +{ + int flags; + u32 fast_ticks_1, fast_ticks_2, _slow_ticks; + + local_irq_save (flags); + fast_ticks_1 = NB85E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT); + _slow_ticks = HIGHRES_TIMER_SLOW_TICKS; + fast_ticks_2 = NB85E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT); + local_irq_restore (flags); + + if (fast_ticks_2 < fast_ticks_1) + _slow_ticks++; + + *slow_ticks = _slow_ticks; + *fast_ticks = fast_ticks_2; +} + +inline void highres_timer_ticks_to_timeval (u32 slow_ticks, u32 fast_ticks, + struct timeval *tv) +{ + unsigned long sec, sec_rem, usec; + + usec = ((fast_ticks * highres_timer_usec_prescale) + >> HIGHRES_TIMER_USEC_SHIFT); + + sec = slow_ticks / HIGHRES_TIMER_SLOW_TICK_RATE; + sec_rem = slow_ticks % HIGHRES_TIMER_SLOW_TICK_RATE; + + usec += sec_rem * (1000000 / HIGHRES_TIMER_SLOW_TICK_RATE); + + tv->tv_sec = sec; + tv->tv_usec = usec; +} + +void highres_timer_read (struct timeval *tv) +{ + u32 fast_ticks, slow_ticks; + highres_timer_read_ticks (&slow_ticks, &fast_ticks); + highres_timer_ticks_to_timeval (slow_ticks, fast_ticks, tv); +} diff -Nru a/arch/v850/kernel/init_task.c b/arch/v850/kernel/init_task.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/init_task.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,42 @@ +/* + * arch/v850/kernel/init_task.c -- Initial task/thread structures + * + * Copyright (C) 2002 NEC Corporation + * Copyright (C) 2002 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ + +#include +#include +#include +#include +#include + +#include +#include + +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS (init_signals); +struct mm_struct init_mm = INIT_MM (init_mm); + +/* + * Initial task structure. + * + * All other task structs will be allocated on slabs in fork.c + */ +struct task_struct init_task = INIT_TASK (init_task); + +/* + * Initial thread structure. + * + * We need to make sure that this is 8192-byte aligned due to the + * way process stacks are handled. This is done by having a special + * "init_task" linker map entry. + */ +union thread_union init_thread_union + __attribute__((__section__(".data.init_task"))) = + { INIT_THREAD_INFO(init_task) }; diff -Nru a/arch/v850/kernel/intv.S b/arch/v850/kernel/intv.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/intv.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,90 @@ +/* + * arch/v850/kernel/intv.S -- Interrupt vectors + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include + +#ifdef CONFIG_V850E_MA1_HIGHRES_TIMER +#include +#endif + +/* Jump to an interrupt/trap handler. These handlers (defined in entry.S) + expect the stack-pointer to be saved in ENTRY_SP, so we use sp to do an + indirect jump (which avoids problems when the handler is more than a signed + 22-bit offset away). */ +#define JUMP_TO_HANDLER(name, sp_save_loc) \ + st.w sp, sp_save_loc; \ + mov hilo(name), sp; \ + jmp [sp] + + + /* Reset vector. */ + .section .intv.reset, "ax" + .org 0x0 + mov hilo(C_SYMBOL_NAME(start)), r1; + jmp [r1] + + + /* Generic interrupt vectors. */ + .section .intv.common, "ax" + .balign 0x10 + JUMP_TO_HANDLER (nmi, NMI_ENTRY_SP) // NMI0 + .balign 0x10 + JUMP_TO_HANDLER (nmi, NMI_ENTRY_SP) // NMI1 + .balign 0x10 + JUMP_TO_HANDLER (nmi, NMI_ENTRY_SP) // NMI2 + + .balign 0x10 + JUMP_TO_HANDLER (trap, ENTRY_SP) // TRAP0n + .balign 0x10 + JUMP_TO_HANDLER (trap, ENTRY_SP) // TRAP1n + + .balign 0x10 + JUMP_TO_HANDLER (illegal_instruction, ENTRY_SP) // illegal insn trap + + .balign 0x10 + JUMP_TO_HANDLER (dbtrap, ENTRY_SP) // DBTRAP insn + + + /* Hardware interrupt vectors. */ + .section .intv.mach, "ax" + .org 0x0 + +#if defined (CONFIG_V850E_MA1_HIGHRES_TIMER) && defined (IRQ_INTCMD) + + /* Interrupts before the highres timer interrupt. */ + .rept IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT) + .balign 0x10 + JUMP_TO_HANDLER (irq, ENTRY_SP) + .endr + + /* The highres timer interrupt. */ + .balign 0x10 + JUMP_TO_HANDLER (C_SYMBOL_NAME (highres_timer_slow_tick_irq), ENTRY_SP) + + /* Interrupts after the highres timer interrupt. */ + .rept NUM_CPU_IRQS - IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT) - 1 + .balign 0x10 + JUMP_TO_HANDLER (irq, ENTRY_SP) + .endr + +#else /* No highres timer */ + + .rept NUM_CPU_IRQS + .balign 0x10 + JUMP_TO_HANDLER (irq, ENTRY_SP) + .endr + +#endif /* Highres timer */ diff -Nru a/arch/v850/kernel/irq.c b/arch/v850/kernel/irq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/irq.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,716 @@ +/* + * arch/v850/kernel/irq.c -- High-level interrupt handling + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * Copyright (C) 1994-2000 Ralf Baechle + * Copyright (C) 1992 Linus Torvalds + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * This file was was derived from the mips version, arch/mips/kernel/irq.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * Controller mappings for all interrupt sources: + */ +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = + { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; + +/* + * Special irq handlers. + */ + +void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } + +/* + * Generic no controller code + */ + +static void enable_none(unsigned int irq) { } +static unsigned int startup_none(unsigned int irq) { return 0; } +static void disable_none(unsigned int irq) { } +static void ack_none(unsigned int irq) +{ + /* + * 'what should we do if we get a hw irq event on an illegal vector'. + * each architecture has to answer this themselves, it doesnt deserve + * a generic callback i think. + */ + printk("received IRQ %d with unknown interrupt type\n", irq); +} + +/* startup is the same as "enable", shutdown is same as "disable" */ +#define shutdown_none disable_none +#define end_none enable_none + +struct hw_interrupt_type no_irq_type = { + "none", + startup_none, + shutdown_none, + enable_none, + disable_none, + ack_none, + end_none +}; + +volatile unsigned long irq_err_count, spurious_count; + +/* + * Generic, controller-independent functions: + */ + +int show_interrupts(struct seq_file *p, void *v) +{ + int i; + struct irqaction * action; + + seq_puts(p, " "); + for (i=0; i < 1 /*smp_num_cpus*/; i++) + seq_printf(p, "CPU%d ", i); + seq_putc(p, '\n'); + + for (i = 0 ; i < NR_IRQS ; i++) { + int j, count, num; + const char *type_name = irq_desc[i].handler->typename; + + action = irq_desc[i].action; + if (!action) + continue; + + count = 0; + num = -1; + for (j = 0; j < NR_IRQS; j++) + if (irq_desc[j].handler->typename == type_name) { + if (i == j) + num = count; + count++; + } + + seq_printf(p, "%3d: ",i); + seq_printf(p, "%10u ", kstat_irqs(i)); + if (count > 1) { + int prec = (num >= 100 ? 3 : num >= 10 ? 2 : 1); + seq_printf(p, " %*s%d", 14 - prec, type_name, num); + } else + seq_printf(p, " %14s", type_name); + seq_printf(p, " %s", action->name); + + for (action=action->next; action; action = action->next) + seq_printf(p, ", %s", action->name); + seq_putc(p, '\n'); + } + seq_printf(p, "ERR: %10lu\n", irq_err_count); + return 0; +} + +/* + * This should really return information about whether + * we should do bottom half handling etc. Right now we + * end up _always_ checking the bottom half, which is a + * waste of time and is not what some drivers would + * prefer. + */ +int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) +{ + int status = 1; /* Force the "do bottom halves" bit */ + + if (!(action->flags & SA_INTERRUPT)) + local_irq_enable(); + + do { + status |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + if (status & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + local_irq_disable(); + + return status; +} + +/* + * Generic enable/disable code: this just calls + * down into the PIC-specific version for the actual + * hardware disable after having gotten the irq + * controller lock. + */ + +/** + * disable_irq_nosync - disable an irq without waiting + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables of an interrupt + * stack. Unlike disable_irq(), this function does not ensure existing + * instances of the IRQ handler have completed before returning. + * + * This function may be called from IRQ context. + */ + +void inline disable_irq_nosync(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + if (!desc->depth++) { + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +/** + * disable_irq - disable an irq and wait for completion + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables of an interrupt + * stack. That is for two disables you need two enables. This + * function waits for any pending IRQ handlers for this interrupt + * to complete before returning. If you use this function while + * holding a resource the IRQ handler may need you will deadlock. + * + * This function may be called - with care - from IRQ context. + */ + +void disable_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + synchronize_irq(irq); +} + +/** + * enable_irq - enable interrupt handling on an irq + * @irq: Interrupt to enable + * + * Re-enables the processing of interrupts on this IRQ line + * providing no disable_irq calls are now in effect. + * + * This function may be called from IRQ context. + */ + +void enable_irq(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + switch (desc->depth) { + case 1: { + unsigned int status = desc->status & ~IRQ_DISABLED; + desc->status = status; + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + desc->status = status | IRQ_REPLAY; + hw_resend_irq(desc->handler,irq); + } + desc->handler->enable(irq); + /* fall-through */ + } + default: + desc->depth--; + break; + case 0: + printk("enable_irq(%u) unbalanced from %p\n", irq, + __builtin_return_address(0)); + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +/* Handle interrupt IRQ. REGS are the registers at the time of ther + interrupt. */ +unsigned int handle_irq (int irq, struct pt_regs *regs) +{ + /* + * We ack quickly, we don't want the irq controller + * thinking we're snobs just because some other CPU has + * disabled global interrupts (we have already done the + * INT_ACK cycles, it's too late to try to pretend to the + * controller that we aren't taking the interrupt). + * + * 0 return value means that this irq is already being + * handled by some other CPU. (or is disabled) + */ + int cpu = smp_processor_id(); + irq_desc_t *desc = irq_desc + irq; + struct irqaction * action; + unsigned int status; + + irq_enter(); + kstat.irqs[cpu][irq]++; + spin_lock(&desc->lock); + desc->handler->ack(irq); + /* + REPLAY is when Linux resends an IRQ that was dropped earlier + WAITING is used by probe to mark irqs that are being tested + */ + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); + status |= IRQ_PENDING; /* we _want_ to handle it */ + + /* + * If the IRQ is disabled for whatever reason, we cannot + * use the action we have. + */ + action = NULL; + if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) { + action = desc->action; + status &= ~IRQ_PENDING; /* we commit to handling */ + status |= IRQ_INPROGRESS; /* we are handling it */ + } + desc->status = status; + + /* + * If there is no IRQ handler or it was disabled, exit early. + Since we set PENDING, if another processor is handling + a different instance of this same irq, the other processor + will take care of it. + */ + if (unlikely(!action)) + goto out; + + /* + * Edge triggered interrupts need to remember + * pending events. + * This applies to any hw interrupts that allow a second + * instance of the same irq to arrive while we are in handle_irq + * or in the handler. But the code here only handles the _second_ + * instance of the irq, not the third or fourth. So it is mostly + * useful for irq hardware that does not mask cleanly in an + * SMP environment. + */ + for (;;) { + spin_unlock(&desc->lock); + handle_IRQ_event(irq, regs, action); + spin_lock(&desc->lock); + + if (likely(!(desc->status & IRQ_PENDING))) + break; + desc->status &= ~IRQ_PENDING; + } + desc->status &= ~IRQ_INPROGRESS; + +out: + /* + * The ->end() handler has to deal with interrupts which got + * disabled while the handler was running. + */ + desc->handler->end(irq); + spin_unlock(&desc->lock); + + irq_exit(); + + return 1; +} + +/** + * request_irq - allocate an interrupt line + * @irq: Interrupt line to allocate + * @handler: Function to be called when the IRQ occurs + * @irqflags: Interrupt type flags + * @devname: An ascii name for the claiming device + * @dev_id: A cookie passed back to the handler function + * + * This call allocates interrupt resources and enables the + * interrupt line and IRQ handling. From the point this + * call is made your handler function may be invoked. Since + * your handler function must clear any interrupt the board + * raises, you must take care both to initialise your hardware + * and to set up the interrupt handler in the right order. + * + * Dev_id must be globally unique. Normally the address of the + * device data structure is used as the cookie. Since the handler + * receives this value it makes sense to use it. + * + * If your interrupt is shared you must pass a non NULL dev_id + * as this is required when freeing the interrupt. + * + * Flags: + * + * SA_SHIRQ Interrupt is shared + * + * SA_INTERRUPT Disable local interrupts while processing + * + * SA_SAMPLE_RANDOM The interrupt can be used for entropy + * + */ + +int request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) +{ + int retval; + struct irqaction * action; + +#if 1 + /* + * Sanity-check: shared interrupts should REALLY pass in + * a real dev-ID, otherwise we'll have trouble later trying + * to figure out which interrupt is which (messes up the + * interrupt freeing logic etc). + */ + if (irqflags & SA_SHIRQ) { + if (!dev_id) + printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]); + } +#endif + + if (irq >= NR_IRQS) + return -EINVAL; + if (!handler) + return -EINVAL; + + action = (struct irqaction *) + kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + action->mask = 0; + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + retval = setup_irq(irq, action); + if (retval) + kfree(action); + return retval; +} + +/** + * free_irq - free an interrupt + * @irq: Interrupt line to free + * @dev_id: Device identity to free + * + * Remove an interrupt handler. The handler is removed and if the + * interrupt line is no longer in use by any driver it is disabled. + * On a shared IRQ the caller must ensure the interrupt is disabled + * on the card it drives before calling this function. The function + * does not return until any executing interrupts for this IRQ + * have completed. + * + * This function may be called from interrupt context. + * + * Bugs: Attempting to free an irq in a handler for the same irq hangs + * the machine. + */ + +void free_irq(unsigned int irq, void *dev_id) +{ + irq_desc_t *desc; + struct irqaction **p; + unsigned long flags; + + if (irq >= NR_IRQS) + return; + + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + for (;;) { + struct irqaction * action = *p; + if (action) { + struct irqaction **pp = p; + p = &action->next; + if (action->dev_id != dev_id) + continue; + + /* Found it - now remove it from the list of entries */ + *pp = action->next; + if (!desc->action) { + desc->status |= IRQ_DISABLED; + desc->handler->shutdown(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + + synchronize_irq(irq); + kfree(action); + return; + } + printk("Trying to free free IRQ%d\n",irq); + spin_unlock_irqrestore(&desc->lock,flags); + return; + } +} + +/* + * IRQ autodetection code.. + * + * This depends on the fact that any interrupt that + * comes in on to an unassigned handler will get stuck + * with "IRQ_WAITING" cleared and the interrupt + * disabled. + */ + +static DECLARE_MUTEX(probe_sem); + +/** + * probe_irq_on - begin an interrupt autodetect + * + * Commence probing for an interrupt. The interrupts are scanned + * and a mask of potential interrupt lines is returned. + * + */ + +unsigned long probe_irq_on(void) +{ + unsigned int i; + irq_desc_t *desc; + unsigned long val; + unsigned long delay; + + down(&probe_sem); + /* + * something may have generated an irq long ago and we want to + * flush such a longstanding irq before considering it as spurious. + */ + for (i = NR_IRQS-1; i > 0; i--) { + desc = irq_desc + i; + + spin_lock_irq(&desc->lock); + if (!irq_desc[i].action) + irq_desc[i].handler->startup(i); + spin_unlock_irq(&desc->lock); + } + + /* Wait for longstanding interrupts to trigger. */ + for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) + /* about 20ms delay */ barrier(); + + /* + * enable any unassigned irqs + * (we must startup again here because if a longstanding irq + * happened in the previous stage, it may have masked itself) + */ + for (i = NR_IRQS-1; i > 0; i--) { + desc = irq_desc + i; + + spin_lock_irq(&desc->lock); + if (!desc->action) { + desc->status |= IRQ_AUTODETECT | IRQ_WAITING; + if (desc->handler->startup(i)) + desc->status |= IRQ_PENDING; + } + spin_unlock_irq(&desc->lock); + } + + /* + * Wait for spurious interrupts to trigger + */ + for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) + /* about 100ms delay */ barrier(); + + /* + * Now filter out any obviously spurious interrupts + */ + val = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + /* It triggered already - consider it spurious. */ + if (!(status & IRQ_WAITING)) { + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } else + if (i < 32) + val |= 1 << i; + } + spin_unlock_irq(&desc->lock); + } + + return val; +} + +/* + * Return a mask of triggered interrupts (this + * can handle only legacy ISA interrupts). + */ + +/** + * probe_irq_mask - scan a bitmap of interrupt lines + * @val: mask of interrupts to consider + * + * Scan the ISA bus interrupt lines and return a bitmap of + * active interrupts. The interrupt probe logic state is then + * returned to its previous value. + * + * Note: we need to scan all the irq's even though we will + * only return ISA irq numbers - just so that we reset them + * all to a known state. + */ +unsigned int probe_irq_mask(unsigned long val) +{ + int i; + unsigned int mask; + + mask = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + if (i < 16 && !(status & IRQ_WAITING)) + mask |= 1 << i; + + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } + spin_unlock_irq(&desc->lock); + } + up(&probe_sem); + + return mask & val; +} + +/* + * Return the one interrupt that triggered (this can + * handle any interrupt source). + */ + +/** + * probe_irq_off - end an interrupt autodetect + * @val: mask of potential interrupts (unused) + * + * Scans the unused interrupt lines and returns the line which + * appears to have triggered the interrupt. If no interrupt was + * found then zero is returned. If more than one interrupt is + * found then minus the first candidate is returned to indicate + * their is doubt. + * + * The interrupt probe logic state is returned to its previous + * value. + * + * BUGS: When used in a module (which arguably shouldnt happen) + * nothing prevents two IRQ probe callers from overlapping. The + * results of this are non-optimal. + */ + +int probe_irq_off(unsigned long val) +{ + int i, irq_found, nr_irqs; + + nr_irqs = 0; + irq_found = 0; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + if (!(status & IRQ_WAITING)) { + if (!nr_irqs) + irq_found = i; + nr_irqs++; + } + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } + spin_unlock_irq(&desc->lock); + } + up(&probe_sem); + + if (nr_irqs > 1) + irq_found = -irq_found; + return irq_found; +} + +/* this was setup_x86_irq but it seems pretty generic */ +int setup_irq(unsigned int irq, struct irqaction * new) +{ + int shared = 0; + unsigned long flags; + struct irqaction *old, **p; + irq_desc_t *desc = irq_desc + irq; + + /* + * Some drivers like serial.c use request_irq() heavily, + * so we have to be careful not to interfere with a + * running system. + */ + if (new->flags & SA_SAMPLE_RANDOM) { + /* + * This function might sleep, we want to call it first, + * outside of the atomic block. + * Yes, this might clear the entropy pool if the wrong + * driver is attempted to be loaded, without actually + * installing a new handler, but is this really a problem, + * only the sysadmin is able to do this. + */ + rand_initialize_irq(irq); + } + + /* + * The following block of code has to be executed atomically + */ + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) { + spin_unlock_irqrestore(&desc->lock,flags); + return -EBUSY; + } + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + *p = new; + + if (!shared) { + desc->depth = 0; + desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS); + desc->handler->startup(irq); + } + spin_unlock_irqrestore(&desc->lock,flags); + + /* register_irq_proc(irq); */ + return 0; +} + +/* Initialize irq handling for IRQs. + BASE_IRQ, BASE_IRQ+INTERVAL, ..., BASE_IRQ+NUM*INTERVAL + to IRQ_TYPE. An IRQ_TYPE of 0 means to use a generic interrupt type. */ +void __init +init_irq_handlers (int base_irq, int num, int interval, + struct hw_interrupt_type *irq_type) +{ + while (num-- > 0) { + irq_desc[base_irq].status = IRQ_DISABLED; + irq_desc[base_irq].action = NULL; + irq_desc[base_irq].depth = 1; + irq_desc[base_irq].handler = irq_type; + base_irq += interval; + } +} diff -Nru a/arch/v850/kernel/ma.c b/arch/v850/kernel/ma.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/ma.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,70 @@ +/* + * arch/v850/kernel/ma.c -- V850E/MA series of cpu chips + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "mach.h" + +void __init mach_sched_init (struct irqaction *timer_action) +{ + /* Start hardware timer. */ + nb85e_timer_d_configure (0, HZ); + /* Install timer interrupt handler. */ + setup_irq (IRQ_INTCMD(0), timer_action); +} + +static struct nb85e_intc_irq_init irq_inits[] = { + { "IRQ", 0, NUM_MACH_IRQS, 1, 7 }, + { "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM, 1, 5 }, + { "DMA", IRQ_INTDMA(0), IRQ_INTDMA_NUM, 1, 2 }, + { "CSI", IRQ_INTCSI(0), IRQ_INTCSI_NUM, 4, 4 }, + { "SER", IRQ_INTSER(0), IRQ_INTSER_NUM, 4, 3 }, + { "SR", IRQ_INTSR(0), IRQ_INTSR_NUM, 4, 4 }, + { "ST", IRQ_INTST(0), IRQ_INTST_NUM, 4, 5 }, + { 0 } +}; +#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1) + +static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS]; + +/* Initialize MA chip interrupts. */ +void __init ma_init_irqs (void) +{ + nb85e_intc_init_irq_types (irq_inits, hw_itypes); +} + +/* Called before configuring an on-chip UART. */ +void ma_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud) +{ + /* We only know about the first two UART channels (though + specific chips may have more). */ + if (chan < 2) { + unsigned bits = 0x3 << (chan * 3); + /* Specify that the relevent pins on the chip should do + serial I/O, not direct I/O. */ + MA_PORT4_PMC |= bits; + /* Specify that we're using the UART, not the CSI device. */ + MA_PORT4_PFC |= bits; + } +} diff -Nru a/arch/v850/kernel/mach.c b/arch/v850/kernel/mach.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/mach.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,17 @@ +/* + * arch/v850/kernel/mach.c -- Defaults for some things defined by "mach.h" + * + * Copyright (C) 2001 NEC Corporation + * Copyright (C) 2001 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include "mach.h" + +/* Called with each timer tick, if non-zero. */ +void (*mach_tick)(void) = 0; diff -Nru a/arch/v850/kernel/mach.h b/arch/v850/kernel/mach.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/mach.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,56 @@ +/* + * arch/v850/kernel/mach.h -- Machine-dependent functions used by v850 port + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_MACH_H__ +#define __V850_MACH_H__ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +void mach_setup (char **cmdline); +void mach_gettimeofday (struct timespec *tv); +void mach_sched_init (struct irqaction *timer_action); +void mach_get_physical_ram (unsigned long *ram_start, unsigned long *ram_len); +void mach_init_irqs (void); + +/* If defined, is called very early in the kernel initialization. The + stack pointer is valid, but very little has been initialized (e.g., + bss is not zeroed yet) when this is called, so care must taken. */ +void mach_early_init (void); + +/* If defined, called after the bootmem allocator has been initialized, + to allow the platform-dependent code to reserve any areas of RAM that + the kernel shouldn't touch. */ +void mach_reserve_bootmem (void) __attribute__ ((__weak__)); + +/* Called with each timer tick, if non-zero. */ +extern void (*mach_tick) (void); + +/* The following establishes aliases for various mach_ functions to the + name by which the rest of the kernal calls them. These statements + should only have an effect in the file that defines the actual functions. */ +#define MACH_ALIAS(to, from) \ + asm (".global " macrology_stringify (C_SYMBOL_NAME (to)) ";" \ + macrology_stringify (C_SYMBOL_NAME (to)) \ + " = " macrology_stringify (C_SYMBOL_NAME (from))) +/* e.g.: MACH_ALIAS (kernel_name, arch_spec_name); */ + +#endif /* __V850_MACH_H__ */ diff -Nru a/arch/v850/kernel/memcons.c b/arch/v850/kernel/memcons.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/memcons.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,134 @@ +/* + * arch/v850/kernel/memcons.c -- Console I/O to a memory buffer + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include + +/* If this device is enabled, the linker map should define start and + end points for its buffer. */ +extern char memcons_output[], memcons_output_end; + +/* Current offset into the buffer. */ +static unsigned long memcons_offs = 0; + +/* Spinlock protecting memcons_offs. */ +static spinlock_t memcons_lock = SPIN_LOCK_UNLOCKED; + + +static size_t write (const char *buf, size_t len) +{ + int flags; + char *point; + + spin_lock_irqsave (memcons_lock, flags); + + point = memcons_output + memcons_offs; + if (point + len >= &memcons_output_end) { + len = &memcons_output_end - point; + memcons_offs = 0; + } else + memcons_offs += len; + + spin_unlock_irqrestore (memcons_lock, flags); + + memcpy (point, buf, len); + + return len; +} + + +/* Low-level console. */ + +static void memcons_write (struct console *co, const char *buf, unsigned len) +{ + while (len > 0) + len -= write (buf, len); +} + +static kdev_t memcons_device (struct console *co) +{ + return MKDEV (TTY_MAJOR, 64 + co->index); +} + +static struct console memcons = +{ + name: "memcons", + write: memcons_write, + device: memcons_device, + flags: CON_PRINTBUFFER, + index: -1, +}; + +void memcons_setup (void) +{ + register_console (&memcons); + printk (KERN_INFO "Console: static memory buffer (memcons)\n"); +} + +/* Higher level TTY interface. */ + +static struct tty_struct *tty_table[1] = { 0 }; +static struct termios *tty_termios[1] = { 0 }; +static struct termios *tty_termios_locked[1] = { 0 }; +static struct tty_driver tty_driver = { 0 }; +static int tty_ref_count = 0; + +int memcons_tty_open (struct tty_struct *tty, struct file *filp) +{ + return 0; +} + +int memcons_tty_write (struct tty_struct *tty, int from_user, + const unsigned char *buf, int len) +{ + return write (buf, len); +} + +int memcons_tty_write_room (struct tty_struct *tty) +{ + return &memcons_output_end - (memcons_output + memcons_offs); +} + +int memcons_tty_chars_in_buffer (struct tty_struct *tty) +{ + /* We have no buffer. */ + return 0; +} + +int __init memcons_tty_init (void) +{ + tty_driver.name = "memcons"; + tty_driver.major = TTY_MAJOR; + tty_driver.minor_start = 64; + tty_driver.num = 1; + tty_driver.type = TTY_DRIVER_TYPE_SYSCONS; + + tty_driver.refcount = &tty_ref_count; + + tty_driver.table = tty_table; + tty_driver.termios = tty_termios; + tty_driver.termios_locked = tty_termios_locked; + + tty_driver.init_termios = tty_std_termios; + + tty_driver.open = memcons_tty_open; + tty_driver.write = memcons_tty_write; + tty_driver.write_room = memcons_tty_write_room; + tty_driver.chars_in_buffer = memcons_tty_chars_in_buffer; + + tty_register_driver (&tty_driver); +} +__initcall (memcons_tty_init); diff -Nru a/arch/v850/kernel/nb85e_intc.c b/arch/v850/kernel/nb85e_intc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/nb85e_intc.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,68 @@ +/* + * arch/v850/kernel/nb85e_intc.c -- NB85E cpu core interrupt controller (INTC) + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include + +#include + +static void irq_nop (unsigned irq) { } + +static unsigned nb85e_intc_irq_startup (unsigned irq) +{ + nb85e_intc_clear_pending_irq (irq); + nb85e_intc_enable_irq (irq); + return 0; +} + +/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array + INITS (which is terminated by an entry with the name field == 0). */ +void __init nb85e_intc_init_irq_types (struct nb85e_intc_irq_init *inits, + struct hw_interrupt_type *hw_irq_types) +{ + struct nb85e_intc_irq_init *init; + for (init = inits; init->name; init++) { + int i; + struct hw_interrupt_type *hwit = hw_irq_types++; + + hwit->typename = init->name; + + hwit->startup = nb85e_intc_irq_startup; + hwit->shutdown = nb85e_intc_disable_irq; + hwit->enable = nb85e_intc_enable_irq; + hwit->disable = nb85e_intc_disable_irq; + hwit->ack = irq_nop; + hwit->end = irq_nop; + + /* Initialize kernel IRQ infrastructure for this interrupt. */ + init_irq_handlers(init->base, init->num, init->interval, hwit); + + /* Set the interrupt priorities. */ + for (i = 0; i < init->num; i++) { + unsigned irq = init->base + i * init->interval; + + /* If the interrupt is currently enabled (all + interrupts are initially disabled), then + assume whoever enabled it has set things up + properly, and avoid messing with it. */ + if (! nb85e_intc_irq_enabled (irq)) + /* This write also (1) disables the + interrupt, and (2) clears any pending + interrupts. */ + NB85E_INTC_IC (irq) + = (NB85E_INTC_IC_PR (init->priority) + | NB85E_INTC_IC_MK); + } + } +} diff -Nru a/arch/v850/kernel/nb85e_timer_d.c b/arch/v850/kernel/nb85e_timer_d.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/nb85e_timer_d.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,54 @@ +/* + * include/asm-v850/nb85e_timer_d.c -- `Timer D' component often used + * with the NB85E cpu core + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include + +#include +#include + +/* Start interval timer TIMER (0-3). The timer will issue the + corresponding INTCMD interrupt RATE times per second. + This function does not enable the interrupt. */ +void nb85e_timer_d_configure (unsigned timer, unsigned rate) +{ + unsigned divlog2, count; + + /* Calculate params for timer. */ + if (! calc_counter_params ( + NB85E_TIMER_D_BASE_FREQ, rate, + NB85E_TIMER_D_TMCD_CS_MIN, NB85E_TIMER_D_TMCD_CS_MAX, 16, + &divlog2, &count)) + printk (KERN_WARNING + "Cannot find interval timer %d setting suitable" + " for rate of %dHz.\n" + "Using rate of %dHz instead.\n", + timer, rate, + (NB85E_TIMER_D_BASE_FREQ >> divlog2) >> 16); + + /* Do the actual hardware timer initialization: */ + + /* Enable timer. */ + NB85E_TIMER_D_TMCD(timer) = NB85E_TIMER_D_TMCD_CAE; + /* Set clock divider. */ + NB85E_TIMER_D_TMCD(timer) + = NB85E_TIMER_D_TMCD_CAE + | NB85E_TIMER_D_TMCD_CS(divlog2); + /* Set timer compare register. */ + NB85E_TIMER_D_CMD(timer) = count; + /* Start counting. */ + NB85E_TIMER_D_TMCD(timer) + = NB85E_TIMER_D_TMCD_CAE + | NB85E_TIMER_D_TMCD_CS(divlog2) + | NB85E_TIMER_D_TMCD_CE; +} diff -Nru a/arch/v850/kernel/nb85e_utils.c b/arch/v850/kernel/nb85e_utils.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/nb85e_utils.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,65 @@ +/* + * include/asm-v850/nb85e_utils.h -- Utility functions associated with + * the NB85E cpu core + * + * Copyright (C) 2001 NEC Corporation + * Copyright (C) 2001 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +/* Note: these functions are often associated with the N85E cpu core, + but not always, which is why they're not in `nb85e.c'. */ + +#include + +/* Calculate counter clock-divider and count values to attain the + desired frequency RATE from the base frequency BASE_FREQ. The + counter is expected to have a clock-divider, which can divide the + system cpu clock by a power of two value from MIN_DIVLOG2 to + MAX_DIV_LOG2, and a word-size of COUNTER_SIZE bits (the counter + counts up and resets whenever it's equal to the compare register, + generating an interrupt or whatever when it does so). The returned + values are: *DIVLOG2 -- log2 of the desired clock divider and *COUNT + -- the counter compare value to use. Returns true if it was possible + to find a reasonable value, otherwise false (and the other return + values will be set to be as good as possible). */ +int calc_counter_params (unsigned long base_freq, + unsigned long rate, + unsigned min_divlog2, unsigned max_divlog2, + unsigned counter_size, + unsigned *divlog2, unsigned *count) +{ + unsigned _divlog2; + int ok = 0; + + /* Find the lowest clock divider setting that can represent RATE. */ + for (_divlog2 = min_divlog2; _divlog2 <= max_divlog2; _divlog2++) { + /* Minimum interrupt rate possible using this divider. */ + int min_int_rate + = (base_freq >> _divlog2) >> counter_size; + + if (min_int_rate <= rate) { + /* This setting is the highest resolution + setting that's slow enough enough to attain + RATE interrupts per second, so use it. */ + ok = 1; + break; + } + } + + if (_divlog2 > max_divlog2) + /* Can't find correct setting. */ + _divlog2 = max_divlog2; + + if (divlog2) + *divlog2 = _divlog2; + if (count) + *count = ((base_freq >> _divlog2) + rate/2) / rate; + + return ok; +} diff -Nru a/arch/v850/kernel/process.c b/arch/v850/kernel/process.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/process.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,282 @@ +/* + * arch/v850/kernel/process.c -- Arch-dependent process handling + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +extern void ret_from_fork (void); + + +/* The idle loop. */ +void default_idle (void) +{ + while (1) { + while (! need_resched ()) + asm ("halt; nop; nop; nop; nop; nop" ::: "cc"); + schedule (); + } +} + +void (*idle)(void) = default_idle; + +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle (void) +{ + /* endless idle loop with no priority at all */ + (*idle) (); +} + +struct spec_reg_name { + const char *name; + int gpr; +}; + +struct spec_reg_name spec_reg_names[] = { + { "sp", GPR_SP }, + { "gp", GPR_GP }, + { "tp", GPR_TP }, + { "ep", GPR_EP }, + { "lp", GPR_LP }, + { 0, 0 } +}; + +void show_regs (struct pt_regs *regs) +{ + int gpr_base, gpr_offs; + + printk (" pc 0x%08lx psw 0x%08lx kernel_mode %d\n", + regs->pc, regs->psw, regs->kernel_mode); + printk (" ctpc 0x%08lx ctpsw 0x%08lx ctbp 0x%08lx\n", + regs->ctpc, regs->ctpsw, regs->ctbp); + + for (gpr_base = 0; gpr_base < NUM_GPRS; gpr_base += 4) { + for (gpr_offs = 0; gpr_offs < 4; gpr_offs++) { + int gpr = gpr_base + gpr_offs; + long val = regs->gpr[gpr]; + struct spec_reg_name *srn; + + for (srn = spec_reg_names; srn->name; srn++) + if (srn->gpr == gpr) + break; + + if (srn->name) + printk ("%7s 0x%08lx", srn->name, val); + else + printk (" r%02d 0x%08lx", gpr, val); + } + + printk ("\n"); + } +} + +/* + * This is the mechanism for creating a new kernel thread. + * + * NOTE! Only a kernel-only process (ie the swapper or direct descendants who + * haven't done an "execve()") should use this: it will work within a system + * call from a "real" process, but the process memory space will not be free'd + * until both the parent and the child have exited. + */ +int kernel_thread (int (*fn)(void *), void *arg, unsigned long flags) +{ + register mm_segment_t fs = get_fs (); + register unsigned long syscall asm (SYSCALL_NUM); + register unsigned long arg0 asm (SYSCALL_ARG0); + register unsigned long ret asm (SYSCALL_RET); + + set_fs (KERNEL_DS); + + /* Clone this thread. */ + arg0 = flags | CLONE_VM; + syscall = __NR_clone; + asm volatile ("trap " SYSCALL_SHORT_TRAP + : "=r" (ret), "=r" (syscall) + : "1" (syscall), "r" (arg0) + : SYSCALL_SHORT_CLOBBERS); + + if (ret == 0) { + /* In child thread, call FN and exit. */ + arg0 = (*fn) (arg); + syscall = __NR_exit; + asm volatile ("trap " SYSCALL_SHORT_TRAP + : "=r" (ret), "=r" (syscall) + : "1" (syscall), "r" (arg0) + : SYSCALL_SHORT_CLOBBERS); + } + + /* In parent. */ + set_fs (fs); + + return ret; +} + +void flush_thread (void) +{ + set_fs (USER_DS); +} + +int copy_thread (int nr, unsigned long clone_flags, + unsigned long stack_start, unsigned long stack_size, + struct task_struct *p, struct pt_regs *regs) +{ + /* Start pushing stuff from the top of the child's kernel stack. */ + unsigned long ksp = (unsigned long)p->thread_info + THREAD_SIZE; + /* We push two `state save' stack fames (see entry.S) on the new + kernel stack: + 1) The innermost one is what switch_thread would have + pushed, and is used when we context switch to the child + thread for the first time. It's set up to return to + ret_from_fork in entry.S. + 2) The outermost one (nearest the top) is what a syscall + trap would have pushed, and is set up to return to the + same location as the parent thread, but with a return + value of 0. */ + struct pt_regs *child_switch_regs, *child_trap_regs; + + /* Trap frame. */ + ksp -= STATE_SAVE_SIZE; + child_trap_regs = (struct pt_regs *)(ksp + STATE_SAVE_PT_OFFSET); + /* Switch frame. */ + ksp -= STATE_SAVE_SIZE; + child_switch_regs = (struct pt_regs *)(ksp + STATE_SAVE_PT_OFFSET); + + /* First copy parent's register state to child. */ + *child_switch_regs = *regs; + *child_trap_regs = *regs; + + /* switch_thread returns to the restored value of the lp + register (r31), so we make that the place where we want to + jump when the child thread begins running. */ + child_switch_regs->gpr[GPR_LP] = (v850_reg_t)ret_from_fork; + + /* Thread state for the child (everything else is on the stack). */ + p->thread.ksp = ksp; + + return 0; +} + +/* + * fill in the user structure for a core dump.. + */ +void dump_thread (struct pt_regs *regs, struct user *dump) +{ +#if 0 /* Later. XXX */ + dump->magic = CMAGIC; + dump->start_code = 0; + dump->start_stack = regs->gpr[GPR_SP]; + dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; + dump->u_dsize = ((unsigned long) (current->mm->brk + + (PAGE_SIZE-1))) >> PAGE_SHIFT; + dump->u_dsize -= dump->u_tsize; + dump->u_ssize = 0; + + if (dump->start_stack < TASK_SIZE) + dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; + + dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump); + dump->regs = *regs; + dump->u_fpvalid = 0; +#endif +} + +/* + * sys_execve() executes a new program. + */ +int sys_execve (char *name, char **argv, char **envp, struct pt_regs *regs) +{ + char *filename = getname (name); + int error = PTR_ERR (filename); + + if (! IS_ERR (filename)) { + error = do_execve (filename, argv, envp, regs); + putname (filename); + } + + return error; +} + +/* This is the common part of the various fork-like system calls (which + are in entry.S). */ +int fork_common (int flags, unsigned long new_sp, struct pt_regs *regs) +{ + struct task_struct *p = do_fork (flags, new_sp, regs, 0, 0); + return IS_ERR (p) ? PTR_ERR (p) : p->pid; +} + + +/* + * These bracket the sleeping functions.. + */ +extern void scheduling_functions_start_here (void); +extern void scheduling_functions_end_here (void); +#define first_sched ((unsigned long) scheduling_functions_start_here) +#define last_sched ((unsigned long) scheduling_functions_end_here) + +unsigned long get_wchan (struct task_struct *p) +{ +#if 0 /* Barf. Figure out the stack-layout later. XXX */ + unsigned long fp, pc; + int count = 0; + + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + pc = thread_saved_pc (&p->thread); + + /* This quite disgusting function walks up the stack, following + saved return address, until it something that's out of bounds + (as defined by `first_sched' and `last_sched'). It then + returns the last PC that was in-bounds. */ + do { + if (fp < stack_page + sizeof (struct task_struct) || + fp >= 8184+stack_page) + return 0; + pc = ((unsigned long *)fp)[1]; + /* FIXME: This depends on the order of these functions. */ + if (pc < first_sched || pc >= last_sched) + return pc; + fp = *(unsigned long *) fp; + } while (count++ < 16); +#endif + + return 0; +} + +void show_trace_task (struct task_struct *t) +{ + /* blarg XXX */ + printk ("show_trace_task: KSP = 0x%lx, USP = 0x%lx, UPC = 0x%lx\n", + t->thread.ksp, KSTK_ESP (t), KSTK_EIP (t)); +} diff -Nru a/arch/v850/kernel/procfs.c b/arch/v850/kernel/procfs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/procfs.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,67 @@ +/* + * arch/v850/kernel/procfs.c -- Introspection functions for /proc filesystem + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include "mach.h" + +static int cpuinfo_print (struct seq_file *m, void *v) +{ + extern unsigned long loops_per_jiffy; + + seq_printf (m, "CPU-Family: v850\nCPU-Arch: %s\n", CPU_ARCH); + +#ifdef CPU_MODEL_LONG + seq_printf (m, "CPU-Model: %s (%s)\n", CPU_MODEL, CPU_MODEL_LONG); +#else + seq_printf (m, "CPU-Model: %s\n", CPU_MODEL); +#endif + +#ifdef CPU_CLOCK_FREQ + seq_printf (m, "CPU-Clock: %ld (%ld MHz)\n", + (long)CPU_CLOCK_FREQ, + (long)CPU_CLOCK_FREQ / 1000000); +#endif + + seq_printf (m, "BogoMips: %lu.%02lu\n", + loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ)) % 100); + +#ifdef PLATFORM_LONG + seq_printf (m, "Platform: %s (%s)\n", PLATFORM, PLATFORM_LONG); +#elif defined (PLATFORM) + seq_printf (m, "Platform: %s\n", PLATFORM); +#endif + + return 0; +} + +static void *cpuinfo_start (struct seq_file *m, loff_t *pos) +{ + return *pos < NR_CPUS ? ((void *) 0x12345678) : NULL; +} + +static void *cpuinfo_next (struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return cpuinfo_start (m, pos); +} + +static void cpuinfo_stop (struct seq_file *m, void *v) +{ +} + +struct seq_operations cpuinfo_op = { + start: cpuinfo_start, + next: cpuinfo_next, + stop: cpuinfo_stop, + show: cpuinfo_print +}; diff -Nru a/arch/v850/kernel/ptrace.c b/arch/v850/kernel/ptrace.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/ptrace.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,202 @@ +/* + * arch/v850/kernel/ptrace.c -- `ptrace' system call + * + * Copyright (C) 2002 NEC Corporation + * Copyright (C) 2002 Miles Bader + * + * Derived from arch/mips/kernel/ptrace.c: + * + * Copyright (C) 1992 Ross Biro + * Copyright (C) Linus Torvalds + * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle + * Copyright (C) 1996 David S. Miller + * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999 MIPS Technologies, Inc. + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +int sys_ptrace(long request, long pid, long addr, long data) +{ + struct task_struct *child; + int rval; + + lock_kernel(); + +#if 0 + printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n", + (int) request, (int) pid, (unsigned long) addr, + (unsigned long) data); +#endif + + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->ptrace & PT_PTRACED) { + rval = -EPERM; + goto out; + } + /* set the ptrace bit in the process flags. */ + current->ptrace |= PT_PTRACED; + rval = 0; + goto out; + } + rval = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + goto out; + + rval = -EPERM; + if (pid == 1) /* you may not mess with init */ + goto out; + + if (request == PTRACE_ATTACH) { + rval = ptrace_attach(child); + goto out_tsk; + } + rval = -ESRCH; + if (!(child->ptrace & PT_PTRACED)) + goto out_tsk; + if (child->state != TASK_STOPPED) { + if (request != PTRACE_KILL) + goto out_tsk; + } + if (child->parent != current) + goto out_tsk; + + switch (request) { + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA:{ + unsigned long tmp; + int copied; + + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + rval = -EIO; + if (copied != sizeof(tmp)) + break; + rval = put_user(tmp,(unsigned long *) data); + + goto out; + } + + /* Read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: + if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) { + struct pt_regs *regs = task_regs (child); + unsigned long val = + *(unsigned long *)((char *)regs + addr); + rval = put_user (val, (unsigned long *)data); + } else { + rval = 0; + rval = -EIO; + } + goto out; + + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + rval = 0; + if (access_process_vm(child, addr, &data, sizeof(data), 1) + == sizeof(data)) + break; + rval = -EIO; + goto out; + + case PTRACE_POKEUSR: + if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) { + struct pt_regs *regs = task_regs (child); + unsigned long *loc = + (unsigned long *)((char *)regs + addr); + *loc = data; + } else { + rval = 0; + rval = -EIO; + } + goto out; + + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: /* rvaltart after signal. */ + rval = -EIO; + if ((unsigned long) data > _NSIG) + break; + if (request == PTRACE_SYSCALL) + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + else + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + child->exit_code = data; + wake_up_process(child); + rval = 0; + break; + + /* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: + rval = 0; + if (child->state == TASK_ZOMBIE) /* already dead */ + break; + child->exit_code = SIGKILL; + wake_up_process(child); + break; + + case PTRACE_DETACH: /* detach a process that was attached. */ + rval = ptrace_detach(child, data); + break; + + default: + rval = -EIO; + goto out; + } + +out_tsk: + put_task_struct(child); +out: + unlock_kernel(); + return rval; +} + +asmlinkage void syscall_trace(void) +{ + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + if (!(current->ptrace & PT_PTRACED)) + return; + /* The 0x80 provides a way for the tracing parent to distinguish + between a syscall stop and SIGTRAP delivery */ + current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0); + current->state = TASK_STOPPED; + notify_parent(current, SIGCHLD); + schedule(); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} + +void ptrace_disable (struct task_struct *child) +{ + /* nothing to do */ +} diff -Nru a/arch/v850/kernel/rte_cb.c b/arch/v850/kernel/rte_cb.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/rte_cb.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,234 @@ +/* + * include/asm-v850/rte_cb.c -- Midas lab RTE-CB series of evaluation boards + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include + +#include +#include + +#include "mach.h" + +static void led_tick (void); + +/* LED access routines. */ +extern unsigned read_leds (int pos, char *buf, int len); +extern unsigned write_leds (int pos, const char *buf, int len); + +#ifdef CONFIG_RTE_CB_MULTI +extern void multi_init (void); +#endif + + +#ifdef CONFIG_ROM_KERNEL +/* Initialization for kernel in ROM. */ +static inline rom_kernel_init (void) +{ + /* If the kernel is in ROM, we have to copy any initialized data + from ROM into RAM. */ + extern unsigned long _data_load_start, _sdata, _edata; + register unsigned long *src = &_data_load_start; + register unsigned long *dst = &_sdata, *end = &_edata; + + while (dst != end) + *dst++ = *src++; +} +#endif /* CONFIG_ROM_KERNEL */ + +void __init mach_early_init (void) +{ + nb85e_intc_disable_irqs (); + +#if defined (CONFIG_ROM_KERNEL) + rom_kernel_init (); +#elif defined (CONFIG_RTE_CB_MULTI) + multi_init (); +#endif +} + +void __init mach_setup (char **cmdline) +{ + printk (KERN_INFO + "CPU: %s\n" + "Platform: %s%s\n", + CPU_MODEL_LONG, + PLATFORM_LONG, +#ifdef CONFIG_ROM_KERNEL + "" +#elif defined (CONFIG_RTE_CB_MULTI) + " (with Multi ROM monitor)" +#else + " (with ROM monitor)" +#endif + ); + + /* Probe for Mother-A, and print a message if we find it. */ + *(volatile long *)MB_A_SRAM_ADDR = 0xDEADBEEF; + if (*(volatile long *)MB_A_SRAM_ADDR == 0xDEADBEEF) { + *(volatile long *)MB_A_SRAM_ADDR = 0x12345678; + if (*(volatile long *)MB_A_SRAM_ADDR == 0x12345678) + printk (KERN_INFO + " NEC SolutionGear/Midas lab" + " RTE-MOTHER-A motherboard\n"); + } + +#if defined (CONFIG_V850E_NB85E_UART_CONSOLE) && !defined (CONFIG_TIME_BOOTUP) + nb85e_uart_cons_init (0); +#endif + + mach_tick = led_tick; +} + +#ifdef CONFIG_TIME_BOOTUP +void initial_boot_done (void) +{ +#ifdef CONFIG_V850E_NB85E_UART_CONSOLE + nb85e_uart_cons_init (0); +#endif +} +#endif + +void machine_restart (char *__unused) +{ +#ifdef CONFIG_RESET_GUARD + disable_reset_guard (); +#endif + asm ("jmp r0"); /* Jump to the reset vector. */ +} + +/* This says `HALt.' in LEDese. */ +static unsigned char halt_leds_msg[] = { 0x76, 0x77, 0x38, 0xF8 }; + +void machine_halt (void) +{ +#ifdef CONFIG_RESET_GUARD + disable_reset_guard (); +#endif + + /* Ignore all interrupts. */ + local_irq_disable (); + + /* Write a little message. */ + write_leds (0, halt_leds_msg, sizeof halt_leds_msg); + + /* Really halt. */ + for (;;) + asm ("halt; nop; nop; nop; nop; nop"); +} + +void machine_power_off (void) +{ + machine_halt (); +} + + +/* Animated LED display for timer tick. */ + +#define TICK_UPD_FREQ 6 +static int tick_frames[][10] = { + { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, -1 }, + { 0x63, 0x5c, -1 }, + { 0x5c, 0x00, -1 }, + { 0x63, 0x00, -1 }, + { -1 } +}; + +static void led_tick () +{ + static unsigned counter = 0; + + if (++counter == (HZ / TICK_UPD_FREQ)) { + /* Which frame we're currently displaying for each digit. */ + static unsigned frame_nums[LED_NUM_DIGITS] = { 0 }; + /* Display image. */ + static unsigned char image[LED_NUM_DIGITS] = { 0 }; + unsigned char prev_image[LED_NUM_DIGITS]; + int write_to_leds = 1; /* true if we should actually display */ + int digit; + + /* We check to see if the physical LEDs contains what we last + wrote to them; if not, we suppress display (this is so that + users can write to the LEDs, and not have their output + overwritten). As a special case, we start writing again if + all the LEDs are blank, or our display image is all zeros + (indicating that this is the initial update, when the actual + LEDs might contain random data). */ + read_leds (0, prev_image, LED_NUM_DIGITS); + for (digit = 0; digit < LED_NUM_DIGITS; digit++) + if (image[digit] != prev_image[digit] + && image[digit] && prev_image[digit]) + { + write_to_leds = 0; + break; + } + + /* Update display image. */ + for (digit = 0; + digit < LED_NUM_DIGITS && tick_frames[digit][0] >= 0; + digit++) + { + int frame = tick_frames[digit][frame_nums[digit]]; + if (frame < 0) { + image[digit] = tick_frames[digit][0]; + frame_nums[digit] = 1; + } else { + image[digit] = frame; + frame_nums[digit]++; + break; + } + } + + if (write_to_leds) + /* Write the display image to the physical LEDs. */ + write_leds (0, image, LED_NUM_DIGITS); + + counter = 0; + } +} + + +/* Mother-A interrupts. */ + +#ifdef CONFIG_RTE_GBUS_INT + +#define L GBUS_INT_PRIORITY_LOW +#define M GBUS_INT_PRIORITY_MEDIUM +#define H GBUS_INT_PRIORITY_HIGH + +static struct gbus_int_irq_init gbus_irq_inits[] = { +#ifdef CONFIG_RTE_MB_A_PCI + { "MB_A_LAN", IRQ_MB_A_LAN, 1, 1, L }, + { "MB_A_PCI1", IRQ_MB_A_PCI1(0), IRQ_MB_A_PCI1_NUM, 1, L }, + { "MB_A_PCI2", IRQ_MB_A_PCI2(0), IRQ_MB_A_PCI2_NUM, 1, L }, + { "MB_A_EXT", IRQ_MB_A_EXT(0), IRQ_MB_A_EXT_NUM, 1, L }, + { "MB_A_USB_OC",IRQ_MB_A_USB_OC(0), IRQ_MB_A_USB_OC_NUM, 1, L }, + { "MB_A_PCMCIA_OC",IRQ_MB_A_PCMCIA_OC, 1, 1, L }, +#endif + { 0 } +}; +#define NUM_GBUS_IRQ_INITS \ + ((sizeof gbus_irq_inits / sizeof gbus_irq_inits[0]) - 1) + +static struct hw_interrupt_type gbus_hw_itypes[NUM_GBUS_IRQ_INITS]; + +#endif /* CONFIG_RTE_GBUS_INT */ + +void __init rte_cb_init_irqs (void) +{ +#ifdef CONFIG_RTE_GBUS_INT + gbus_int_init_irqs (); + gbus_int_init_irq_types (gbus_irq_inits, gbus_hw_itypes); +#endif /* CONFIG_RTE_GBUS_INT */ +} diff -Nru a/arch/v850/kernel/rte_cb_leds.c b/arch/v850/kernel/rte_cb_leds.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/rte_cb_leds.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,135 @@ +/* + * include/asm-v850/rte_cb_leds.c -- Midas lab RTE-CB board LED device support + * + * Copyright (C) 2002 NEC Corporation + * Copyright (C) 2002 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include + +#include + +#define LEDS_MINOR 169 /* Minor device number, using misc major. */ + +/* The actual LED hardware is write-only, so we hold the contents here too. */ +static unsigned char leds_image[LED_NUM_DIGITS] = { 0 }; + +/* Spinlock protecting the above leds. */ +static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED; + +/* Common body of LED read/write functions, checks POS and LEN for + correctness, declares a variable using IMG_DECL, initialized pointing at + the POS position in the LED image buffer, and and iterates COPY_EXPR + until BUF is equal to the last buffer position; finally, sets LEN to be + the amount actually copied. IMG should be a variable declaration + (without an initializer or a terminating semicolon); POS, BUF, and LEN + should all be simple variables. */ +#define DO_LED_COPY(img_decl, pos, buf, len, copy_expr) \ +do { \ + if (pos > LED_NUM_DIGITS) \ + len = 0; \ + else { \ + if (pos + len > LED_NUM_DIGITS) \ + len = LED_NUM_DIGITS - pos; \ + \ + if (len > 0) { \ + int _flags; \ + const char *_end = buf + len; \ + img_decl = &leds_image[pos]; \ + \ + spin_lock_irqsave (leds_lock, _flags); \ + do \ + (copy_expr); \ + while (buf != _end); \ + spin_unlock_irqrestore (leds_lock, _flags); \ + } \ + } \ +} while (0) + +/* Read LEN bytes from LEDs at position POS, into BUF. + Returns actual amount read. */ +unsigned read_leds (unsigned pos, char *buf, unsigned len) +{ + DO_LED_COPY (const char *img, pos, buf, len, *buf++ = *img++); + return len; +} + +/* Write LEN bytes to LEDs at position POS, from BUF. + Returns actual amount written. */ +unsigned write_leds (unsigned pos, const char *buf, unsigned len) +{ + /* We write the actual LED values backwards, because + increasing memory addresses reflect LEDs right-to-left. */ + volatile char *led = &LED (LED_NUM_DIGITS - pos - 1); + /* We invert the value written to the hardware, because 1 = off, + and 0 = on. */ + DO_LED_COPY (char *img, pos, buf, len, + *led-- = 0xFF ^ (*img++ = *buf++)); + return len; +} + + +/* Device functions. */ + +static ssize_t leds_dev_read (struct file *file, char *buf, size_t len, + loff_t *pos) +{ + char temp_buf[LED_NUM_DIGITS]; + len = read_leds (*pos, temp_buf, len); + if (copy_to_user (buf, temp_buf, len)) + return -EFAULT; + *pos += len; + return len; +} + +static ssize_t leds_dev_write (struct file *file, const char *buf, size_t len, + loff_t *pos) +{ + char temp_buf[LED_NUM_DIGITS]; + if (copy_from_user (temp_buf, buf, min_t(size_t, len, LED_NUM_DIGITS))) + return -EFAULT; + len = write_leds (*pos, temp_buf, len); + *pos += len; + return len; +} + +static loff_t leds_dev_lseek (struct file *file, loff_t offs, int whence) +{ + if (whence == 1) + offs += file->f_pos; /* relative */ + else if (whence == 2) + offs += LED_NUM_DIGITS; /* end-relative */ + + if (offs >= 0 && offs <= LED_NUM_DIGITS) + file->f_pos = offs; + else + return -EINVAL; +} + +static struct file_operations leds_fops = { + read: leds_dev_read, + write: leds_dev_write, + llseek: leds_dev_lseek +}; + +static struct miscdevice leds_miscdev = { + name: "leds", + minor: LEDS_MINOR, + fops: &leds_fops +}; + +int __init leds_dev_init (void) +{ + return misc_register (&leds_miscdev); +} + +__initcall (leds_dev_init); diff -Nru a/arch/v850/kernel/rte_cb_multi.c b/arch/v850/kernel/rte_cb_multi.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/rte_cb_multi.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,85 @@ +/* + * include/asm-v850/rte_multi.c -- Support for Multi debugger monitor ROM + * on Midas lab RTE-CB series of evaluation boards + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include + +#include + +/* A table of which interrupt vectors to install, since blindly + installing all of them makes the debugger stop working. This is a + list of offsets in the interrupt vector area; each entry means to + copy that particular 16-byte vector. An entry less than zero ends + the table. */ +static long multi_intv_install_table[] = { + 0x40, 0x50, /* trap vectors */ + /* Note -- illegal insn trap is used by the debugger. */ + 0xD0, 0xE0, 0xF0, /* GINT1 - GINT3 */ + 0x240, 0x250, 0x260, 0x270, /* timer D interrupts */ + 0x2D0, 0x2E0, 0x2F0, /* UART channel 0 */ + 0x310, 0x320, 0x330, /* UART channel 1 */ + 0x350, 0x360, 0x370, /* UART channel 2 */ + -1 +}; + +/* Early initialization for kernel using Multi debugger ROM monitor. */ +void __init multi_init (void) +{ + /* We're using the Multi debugger monitor, so we have to install + the interrupt vectors. The monitor doesn't allow them to be + initially downloaded into their final destination because + it's in the monitor's scratch-RAM area. Unfortunately, Multi + also doesn't deal correctly with ELF sections where the LMA + and VMA differ -- it just ignores the LMA -- so we can't use + that feature to work around the problem. What we do instead + is just put the interrupt vectors into a normal section, and + do the necessary copying and relocation here. Since the + interrupt vector basically only contains `jr' instructions + and no-ops, it's not that hard. */ + extern unsigned long _intv_load_start, _intv_start; + register unsigned long *src = &_intv_load_start; + register unsigned long *dst = (unsigned long *)INTV_BASE; + register unsigned long jr_fixup = (char *)&_intv_start - (char *)dst; + register long *ii; + + /* Copy interupt vectors as instructed by multi_intv_install_table. */ + for (ii = multi_intv_install_table; *ii >= 0; ii++) { + /* Copy 16-byte interrupt vector at offset *ii. */ + int boffs; + for (boffs = 0; boffs < 0x10; boffs += sizeof *src) { + /* Copy a single word, fixing up the jump offs + if it's a `jr' instruction. */ + int woffs = (*ii + boffs) / sizeof *src; + unsigned long word = src[woffs]; + + if ((word & 0xFC0) == 0x780) { + /* A `jr' insn, fix up its offset (and yes, the + wierd half-word swapping is intentional). */ + unsigned short hi = word & 0xFFFF; + unsigned short lo = word >> 16; + unsigned long udisp22 + = lo + ((hi & 0x3F) << 16); + long disp22 = (long)(udisp22 << 10) >> 10; + + disp22 += jr_fixup; + + hi = ((disp22 >> 16) & 0x3F) | 0x780; + lo = disp22 & 0xFFFF; + + word = hi + (lo << 16); + } + + dst[woffs] = word; + } + } +} diff -Nru a/arch/v850/kernel/rte_ma1_cb.c b/arch/v850/kernel/rte_ma1_cb.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/rte_ma1_cb.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,101 @@ +/* + * arch/v850/kernel/rte_ma1_cb.c -- Midas labs RTE-V850E/MA1-CB board + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "mach.h" + + +/* SRAM and SDRAM are almost contiguous (with a small hole in between; + see mach_reserve_bootmem for details), so just use both as one big area. */ +#define RAM_START SRAM_ADDR +#define RAM_END (SDRAM_ADDR + SDRAM_SIZE) + + +void __init mach_get_physical_ram (unsigned long *ram_start, + unsigned long *ram_len) +{ + *ram_start = RAM_START; + *ram_len = RAM_END - RAM_START; +} + +void __init mach_reserve_bootmem () +{ +#ifdef CONFIG_RTE_CB_MULTI + /* Prevent the kernel from touching the monitor's scratch RAM. */ + reserve_bootmem (MON_SCRATCH_ADDR, MON_SCRATCH_SIZE); +#endif + + /* The space between SRAM and SDRAM is filled with duplicate + images of SRAM. Prevent the kernel from using them. */ + reserve_bootmem (SRAM_ADDR + SRAM_SIZE, + SDRAM_ADDR - (SRAM_ADDR + SRAM_SIZE)); +} + +void mach_gettimeofday (struct timespec *tv) +{ + tv->tv_sec = 0; + tv->tv_nsec = 0; +} + +/* Called before configuring an on-chip UART. */ +void rte_ma1_cb_uart_pre_configure (unsigned chan, + unsigned cflags, unsigned baud) +{ + /* The RTE-MA1-CB connects some general-purpose I/O pins on the + CPU to the RTS/CTS lines of UART 0's serial connection. + I/O pins P42 and P43 are RTS and CTS respectively. */ + if (chan == 0) { + /* Put P42 & P43 in I/O port mode. */ + MA_PORT4_PMC &= ~0xC; + /* Make P42 and output, and P43 an input. */ + MA_PORT4_PM = (MA_PORT4_PM & ~0xC) | 0x8; + } + + /* Do pre-configuration for the actual UART. */ + ma_uart_pre_configure (chan, cflags, baud); +} + +void __init mach_init_irqs (void) +{ + unsigned tc; + + /* Initialize interrupts. */ + ma_init_irqs (); + rte_cb_init_irqs (); + + /* Use falling-edge-sensitivity for interrupts . */ + NB85E_TIMER_C_SESC (0) &= ~0xC; + NB85E_TIMER_C_SESC (1) &= ~0xF; + + /* INTP000-INTP011 are shared with `Timer C', so we have to set + up Timer C to pass them through as raw interrupts. */ + for (tc = 0; tc < 2; tc++) + /* Turn on the timer. */ + NB85E_TIMER_C_TMCC0 (tc) |= NB85E_TIMER_C_TMCC0_CAE; + + /* Make sure the relevent port0/port1 pins are assigned + interrupt duty. We used INTP001-INTP011 (don't screw with + INTP000 because the monitor uses it). */ + MA_PORT0_PMC |= 0x4; /* P02 (INTP001) in IRQ mode. */ + MA_PORT1_PMC |= 0x6; /* P11 (INTP010) & P12 (INTP011) in IRQ mode.*/ +} diff -Nru a/arch/v850/kernel/rte_mb_a_pci.c b/arch/v850/kernel/rte_mb_a_pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/rte_mb_a_pci.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,781 @@ +/* + * arch/v850/kernel/mb_a_pci.c -- PCI support for Midas lab RTE-MOTHER-A board + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* __nomods_init is like __devinit, but is a no-op when modules are enabled. + This is used by some routines that can be called either during boot + or by a module. */ +#ifdef CONFIG_MODULES +#define __nomods_init /*nothing*/ +#else +#define __nomods_init __devinit +#endif + +/* PCI devices on the Mother-A board can only do DMA to/from the MB SRAM + (the RTE-V850E/MA1-CB cpu board doesn't support PCI access to + CPU-board memory), and since linux DMA buffers are allocated in + normal kernel memory, we basically have to copy DMA blocks around + (this is like a `bounce buffer'). When a DMA block is `mapped', we + allocate an identically sized block in MB SRAM, and if we're doing + output to the device, copy the CPU-memory block to the MB-SRAM block. + When an active block is `unmapped', we will copy the block back to + CPU memory if necessary, and then deallocate the MB SRAM block. + Ack. */ + +/* Where the motherboard SRAM is in the PCI-bus address space (the + first 512K of it is also mapped at PCI address 0). */ +#define PCI_MB_SRAM_ADDR 0x800000 + +/* Convert CPU-view MB SRAM address to/from PCI-view addresses of the + same memory. */ +#define MB_SRAM_TO_PCI(mb_sram_addr) \ + ((dma_addr_t)mb_sram_addr - MB_A_SRAM_ADDR + PCI_MB_SRAM_ADDR) +#define PCI_TO_MB_SRAM(pci_addr) \ + (void *)(pci_addr - PCI_MB_SRAM_ADDR + MB_A_SRAM_ADDR) + +static void pcibios_assign_resources (void); + +struct mb_pci_dev_irq { + unsigned dev; /* PCI device number */ + unsigned irq_base; /* First IRQ */ + unsigned query_pin; /* True if we should read the device's + Interrupt Pin info, and allocate + interrupt IRQ_BASE + PIN. */ +}; + +/* PCI interrupts are mapped statically to GBUS interrupts. */ +static struct mb_pci_dev_irq mb_pci_dev_irqs[] = { + /* Motherboard SB82558 ethernet controller */ + { 10, IRQ_MB_A_LAN, 0 }, + /* PCI slot 1 */ + { 8, IRQ_MB_A_PCI1(0), 1 }, + /* PCI slot 2 */ + { 9, IRQ_MB_A_PCI2(0), 1 } +}; +#define NUM_MB_PCI_DEV_IRQS \ + (sizeof mb_pci_dev_irqs / sizeof mb_pci_dev_irqs[0]) + + +/* PCI configuration primitives. */ + +#define CONFIG_DMCFGA(bus, devfn, offs) \ + (0x80000000 \ + | ((offs) & ~0x3) \ + | ((devfn) << 8) \ + | ((bus)->number << 16)) + +static int +mb_pci_read (struct pci_bus *bus, unsigned devfn, int offs, int size, u32 *rval) +{ + u32 addr; + int flags; + + local_irq_save (flags); + + MB_A_PCI_PCICR = 0x7; + MB_A_PCI_DMCFGA = CONFIG_DMCFGA (bus, devfn, offs); + + addr = MB_A_PCI_IO_ADDR + (offs & 0x3); + + switch (size) { + case 1: *rval = *(volatile u8 *)addr; break; + case 2: *rval = *(volatile u16 *)addr; break; + case 4: *rval = *(volatile u32 *)addr; break; + } + + if (MB_A_PCI_PCISR & 0x2000) { + MB_A_PCI_PCISR = 0x2000; + *rval = ~0; + } + + MB_A_PCI_DMCFGA = 0; + + local_irq_restore (flags); + + return PCIBIOS_SUCCESSFUL; +} + +static int +mb_pci_write (struct pci_bus *bus, unsigned devfn, int offs, int size, u32 val) +{ + u32 addr; + int flags; + + local_irq_save (flags); + + MB_A_PCI_PCICR = 0x7; + MB_A_PCI_DMCFGA = CONFIG_DMCFGA (bus, devfn, offs); + + addr = MB_A_PCI_IO_ADDR + (offs & 0x3); + + switch (size) { + case 1: *(volatile u8 *)addr = val; break; + case 2: *(volatile u16 *)addr = val; break; + case 4: *(volatile u32 *)addr = val; break; + } + + if (MB_A_PCI_PCISR & 0x2000) + MB_A_PCI_PCISR = 0x2000; + + MB_A_PCI_DMCFGA = 0; + + local_irq_restore (flags); + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops mb_pci_config_ops = { + .read = mb_pci_read, + .write = mb_pci_write, +}; + + +/* PCI Initialization. */ + +static struct pci_bus *mb_pci_bus = 0; + +/* Do initial PCI setup. */ +static int __devinit pcibios_init (void) +{ + u32 id = MB_A_PCI_PCIHIDR; + u16 vendor = id & 0xFFFF; + u16 device = (id >> 16) & 0xFFFF; + + if (vendor == PCI_VENDOR_ID_PLX && device == PCI_DEVICE_ID_PLX_9080) { + printk (KERN_INFO + "PCI: PLX Technology PCI9080 HOST/PCI bridge\n"); + + MB_A_PCI_PCICR = 0x147; + MB_A_PCI_DMLBAM = 0x0; + + MB_A_PCI_PCIBAR0 = 0x007FFF00; + MB_A_PCI_PCIBAR1 = 0x0000FF00; + MB_A_PCI_PCIBAR2 = 0x00800000; + + MB_A_PCI_PCILTR = 0x20; + + MB_A_PCI_PCIPBAM |= 0x3; + + MB_A_PCI_PCISR = ~0; /* Clear errors. */ + + /* Reprogram the motherboard's IO/config address space, + as we don't support the GCS7 address space that the + default uses. Note that we have to give the address + from the motherboard's point of view, which is + different than the CPU's. */ + MB_A_PCI_DMLBAI = MB_A_PCI_IO_ADDR - GCS5_ADDR; + MB_A_PCI_DMRR = ~(MB_A_PCI_MEM_SIZE - 1); + + mb_pci_bus = pci_scan_bus (0, &mb_pci_config_ops, 0); + + pcibios_assign_resources (); + } else + printk (KERN_ERR "PCI: HOST/PCI bridge not found\n"); + + return 0; +} + +subsys_initcall (pcibios_init); + +char __devinit *pcibios_setup (char *option) +{ + /* Don't handle any options. */ + return option; +} + + +int __nomods_init pcibios_enable_device (struct pci_dev *dev, int mask) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for (idx = 0; idx < 6; idx++) { + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because " + "of resource collisions\n", dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", + dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + + +/* Resource allocation. */ +static void __devinit pcibios_assign_resources (void) +{ + struct pci_dev *dev; + struct resource *r; + + pci_for_each_dev (dev) { + int di_num; + unsigned class = dev->class >> 8; + + if (class && class != PCI_CLASS_BRIDGE_HOST) { + unsigned r_num; + for(r_num = 0; r_num < 6; r_num++) { + r = &dev->resource[r_num]; + if (!r->start && r->end) + pci_assign_resource (dev, r_num); + } + } + + /* Assign interrupts. */ + for (di_num = 0; di_num < NUM_MB_PCI_DEV_IRQS; di_num++) { + struct mb_pci_dev_irq *di = &mb_pci_dev_irqs[di_num]; + + if (di->dev == PCI_SLOT (dev->devfn)) { + unsigned irq = di->irq_base; + + if (di->query_pin) { + /* Find out which interrupt pin + this device uses (each PCI + slot has 4). */ + u8 irq_pin; + + pci_read_config_byte (dev, + PCI_INTERRUPT_PIN, + &irq_pin); + + if (irq_pin == 0) + /* Doesn't use interrupts. */ + continue; + else + irq += irq_pin - 1; + } + + pcibios_update_irq (dev, irq); + } + } + } +} + +void __devinit pcibios_update_irq (struct pci_dev *dev, int irq) +{ + dev->irq = irq; + pci_write_config_byte (dev, PCI_INTERRUPT_LINE, irq); +} + +void __nomods_init +pcibios_update_resource (struct pci_dev *dev, struct resource *root, + struct resource *r, int resource) +{ + u32 new, check; + int reg; + + if (r->flags & IORESOURCE_IO) + new = (((r->start - MB_A_PCI_IO_ADDR) + & PCI_BASE_ADDRESS_IO_MASK) + | PCI_BASE_ADDRESS_SPACE_IO); + else if (r->flags & IORESOURCE_MEM) + new = (((r->start - MB_A_PCI_MEM_ADDR) + & PCI_BASE_ADDRESS_MEM_MASK) + | PCI_BASE_ADDRESS_MEM_TYPE_32 + | ((r->flags & IORESOURCE_PREFETCH) + ? PCI_BASE_ADDRESS_MEM_PREFETCH + : 0) + | PCI_BASE_ADDRESS_SPACE_MEMORY); + else + panic ("pcibios_update_resource: unknown resource type"); + + if (resource < 6) + reg = PCI_BASE_ADDRESS_0 + 4*resource; + else if (resource == PCI_ROM_RESOURCE) { + r->flags |= PCI_ROM_ADDRESS_ENABLE; + new |= PCI_ROM_ADDRESS_ENABLE; + reg = dev->rom_base_reg; + } else + return; + + pci_write_config_dword(dev, reg, new); + pci_read_config_dword(dev, reg, &check); + if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) { + printk (KERN_ERR "PCI: Error while updating region " + "%s/%d (%08x != %08x)\n", dev->slot_name, resource, + new, check); + } +} + + +/* Stubs for things we don't use. */ + +struct pci_fixup pcibios_fixups[] = { { 0 } }; + +/* Called after each bus is probed, but before its children are examined. */ +void pcibios_fixup_bus(struct pci_bus *b) +{ +} + +void +pcibios_align_resource (void *data, struct resource *res, + unsigned long size, unsigned long align) +{ +} + +void pcibios_set_master (struct pci_dev *dev) +{ +} + + +/* Mother-A SRAM memory allocation. This is a simple first-fit allocator. */ + +/* A memory free-list node. */ +struct mb_sram_free_area { + void *mem; + unsigned long size; + struct mb_sram_free_area *next; +}; + +/* The tail of the free-list, which starts out containing all the SRAM. */ +static struct mb_sram_free_area mb_sram_free_tail = { + (void *)MB_A_SRAM_ADDR, MB_A_SRAM_SIZE, 0 +}; + +/* The free-list. */ +static struct mb_sram_free_area *mb_sram_free_areas = &mb_sram_free_tail; + +/* The free-list of free free-list nodes. (:-) */ +static struct mb_sram_free_area *mb_sram_free_free_areas = 0; + +/* Spinlock protecting the above globals. */ +static spinlock_t mb_sram_lock = SPIN_LOCK_UNLOCKED; + +/* Allocate a memory block at least SIZE bytes long in the Mother-A SRAM + space. */ +static void *alloc_mb_sram (size_t size) +{ + struct mb_sram_free_area *prev, *fa; + int flags; + void *mem = 0; + + spin_lock_irqsave (mb_sram_lock, flags); + + /* Look for a free area that can contain SIZE bytes. */ + for (prev = 0, fa = mb_sram_free_areas; fa; prev = fa, fa = fa->next) + if (fa->size >= size) { + /* Found one! */ + mem = fa->mem; + + if (fa->size == size) { + /* In fact, it fits exactly, so remove + this node from the free-list. */ + if (prev) + prev->next = fa->next; + else + mb_sram_free_areas = fa->next; + /* Put it on the free-list-entry-free-list. */ + fa->next = mb_sram_free_free_areas; + mb_sram_free_free_areas = fa; + } else { + /* FA is bigger than SIZE, so just + reduce its size to account for this + allocation. */ + fa->mem += size; + fa->size -= size; + } + + break; + } + + spin_unlock_irqrestore (mb_sram_lock, flags); + + return mem; +} + +/* Return the memory area MEM of size SIZE to the MB SRAM free pool. */ +static void free_mb_sram (void *mem, size_t size) +{ + struct mb_sram_free_area *prev, *fa, *new_fa; + int flags; + void *end = mem + size; + + spin_lock_irqsave (mb_sram_lock, flags); + + retry: + /* Find an adjacent free-list entry. */ + for (prev = 0, fa = mb_sram_free_areas; fa; prev = fa, fa = fa->next) + if (fa->mem == end) { + /* FA is just after MEM, grow down to encompass it. */ + fa->mem = mem; + fa->size += size; + goto done; + } else if (fa->mem + fa->size == mem) { + struct mb_sram_free_area *next_fa = fa->next; + + /* FA is just before MEM, expand to encompass it. */ + fa->size += size; + + /* See if FA can now be merged with its successor. */ + if (next_fa && fa->mem + fa->size == next_fa->mem) { + /* Yup; merge NEXT_FA's info into FA. */ + fa->size += next_fa->size; + fa->next = next_fa->next; + /* Free NEXT_FA. */ + next_fa->next = mb_sram_free_free_areas; + mb_sram_free_free_areas = next_fa; + } + goto done; + } else if (fa->mem > mem) + /* We've reached the right spot in the free-list + without finding an adjacent free-area, so add + a new free area to hold mem. */ + break; + + /* Make a new free-list entry. */ + + /* First, get a free-list entry. */ + if (! mb_sram_free_free_areas) { + /* There are none, so make some. */ + void *block; + size_t block_size = sizeof (struct mb_sram_free_area) * 8; + + /* Don't hold the lock while calling kmalloc (I'm not + sure whether it would be a problem, since we use + GFP_ATOMIC, but it makes me nervous). */ + spin_unlock_irqrestore (mb_sram_lock, flags); + + block = kmalloc (block_size, GFP_ATOMIC); + if (! block) + panic ("free_mb_sram: can't allocate free-list entry"); + + /* Now get the lock back. */ + spin_lock_irqsave (mb_sram_lock, flags); + + /* Add the new free free-list entries. */ + while (block_size > 0) { + struct mb_sram_free_area *nfa = block; + nfa->next = mb_sram_free_free_areas; + mb_sram_free_free_areas = nfa; + block += sizeof *nfa; + block_size -= sizeof *nfa; + } + + /* Since we dropped the lock to call kmalloc, the + free-list could have changed, so retry from the + beginning. */ + goto retry; + } + + /* Remove NEW_FA from the free-list of free-list entries. */ + new_fa = mb_sram_free_free_areas; + mb_sram_free_free_areas = new_fa->next; + + /* NEW_FA initially holds only MEM. */ + new_fa->mem = mem; + new_fa->size = size; + + /* Insert NEW_FA in the free-list between PREV and FA. */ + new_fa->next = fa; + if (prev) + prev->next = new_fa; + else + mb_sram_free_areas = new_fa; + + done: + spin_unlock_irqrestore (mb_sram_lock, flags); +} + + +/* Maintainence of CPU -> Mother-A DMA mappings. */ + +struct dma_mapping { + void *cpu_addr; + void *mb_sram_addr; + size_t size; + struct dma_mapping *next; +}; + +/* A list of mappings from CPU addresses to MB SRAM addresses for active + DMA blocks (that have been `granted' to the PCI device). */ +static struct dma_mapping *active_dma_mappings = 0; + +/* A list of free mapping objects. */ +static struct dma_mapping *free_dma_mappings = 0; + +/* Spinlock protecting the above globals. */ +static spinlock_t dma_mappings_lock = SPIN_LOCK_UNLOCKED; + +static struct dma_mapping *new_dma_mapping (size_t size) +{ + int flags; + struct dma_mapping *mapping; + void *mb_sram_block = alloc_mb_sram (size); + + if (! mb_sram_block) + return 0; + + spin_lock_irqsave (dma_mappings_lock, flags); + + if (! free_dma_mappings) { + /* We're out of mapping structures, make more. */ + void *mblock; + size_t mblock_size = sizeof (struct dma_mapping) * 8; + + /* Don't hold the lock while calling kmalloc (I'm not + sure whether it would be a problem, since we use + GFP_ATOMIC, but it makes me nervous). */ + spin_unlock_irqrestore (dma_mappings_lock, flags); + + mblock = kmalloc (mblock_size, GFP_ATOMIC); + if (! mblock) { + free_mb_sram (mb_sram_block, size); + return 0; + } + + /* Get the lock back. */ + spin_lock_irqsave (dma_mappings_lock, flags); + + /* Add the new mapping structures to the free-list. */ + while (mblock_size > 0) { + struct dma_mapping *fm = mblock; + fm->next = free_dma_mappings; + free_dma_mappings = fm; + mblock += sizeof *fm; + mblock_size -= sizeof *fm; + } + } + + /* Get a mapping struct from the freelist. */ + mapping = free_dma_mappings; + free_dma_mappings = mapping->next; + + /* Initialize the mapping. Other fields should be filled in by + caller. */ + mapping->mb_sram_addr = mb_sram_block; + mapping->size = size; + + /* Add it to the list of active mappings. */ + mapping->next = active_dma_mappings; + active_dma_mappings = mapping; + + spin_unlock_irqrestore (dma_mappings_lock, flags); + + return mapping; +} + +static struct dma_mapping *find_dma_mapping (void *mb_sram_addr) +{ + int flags; + struct dma_mapping *mapping; + + spin_lock_irqsave (dma_mappings_lock, flags); + + for (mapping = active_dma_mappings; mapping; mapping = mapping->next) + if (mapping->mb_sram_addr == mb_sram_addr) { + spin_unlock_irqrestore (dma_mappings_lock, flags); + return mapping; + } + + panic ("find_dma_mapping: unmapped PCI DMA addr 0x%x", + MB_SRAM_TO_PCI (mb_sram_addr)); +} + +static struct dma_mapping *deactivate_dma_mapping (void *mb_sram_addr) +{ + int flags; + struct dma_mapping *mapping, *prev; + + spin_lock_irqsave (dma_mappings_lock, flags); + + for (prev = 0, mapping = active_dma_mappings; + mapping; + prev = mapping, mapping = mapping->next) + { + if (mapping->mb_sram_addr == mb_sram_addr) { + /* This is the MAPPING; deactivate it. */ + if (prev) + prev->next = mapping->next; + else + active_dma_mappings = mapping->next; + + spin_unlock_irqrestore (dma_mappings_lock, flags); + + return mapping; + } + } + + panic ("deactivate_dma_mapping: unmapped PCI DMA addr 0x%x", + MB_SRAM_TO_PCI (mb_sram_addr)); +} + +/* Return MAPPING to the freelist. */ +static inline void +free_dma_mapping (struct dma_mapping *mapping) +{ + int flags; + + free_mb_sram (mapping->mb_sram_addr, mapping->size); + + spin_lock_irqsave (dma_mappings_lock, flags); + + mapping->next = free_dma_mappings; + free_dma_mappings = mapping; + + spin_unlock_irqrestore (dma_mappings_lock, flags); +} + + +/* Single PCI DMA mappings. */ + +/* `Grant' to PDEV the memory block at CPU_ADDR, for doing DMA. The + 32-bit PCI bus mastering address to use is returned. the device owns + this memory until either pci_unmap_single or pci_dma_sync_single is + performed. */ +dma_addr_t +pci_map_single (struct pci_dev *pdev, void *cpu_addr, size_t size, int dir) +{ + struct dma_mapping *mapping = new_dma_mapping (size); + + if (! mapping) + return 0; + + mapping->cpu_addr = cpu_addr; + + if (dir == PCI_DMA_BIDIRECTIONAL || dir == PCI_DMA_TODEVICE) + memcpy (mapping->mb_sram_addr, cpu_addr, size); + + return MB_SRAM_TO_PCI (mapping->mb_sram_addr); +} + +/* Return to the CPU the PCI DMA memory block previously `granted' to + PDEV, at DMA_ADDR. */ +void pci_unmap_single (struct pci_dev *pdev, dma_addr_t dma_addr, size_t size, + int dir) +{ + void *mb_sram_addr = PCI_TO_MB_SRAM (dma_addr); + struct dma_mapping *mapping = deactivate_dma_mapping (mb_sram_addr); + + if (size != mapping->size) + panic ("pci_unmap_single: size (%d) doesn't match" + " size of mapping at PCI DMA addr 0x%x (%d)\n", + size, dma_addr, mapping->size); + + /* Copy back the DMA'd contents if necessary. */ + if (dir == PCI_DMA_BIDIRECTIONAL || dir == PCI_DMA_FROMDEVICE) + memcpy (mapping->cpu_addr, mb_sram_addr, size); + + /* Return mapping to the freelist. */ + free_dma_mapping (mapping); +} + +/* Make physical memory consistant for a single streaming mode DMA + translation after a transfer. + + If you perform a pci_map_single() but wish to interrogate the + buffer using the cpu, yet do not wish to teardown the PCI dma + mapping, you must call this function before doing so. At the next + point you give the PCI dma address back to the card, the device + again owns the buffer. */ +void +pci_dma_sync_single (struct pci_dev *pdev, dma_addr_t dma_addr, size_t size, + int dir) +{ + void *mb_sram_addr = PCI_TO_MB_SRAM (dma_addr); + struct dma_mapping *mapping = find_dma_mapping (mb_sram_addr); + + /* Synchronize the DMA buffer with the CPU buffer if necessary. */ + if (dir == PCI_DMA_FROMDEVICE) + memcpy (mapping->cpu_addr, mb_sram_addr, size); + else if (dir == PCI_DMA_TODEVICE) + memcpy (mb_sram_addr, mapping->cpu_addr, size); + else + panic("pci_dma_sync_single: unsupported sync dir: %d", dir); +} + + +/* Scatter-gather PCI DMA mappings. */ + +/* Do multiple DMA mappings at once. */ +int +pci_map_sg (struct pci_dev *pdev, struct scatterlist *sg, int sg_len, int dir) +{ + BUG (); + return 0; +} + +/* Unmap multiple DMA mappings at once. */ +void +pci_unmap_sg (struct pci_dev *pdev, struct scatterlist *sg, int sg_len,int dir) +{ + BUG (); +} + +/* Make physical memory consistant for a set of streaming mode DMA + translations after a transfer. The same as pci_dma_sync_single but + for a scatter-gather list, same rules and usage. */ + +void +pci_dma_sync_sg (struct pci_dev *dev, struct scatterlist *sg, int sg_len, + int dir) +{ + BUG (); +} + + +/* PCI mem mapping. */ + +/* Allocate and map kernel buffer using consistent mode DMA for PCI + device. Returns non-NULL cpu-view pointer to the buffer if + successful and sets *DMA_ADDR to the pci side dma address as well, + else DMA_ADDR is undefined. */ +void * +pci_alloc_consistent (struct pci_dev *pdev, size_t size, dma_addr_t *dma_addr) +{ + void *mb_sram_mem = alloc_mb_sram (size); + if (mb_sram_mem) + *dma_addr = MB_SRAM_TO_PCI (mb_sram_mem); + return mb_sram_mem; +} + +/* Free and unmap a consistent DMA buffer. CPU_ADDR and DMA_ADDR must + be values that were returned from pci_alloc_consistent. SIZE must be + the same as what as passed into pci_alloc_consistent. References to + the memory and mappings assosciated with CPU_ADDR or DMA_ADDR past + this call are illegal. */ +void +pci_free_consistent (struct pci_dev *pdev, size_t size, void *cpu_addr, + dma_addr_t dma_addr) +{ + void *mb_sram_mem = PCI_TO_MB_SRAM (dma_addr); + free_mb_sram (mb_sram_mem, size); +} + + +/* symbol exports (for modules) */ + +EXPORT_SYMBOL (pci_map_single); +EXPORT_SYMBOL (pci_unmap_single); +EXPORT_SYMBOL (pci_alloc_consistent); +EXPORT_SYMBOL (pci_free_consistent); +EXPORT_SYMBOL (pci_dma_sync_single); diff -Nru a/arch/v850/kernel/rte_nb85e_cb.c b/arch/v850/kernel/rte_nb85e_cb.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/rte_nb85e_cb.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,54 @@ +/* + * arch/v850/kernel/rte_nb85e_cb.c -- Midas labs RTE-V850E/NB85E-CB board + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "mach.h" + +void __init mach_get_physical_ram (unsigned long *ram_start, + unsigned long *ram_len) +{ + /* We just use SDRAM here; the kernel itself is in SRAM. */ + *ram_start = SDRAM_ADDR; + *ram_len = SDRAM_SIZE; +} + +void __init mach_reserve_bootmem () +{ + extern char _root_fs_image_start, _root_fs_image_end; + u32 root_fs_image_start = (u32)&_root_fs_image_start; + u32 root_fs_image_end = (u32)&_root_fs_image_end; + + /* Reserve the memory used by the root filesystem image if it's + in RAM. */ + if (root_fs_image_start >= RAM_START && root_fs_image_start < RAM_END) + reserve_bootmem (root_fs_image_start, + root_fs_image_end - root_fs_image_start); +} + +void mach_gettimeofday (struct timespec *tv) +{ + tv->tv_sec = 0; + tv->tv_nsec = 0; +} diff -Nru a/arch/v850/kernel/semaphore.c b/arch/v850/kernel/semaphore.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/semaphore.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,164 @@ +/* + * arch/v850/kernel/semaphore.c -- Semaphore support + * + * Copyright (C) 1998-2000 IBM Corporation + * Copyright (C) 1999 Linus Torvalds + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * This file is a copy of the s390 version, arch/s390/kernel/semaphore.c + * Author(s): Martin Schwidefsky + * which was derived from the i386 version, linux/arch/i386/kernel/semaphore.c + */ + +#include + +#include + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to acquire the semaphore, while the "sleeping" + * variable is a count of such acquires. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * "sleeping" and the contention routine ordering is + * protected by the semaphore spinlock. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ + +/* + * Logic: + * - only on a boundary condition do we need to care. When we go + * from a negative count to a non-negative, we wake people up. + * - when we go from a non-negative count to a negative do we + * (a) synchronize with the "sleeper" count and (b) make sure + * that we're on the wakeup list before we synchronize so that + * we cannot lose wakeup events. + */ + +void __up(struct semaphore *sem) +{ + wake_up(&sem->wait); +} + +static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED; + +void __down(struct semaphore * sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + tsk->state = TASK_UNINTERRUPTIBLE; + add_wait_queue_exclusive(&sem->wait, &wait); + + spin_lock_irq(&semaphore_lock); + sem->sleepers++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + sem->sleepers = 0; + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irq(&semaphore_lock); + + schedule(); + tsk->state = TASK_UNINTERRUPTIBLE; + spin_lock_irq(&semaphore_lock); + } + spin_unlock_irq(&semaphore_lock); + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + wake_up(&sem->wait); +} + +int __down_interruptible(struct semaphore * sem) +{ + int retval = 0; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + tsk->state = TASK_INTERRUPTIBLE; + add_wait_queue_exclusive(&sem->wait, &wait); + + spin_lock_irq(&semaphore_lock); + sem->sleepers ++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * With signals pending, this turns into + * the trylock failure case - we won't be + * sleeping, and we* can't get the lock as + * it has contention. Just correct the count + * and exit. + */ + if (signal_pending(current)) { + retval = -EINTR; + sem->sleepers = 0; + atomic_add(sleepers, &sem->count); + break; + } + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock. The + * "-1" is because we're still hoping to get + * the lock. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + sem->sleepers = 0; + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irq(&semaphore_lock); + + schedule(); + tsk->state = TASK_INTERRUPTIBLE; + spin_lock_irq(&semaphore_lock); + } + spin_unlock_irq(&semaphore_lock); + tsk->state = TASK_RUNNING; + remove_wait_queue(&sem->wait, &wait); + wake_up(&sem->wait); + return retval; +} + +/* + * Trylock failed - make sure we correct for + * having decremented the count. + */ +int __down_trylock(struct semaphore * sem) +{ + unsigned long flags; + int sleepers; + + spin_lock_irqsave(&semaphore_lock, flags); + sleepers = sem->sleepers + 1; + sem->sleepers = 0; + + /* + * Add "everybody else" and us into it. They aren't + * playing, because we own the spinlock. + */ + if (!atomic_add_negative(sleepers, &sem->count)) + wake_up(&sem->wait); + + spin_unlock_irqrestore(&semaphore_lock, flags); + return 1; +} diff -Nru a/arch/v850/kernel/setup.c b/arch/v850/kernel/setup.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/setup.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,273 @@ +/* + * arch/v850/kernel/setup.c -- Arch-dependent initialization functions + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mach.h" + +/* These symbols are all defined in the linker map to delineate various + statically allocated regions of memory. */ + +extern char _intv_start, _intv_end; +/* `kram' is only used if the kernel uses part of normal user RAM. */ +extern char _kram_start __attribute__ ((__weak__)); +extern char _kram_end __attribute__ ((__weak__)); +extern char _init_start, _init_end; +extern char _bootmap; +extern char _stext, _etext, _sdata, _edata, _sbss, _ebss; +/* Many platforms use an embedded root image. */ +extern char _root_fs_image_start __attribute__ ((__weak__)); +extern char _root_fs_image_end __attribute__ ((__weak__)); + + +char command_line[512]; +char saved_command_line[512]; + +/* Memory not used by the kernel. */ +static unsigned long total_ram_pages; + +/* System RAM. */ +static unsigned long ram_start = 0, ram_len = 0; + + +#define ADDR_TO_PAGE_UP(x) ((((unsigned long)x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#define ADDR_TO_PAGE(x) (((unsigned long)x) >> PAGE_SHIFT) +#define PAGE_TO_ADDR(x) (((unsigned long)x) << PAGE_SHIFT) + +static void init_mem_alloc (unsigned long ram_start, unsigned long ram_len); + +void set_mem_root (void *addr, size_t len, char *cmd_line); + + +void __init setup_arch (char **cmdline) +{ + /* Keep a copy of command line */ + *cmdline = command_line; + memcpy (saved_command_line, command_line, sizeof saved_command_line); + saved_command_line[sizeof saved_command_line - 1] = '\0'; + + console_verbose (); + + init_mm.start_code = (unsigned long) &_stext; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_kram_end; + + /* Find out what mem this machine has. */ + mach_get_physical_ram (&ram_start, &ram_len); + /* ... and tell the kernel about it. */ + init_mem_alloc (ram_start, ram_len); + + /* do machine-specific setups. */ + mach_setup (cmdline); + +#ifdef CONFIG_MTD + if (!ROOT_DEV && &_root_fs_image_end > &_root_fs_image_start) + set_mem_root (&_root_fs_image_start, + &_root_fs_image_end - &_root_fs_image_start, + *cmdline); +#endif +} + +void __init trap_init (void) +{ +} + +#ifdef CONFIG_MTD +/* Set the root filesystem to be the given memory region. + Some parameter may be appended to CMD_LINE. */ +void set_mem_root (void *addr, size_t len, char *cmd_line) +{ + /* The only way to pass info to the MTD slram driver is via + the command line. */ + if (*cmd_line) { + cmd_line += strlen (cmd_line); + *cmd_line++ = ' '; + } + sprintf (cmd_line, "slram=root,0x%x,+0x%x", (u32)addr, (u32)len); + + ROOT_DEV = MKDEV (MTD_BLOCK_MAJOR, 0); +} +#endif + + +static void irq_nop (unsigned irq) { } +static unsigned irq_zero (unsigned irq) { return 0; } + +static void nmi_end (unsigned irq) +{ + if (irq != IRQ_NMI (0)) { + printk (KERN_CRIT "NMI %d is unrecoverable; restarting...", + irq - IRQ_NMI (0)); + machine_restart (0); + } +} + +static struct hw_interrupt_type nmi_irq_type = { + "NMI", + irq_zero, /* startup */ + irq_nop, /* shutdown */ + irq_nop, /* enable */ + irq_nop, /* disable */ + irq_nop, /* ack */ + nmi_end, /* end */ +}; + +void __init init_IRQ (void) +{ + init_irq_handlers (0, NUM_MACH_IRQS, 1, 0); + init_irq_handlers (IRQ_NMI (0), NUM_NMIS, 1, &nmi_irq_type); + mach_init_irqs (); +} + + +void __init mem_init (void) +{ + max_mapnr = MAP_NR (ram_start + ram_len); + + num_physpages = ADDR_TO_PAGE (ram_len); + + total_ram_pages = free_all_bootmem (); + + printk (KERN_INFO + "Memory: %luK/%luK available" + " (%luK kernel code, %luK data)\n", + PAGE_TO_ADDR (nr_free_pages()) / 1024, + ram_len / 1024, + ((unsigned long)&_etext - (unsigned long)&_stext) / 1024, + ((unsigned long)&_ebss - (unsigned long)&_sdata) / 1024); +} + +void free_initmem (void) +{ + unsigned long ram_end = ram_start + ram_len; + unsigned long start = PAGE_ALIGN ((unsigned long)(&_init_start)); + + if (start >= ram_start && start < ram_end) { + unsigned long addr; + unsigned long end = PAGE_ALIGN ((unsigned long)(&_init_end)); + + if (end > ram_end) + end = ram_end; + + printk("Freeing unused kernel memory: %ldK freed\n", + (end - start) / 1024); + + for (addr = start; addr < end; addr += PAGE_SIZE) { + struct page *page = virt_to_page (addr); + ClearPageReserved (page); + set_page_count (page, 1); + __free_page (page); + total_ram_pages++; + } + } +} + + +/* Initialize the `bootmem allocator'. RAM_START and RAM_LEN identify + what RAM may be used. */ +static void __init +init_bootmem_alloc (unsigned long ram_start, unsigned long ram_len) +{ + /* The part of the kernel that's in the same managed RAM space + used for general allocation. */ + unsigned long kram_start = (unsigned long)&_kram_start; + unsigned long kram_end = (unsigned long)&_kram_end; + /* End of the managed RAM space. */ + unsigned long ram_end = ram_start + ram_len; + /* Address range of the interrupt vector table. */ + unsigned long intv_start = (unsigned long)&_intv_start; + unsigned long intv_end = (unsigned long)&_intv_end; + /* True if the interrupt vectors are in the managed RAM area. */ + int intv_in_ram = (intv_end > ram_start && intv_start < ram_end); + /* True if the interrupt vectors are inside the kernel's RAM. */ + int intv_in_kram = (intv_end > kram_start && intv_start < kram_end); + /* A pointer to an optional function that reserves platform-specific + memory regions. We declare the pointer `volatile' to avoid gcc + turning the call into a static call (the problem is that since + it's a weak symbol, a static call may end up trying to reference + the location 0x0, which is not always reachable). */ + void (*volatile mrb) (void) = mach_reserve_bootmem; + /* The bootmem allocator's allocation bitmap. */ + unsigned long bootmap = (unsigned long)&_bootmap; + unsigned long bootmap_len; + + /* Round bootmap location up to next page. */ + bootmap = PAGE_TO_ADDR (ADDR_TO_PAGE_UP (bootmap)); + + /* Initialize bootmem allocator. */ + bootmap_len = init_bootmem_node (NODE_DATA (0), + ADDR_TO_PAGE (bootmap), + ADDR_TO_PAGE (PAGE_OFFSET), + ADDR_TO_PAGE (ram_end)); + + /* Now make the RAM actually allocatable (it starts out `reserved'). */ + free_bootmem (ram_start, ram_len); + + if (kram_end > kram_start) + /* Reserve the RAM part of the kernel's address space, so it + doesn't get allocated. */ + reserve_bootmem (kram_start, kram_end - kram_start); + + if (intv_in_ram && !intv_in_kram) + /* Reserve the interrupt vector space. */ + reserve_bootmem (intv_start, intv_end - intv_start); + + if (bootmap >= ram_start && bootmap < ram_end) + /* Reserve the bootmap space. */ + reserve_bootmem (bootmap, bootmap_len); + + /* Reserve the memory used by the root filesystem image if it's + in RAM. */ + if (&_root_fs_image_end > &_root_fs_image_start + && (unsigned long)&_root_fs_image_start >= ram_start + && (unsigned long)&_root_fs_image_start < ram_end) + reserve_bootmem ((unsigned long)&_root_fs_image_start, + &_root_fs_image_end - &_root_fs_image_start); + + /* Let the platform-dependent code reserve some too. */ + if (mrb) + (*mrb) (); +} + +/* Tell the kernel about what RAM it may use for memory allocation. */ +static void __init +init_mem_alloc (unsigned long ram_start, unsigned long ram_len) +{ + unsigned i; + unsigned long zones_size[MAX_NR_ZONES]; + + init_bootmem_alloc (ram_start, ram_len); + + for (i = 0; i < MAX_NR_ZONES; i++) + zones_size[i] = 0; + + /* We stuff all the memory into one area, which includes the + initial gap from PAGE_OFFSET to ram_start. */ + zones_size[ZONE_DMA] + = ADDR_TO_PAGE (ram_len + (ram_start - PAGE_OFFSET)); + + free_area_init_node (0, NODE_DATA(0), 0, zones_size, + ADDR_TO_PAGE (PAGE_OFFSET), 0); + mem_map = NODE_DATA(0)->node_mem_map; +} diff -Nru a/arch/v850/kernel/signal.c b/arch/v850/kernel/signal.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/signal.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,523 @@ +/* + * arch/v850/kernel/signal.c -- Signal handling + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * Copyright (C) 1999,2000,2002 Niibe Yutaka & Kaz Kojima + * Copyright (C) 1991,1992 Linus Torvalds + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson + * + * This file was derived from the sh version, arch/sh/kernel/signal.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define DEBUG_SIG 0 + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +asmlinkage int +sys_sigsuspend(old_sigset_t mask, struct pt_regs *regs) +{ + sigset_t saveset; + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sig->siglock); + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + spin_unlock_irq(¤t->sig->siglock); + + regs->gpr[GPR_RVAL] = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(regs, &saveset)) + return -EINTR; + } +} + +asmlinkage int +sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, + struct pt_regs *regs) +{ + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + spin_lock_irq(¤t->sig->siglock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(); + spin_unlock_irq(¤t->sig->siglock); + + regs->gpr[GPR_RVAL] = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(regs, &saveset)) + return -EINTR; + } +} + +asmlinkage int +sys_sigaction(int sig, const struct old_sigaction *act, + struct old_sigaction *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +asmlinkage int +sys_sigaltstack(const stack_t *uss, stack_t *uoss, + struct pt_regs *regs) +{ + return do_sigaltstack(uss, uoss, regs->gpr[GPR_SP]); +} + + +/* + * Do a signal return; undo the signal stack. + */ + +struct sigframe +{ + struct sigcontext sc; + unsigned long extramask[_NSIG_WORDS-1]; + unsigned long tramp[2]; /* signal trampoline */ +}; + +struct rt_sigframe +{ + struct siginfo *pinfo; + void *puc; + struct siginfo info; + struct ucontext uc; + unsigned long tramp[2]; /* signal trampoline */ +}; + +static int +restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *rval_p) +{ + unsigned int err = 0; + +#define COPY(x) err |= __get_user(regs->x, &sc->regs.x) + COPY(gpr[0]); COPY(gpr[1]); COPY(gpr[2]); COPY(gpr[3]); + COPY(gpr[4]); COPY(gpr[5]); COPY(gpr[6]); COPY(gpr[7]); + COPY(gpr[8]); COPY(gpr[9]); COPY(gpr[10]); COPY(gpr[11]); + COPY(gpr[12]); COPY(gpr[13]); COPY(gpr[14]); COPY(gpr[15]); + COPY(gpr[16]); COPY(gpr[17]); COPY(gpr[18]); COPY(gpr[19]); + COPY(gpr[20]); COPY(gpr[21]); COPY(gpr[22]); COPY(gpr[23]); + COPY(gpr[24]); COPY(gpr[25]); COPY(gpr[26]); COPY(gpr[27]); + COPY(gpr[28]); COPY(gpr[29]); COPY(gpr[30]); COPY(gpr[31]); + COPY(pc); COPY(psw); + COPY(ctpc); COPY(ctpsw); COPY(ctbp); +#undef COPY + + return err; +} + +asmlinkage int sys_sigreturn(struct pt_regs *regs) +{ + struct sigframe *frame = (struct sigframe *)regs->gpr[GPR_SP]; + sigset_t set; + int rval; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + + if (__get_user(set.sig[0], &frame->sc.oldmask) + || (_NSIG_WORDS > 1 + && __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sig->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sig->siglock); + + if (restore_sigcontext(regs, &frame->sc, &rval)) + goto badframe; + return rval; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) +{ + struct rt_sigframe *frame = (struct rt_sigframe *)regs->gpr[GPR_SP]; + sigset_t set; + stack_t st; + int rval; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sig->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sig->siglock); + + if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval)) + goto badframe; + + if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, regs->gpr[GPR_SP]); + + return rval; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +/* + * Set up a signal frame. + */ + +static int +setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, + unsigned long mask) +{ + int err = 0; + +#define COPY(x) err |= __put_user(regs->x, &sc->regs.x) + COPY(gpr[0]); COPY(gpr[1]); COPY(gpr[2]); COPY(gpr[3]); + COPY(gpr[4]); COPY(gpr[5]); COPY(gpr[6]); COPY(gpr[7]); + COPY(gpr[8]); COPY(gpr[9]); COPY(gpr[10]); COPY(gpr[11]); + COPY(gpr[12]); COPY(gpr[13]); COPY(gpr[14]); COPY(gpr[15]); + COPY(gpr[16]); COPY(gpr[17]); COPY(gpr[18]); COPY(gpr[19]); + COPY(gpr[20]); COPY(gpr[21]); COPY(gpr[22]); COPY(gpr[23]); + COPY(gpr[24]); COPY(gpr[25]); COPY(gpr[26]); COPY(gpr[27]); + COPY(gpr[28]); COPY(gpr[29]); COPY(gpr[30]); COPY(gpr[31]); + COPY(pc); COPY(psw); + COPY(ctpc); COPY(ctpsw); COPY(ctbp); +#undef COPY + + err |= __put_user(mask, &sc->oldmask); + + return err; +} + +/* + * Determine which stack to use.. + */ +static inline void * +get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) +{ + /* Default to using normal stack */ + unsigned long sp = regs->gpr[GPR_SP]; + + if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) + sp = current->sas_ss_sp + current->sas_ss_size; + + return (void *)((sp - frame_size) & -8UL); +} + +static void setup_frame(int sig, struct k_sigaction *ka, + sigset_t *set, struct pt_regs *regs) +{ + struct sigframe *frame; + int err = 0; + int signal; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + signal = current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig; + + err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); + + if (_NSIG_WORDS > 1) { + err |= __copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + } + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) { + regs->gpr[GPR_LP] = (unsigned long) ka->sa.sa_restorer; + } else { + /* Note, these encodings are _little endian_! */ + + /* addi __NR_sigreturn, r0, r12 */ + err |= __put_user(0x6600 | (__NR_sigreturn << 16), + frame->tramp + 0); + /* trap 0 */ + err |= __put_user(0x010007e0, + frame->tramp + 1); + + regs->gpr[GPR_LP] = (unsigned long)frame->tramp; + + flush_cache_sigtramp (regs->gpr[GPR_LP]); + } + + if (err) + goto give_sigsegv; + + /* Set up registers for signal handler */ + regs->gpr[GPR_SP] = (unsigned long) frame; + regs->gpr[GPR_ARG0] = signal; /* Arg for signal handler */ + regs->pc = (unsigned long) ka->sa.sa_handler; + + set_fs(USER_DS); + +#if DEBUG_SIG + printk("SIG deliver (%s:%d): sp=%p pc=%08lx ra=%08lx\n", + current->comm, current->pid, frame, regs->pc, ); +#endif + + return; + +give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); +} + +static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + struct rt_sigframe *frame; + int err = 0; + int signal; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + signal = current_thread_info()->exec_domain + && current_thread_info()->exec_domain->signal_invmap + && sig < 32 + ? current_thread_info()->exec_domain->signal_invmap[sig] + : sig; + + err |= __put_user(&frame->info, &frame->pinfo); + err |= __put_user(&frame->uc, &frame->puc); + err |= copy_siginfo_to_user(&frame->info, info); + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user((void *)current->sas_ss_sp, + &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->gpr[GPR_SP]), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.uc_mcontext, + regs, set->sig[0]); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) { + regs->gpr[GPR_LP] = (unsigned long) ka->sa.sa_restorer; + } else { + /* Note, these encodings are _little endian_! */ + + /* addi __NR_sigreturn, r0, r12 */ + err |= __put_user(0x6600 | (__NR_sigreturn << 16), + frame->tramp + 0); + /* trap 0 */ + err |= __put_user(0x010007e0, + frame->tramp + 1); + + regs->gpr[GPR_LP] = (unsigned long)frame->tramp; + + flush_cache_sigtramp (regs->gpr[GPR_LP]); + } + + if (err) + goto give_sigsegv; + + /* Set up registers for signal handler */ + regs->gpr[GPR_SP] = (unsigned long) frame; + regs->gpr[GPR_ARG0] = signal; /* Arg for signal handler */ + regs->pc = (unsigned long) ka->sa.sa_handler; + + set_fs(USER_DS); + +#if DEBUG_SIG + printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", + current->comm, current->pid, frame, regs->pc, regs->pr); +#endif + + return; + +give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); +} + +/* + * OK, we're invoking a handler + */ + +static void +handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, + struct pt_regs * regs) +{ + struct k_sigaction *ka = ¤t->sig->action[sig-1]; + + /* Are we from a system call? */ + if (PT_REGS_SYSCALL (regs)) { + /* If so, check system call restarting.. */ + switch (regs->gpr[GPR_RVAL]) { + case -ERESTARTNOHAND: + regs->gpr[GPR_RVAL] = -EINTR; + break; + + case -ERESTARTSYS: + if (!(ka->sa.sa_flags & SA_RESTART)) { + regs->gpr[GPR_RVAL] = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + regs->gpr[12] = PT_REGS_SYSCALL (regs); + regs->pc -= 4; /* Size of `trap 0' insn. */ + } + + PT_REGS_SET_SYSCALL (regs, 0); + } + + /* Set up the stack frame */ + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(sig, ka, info, oldset, regs); + else + setup_frame(sig, ka, oldset, regs); + + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + + if (!(ka->sa.sa_flags & SA_NODEFER)) { + spin_lock_irq(¤t->sig->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sig->siglock); + } +} + +/* + * Note that 'init' is a special process: it doesn't get signals it doesn't + * want to handle. Thus you cannot kill init even with a SIGKILL even by + * mistake. + * + * Note that we go through the signals twice: once to check the signals that + * the kernel can handle, and then we build all the user-level signal handling + * stack-frames in one go after that. + */ +int do_signal(struct pt_regs *regs, sigset_t *oldset) +{ + siginfo_t info; + int signr; + + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from + * kernel mode. Just return without doing anything + * if so. + */ + if (!user_mode(regs)) + return 1; + + if (!oldset) + oldset = ¤t->blocked; + + signr = get_signal_to_deliver(&info, regs); + if (signr > 0) { + /* Whee! Actually deliver the signal. */ + handle_signal(signr, &info, oldset, regs); + return 1; + } + + /* Did we come from a system call? */ + if (PT_REGS_SYSCALL (regs)) { + /* Restart the system call - no handlers present */ + if (regs->gpr[GPR_RVAL] == -ERESTARTNOHAND || + regs->gpr[GPR_RVAL] == -ERESTARTSYS || + regs->gpr[GPR_RVAL] == -ERESTARTNOINTR) { + regs->gpr[12] = PT_REGS_SYSCALL (regs); + regs->pc -= 4; /* Size of `trap 0' insn. */ + } + } + return 0; +} diff -Nru a/arch/v850/kernel/sim.c b/arch/v850/kernel/sim.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/sim.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,174 @@ +/* + * arch/v850/kernel/sim.c -- Machine-specific stuff for GDB v850e simulator + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "mach.h" + +/* The name of a file containing the root filesystem. */ +#define ROOT_FS "rootfs.image" + +extern void simcons_setup (void); +extern void simcons_poll_ttys (void); +extern void set_mem_root (void *addr, size_t len, char *cmd_line); + +static int read_file (const char *name, + unsigned long *addr, unsigned long *len, + const char **err); + +void __init mach_setup (char **cmdline) +{ + const char *err; + unsigned long root_dev_addr, root_dev_len; + + printk (KERN_INFO "CPU: NEC V850E (GDB simulator)\n"); + + simcons_setup (); + + printk (KERN_INFO "Reading root filesystem: %s", ROOT_FS); + + if (read_file (ROOT_FS, &root_dev_addr, &root_dev_len, &err)) { + printk (" (size %luK)\n", root_dev_len / 1024); + set_mem_root ((void *)root_dev_addr, (size_t)root_dev_len, + *cmdline); + } else + printk ("...%s failed!\n", err); +} + +void mach_get_physical_ram (unsigned long *ram_start, unsigned long *ram_len) +{ + *ram_start = RAM_ADDR; + *ram_len = RAM_SIZE; +} + +void __init mach_sched_init (struct irqaction *timer_action) +{ + /* ...do magic timer initialization?... */ + mach_tick = simcons_poll_ttys; + setup_irq (0, timer_action); +} + + +static void irq_nop (unsigned irq) { } +static unsigned irq_zero (unsigned irq) { return 0; } + +static struct hw_interrupt_type sim_irq_type = { + "IRQ", + irq_zero, /* startup */ + irq_nop, /* shutdown */ + irq_nop, /* enable */ + irq_nop, /* disable */ + irq_nop, /* ack */ + irq_nop, /* end */ +}; + +void __init mach_init_irqs (void) +{ + init_irq_handlers (0, NUM_MACH_IRQS, 1, &sim_irq_type); +} + + +void mach_gettimeofday (struct timespec *tv) +{ + long timeval[2], timezone[2]; + int rval = V850_SIM_SYSCALL (gettimeofday, timeval, timezone); + if (rval == 0) { + tv->tv_sec = timeval[0]; + tv->tv_nsec = timeval[1] * 1000; + } +} + +void machine_restart (char *__unused) +{ + V850_SIM_SYSCALL (write, 1, "RESTART\n", 8); + V850_SIM_SYSCALL (exit, 0); +} + +void machine_halt (void) +{ + V850_SIM_SYSCALL (write, 1, "HALT\n", 5); + V850_SIM_SYSCALL (exit, 0); +} + +void machine_power_off (void) +{ + V850_SIM_SYSCALL (write, 1, "POWER OFF\n", 10); + V850_SIM_SYSCALL (exit, 0); +} + + +/* Load data from a file called NAME into ram. The address and length + of the data image are returned in ADDR and LEN. */ +static int __init +read_file (const char *name, + unsigned long *addr, unsigned long *len, + const char **err) +{ + int rval, fd; + unsigned long cur, left; + /* Note this is not a normal stat buffer, it's an ad-hoc + structure defined by the simulator. */ + unsigned long stat_buf[10]; + + /* Stat the file to find out the length. */ + rval = V850_SIM_SYSCALL (stat, name, stat_buf); + if (rval < 0) { + if (err) *err = "stat"; + return 0; + } + *len = stat_buf[4]; + + /* Open the file; `0' is O_RDONLY. */ + fd = V850_SIM_SYSCALL (open, name, 0); + if (fd < 0) { + if (err) *err = "open"; + return 0; + } + + *addr = (unsigned long)alloc_bootmem(*len); + if (! *addr) { + V850_SIM_SYSCALL (close, fd); + if (err) *err = "alloc_bootmem"; + return 0; + } + + cur = *addr; + left = *len; + while (left > 0) { + int chunk = V850_SIM_SYSCALL (read, fd, cur, left); + if (chunk <= 0) + break; + cur += chunk; + left -= chunk; + } + V850_SIM_SYSCALL (close, fd); + if (left > 0) { + /* Some read failed. */ + free_bootmem (*addr, *len); + if (err) *err = "read"; + return 0; + } + + return 1; +} diff -Nru a/arch/v850/kernel/sim85e2c.c b/arch/v850/kernel/sim85e2c.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/sim85e2c.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,147 @@ +/* + * arch/v850/kernel/sim85e2c.c -- Machine-specific stuff for + * V850E2 RTL simulator + * + * Copyright (C) 2002 NEC Corporation + * Copyright (C) 2002 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "mach.h" + +extern void memcons_setup (void); + + +void __init mach_early_init (void) +{ + extern int panic_timeout; + + /* Don't stop the simulator at `halt' instructions. */ + NOTHAL = 1; + + /* The sim85e2c simulator tracks `undefined' values, so to make + debugging easier, we begin by zeroing out all otherwise + undefined registers. This is not strictly necessary. + + The registers we zero are: + Every GPR except: + stack-pointer (r3) + task-pointer (r16) + our return addr (r31) + Every system register (SPR) that we know about except for + the PSW (SPR 5), which we zero except for the + disable-interrupts bit. + */ + + /* GPRs */ + asm volatile (" mov r0, r1 ; mov r0, r2 "); + asm volatile ("mov r0, r4 ; mov r0, r5 ; mov r0, r6 ; mov r0, r7 "); + asm volatile ("mov r0, r8 ; mov r0, r9 ; mov r0, r10; mov r0, r11"); + asm volatile ("mov r0, r12; mov r0, r13; mov r0, r14; mov r0, r15"); + asm volatile (" mov r0, r17; mov r0, r18; mov r0, r19"); + asm volatile ("mov r0, r20; mov r0, r21; mov r0, r22; mov r0, r23"); + asm volatile ("mov r0, r24; mov r0, r25; mov r0, r26; mov r0, r27"); + asm volatile ("mov r0, r28; mov r0, r29; mov r0, r30"); + + /* SPRs */ + asm volatile ("ldsr r0, 0; ldsr r0, 1; ldsr r0, 2; ldsr r0, 3"); + asm volatile ("ldsr r0, 4"); + asm volatile ("addi 0x20, r0, r1; ldsr r1, 5"); /* PSW */ + asm volatile ("ldsr r0, 16; ldsr r0, 17; ldsr r0, 18; ldsr r0, 19"); + asm volatile ("ldsr r0, 20"); + + /* Turn on the caches. */ + NA85E2C_CACHE_BTSC + |= (NA85E2C_CACHE_BTSC_ICM | NA85E2C_CACHE_BTSC_DCM0); + NA85E2C_BUSM_BHC = 0xFFFF; + + /* Ensure that the simulator halts on a panic, instead of going + into an infinite loop inside the panic function. */ + panic_timeout = -1; +} + +void __init mach_setup (char **cmdline) +{ + printk (KERN_INFO "CPU: NEC V850E2 (sim85e2c simulator)\n"); + + memcons_setup (); +} + +void mach_get_physical_ram (unsigned long *ram_start, unsigned long *ram_len) +{ + /* There are 3 possible areas we can use: + IRAM (1MB) is fast for instruction fetches, but slow for data + DRAM (1020KB) is fast for data, but slow for instructions + ERAM is cached, so should be fast for both insns and data, + _but_ currently only supports write-through caching, so + writes are slow. + Since there's really no area that's good for general kernel + use, we use DRAM -- it won't be good for user programs + (which will be loaded into kernel allocated memory), but + currently we're more concerned with testing the kernel. */ + *ram_start = DRAM_ADDR; + *ram_len = R0_RAM_ADDR - DRAM_ADDR; +} + +void __init mach_sched_init (struct irqaction *timer_action) +{ + /* The simulator actually cycles through all interrupts + periodically. We just pay attention to IRQ0, which gives us + 1/64 the rate of the periodic interrupts. */ + setup_irq (0, timer_action); +} + +void mach_gettimeofday (struct timespec *tv) +{ + tv->tv_sec = 0; + tv->tv_nsec = 0; +} + +/* Interrupts */ + +struct nb85e_intc_irq_init irq_inits[] = { + { "IRQ", 0, NUM_MACH_IRQS, 1, 7 }, + { 0 } +}; +struct hw_interrupt_type hw_itypes[1]; + +/* Initialize interrupts. */ +void __init mach_init_irqs (void) +{ + nb85e_intc_init_irq_types (irq_inits, hw_itypes); +} + + +void machine_halt (void) __attribute__ ((noreturn)); +void machine_halt (void) +{ + SIMFIN = 0; /* Halt immediately. */ + for (;;) {} +} + +void machine_restart (char *__unused) +{ + machine_halt (); +} + +void machine_power_off (void) +{ + machine_halt (); +} diff -Nru a/arch/v850/kernel/simcons.c b/arch/v850/kernel/simcons.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/simcons.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,158 @@ +/* + * arch/v850/kernel/simcons.c -- Console I/O for GDB v850e simulator + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* Low-level console. */ + +static void simcons_write (struct console *co, const char *buf, unsigned len) +{ + V850_SIM_SYSCALL (write, 1, buf, len); +} + +static int simcons_read (struct console *co, const char *buf, unsigned len) +{ + return V850_SIM_SYSCALL (read, 0, buf, len); +} + +static kdev_t simcons_device (struct console *c) +{ + return mk_kdev (TTY_MAJOR, 64 + c->index); +} + +static struct console simcons = +{ + .name = "simcons", + .write = simcons_write, + .read = simcons_read, + .device = simcons_device, + .flags = CON_PRINTBUFFER, + .index = -1, +}; + +/* Higher level TTY interface. */ + +static struct tty_struct *tty_table[1] = { 0 }; +static struct termios *tty_termios[1] = { 0 }; +static struct termios *tty_termios_locked[1] = { 0 }; +static struct tty_driver tty_driver = { 0 }; +static int tty_refcount = 0; + +int simcons_tty_open (struct tty_struct *tty, struct file *filp) +{ + return 0; +} + +int simcons_tty_write (struct tty_struct *tty, int from_user, + const unsigned char *buf, int count) +{ + return V850_SIM_SYSCALL (write, 1, buf, count); +} + +int simcons_tty_write_room (struct tty_struct *tty) +{ + /* Completely arbitrary. */ + return 0x100000; +} + +int simcons_tty_chars_in_buffer (struct tty_struct *tty) +{ + /* We have no buffer. */ + return 0; +} + +int __init simcons_tty_init (void) +{ + tty_driver.name = "simcons"; + tty_driver.major = TTY_MAJOR; + tty_driver.minor_start = 64; + tty_driver.num = 1; + tty_driver.type = TTY_DRIVER_TYPE_SYSCONS; + + tty_driver.refcount = &tty_refcount; + + tty_driver.table = tty_table; + tty_driver.termios = tty_termios; + tty_driver.termios_locked = tty_termios_locked; + + tty_driver.init_termios = tty_std_termios; + + tty_driver.open = simcons_tty_open; + tty_driver.write = simcons_tty_write; + tty_driver.write_room = simcons_tty_write_room; + tty_driver.chars_in_buffer = simcons_tty_chars_in_buffer; + + tty_register_driver (&tty_driver); +} +__initcall (simcons_tty_init); + +/* Poll for input on the console, and if there's any, deliver it to the + tty driver. */ +void simcons_poll_tty (struct tty_struct *tty) +{ + int flip = 0, send_break = 0; + struct pollfd pfd; + pfd.fd = 0; + pfd.events = POLLIN; + + if (V850_SIM_SYSCALL (poll, &pfd, 1, 0) > 0) { + if (pfd.revents & POLLIN) { + int left = TTY_FLIPBUF_SIZE - tty->flip.count; + + if (left > 0) { + unsigned char *buf = tty->flip.char_buf_ptr; + int rd = V850_SIM_SYSCALL (read, 0, buf, left); + + if (rd > 0) { + tty->flip.count += rd; + tty->flip.char_buf_ptr += rd; + memset (tty->flip.flag_buf_ptr, 0, rd); + tty->flip.flag_buf_ptr += rd; + flip = 1; + } else + send_break = 1; + } + } else if (pfd.revents & POLLERR) + send_break = 1; + } + + if (send_break) { + tty_insert_flip_char (tty, 0, TTY_BREAK); + flip = 1; + } + + if (flip) + tty_schedule_flip (tty); +} + +void simcons_poll_ttys (void) +{ + if (tty_table[0]) + simcons_poll_tty (tty_table[0]); +} + +void simcons_setup (void) +{ + V850_SIM_SYSCALL (make_raw, 0); + register_console (&simcons); + printk (KERN_INFO "Console: GDB/v850e simulator stdio\n"); +} diff -Nru a/arch/v850/kernel/syscalls.c b/arch/v850/kernel/syscalls.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/syscalls.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,197 @@ +/* + * arch/v850/kernel/syscalls.c -- Various system-call definitions not + * defined in machine-independent code + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * This file was derived the ppc version, arch/ppc/kernel/syscalls.c + * ... which was derived from "arch/i386/kernel/sys_i386.c" by Gary Thomas; + * modified by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras (paulus@cs.anu.edu.au). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. + */ +int +sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) +{ + int version, ret; + + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + ret = -EINVAL; + switch (call) { + case SEMOP: + ret = sys_semop (first, (struct sembuf *)ptr, second); + break; + case SEMGET: + ret = sys_semget (first, second, third); + break; + case SEMCTL: + { + union semun fourth; + + if (!ptr) + break; + if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long))) + || (ret = get_user(fourth.__pad, (void **)ptr))) + break; + ret = sys_semctl (first, second, third, fourth); + break; + } + case MSGSND: + ret = sys_msgsnd (first, (struct msgbuf *) ptr, second, third); + break; + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; + + if (!ptr) + break; + if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp))) + || (ret = copy_from_user(&tmp, + (struct ipc_kludge *) ptr, + sizeof (tmp)))) + break; + ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, + third); + break; + } + default: + ret = sys_msgrcv (first, (struct msgbuf *) ptr, + second, fifth, third); + break; + } + break; + case MSGGET: + ret = sys_msgget ((key_t) first, second); + break; + case MSGCTL: + ret = sys_msgctl (first, second, (struct msqid_ds *) ptr); + break; + case SHMAT: + switch (version) { + default: { + ulong raddr; + + if ((ret = verify_area(VERIFY_WRITE, (ulong*) third, + sizeof(ulong)))) + break; + ret = sys_shmat (first, (char *) ptr, second, &raddr); + if (ret) + break; + ret = put_user (raddr, (ulong *) third); + break; + } + case 1: /* iBCS2 emulator entry point */ + if (!segment_eq(get_fs(), get_ds())) + break; + ret = sys_shmat (first, (char *) ptr, second, + (ulong *) third); + break; + } + break; + case SHMDT: + ret = sys_shmdt ((char *)ptr); + break; + case SHMGET: + ret = sys_shmget (first, second, third); + break; + case SHMCTL: + ret = sys_shmctl (first, second, (struct shmid_ds *) ptr); + break; + } + + return ret; +} + +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way unix traditionally does this, though. + */ +int sys_pipe (int *fildes) +{ + int fd[2]; + int error; + + error = do_pipe (fd); + if (!error) { + if (copy_to_user (fildes, fd, 2*sizeof (int))) + error = -EFAULT; + } + return error; +} + +static inline unsigned long +do_mmap2 (unsigned long addr, size_t len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + struct file * file = NULL; + int ret = -EBADF; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (! (flags & MAP_ANONYMOUS)) { + if (!(file = fget (fd))) + goto out; + } + + down_write (¤t->mm->mmap_sem); + ret = do_mmap_pgoff (file, addr, len, prot, flags, pgoff); + up_write (¤t->mm->mmap_sem); + if (file) + fput (file); +out: + return ret; +} + +unsigned long sys_mmap2 (unsigned long addr, size_t len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + return do_mmap2 (addr, len, prot, flags, fd, pgoff); +} + +unsigned long sys_mmap (unsigned long addr, size_t len, + unsigned long prot, unsigned long flags, + unsigned long fd, off_t offset) +{ + int err = -EINVAL; + + if (offset & ~PAGE_MASK) + goto out; + + err = do_mmap2 (addr, len, prot, flags, fd, offset >> PAGE_SHIFT); +out: + return err; +} diff -Nru a/arch/v850/kernel/time.c b/arch/v850/kernel/time.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/time.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,193 @@ +/* + * linux/arch/v850/kernel/time.c -- Arch-dependent timer functions + * + * Copyright (C) 1991, 1992, 1995, 2001, 2002 Linus Torvalds + * + * This file contains the v850-specific time handling details. + * Most of the stuff is located in the machine specific files. + * + * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 + * "A Kernel Model for Precision Timekeeping" by Dave Mills + */ + +#include /* CONFIG_HEARTBEAT */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mach.h" + +u64 jiffies_64; + +#define TICK_SIZE (tick_nsec / 1000) + +static inline void do_profile (unsigned long pc) +{ + if (prof_buffer && current->pid) { + extern int _stext; + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + if (pc < prof_len) + ++prof_buffer[pc]; + else + /* + * Don't ignore out-of-bounds PC values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + ++prof_buffer[prof_len-1]; + } +} + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + */ +static void timer_interrupt (int irq, void *dummy, struct pt_regs *regs) +{ +#if 0 + /* last time the cmos clock got updated */ + static long last_rtc_update=0; +#endif + + /* may need to kick the hardware timer */ + if (mach_tick) + mach_tick (); + + do_timer (regs); + + if (! user_mode (regs)) + do_profile (regs->pc); + +#if 0 + /* + * If we have an externally synchronized Linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + */ + if ((time_status & STA_UNSYNC) == 0 && + xtime.tv_sec > last_rtc_update + 660 && + (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && + (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { + if (set_rtc_mmss (xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + } +#ifdef CONFIG_HEARTBEAT + /* use power LED as a heartbeat instead -- much more useful + for debugging -- based on the version for PReP by Cort */ + /* acts like an actual heart beat -- ie thump-thump-pause... */ + if (mach_heartbeat) { + static unsigned cnt = 0, period = 0, dist = 0; + + if (cnt == 0 || cnt == dist) + mach_heartbeat ( 1 ); + else if (cnt == 7 || cnt == dist+7) + mach_heartbeat ( 0 ); + + if (++cnt > period) { + cnt = 0; + /* The hyperbolic function below modifies the heartbeat period + * length in dependency of the current (5min) load. It goes + * through the points f(0)=126, f(1)=86, f(5)=51, + * f(inf)->30. */ + period = ((672<= 1000000) { + usec -= 1000000; + sec++; + } + + tv->tv_sec = sec; + tv->tv_usec = usec; +} + +void do_settimeofday (struct timeval *tv) +{ + write_lock_irq (&xtime_lock); + + /* This is revolting. We need to set the xtime.tv_nsec + * correctly. However, the value in this location is + * is value at the last tick. + * Discover what correction gettimeofday + * would have done, and then undo it! + */ +#if 0 + tv->tv_usec -= mach_gettimeoffset (); +#endif + + while (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + + xtime.tv_sec = tv->tv_sec; + xtime.tv_nsec = tv->tv_usec * 1000; + + time_adjust = 0; /* stop active adjtime () */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + + write_unlock_irq (&xtime_lock); +} + +static int timer_dev_id; +static struct irqaction timer_irqaction = { + timer_interrupt, + SA_INTERRUPT, + 0, + "timer", + &timer_dev_id, + NULL +}; + +void time_init (void) +{ + mach_gettimeofday (&xtime); + mach_sched_init (&timer_irqaction); +} diff -Nru a/arch/v850/kernel/v850_ksyms.c b/arch/v850/kernel/v850_ksyms.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/kernel/v850_ksyms.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +extern void *trap_table; +EXPORT_SYMBOL (trap_table); + +/* platform dependent support */ +extern void dump_thread (struct pt_regs *, struct user *); +EXPORT_SYMBOL (dump_thread); +EXPORT_SYMBOL (kernel_thread); +EXPORT_SYMBOL (__bug); + +/* Networking helper routines. */ +EXPORT_SYMBOL (csum_partial_copy); +EXPORT_SYMBOL (csum_partial_copy_from_user); +EXPORT_SYMBOL (ip_compute_csum); +EXPORT_SYMBOL (ip_fast_csum); + +/* string / mem functions */ +EXPORT_SYMBOL_NOVERS (strcpy); +EXPORT_SYMBOL_NOVERS (strncpy); +EXPORT_SYMBOL_NOVERS (strcat); +EXPORT_SYMBOL_NOVERS (strncat); +EXPORT_SYMBOL_NOVERS (strcmp); +EXPORT_SYMBOL_NOVERS (strncmp); +EXPORT_SYMBOL_NOVERS (strchr); +EXPORT_SYMBOL_NOVERS (strlen); +EXPORT_SYMBOL_NOVERS (strnlen); +EXPORT_SYMBOL_NOVERS (strpbrk); +EXPORT_SYMBOL_NOVERS (strtok); +EXPORT_SYMBOL_NOVERS (strrchr); +EXPORT_SYMBOL_NOVERS (strstr); +EXPORT_SYMBOL_NOVERS (memset); +EXPORT_SYMBOL_NOVERS (memcpy); +EXPORT_SYMBOL_NOVERS (memmove); +EXPORT_SYMBOL_NOVERS (memcmp); +EXPORT_SYMBOL_NOVERS (memscan); + +/* semaphores */ +EXPORT_SYMBOL_NOVERS (__down); +EXPORT_SYMBOL_NOVERS (__down_interruptible); +EXPORT_SYMBOL_NOVERS (__down_trylock); +EXPORT_SYMBOL_NOVERS (__up); + +/* + * libgcc functions - functions that are used internally by the + * compiler... (prototypes are not correct though, but that + * doesn't really matter since they're not versioned). + */ +extern void __ashldi3 (void); +extern void __ashrdi3 (void); +extern void __lshrdi3 (void); +extern void __muldi3 (void); +extern void __negdi2 (void); + +EXPORT_SYMBOL_NOVERS (__ashldi3); +EXPORT_SYMBOL_NOVERS (__ashrdi3); +EXPORT_SYMBOL_NOVERS (__lshrdi3); +EXPORT_SYMBOL_NOVERS (__muldi3); +EXPORT_SYMBOL_NOVERS (__negdi2); diff -Nru a/arch/v850/lib/Makefile b/arch/v850/lib/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/lib/Makefile Mon Nov 4 14:31:04 2002 @@ -0,0 +1,9 @@ +# +# arch/v850/lib/Makefile +# + +L_TARGET = lib.a +obj-y = ashrdi3.o ashldi3.o lshrdi3.o muldi3.o negdi2.o \ + checksum.o memcpy.o memset.o + +include $(TOPDIR)/Rules.make diff -Nru a/arch/v850/lib/ashldi3.c b/arch/v850/lib/ashldi3.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/lib/ashldi3.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,62 @@ +/* ashldi3.c extracted from gcc-2.95.2/libgcc2.c which is: */ +/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC 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 GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define BITS_PER_UNIT 8 + +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef int word_type __attribute__ ((mode (__word__))); + +struct DIstruct {SItype high, low;}; + +typedef union +{ + struct DIstruct s; + DItype ll; +} DIunion; + +DItype +__ashldi3 (DItype u, word_type b) +{ + DIunion w; + word_type bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof (SItype) * BITS_PER_UNIT) - b; + if (bm <= 0) + { + w.s.low = 0; + w.s.high = (USItype)uu.s.low << -bm; + } + else + { + USItype carries = (USItype)uu.s.low >> bm; + w.s.low = (USItype)uu.s.low << b; + w.s.high = ((USItype)uu.s.high << b) | carries; + } + + return w.ll; +} diff -Nru a/arch/v850/lib/ashrdi3.c b/arch/v850/lib/ashrdi3.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/lib/ashrdi3.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,63 @@ +/* ashrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */ +/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC 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 GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define BITS_PER_UNIT 8 + +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef int word_type __attribute__ ((mode (__word__))); + +struct DIstruct {SItype high, low;}; + +typedef union +{ + struct DIstruct s; + DItype ll; +} DIunion; + +DItype +__ashrdi3 (DItype u, word_type b) +{ + DIunion w; + word_type bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof (SItype) * BITS_PER_UNIT) - b; + if (bm <= 0) + { + /* w.s.high = 1..1 or 0..0 */ + w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1); + w.s.low = uu.s.high >> -bm; + } + else + { + USItype carries = (USItype)uu.s.high << bm; + w.s.high = uu.s.high >> b; + w.s.low = ((USItype)uu.s.low >> b) | carries; + } + + return w.ll; +} diff -Nru a/arch/v850/lib/checksum.c b/arch/v850/lib/checksum.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/lib/checksum.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,151 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * MIPS specific IP/TCP/UDP checksumming routines + * + * Authors: Ralf Baechle, + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * 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. + * + * $Id: checksum.c,v 1.1 2002/09/28 14:58:40 gerg Exp $ + */ +#include +#include +#include +#include +#include + +static inline unsigned short from32to16 (unsigned long sum) +{ + unsigned int result; + /* + %0 %1 + hsw %1, %0 H L L H + add %1, %0 H L H+L+C H+L + */ + asm ("hsw %1, %0; add %1, %0" : "=&r" (result) : "r" (sum)); + return result >> 16; +} + +static inline unsigned int do_csum(const unsigned char * buff, int len) +{ + int odd, count; + unsigned int result = 0; + + if (len <= 0) + goto out; + odd = 1 & (unsigned long) buff; + if (odd) { + result = be16_to_cpu(*buff); + len--; + buff++; + } + count = len >> 1; /* nr of 16-bit words.. */ + if (count) { + if (2 & (unsigned long) buff) { + result += *(unsigned short *) buff; + count--; + len -= 2; + buff += 2; + } + count >>= 1; /* nr of 32-bit words.. */ + if (count) { + unsigned int carry = 0; + do { + unsigned int w = *(unsigned int *) buff; + count--; + buff += 4; + result += carry; + result += w; + carry = (w > result); + } while (count); + result += carry; + result = (result & 0xffff) + (result >> 16); + } + if (len & 2) { + result += *(unsigned short *) buff; + buff += 2; + } + } + if (len & 1) + result += le16_to_cpu(*buff); + result = from32to16(result); + if (odd) + result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); +out: + return result; +} + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + */ +unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl) +{ + return ~do_csum(iph,ihl*4); +} + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ +unsigned short ip_compute_csum(const unsigned char * buff, int len) +{ + return ~do_csum(buff,len); +} + +/* + * computes a partial checksum, e.g. for TCP/UDP fragments + */ +unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum) +{ + unsigned int result = do_csum(buff, len); + + /* add in old sum, and carry.. */ + result += sum; + if(sum > result) + result += 1; + return result; +} + +/* + * copy while checksumming, otherwise like csum_partial + */ +unsigned int csum_partial_copy(const char *src, char *dst, + int len, unsigned int sum) +{ + /* + * It's 2:30 am and I don't feel like doing it real ... + * This is lots slower than the real thing (tm) + */ + sum = csum_partial(src, len, sum); + memcpy(dst, src, len); + + return sum; +} + +/* + * Copy from userspace and compute checksum. If we catch an exception + * then zero the rest of the buffer. + */ +unsigned int csum_partial_copy_from_user (const char *src, char *dst, + int len, unsigned int sum, + int *err_ptr) +{ + int missing; + + missing = copy_from_user(dst, src, len); + if (missing) { + memset(dst + len - missing, 0, missing); + *err_ptr = -EFAULT; + } + + return csum_partial(dst, len, sum); +} diff -Nru a/arch/v850/lib/lshrdi3.c b/arch/v850/lib/lshrdi3.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/lib/lshrdi3.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,62 @@ +/* lshrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */ +/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC 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 GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define BITS_PER_UNIT 8 + +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef int word_type __attribute__ ((mode (__word__))); + +struct DIstruct {SItype high, low;}; + +typedef union +{ + struct DIstruct s; + DItype ll; +} DIunion; + +DItype +__lshrdi3 (DItype u, word_type b) +{ + DIunion w; + word_type bm; + DIunion uu; + + if (b == 0) + return u; + + uu.ll = u; + + bm = (sizeof (SItype) * BITS_PER_UNIT) - b; + if (bm <= 0) + { + w.s.high = 0; + w.s.low = (USItype)uu.s.high >> -bm; + } + else + { + USItype carries = (USItype)uu.s.high << bm; + w.s.high = (USItype)uu.s.high >> b; + w.s.low = ((USItype)uu.s.low >> b) | carries; + } + + return w.ll; +} diff -Nru a/arch/v850/lib/memcpy.c b/arch/v850/lib/memcpy.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/lib/memcpy.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,97 @@ +/* + * arch/v850/lib/memcpy.c -- Memory copying + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include +#include + +#define CHUNK_SIZE 32 /* bytes */ +#define CHUNK_ALIGNED(addr) (((unsigned long)addr & 0x3) == 0) + +/* Note that this macro uses 8 call-clobbered registers (not including + R1), which are few enough so that the following functions don't need + to spill anything to memory. It also uses R1, which is nominally + reserved for the assembler, but here it should be OK. */ +#define COPY_CHUNK(src, dst) \ + asm ("mov %0, ep;" \ + "sld.w 0[ep], r1; sld.w 4[ep], r12;" \ + "sld.w 8[ep], r13; sld.w 12[ep], r14;" \ + "sld.w 16[ep], r15; sld.w 20[ep], r17;" \ + "sld.w 24[ep], r18; sld.w 28[ep], r19;" \ + "mov %1, ep;" \ + "sst.w r1, 0[ep]; sst.w r12, 4[ep];" \ + "sst.w r13, 8[ep]; sst.w r14, 12[ep];" \ + "sst.w r15, 16[ep]; sst.w r17, 20[ep];" \ + "sst.w r18, 24[ep]; sst.w r19, 28[ep]" \ + :: "r" (src), "r" (dst) \ + : "r1", "r12", "r13", "r14", "r15", \ + "r17", "r18", "r19", "ep", "memory"); + +void *memcpy (void *dst, const void *src, __kernel_size_t size) +{ + char *_dst = dst; + const char *_src = src; + + if (size >= CHUNK_SIZE && CHUNK_ALIGNED(_src) && CHUNK_ALIGNED(_dst)) { + /* Copy large blocks efficiently. */ + unsigned count; + for (count = size / CHUNK_SIZE; count; count--) { + COPY_CHUNK (_src, _dst); + _src += CHUNK_SIZE; + _dst += CHUNK_SIZE; + } + size %= CHUNK_SIZE; + } + + if (size > 0) + do + *_dst++ = *_src++; + while (--size); + + return dst; +} + +void bcopy (const char *src, char *dst, int size) +{ + memcpy (dst, src, size); +} + +void *memmove (void *dst, const void *src, __kernel_size_t size) +{ + if ((unsigned long)dst < (unsigned long)src + || (unsigned long)src + size < (unsigned long)dst) + return memcpy (dst, src, size); + else { + char *_dst = dst + size; + const char *_src = src + size; + + if (size >= CHUNK_SIZE + && CHUNK_ALIGNED (_src) && CHUNK_ALIGNED (_dst)) + { + /* Copy large blocks efficiently. */ + unsigned count; + for (count = size / CHUNK_SIZE; count; count--) { + _src -= CHUNK_SIZE; + _dst -= CHUNK_SIZE; + COPY_CHUNK (_src, _dst); + } + size %= CHUNK_SIZE; + } + + if (size > 0) + do + *--_dst = *--_src; + while (--size); + + return _dst; + } +} diff -Nru a/arch/v850/lib/memset.c b/arch/v850/lib/memset.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/lib/memset.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,61 @@ +/* + * arch/v850/lib/memset.c -- Memory initialization + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#include + +void *memset (void *dst, int val, __kernel_size_t count) +{ + if (count) { + register unsigned loop; + register void *ptr asm ("ep") = dst; + + /* replicate VAL into a long. */ + val &= 0xff; + val |= val << 8; + val |= val << 16; + + /* copy initial unaligned bytes. */ + if ((long)ptr & 1) { + *((char *)ptr)++ = val; + count--; + } + if (count > 2 && ((long)ptr & 2)) { + *((short *)ptr)++ = val; + count -= 2; + } + + /* 32-byte copying loop. */ + for (loop = count / 32; loop; loop--) { + asm ("sst.w %0, 0[ep]; sst.w %0, 4[ep];" + "sst.w %0, 8[ep]; sst.w %0, 12[ep];" + "sst.w %0, 16[ep]; sst.w %0, 20[ep];" + "sst.w %0, 24[ep]; sst.w %0, 28[ep]" + :: "r" (val) : "memory"); + ptr += 32; + } + count %= 32; + + /* long copying loop. */ + for (loop = count / 4; loop; loop--) + *((long *)ptr)++ = val; + count %= 4; + + /* finish up with any trailing bytes. */ + if (count & 2) + *((short *)ptr)++ = val; + if (count & 1) + *(char *)ptr = val; + } + + return dst; +} diff -Nru a/arch/v850/lib/muldi3.c b/arch/v850/lib/muldi3.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/lib/muldi3.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,61 @@ +/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and + gcc-2.7.2.3/longlong.h which is: */ +/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 2001 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC 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 GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("mulu %3, %0, %1" \ + : "=r" ((USItype)(w0)), \ + "=r" ((USItype)(w1)) \ + : "%0" ((USItype)(u)), \ + "r" ((USItype)(v))) + +#define __umulsidi3(u, v) \ + ({DIunion __w; \ + umul_ppmm (__w.s.high, __w.s.low, u, v); \ + __w.ll; }) + +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef int word_type __attribute__ ((mode (__word__))); + +struct DIstruct {SItype high, low;}; + +typedef union +{ + struct DIstruct s; + DItype ll; +} DIunion; + +DItype +__muldi3 (DItype u, DItype v) +{ + DIunion w; + DIunion uu, vv; + + uu.ll = u, + vv.ll = v; + + w.ll = __umulsidi3 (uu.s.low, vv.s.low); + w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high + + (USItype) uu.s.high * (USItype) vv.s.low); + + return w.ll; +} diff -Nru a/arch/v850/lib/negdi2.c b/arch/v850/lib/negdi2.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/lib/negdi2.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,25 @@ +/* + * arch/v850/lib/negdi2.c -- 64-bit negation + * + * Copyright (C) 2001 NEC Corporation + * Copyright (C) 2001 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +typedef int DItype __attribute__ ((mode (DI))); + +DItype __negdi2 (DItype x) +{ + __asm__ __volatile__ + ("not r6, r10;" + "add 1, r10;" + "setf c, r6;" + "not r7, r11;" + "add r6, r11" + ::: "r6", "r7", "r10", "r11"); +} diff -Nru a/arch/v850/rte_ma1_cb-ksram.ld b/arch/v850/rte_ma1_cb-ksram.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/rte_ma1_cb-ksram.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,152 @@ +/* Linker script for the Midas labs RTE-V850E/MA1-CB evaluation board + (CONFIG_RTE_CB_MA1), with kernel in SRAM, under Multi debugger. */ + +/* Note, all symbols are prefixed with an extra `_' for compatibility with + the existing linux sources. */ + +_jiffies = _jiffies_64 ; + +MEMORY { + /* 1MB of SRAM; we can't use the last 32KB, because it's used by + the monitor scratch-RAM. This memory is mirrored 4 times. */ + SRAM : ORIGIN = 0x00400000, LENGTH = 0x000F8000 + /* Monitor scratch RAM; only the interrupt vectors should go here. */ + MRAM : ORIGIN = 0x004F8000, LENGTH = 0x00008000 + /* 32MB of SDRAM. */ + SDRAM : ORIGIN = 0x00800000, LENGTH = 0x02000000 +} + +SECTIONS { + .text : { + __kram_start = . ; + + __stext = . ; + *(.text) + *(.exit.text) /* 2.5 convention */ + *(.text.exit) /* 2.4 convention */ + *(.text.lock) + *(.exitcall.exit) + __real_etext = . ; /* There may be data after here. */ + *(.rodata) + + . = ALIGN (0x4) ; + *(.kstrtab) + + . = ALIGN (4) ; + *(.call_table_data) + *(.call_table_text) + + . = ALIGN (16) ; /* Exception table. */ + ___start___ex_table = . ; + *(__ex_table) + ___stop___ex_table = . ; + + ___start___ksymtab = . ;/* Kernel symbol table. */ + *(__ksymtab) + ___stop___ksymtab = . ; + . = ALIGN (4) ; + __etext = . ; + } > SRAM + + .data ALIGN (0x4) : { + __sdata = . ; + ___data_start = . ; + *(.data) + *(.exit.data) /* 2.5 convention */ + *(.data.exit) /* 2.4 convention */ + . = ALIGN (16) ; + *(.data.cacheline_aligned) + . = ALIGN (0x2000) ; + *(.data.init_task) + . = ALIGN (0x2000) ; + __edata = . ; + } > SRAM + + .bss ALIGN (0x4) : { + __sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN (4) ; + __init_stack_end = . ; + __ebss = . ; + } > SRAM + + .init ALIGN (4096) : { + __init_start = . ; + *(.init.text) /* 2.5 convention */ + *(.init.data) + *(.text.init) /* 2.4 convention */ + *(.data.init) + . = ALIGN (16) ; + ___setup_start = . ; + *(.init.setup) /* 2.5 convention */ + *(.setup.init) /* 2.4 convention */ + ___setup_end = . ; + ___initcall_start = . ; + *(.initcall.init) + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + . = ALIGN (4) ; + ___initcall_end = . ; + } > SRAM + + /* This provides address at which the interrupt vectors are + initially loaded by the loader. */ + __intv_load_start = ALIGN (0x10) ; + + /* Interrupt vector space. Because we're using the monitor + ROM, Instead of the native interrupt vector, we must use the + `alternate interrupt vector' area. Note that this is in + `SRAM' space, which is not currently used by the kernel (the + kernel uses `SDRAM' space). */ + + /* We can't load the interrupt vectors directly into their + target location, because the monitor ROM for the GHS Multi + debugger barfs if we try. Unfortunately, Multi also doesn't + deal correctly with ELF sections where the LMA and VMA differ + (it just ignores the LMA), so we can't use that feature to + work around the problem! What we do instead is just put the + interrupt vectors into a normal section, and have the + `mach_early_init' function for Midas boards do the necessary + copying and relocation at runtime (this section basically + only contains `jr' instructions, so it's not that hard). + + This the section structure I initially tried to use (which more + accurately expresses the intent): + + .intv 0x007F8000 : AT (ADDR (.init) + SIZEOF (.init)) { + ... + } > MRAM + */ + + .intv ALIGN (0x10) : { + __intv_start = . ; + *(.intv.reset) /* Reset vector */ + *(.intv.common) /* Vectors common to all v850e proc. */ + *(.intv.mach) /* Machine-specific int. vectors. */ + __intv_end = . ; + + /* This is here so that when we free init memory, the initial + load-area of the interrupt vectors is freed too. */ + __init_end = __intv_end; + + __kram_end = __init_end ; + } > SRAM + + .bootmap ALIGN (4096) : { + __bootmap = . ; + . = . + 4096 ; /* enough for 128MB. */ + } > SRAM + + /* Device contents for the root filesystem. */ + .root : { + __root_fs_image_start = . ; + *(.root) + __root_fs_image_end = . ; + } > SDRAM +} diff -Nru a/arch/v850/rte_ma1_cb-rom.ld b/arch/v850/rte_ma1_cb-rom.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/rte_ma1_cb-rom.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,115 @@ +/* Linker script for the Midas labs RTE-V850E/MA1-CB evaluation board + (CONFIG_RTE_CB_MA1), with kernel in ROM. */ + +/* Note, all symbols are prefixed with an extra `_' for compatibility with + the existing linux sources. */ + +_jiffies = _jiffies_64 ; + +MEMORY { + ROM : ORIGIN = 0x00000000, LENGTH = 0x00100000 + /* 1MB of SRAM. This memory is mirrored 4 times. */ + SRAM : ORIGIN = 0x00400000, LENGTH = 0x00100000 + /* 32MB of SDRAM. */ + SDRAM : ORIGIN = 0x00800000, LENGTH = 0x02000000 +} + +SECTIONS { + /* Interrupt vector space. */ + .intv { + __intv_start = . ; + *(.intv.reset) /* Reset vector */ + *(.intv.common) /* Vectors common to all v850e proc. */ + *(.intv.mach) /* Machine-specific int. vectors. */ + __intv_end = . ; + } > ROM + + .text : { + __stext = . ; + *(.text) + *(.exit.text) /* 2.5 convention */ + *(.text.exit) /* 2.4 convention */ + *(.text.lock) + *(.exitcall.exit) + __real_etext = . ; /* There may be data after here. */ + *(.rodata) + . = ALIGN (0x4) ; + *(.kstrtab) + . = ALIGN (16) ; /* Exception table. */ + ___start___ex_table = . ; + *(__ex_table) + ___stop___ex_table = . ; + + ___start___ksymtab = . ;/* Kernel symbol table. */ + *(__ksymtab) + ___stop___ksymtab = . ; + . = ALIGN (4) ; + __etext = . ; + } > ROM + + __data_load_start = . ; + + .data : { + __kram_start = . ; + + __sdata = . ; + ___data_start = . ; + *(.data) + *(.exit.data) /* 2.5 convention */ + *(.data.exit) /* 2.4 convention */ + . = ALIGN (16) ; + *(.data.cacheline_aligned) + . = ALIGN (0x2000) ; + *(.data.init_task) + . = ALIGN (0x2000) ; + __edata = . ; + } > SRAM AT> ROM + + .bss ALIGN (0x4) : { + __sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN (4) ; + __init_stack_end = . ; + __ebss = . ; + } > SRAM + + .init ALIGN (4096) : { + __init_start = . ; + *(.init.text) /* 2.5 convention */ + *(.init.data) + *(.text.init) /* 2.4 convention */ + *(.data.init) + . = ALIGN (16) ; + ___setup_start = . ; + *(.init.setup) /* 2.5 convention */ + *(.setup.init) /* 2.4 convention */ + ___setup_end = . ; + ___initcall_start = . ; + *(.initcall.init) + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + . = ALIGN (4) ; + ___initcall_end = . ; + __init_end = . ; + + __kram_end = . ; + } > SRAM + + .bootmap ALIGN (4096) : { + __bootmap = . ; + . = . + 4096 ; /* enough for 128MB. */ + } > SRAM + + /* device contents for the root filesystem. */ + .root ALIGN (4096) { + __root_fs_image_start = . ; + *(.root) + __root_fs_image_end = . ; + } > SDRAM +} diff -Nru a/arch/v850/rte_ma1_cb.ld b/arch/v850/rte_ma1_cb.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/rte_ma1_cb.ld Mon Nov 4 14:31:03 2002 @@ -0,0 +1,152 @@ +/* Linker script for the Midas labs RTE-V850E/MA1-CB evaluation board + (CONFIG_RTE_CB_MA1), with kernel in SDRAM, under Multi debugger. */ + +/* Note, all symbols are prefixed with an extra `_' for compatibility with + the existing linux sources. */ + +_jiffies = _jiffies_64 ; + +MEMORY { + /* 1MB of SRAM; we can't use the last 32KB, because it's used by + the monitor scratch-RAM. This memory is mirrored 4 times. */ + SRAM : ORIGIN = 0x00400000, LENGTH = 0x000F8000 + /* Monitor scratch RAM; only the interrupt vectors should go here. */ + MRAM : ORIGIN = 0x004F8000, LENGTH = 0x00008000 + /* 32MB of SDRAM. */ + SDRAM : ORIGIN = 0x00800000, LENGTH = 0x02000000 +} + +SECTIONS { + .bootmap : { + __bootmap = . ; + . = . + 4096 ; /* enough for 128MB. */ + } > SRAM + + .text : { + __kram_start = . ; + + __stext = . ; + *(.text) + *(.exit.text) /* 2.5 convention */ + *(.text.exit) /* 2.4 convention */ + *(.text.lock) + *(.exitcall.exit) + __real_etext = . ; /* There may be data after here. */ + *(.rodata) + + . = ALIGN (0x4) ; + *(.kstrtab) + + . = ALIGN (4) ; + *(.call_table_data) + *(.call_table_text) + + . = ALIGN (16) ; /* Exception table. */ + ___start___ex_table = . ; + *(__ex_table) + ___stop___ex_table = . ; + + ___start___ksymtab = . ;/* Kernel symbol table. */ + *(__ksymtab) + ___stop___ksymtab = . ; + . = ALIGN (4) ; + __etext = . ; + } > SDRAM + + .data ALIGN (0x4) : { + __sdata = . ; + ___data_start = . ; + *(.data) + *(.exit.data) /* 2.5 convention */ + *(.data.exit) /* 2.4 convention */ + . = ALIGN (16) ; + *(.data.cacheline_aligned) + . = ALIGN (0x2000) ; + *(.data.init_task) + . = ALIGN (0x2000) ; + __edata = . ; + } > SDRAM + + .bss ALIGN (0x4) : { + __sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN (4) ; + __init_stack_end = . ; + __ebss = . ; + } > SDRAM + + .init ALIGN (4096) : { + __init_start = . ; + *(.init.text) /* 2.5 convention */ + *(.init.data) + *(.text.init) /* 2.4 convention */ + *(.data.init) + . = ALIGN (16) ; + ___setup_start = . ; + *(.init.setup) /* 2.5 convention */ + *(.setup.init) /* 2.4 convention */ + ___setup_end = . ; + ___initcall_start = . ; + *(.initcall.init) + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + . = ALIGN (4) ; + ___initcall_end = . ; + } > SDRAM + + /* This provides address at which the interrupt vectors are + initially loaded by the loader. */ + __intv_load_start = ALIGN (0x10) ; + + /* Interrupt vector space. Because we're using the monitor + ROM, Instead of the native interrupt vector, we must use the + `alternate interrupt vector' area. Note that this is in + `SRAM' space, which is not currently used by the kernel (the + kernel uses `SDRAM' space). */ + + /* We can't load the interrupt vectors directly into their + target location, because the monitor ROM for the GHS Multi + debugger barfs if we try. Unfortunately, Multi also doesn't + deal correctly with ELF sections where the LMA and VMA differ + (it just ignores the LMA), so we can't use that feature to + work around the problem! What we do instead is just put the + interrupt vectors into a normal section, and have the + `mach_early_init' function for Midas boards do the necessary + copying and relocation at runtime (this section basically + only contains `jr' instructions, so it's not that hard). + + This the section structure I initially tried to use (which more + accurately expresses the intent): + + .intv 0x007F8000 : AT (ADDR (.init) + SIZEOF (.init)) { + ... + } > MRAM + */ + + .intv ALIGN (0x10) : { + __intv_start = . ; + *(.intv.reset) /* Reset vector */ + *(.intv.common) /* Vectors common to all v850e proc. */ + *(.intv.mach) /* Machine-specific int. vectors. */ + __intv_end = . ; + + /* This is here so that when we free init memory, the initial + load-area of the interrupt vectors is freed too. */ + __init_end = __intv_end; + + __kram_end = . ; + } > SDRAM + + /* Device contents for the root filesystem. */ + .root ALIGN (4096) : { + __root_fs_image_start = . ; + *(.root) + __root_fs_image_end = . ; + } > SDRAM +} diff -Nru a/arch/v850/sim.ld b/arch/v850/sim.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/sim.ld Mon Nov 4 14:31:03 2002 @@ -0,0 +1,108 @@ +/* Linker script for the gdb v850e simulator (CONFIG_V850E_SIM). */ + +/* Note, all symbols are prefixed with an extra `_' for compatibility with + the existing linux sources. */ + +_jiffies = _jiffies_64 ; + +MEMORY { + /* Interrupt vectors. */ + INTV : ORIGIN = 0x0, LENGTH = 0xe0 + /* 16MB of RAM. + This must match RAM_ADDR and RAM_SIZE in include/asm-v580/sim.h */ + RAM : ORIGIN = 0x8F000000, LENGTH = 0x01000000 +} + +SECTIONS { + .intv : { + __intv_start = . ; + *(.intv.reset) /* Reset vector */ + *(.intv.common) /* Vectors common to all v850e proc. */ + *(.intv.mach) /* Machine-specific int. vectors. */ + __intv_end = . ; + } > INTV + + .text : { + __kram_start = . ; + + __stext = . ; + *(.text) + *(.exit.text) /* 2.5 convention */ + *(.text.exit) /* 2.4 convention */ + *(.text.lock) + *(.exitcall.exit) + __real_etext = . ; /* There may be data after here. */ + *(.rodata) + . = ALIGN (0x4) ; + *(.kstrtab) + + . = ALIGN (4) ; + *(.call_table_data) + *(.call_table_text) + + . = ALIGN (16) ; /* Exception table. */ + ___start___ex_table = . ; + *(__ex_table) + ___stop___ex_table = . ; + + ___start___ksymtab = . ;/* Kernel symbol table. */ + *(__ksymtab) + ___stop___ksymtab = . ; + . = ALIGN (4) ; + __etext = . ; + } > RAM + + .data ALIGN (0x4) : { + __sdata = . ; + *(.data) + *(.exit.data) /* 2.5 convention */ + *(.data.exit) /* 2.4 convention */ + . = ALIGN (16) ; + *(.data.cacheline_aligned) + . = ALIGN (0x2000) ; + *(.data.init_task) + . = ALIGN (0x2000) ; + __edata = . ; + } > RAM + + .bss ALIGN (0x4) : { + __sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN (4) ; + __init_stack_end = . ; + __ebss = . ; + } > RAM + + .init ALIGN (4096) : { + __init_start = . ; + *(.init.text) /* 2.5 convention */ + *(.init.data) + *(.text.init) /* 2.4 convention */ + *(.data.init) + . = ALIGN (16) ; + ___setup_start = . ; + *(.init.setup) /* 2.5 convention */ + *(.setup.init) /* 2.4 convention */ + ___setup_end = . ; + ___initcall_start = . ; + *(.initcall.init) + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + . = ALIGN (4) ; + ___initcall_end = . ; + __init_end = . ; + + __kram_end = . ; + } > RAM + + .bootmap ALIGN (4096) : { + __bootmap = . ; + . = . + 4096 ; /* enough for 128MB. */ + } > RAM +} diff -Nru a/arch/v850/sim85e2c.ld b/arch/v850/sim85e2c.ld --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/sim85e2c.ld Mon Nov 4 14:31:04 2002 @@ -0,0 +1,135 @@ +/* Linker script for the sim85e2c simulator, which is a verilog simulation of + the V850E2 NA85E2C cpu core (CONFIG_V850E2_SIM85E2C). */ + +/* Note, all symbols are prefixed with an extra `_' for compatibility with + the existing linux sources. */ + +_jiffies = _jiffies_64 ; + +MEMORY { + /* 1MB of `instruction RAM', starting at 0. + Instruction fetches are much faster from IRAM than from DRAM. + This should match IRAM_ADDR in "include/asm-v580/sim85e2c.h". */ + IRAM : ORIGIN = 0x00000000, LENGTH = 0x00100000 + + /* 1MB of `data RAM', below and contiguous with the I/O space. + Data fetches are much faster from DRAM than from IRAM. + This should match DRAM_ADDR in "include/asm-v580/sim85e2c.h". */ + DRAM : ORIGIN = 0xfff00000, LENGTH = 0x000ff000 + /* We have to load DRAM at a mirror-address of 0x1ff00000, + because the simulator's preprocessing script isn't smart + enough to deal with the above LMA. */ + DRAM_LOAD : ORIGIN = 0x1ff00000, LENGTH = 0x000ff000 + + /* `external ram' (CS1 area), comes after IRAM. + This should match ERAM_ADDR in "include/asm-v580/sim85e2c.h". */ + ERAM : ORIGIN = 0x00100000, LENGTH = 0x07f00000 +} + +SECTIONS { + .intv : { + __intv_start = . ; + *(.intv) /* Interrupt vectors. */ + *(.intv.reset) /* Reset vector */ + *(.intv.common) /* Vectors common to all v850e proc. */ + *(.intv.mach) /* Machine-specific int. vectors. */ + __intv_end = . ; + } > IRAM + + .text : { + __stext = . ; + *(.text) + *(.exit.text) /* 2.5 convention */ + *(.text.exit) /* 2.4 convention */ + *(.text.lock) + *(.exitcall.exit) + __real_etext = . ; /* There may be data after here. */ + *(.rodata) + . = ALIGN (0x4) ; + *(.kstrtab) + + . = ALIGN (4) ; + *(.call_table_data) + *(.call_table_text) + + . = ALIGN (16) ; /* Exception table. */ + ___start___ex_table = . ; + *(__ex_table) + ___stop___ex_table = . ; + + ___start___ksymtab = . ;/* Kernel symbol table. */ + *(__ksymtab) + ___stop___ksymtab = . ; + . = ALIGN (4) ; + __etext = . ; + } > IRAM + + .init ALIGN (4096) : { + __init_start = . ; + *(.init.text) /* 2.5 convention */ + *(.init.data) + *(.text.init) /* 2.4 convention */ + *(.data.init) + . = ALIGN (16) ; + ___setup_start = . ; + *(.init.setup) /* 2.5 convention */ + *(.setup.init) /* 2.4 convention */ + ___setup_end = . ; + ___initcall_start = . ; + *(.initcall.init) + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + . = ALIGN (4) ; + ___initcall_end = . ; + __init_end = . ; + } > IRAM + + .data : { + __kram_start = . ; + + __sdata = . ; + *(.data) + *(.exit.data) /* 2.5 convention */ + *(.data.exit) /* 2.4 convention */ + . = ALIGN (16) ; + *(.data.cacheline_aligned) + . = ALIGN (0x2000) ; + *(.data.init_task) + . = ALIGN (0x2000) ; + __edata = . ; + } > DRAM AT> DRAM_LOAD + + .bss ALIGN (0x4) : { + __sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN (4) ; + __init_stack_end = . ; + __ebss = . ; + } > DRAM AT> DRAM_LOAD + + /* Device contents for the root filesystem. */ + .root ALIGN (4096) : { + __root_fs_image_start = . ; + *(.root) + __root_fs_image_end = . ; + } > DRAM AT> DRAM_LOAD + + .memcons : { + _memcons_output = . ; + . = . + 0x8000 ; + _memcons_output_end = . ; + + __kram_end = . ; + } > DRAM AT> DRAM_LOAD + + .bootmap ALIGN (4096) : { + __bootmap = . ; + . = . + 4096 ; /* enough for 128MB. */ + } > DRAM AT> DRAM_LOAD +} diff -Nru a/arch/v850/vmlinux.lds.S b/arch/v850/vmlinux.lds.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/v850/vmlinux.lds.S Mon Nov 4 14:31:04 2002 @@ -0,0 +1,31 @@ +#include + +#ifdef CONFIG_V850E_SIM +# include "sim.ld" +#endif + +#ifdef CONFIG_V850E2_SIM85E2C +# include "sim85e2c.ld" +#endif + +#ifdef CONFIG_V850E2_FPGA85E2C +# include "fpga85e2c.ld" +#endif + +#ifdef CONFIG_V850E2_ANNA +# ifdef CONFIG_ROM_KERNEL +# include "anna-rom.ld" +# else +# include "anna.ld" +# endif +#endif + +#ifdef CONFIG_RTE_CB_MA1 +# ifdef CONFIG_ROM_KERNEL +# include "rte_ma1_cb-rom.ld" +# elif CONFIG_RTE_CB_MA1_KSRAM +# include "rte_ma1_cb-ksram.ld" +# else /* !CONFIG_ROM_KERNEL && !CONFIG_RTE_CB_MA1_KSRAM */ +# include "rte_ma1_cb.ld" +# endif /* CONFIG_ROM_KERNEL */ +#endif /* CONFIG_RTE_CB_MA1 */ diff -Nru a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig --- a/arch/x86_64/Kconfig Mon Nov 4 14:31:02 2002 +++ b/arch/x86_64/Kconfig Mon Nov 4 14:31:02 2002 @@ -25,6 +25,14 @@ 486, 586, Pentiums, and various instruction-set-compatible chips by AMD, Cyrix, and others. +config MMU + bool + default y + +config SWAP + bool + default y + config ISA bool help diff -Nru a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c --- a/arch/x86_64/ia32/ptrace32.c Mon Nov 4 14:31:01 2002 +++ b/arch/x86_64/ia32/ptrace32.c Mon Nov 4 14:31:01 2002 @@ -185,17 +185,6 @@ __u32 val; switch (request) { - case PTRACE_TRACEME: - case PTRACE_ATTACH: - case PTRACE_SYSCALL: - case PTRACE_CONT: - case PTRACE_KILL: - case PTRACE_SINGLESTEP: - case PTRACE_DETACH: - case PTRACE_SETOPTIONS: - ret = sys_ptrace(request, pid, addr, data); - return ret; - case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: case PTRACE_POKEDATA: @@ -211,7 +200,8 @@ break; default: - return -EIO; + ret = sys_ptrace(request, pid, addr, data); + return ret; } child = find_target(request, pid, &ret); diff -Nru a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c --- a/arch/x86_64/kernel/irq.c Mon Nov 4 14:31:01 2002 +++ b/arch/x86_64/kernel/irq.c Mon Nov 4 14:31:01 2002 @@ -151,7 +151,7 @@ #else for_each_cpu(j) seq_printf(p, "%10u ", - kstat.irqs[j][i]); + kstat_cpu(j).irqs[i]); #endif seq_printf(p, " %14s", irq_desc[i].handler->typename); seq_printf(p, " %s", action->name); @@ -328,7 +328,7 @@ if (irq > 256) BUG(); irq_enter(); - kstat.irqs[cpu][irq]++; + kstat_cpu(cpu).irqs[irq]++; spin_lock(&desc->lock); desc->handler->ack(irq); /* diff -Nru a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c --- a/arch/x86_64/kernel/process.c Mon Nov 4 14:31:00 2002 +++ b/arch/x86_64/kernel/process.c Mon Nov 4 14:31:00 2002 @@ -59,7 +59,7 @@ asmlinkage extern void ret_from_fork(void); int sys_arch_prctl(int code, unsigned long addr); -unsigned long kernel_thread_flags = CLONE_VM; +unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED; int hlt_counter; diff -Nru a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c --- a/arch/x86_64/kernel/ptrace.c Mon Nov 4 14:31:01 2002 +++ b/arch/x86_64/kernel/ptrace.c Mon Nov 4 14:31:01 2002 @@ -405,17 +405,8 @@ break; } - case PTRACE_SETOPTIONS: { - if (data & PTRACE_O_TRACESYSGOOD) - child->ptrace |= PT_TRACESYSGOOD; - else - child->ptrace &= ~PT_TRACESYSGOOD; - ret = 0; - break; - } - default: - ret = -EIO; + ret = ptrace_request(child, request, addr, data); break; } out_tsk: diff -Nru a/drivers/Makefile b/drivers/Makefile --- a/drivers/Makefile Mon Nov 4 14:31:02 2002 +++ b/drivers/Makefile Mon Nov 4 14:31:02 2002 @@ -6,6 +6,7 @@ # obj-$(CONFIG_PCI) += pci/ +obj-$(CONFIG_PARISC) += parisc/ obj-$(CONFIG_ACPI) += acpi/ obj-y += serial/ obj-$(CONFIG_PARPORT) += parport/ diff -Nru a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c --- a/drivers/acorn/block/fd1772.c Mon Nov 4 14:31:01 2002 +++ b/drivers/acorn/block/fd1772.c Mon Nov 4 14:31:01 2002 @@ -1206,7 +1206,7 @@ static void redo_fd_request(void) { - int device, drive, type; + int drive, type; struct archy_floppy_struct *floppy; DPRINT(("redo_fd_request: CURRENT=%p dev=%s CURRENT->sector=%ld\n", @@ -1218,10 +1218,9 @@ if (blk_queue_empty(QUEUE)) goto the_end; - device = minor(CURRENT->rq_dev); - drive = device & 3; - type = device >> 2; - floppy = &unit[drive]; + floppy = CURRENT->rq_disk->private_data; + drive = floppy - unit; + type = fd_device[drive]; if (!floppy->connected) { /* drive not connected */ @@ -1463,13 +1462,11 @@ static int floppy_open(struct inode *inode, struct file *filp) { int drive = minor(inode->i_rdev) & 3; - int old_dev; + int type = minor(inode->i_rdev) >> 2; + int old_dev = fd_device[drive]; - old_dev = fd_device[drive]; - - if (fd_ref[drive]) - if (old_dev != inode->i_rdev) - return -EBUSY; + if (fd_ref[drive] && old_dev != type) + return -EBUSY; if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL)) return -EBUSY; @@ -1479,10 +1476,10 @@ else fd_ref[drive]++; - fd_device[drive] = inode->i_rdev; + fd_device[drive] = type; - if (old_dev && old_dev != inode->i_rdev) - invalidate_buffers(old_dev); + if (old_dev && old_dev != type) + invalidate_buffers(mk_kdev(MAJOR_NR, drive + (old_dev<<2))); if (filp->f_flags & O_NDELAY) return 0; diff -Nru a/drivers/acpi/Makefile b/drivers/acpi/Makefile --- a/drivers/acpi/Makefile Mon Nov 4 14:31:02 2002 +++ b/drivers/acpi/Makefile Mon Nov 4 14:31:02 2002 @@ -32,7 +32,7 @@ # # ACPI Bus and Device Drivers # -obj-$(CONFIG_ACPI_BUS) += bus.o driverfs.o +obj-$(CONFIG_ACPI_BUS) += bus.o obj-$(CONFIG_ACPI_AC) += ac.o obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_BUTTON) += button.o diff -Nru a/drivers/acpi/acpi_bus.h b/drivers/acpi/acpi_bus.h --- a/drivers/acpi/acpi_bus.h Mon Nov 4 14:31:01 2002 +++ b/drivers/acpi/acpi_bus.h Mon Nov 4 14:31:01 2002 @@ -27,7 +27,7 @@ #define __ACPI_BUS_H__ #include -#include +#include #include "include/acpi.h" @@ -255,7 +255,7 @@ struct acpi_device_ops ops; struct acpi_driver *driver; void *driver_data; - struct driver_dir_entry driverfs_dir; + struct kobject kobj; }; #define acpi_driver_data(d) ((d)->driver_data) @@ -274,6 +274,7 @@ u32 data; }; +extern struct subsystem acpi_subsys; /* * External Functions diff -Nru a/drivers/acpi/bus.c b/drivers/acpi/bus.c --- a/drivers/acpi/bus.c Mon Nov 4 14:31:02 2002 +++ b/drivers/acpi/bus.c Mon Nov 4 14:31:02 2002 @@ -675,6 +675,9 @@ return_VALUE(-ENODEV); } +struct subsystem acpi_subsys = { + .kobj = { .name = "acpi" }, +}; static int __init acpi_init (void) { @@ -692,6 +695,8 @@ printk(KERN_INFO PREFIX "Disabled via command line (acpi=off)\n"); return -ENODEV; } + + firmware_register(&acpi_subsys); result = acpi_bus_init(); diff -Nru a/drivers/acpi/driverfs.c b/drivers/acpi/driverfs.c --- a/drivers/acpi/driverfs.c Mon Nov 4 14:31:01 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,46 +0,0 @@ -/* - * driverfs.c - ACPI bindings for driverfs. - * - * Copyright (c) 2002 Patrick Mochel - * Copyright (c) 2002 The Open Source Development Lab - * - */ - -#include -#include -#include - -#include "acpi_bus.h" - -static struct driver_dir_entry acpi_dir = { - .name = "acpi", - .mode = (S_IRWXU | S_IRUGO | S_IXUGO), -}; - -/* driverfs ops for ACPI attribute files go here, when/if - * there are ACPI attribute files. - * For now, we just have directory creation and removal. - */ - -void acpi_remove_dir(struct acpi_device * dev) -{ - if (dev) - driverfs_remove_dir(&dev->driverfs_dir); -} - -int acpi_create_dir(struct acpi_device * dev) -{ - struct driver_dir_entry * parent; - - parent = dev->parent ? &dev->parent->driverfs_dir : &acpi_dir; - dev->driverfs_dir.name = dev->pnp.bus_id; - dev->driverfs_dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO); - return driverfs_create_dir(&dev->driverfs_dir,parent); -} - -static int __init acpi_driverfs_init(void) -{ - return driverfs_create_dir(&acpi_dir,NULL); -} - -subsys_initcall(acpi_driverfs_init); diff -Nru a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c --- a/drivers/acpi/events/evxfregn.c Mon Nov 4 14:31:01 2002 +++ b/drivers/acpi/events/evxfregn.c Mon Nov 4 14:31:01 2002 @@ -2,7 +2,7 @@ * * Module Name: evxfregn - External Interfaces, ACPI Operation Regions and * Address Spaces. - * $Revision: 51 $ + * $Revision: 52 $ * *****************************************************************************/ @@ -210,8 +210,8 @@ } ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, - "Installing address handler for region %s(%X) on Device %p(%p)\n", - acpi_ut_get_region_name (space_id), space_id, node, obj_desc)); + "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n", + acpi_ut_get_region_name (space_id), space_id, node->name.ascii, node, obj_desc)); /* * Now we can install the handler diff -Nru a/drivers/acpi/include/acconfig.h b/drivers/acpi/include/acconfig.h --- a/drivers/acpi/include/acconfig.h Mon Nov 4 14:31:02 2002 +++ b/drivers/acpi/include/acconfig.h Mon Nov 4 14:31:02 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acconfig.h - Global configuration constants - * $Revision: 114 $ + * $Revision: 115 $ * *****************************************************************************/ @@ -54,7 +54,7 @@ /* Version string */ -#define ACPI_CA_VERSION 0x20021022 +#define ACPI_CA_VERSION 0x20021101 /* Version of ACPI supported */ diff -Nru a/drivers/acpi/include/acparser.h b/drivers/acpi/include/acparser.h --- a/drivers/acpi/include/acparser.h Mon Nov 4 14:31:02 2002 +++ b/drivers/acpi/include/acparser.h Mon Nov 4 14:31:02 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: acparser.h - AML Parser subcomponent prototypes and defines - * $Revision: 62 $ + * $Revision: 63 $ * *****************************************************************************/ @@ -89,9 +89,9 @@ acpi_status acpi_ps_get_next_namepath ( + acpi_walk_state *walk_state, acpi_parse_state *parser_state, acpi_parse_object *arg, - u32 *arg_count, u8 method_call); acpi_parse_object * @@ -100,9 +100,9 @@ acpi_status acpi_ps_get_next_arg ( + acpi_walk_state *walk_state, acpi_parse_state *parser_state, u32 arg_type, - u32 *arg_count, acpi_parse_object **return_arg); diff -Nru a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c --- a/drivers/acpi/namespace/nsalloc.c Mon Nov 4 14:31:02 2002 +++ b/drivers/acpi/namespace/nsalloc.c Mon Nov 4 14:31:02 2002 @@ -1,7 +1,7 @@ /******************************************************************************* * * Module Name: nsalloc - Namespace allocation and deletion utilities - * $Revision: 75 $ + * $Revision: 77 $ * ******************************************************************************/ @@ -125,6 +125,7 @@ } +#ifdef ACPI_ALPHABETIC_NAMESPACE /******************************************************************************* * * FUNCTION: Acpi_ns_compare_names @@ -170,8 +171,9 @@ } } - return (*(s32 *) reversed_name1 - *(s32 *) reversed_name2); + return (*(int *) reversed_name1 - *(int *) reversed_name2); } +#endif /******************************************************************************* @@ -204,7 +206,10 @@ { u16 owner_id = TABLE_ID_DSDT; acpi_namespace_node *child_node; +#ifdef ACPI_ALPHABETIC_NAMESPACE + acpi_namespace_node *previous_child_node; +#endif ACPI_FUNCTION_TRACE ("Ns_install_node"); @@ -228,6 +233,7 @@ node->peer = parent_node; } else { +#ifdef ACPI_ALPHABETIC_NAMESPACE /* * Walk the list whilst searching for the the correct * alphabetic placement. @@ -276,6 +282,19 @@ parent_node->child = node; } } +#else + while (!(child_node->flags & ANOBJ_END_OF_PEER_LIST)) { + child_node = child_node->peer; + } + + child_node->peer = node; + + /* Clear end-of-list flag */ + + child_node->flags &= ~ANOBJ_END_OF_PEER_LIST; + node->flags |= ANOBJ_END_OF_PEER_LIST; + node->peer = parent_node; +#endif } /* Init the new entry */ diff -Nru a/drivers/acpi/osl.c b/drivers/acpi/osl.c --- a/drivers/acpi/osl.c Mon Nov 4 14:31:02 2002 +++ b/drivers/acpi/osl.c Mon Nov 4 14:31:02 2002 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -717,6 +718,9 @@ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Waiting for semaphore[%p|%d|%d]\n", handle, units, timeout)); + if (in_atomic()) + timeout = 0; + switch (timeout) { /* @@ -838,7 +842,7 @@ u32 acpi_os_get_thread_id (void) { - if (!in_interrupt()) + if (!in_atomic()) return current->pid; return 0; diff -Nru a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c --- a/drivers/acpi/parser/psargs.c Mon Nov 4 14:31:01 2002 +++ b/drivers/acpi/parser/psargs.c Mon Nov 4 14:31:01 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: psargs - Parse AML opcode arguments - * $Revision: 64 $ + * $Revision: 65 $ * *****************************************************************************/ @@ -95,6 +95,7 @@ break; default: + /* Can't get here, only 2 bits / 4 cases */ break; } @@ -127,6 +128,8 @@ ACPI_FUNCTION_TRACE ("Ps_get_next_package_end"); + /* Function below changes Parser_state->Aml */ + length = (NATIVE_UINT) acpi_ps_get_next_package_length (parser_state); return_PTR (start + length); /* end of package */ @@ -184,21 +187,21 @@ /* Two name segments */ - end += 9; + end += 1 + (2 * ACPI_NAME_SIZE); break; case AML_MULTI_NAME_PREFIX_OP: /* Multiple name segments, 4 chars each */ - end += 2 + ((ACPI_SIZE) ACPI_GET8 (end + 1) * 4); + end += 2 + ((ACPI_SIZE) ACPI_GET8 (end + 1) * ACPI_NAME_SIZE); break; default: /* Single name segment */ - end += 4; + end += ACPI_NAME_SIZE; break; } @@ -215,8 +218,8 @@ * 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 + * Method_call - Whether the namepath can possibly be the + * start of a method call * * RETURN: Status * @@ -230,9 +233,9 @@ acpi_status acpi_ps_get_next_namepath ( + acpi_walk_state *walk_state, acpi_parse_state *parser_state, acpi_parse_object *arg, - u32 *arg_count, u8 method_call) { NATIVE_CHAR *path; @@ -267,12 +270,15 @@ * object (MUST BE mode EXECUTE to perform upsearch) */ status = acpi_ns_lookup (&scope_info, path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, - ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL, - &node); + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL, &node); if (ACPI_SUCCESS (status) && method_call) { if (node->type == ACPI_TYPE_METHOD) { + /* + * This name is actually a control method invocation + */ method_desc = acpi_ns_get_attached_object (node); - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Control Method - %p Desc %p Path=%p\n", + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "Control Method - %p Desc %p Path=%p\n", node, method_desc, path)); name_op = acpi_ps_alloc_op (AML_INT_NAMEPATH_OP); @@ -283,7 +289,6 @@ /* Change arg into a METHOD CALL and attach name to it */ acpi_ps_init_op (arg, AML_INT_METHODCALL_OP); - name_op->common.value.name = path; /* Point METHODCALL/NAME to the METHOD Node */ @@ -292,15 +297,19 @@ acpi_ps_append_arg (arg, name_op); if (!method_desc) { - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Control Method - %p has no attached object\n", + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "Control Method - %p has no attached object\n", node)); return_ACPI_STATUS (AE_AML_INTERNAL); } - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Control Method - %p Args %X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "Control Method - %p Args %X\n", node, method_desc->method.param_count)); - *arg_count = method_desc->method.param_count; + /* Get the number of arguments to expect */ + + walk_state->arg_count = method_desc->method.param_count; return_ACPI_STATUS (AE_OK); } @@ -310,6 +319,29 @@ * (See code below) */ } + + if (ACPI_FAILURE (status)) { + /* + * 1) Any error other than NOT_FOUND is always severe + * 2) NOT_FOUND is only important if we are executing a method. + * 3) If executing a Cond_ref_of opcode, NOT_FOUND is ok. + */ + if ((((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) && + (status == AE_NOT_FOUND) && + (walk_state->op->common.aml_opcode != AML_COND_REF_OF_OP)) || + + (status != AE_NOT_FOUND)) { + ACPI_REPORT_NSERROR (path, status); + } + else { + /* + * We got a NOT_FOUND during table load or we encountered + * a Cond_ref_of(x) where the target does not exist. + * -- either case is ok + */ + status = AE_OK; + } + } } /* @@ -410,6 +442,7 @@ default: + ACPI_REPORT_ERROR (("Invalid Arg_type %X\n", arg_type)); break; } @@ -435,7 +468,7 @@ acpi_parse_state *parser_state) { u32 aml_offset = ACPI_PTR_DIFF (parser_state->aml, - parser_state->aml_start); + parser_state->aml_start); acpi_parse_object *field; u16 opcode; u32 name; @@ -484,7 +517,7 @@ ACPI_MOVE_UNALIGNED32_TO_32 (&name, parser_state->aml); acpi_ps_set_name (field, name); - parser_state->aml += 4; + parser_state->aml += ACPI_NAME_SIZE; /* Get the length which is encoded as a package length */ @@ -513,6 +546,7 @@ break; default: + /* Opcode was set in previous switch */ break; } @@ -539,9 +573,9 @@ acpi_status acpi_ps_get_next_arg ( + acpi_walk_state *walk_state, acpi_parse_state *parser_state, u32 arg_type, - u32 *arg_count, acpi_parse_object **return_arg) { acpi_parse_object *arg = NULL; @@ -620,7 +654,8 @@ /* Fill in bytelist data */ - arg->common.value.size = ACPI_PTR_DIFF (parser_state->pkg_end, parser_state->aml); + arg->common.value.size = ACPI_PTR_DIFF (parser_state->pkg_end, + parser_state->aml); arg->named.data = parser_state->aml; /* Skip to End of byte data */ @@ -645,12 +680,12 @@ return_ACPI_STATUS (AE_NO_MEMORY); } - status = acpi_ps_get_next_namepath (parser_state, arg, arg_count, 0); + status = acpi_ps_get_next_namepath (walk_state, parser_state, arg, 0); } else { /* single complex argument, nothing returned */ - *arg_count = 1; + walk_state->arg_count = 1; } break; @@ -660,7 +695,7 @@ /* single complex argument, nothing returned */ - *arg_count = 1; + walk_state->arg_count = 1; break; @@ -671,7 +706,7 @@ if (parser_state->aml < parser_state->pkg_end) { /* non-empty list of variable arguments, nothing returned */ - *arg_count = ACPI_VAR_ARGS; + walk_state->arg_count = ACPI_VAR_ARGS; } break; diff -Nru a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c --- a/drivers/acpi/parser/psparse.c Mon Nov 4 14:31:01 2002 +++ b/drivers/acpi/parser/psparse.c Mon Nov 4 14:31:01 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: psparse - Parser top level AML parse routines - * $Revision: 133 $ + * $Revision: 134 $ * *****************************************************************************/ @@ -460,7 +460,8 @@ status = acpi_ps_next_parse_state (walk_state, op, status); } - acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); + acpi_ps_pop_scope (parser_state, &op, + &walk_state->arg_types, &walk_state->arg_count); ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", op)); } else if (walk_state->prev_op) { @@ -480,7 +481,8 @@ if (!op) { /* Get the next opcode from the AML stream */ - walk_state->aml_offset = ACPI_PTR_DIFF (parser_state->aml, parser_state->aml_start); + walk_state->aml_offset = ACPI_PTR_DIFF (parser_state->aml, + parser_state->aml_start); walk_state->opcode = acpi_ps_peek_opcode (parser_state); /* @@ -537,9 +539,8 @@ */ while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) && (GET_CURRENT_ARG_TYPE (walk_state->arg_types) != ARGP_NAME)) { - status = acpi_ps_get_next_arg (parser_state, - GET_CURRENT_ARG_TYPE (walk_state->arg_types), - &walk_state->arg_count, &arg); + status = acpi_ps_get_next_arg (walk_state, parser_state, + GET_CURRENT_ARG_TYPE (walk_state->arg_types), &arg); if (ACPI_FAILURE (status)) { goto close_this_op; } @@ -593,7 +594,7 @@ * Defer final parsing of an Operation_region body, * because we don't have enough info in the first pass * to parse it correctly (i.e., there may be method - * calls within the Term_arg elements of the body. + * calls within the Term_arg elements of the body.) * * However, we must continue parsing because * the opregion is not a standalone package -- @@ -673,20 +674,14 @@ /* Fill in constant or string argument directly */ acpi_ps_get_next_simple_arg (parser_state, - GET_CURRENT_ARG_TYPE (walk_state->arg_types), op); + GET_CURRENT_ARG_TYPE (walk_state->arg_types), op); break; case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */ - status = acpi_ps_get_next_namepath (parser_state, op, &walk_state->arg_count, 1); + status = acpi_ps_get_next_namepath (walk_state, parser_state, op, 1); if (ACPI_FAILURE (status)) { - /* NOT_FOUND is an error only if we are actually executing a method */ - - if ((((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) && - (status == AE_NOT_FOUND)) || - (status != AE_NOT_FOUND)) { - goto close_this_op; - } + goto close_this_op; } walk_state->arg_types = 0; @@ -697,21 +692,14 @@ /* Op is not a constant or string, append each argument */ - while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) && !walk_state->arg_count) { + while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) && + !walk_state->arg_count) { walk_state->aml_offset = ACPI_PTR_DIFF (parser_state->aml, parser_state->aml_start); - status = acpi_ps_get_next_arg (parser_state, - GET_CURRENT_ARG_TYPE (walk_state->arg_types), - &walk_state->arg_count, &arg); + status = acpi_ps_get_next_arg (walk_state, parser_state, + GET_CURRENT_ARG_TYPE (walk_state->arg_types), &arg); if (ACPI_FAILURE (status)) { - /* NOT_FOUND is an error only if we are actually executing a method */ - - if ((((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) && - (status == AE_NOT_FOUND) && - (op->common.aml_opcode != AML_COND_REF_OF_OP)) || - (status != AE_NOT_FOUND)) { - goto close_this_op; - } + goto close_this_op; } if (arg) { @@ -784,7 +772,8 @@ if (walk_state->arg_count) { /* There are arguments (complex ones), push Op and prepare for argument */ - status = acpi_ps_push_scope (parser_state, op, walk_state->arg_types, walk_state->arg_count); + status = acpi_ps_push_scope (parser_state, op, + walk_state->arg_types, walk_state->arg_count); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -866,7 +855,8 @@ case AE_CTRL_END: - acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); + acpi_ps_pop_scope (parser_state, &op, + &walk_state->arg_types, &walk_state->arg_count); if (op) { walk_state->op = op; @@ -889,7 +879,8 @@ /* Pop off scopes until we find the While */ while (!op || (op->common.aml_opcode != AML_WHILE_OP)) { - acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); + acpi_ps_pop_scope (parser_state, &op, + &walk_state->arg_types, &walk_state->arg_count); } /* Close this iteration of the While loop */ @@ -917,7 +908,8 @@ if (op) { acpi_ps_complete_this_op (walk_state, op); } - acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); + acpi_ps_pop_scope (parser_state, &op, + &walk_state->arg_types, &walk_state->arg_count); } while (op); @@ -930,7 +922,8 @@ if (op) { acpi_ps_complete_this_op (walk_state, op); } - acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); + acpi_ps_pop_scope (parser_state, &op, + &walk_state->arg_types, &walk_state->arg_count); } while (op); @@ -940,7 +933,8 @@ */ #if 0 if (op == NULL) { - acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); + acpi_ps_pop_scope (parser_state, &op, + &walk_state->arg_types, &walk_state->arg_count); } #endif walk_state->prev_op = op; @@ -951,7 +945,8 @@ /* This scope complete? */ if (acpi_ps_has_completed_scope (parser_state)) { - acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); + acpi_ps_pop_scope (parser_state, &op, + &walk_state->arg_types, &walk_state->arg_count); ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", op)); } else { @@ -991,7 +986,8 @@ acpi_ps_complete_this_op (walk_state, op); } - acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); + acpi_ps_pop_scope (parser_state, &op, + &walk_state->arg_types, &walk_state->arg_count); } while (op); @@ -1007,7 +1003,8 @@ acpi_ps_complete_this_op (walk_state, op); } - acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, &walk_state->arg_count); + acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, + &walk_state->arg_count); } while (op); @@ -1117,7 +1114,8 @@ if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) { terminate_status = acpi_ds_terminate_control_method (walk_state); if (ACPI_FAILURE (terminate_status)) { - ACPI_REPORT_ERROR (("Could not terminate control method properly\n")); + ACPI_REPORT_ERROR (( + "Could not terminate control method properly\n")); /* Ignore error and continue */ } @@ -1142,7 +1140,8 @@ * If the method return value is not used by the parent, * The object is deleted */ - status = acpi_ds_restart_control_method (walk_state, previous_walk_state->return_desc); + status = acpi_ds_restart_control_method (walk_state, + previous_walk_state->return_desc); if (ACPI_SUCCESS (status)) { walk_state->walk_type |= ACPI_WALK_METHOD_RESTART; } @@ -1152,7 +1151,8 @@ acpi_ut_remove_reference (previous_walk_state->return_desc); - ACPI_REPORT_ERROR (("Method execution failed, %s\n", acpi_format_exception (status))); + ACPI_REPORT_ERROR (("Method execution failed, %s\n", + acpi_format_exception (status))); ACPI_DUMP_PATHNAME (walk_state->method_node, "Method pathname: ", ACPI_LV_ERROR, _COMPONENT); } diff -Nru a/drivers/acpi/processor.c b/drivers/acpi/processor.c --- a/drivers/acpi/processor.c Mon Nov 4 14:31:02 2002 +++ b/drivers/acpi/processor.c Mon Nov 4 14:31:02 2002 @@ -1761,6 +1761,9 @@ ACPI_FUNCTION_TRACE("acpi_cpufreq_init"); + if (!pr->flags.performance) + return_VALUE(0); + if (cpufreq_usage_count) { if (pr->flags.performance == 1) cpufreq_usage_count++; diff -Nru a/drivers/acpi/scan.c b/drivers/acpi/scan.c --- a/drivers/acpi/scan.c Mon Nov 4 14:31:01 2002 +++ b/drivers/acpi/scan.c Mon Nov 4 14:31:01 2002 @@ -25,20 +25,52 @@ static LIST_HEAD(acpi_device_list); static spinlock_t acpi_device_lock = SPIN_LOCK_UNLOCKED; -static int -acpi_device_register ( - struct acpi_device *device, - struct acpi_device *parent) +static void acpi_device_release(struct kobject * kobj) { - return acpi_create_dir(device); + struct acpi_device * dev = container_of(kobj,struct acpi_device,kobj); + kfree(dev); } +static struct subsystem acpi_namespace_subsys = { + .kobj = { .name = "namespace" }, + .parent = &acpi_subsys, + .release = acpi_device_release, +}; + + +static void acpi_device_register(struct acpi_device * device, struct acpi_device * parent) +{ + /* + * Linkage + * ------- + * Link this device to its parent and siblings. + */ + INIT_LIST_HEAD(&device->children); + INIT_LIST_HEAD(&device->node); + INIT_LIST_HEAD(&device->g_list); + + spin_lock(&acpi_device_lock); + if (device->parent) { + list_add_tail(&device->node, &device->parent->children); + list_add_tail(&device->g_list,&device->parent->g_list); + } else + list_add_tail(&device->g_list,&acpi_device_list); + spin_unlock(&acpi_device_lock); + + kobject_init(&device->kobj); + strncpy(device->kobj.name,device->pnp.bus_id,KOBJ_NAME_LEN); + if (parent) + device->kobj.parent = &parent->kobj; + device->kobj.subsys = &acpi_namespace_subsys; + kobject_register(&device->kobj); +} static int acpi_device_unregister ( - struct acpi_device *device) + struct acpi_device *device, + int type) { - acpi_remove_dir(device); + kobject_unregister(&device->kobj); return 0; } @@ -443,16 +475,6 @@ return_VALUE(0); } -static int -acpi_bus_remove ( - struct acpi_device *device, - int type) -{ - acpi_device_unregister(device); - kfree(device); - return 0; -} - static void acpi_device_get_busid(struct acpi_device * device, acpi_handle handle, int type) { char bus_id[5] = {'?',0}; @@ -584,28 +606,31 @@ void acpi_device_get_debug_info(struct acpi_device * device, acpi_handle handle, int type) { -#ifdef CONFIG_ACPI_DEBUG +#ifdef CONFIG_ACPI_DEBUG_OUTPUT char *type_string = NULL; char name[80] = {'?','\0'}; acpi_buffer buffer = {sizeof(name), name}; - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - switch (type) { case ACPI_BUS_TYPE_DEVICE: type_string = "Device"; + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); break; case ACPI_BUS_TYPE_POWER: type_string = "Power Resource"; + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); break; case ACPI_BUS_TYPE_PROCESSOR: type_string = "Processor"; + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); break; case ACPI_BUS_TYPE_SYSTEM: type_string = "System"; + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); break; case ACPI_BUS_TYPE_THERMAL: type_string = "Thermal Zone"; + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); break; case ACPI_BUS_TYPE_POWER_BUTTON: type_string = "Power Button"; @@ -618,29 +643,7 @@ } pr_debug("Found %s %s [%p]\n", type_string, name, handle); -#endif /*CONFIG_ACPI_DEBUG*/ -} - -static void acpi_device_attach(struct acpi_device * device, struct acpi_device * parent) -{ - /* - * Linkage - * ------- - * Link this device to its parent and siblings. - */ - INIT_LIST_HEAD(&device->children); - INIT_LIST_HEAD(&device->node); - INIT_LIST_HEAD(&device->g_list); - - spin_lock(&acpi_device_lock); - if (device->parent) { - list_add_tail(&device->node, &device->parent->children); - list_add_tail(&device->g_list,&device->parent->g_list); - } else - list_add_tail(&device->g_list,&acpi_device_list); - spin_unlock(&acpi_device_lock); - - acpi_device_register(device, parent); +#endif /*CONFIG_ACPI_DEBUG_OUTPUT*/ } static int @@ -741,7 +744,7 @@ acpi_device_get_debug_info(device,handle,type); - acpi_device_attach(device,parent); + acpi_device_register(device,parent); /* * Bind _ADR-Based Devices @@ -760,7 +763,7 @@ * ---------------------- * If there's a hardware id (_HID) or compatible ids (_CID) we check * to see if there's a driver installed for this kind of device. Note - * that drivers can install before or after a device in enumerated. + * that drivers can install before or after a device is enumerated. * * TBD: Assumes LDM provides driver hot-plug capability. */ @@ -822,14 +825,10 @@ /* * If this is a scope object then parse it (depth-first). */ - if (type == ACPI_TYPE_ANY) { - /* Hack to get around scope identity problem */ - status = acpi_get_next_object(ACPI_TYPE_ANY, chandle, 0, NULL); - if (ACPI_SUCCESS(status)) { - level++; - phandle = chandle; - chandle = 0; - } + if (type == ACPI_TYPE_LOCAL_SCOPE) { + level++; + phandle = chandle; + chandle = 0; continue; } @@ -900,11 +899,11 @@ */ if (acpi_fadt.pwr_button == 0) result = acpi_bus_add(&device, acpi_root, - ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_POWER_BUTTON); + NULL, ACPI_BUS_TYPE_POWER_BUTTON); if (acpi_fadt.sleep_button == 0) result = acpi_bus_add(&device, acpi_root, - ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_SLEEP_BUTTON); + NULL, ACPI_BUS_TYPE_SLEEP_BUTTON); return_VALUE(result); } @@ -919,6 +918,8 @@ if (acpi_disabled) return_VALUE(0); + subsystem_register(&acpi_namespace_subsys); + /* * Create the root device in the bus's device tree */ @@ -935,7 +936,7 @@ result = acpi_bus_scan(acpi_root); if (result) - acpi_bus_remove(acpi_root, ACPI_BUS_REMOVAL_NORMAL); + acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); Done: return_VALUE(result); diff -Nru a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c --- a/drivers/acpi/tables/tbutils.c Mon Nov 4 14:31:01 2002 +++ b/drivers/acpi/tables/tbutils.c Mon Nov 4 14:31:01 2002 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: tbutils - Table manipulation utilities - * $Revision: 56 $ + * $Revision: 57 $ * *****************************************************************************/ @@ -175,8 +175,8 @@ /* Return the appropriate exception */ if (checksum) { - ACPI_REPORT_WARNING (("Invalid checksum (%X) in table %4.4s\n", - (u32) checksum, table_header->signature)); + ACPI_REPORT_WARNING (("Invalid checksum in table [%4.4s] (%02X, sum %02X is not zero)\n", + table_header->signature, (u32) table_header->checksum, (u32) checksum)); status = AE_BAD_CHECKSUM; } diff -Nru a/drivers/atm/zatm.c b/drivers/atm/zatm.c --- a/drivers/atm/zatm.c Mon Nov 4 14:31:01 2002 +++ b/drivers/atm/zatm.c Mon Nov 4 14:31:01 2002 @@ -1260,13 +1260,13 @@ /* don't handle RD */ if (reason & uPD98401_INT_SPE) printk(KERN_ALERT DEV_LABEL "(itf %d): system parity " - "error at 0x%08lx\n",dev->number,zin(ADDR)); + "error at 0x%08x\n",dev->number,zin(ADDR)); if (reason & uPD98401_INT_CPE) printk(KERN_ALERT DEV_LABEL "(itf %d): control memory " - "parity error at 0x%08lx\n",dev->number,zin(ADDR)); + "parity error at 0x%08x\n",dev->number,zin(ADDR)); if (reason & uPD98401_INT_SBE) { printk(KERN_ALERT DEV_LABEL "(itf %d): system bus " - "error at 0x%08lx\n",dev->number,zin(ADDR)); + "error at 0x%08x\n",dev->number,zin(ADDR)); event_dump(); } /* don't handle IND */ @@ -1448,7 +1448,7 @@ } while (t0 > t1 || t1 > t2); /* loop if wrapping ... */ zatm_dev->khz = t2-2*t1+t0; - printk(KERN_NOTICE DEV_LABEL "(itf %d): uPD98401 %ld.%ld at %d.%03d " + printk(KERN_NOTICE DEV_LABEL "(itf %d): uPD98401 %d.%d at %d.%03d " "MHz\n",dev->number, (zin(VER) & uPD98401_MAJOR) >> uPD98401_MAJOR_SHIFT, zin(VER) & uPD98401_MINOR,zatm_dev->khz/1000,zatm_dev->khz % 1000); diff -Nru a/drivers/base/Makefile b/drivers/base/Makefile --- a/drivers/base/Makefile Mon Nov 4 14:31:02 2002 +++ b/drivers/base/Makefile Mon Nov 4 14:31:02 2002 @@ -2,13 +2,15 @@ obj-y := core.o sys.o interface.o power.o bus.o \ driver.o class.o intf.o platform.o \ - cpu.o + cpu.o firmware.o + +obj-$(CONFIG_NUMA) += node.o memblk.o obj-y += fs/ obj-$(CONFIG_HOTPLUG) += hotplug.o export-objs := core.o power.o sys.o bus.o driver.o \ - class.o intf.o platform.o cpu.o + class.o intf.o platform.o firmware.o include $(TOPDIR)/Rules.make diff -Nru a/drivers/base/base.h b/drivers/base/base.h --- a/drivers/base/base.h Mon Nov 4 14:31:01 2002 +++ b/drivers/base/base.h Mon Nov 4 14:31:01 2002 @@ -10,43 +10,14 @@ extern spinlock_t device_lock; extern struct semaphore device_sem; -extern struct device * get_device_locked(struct device *); - extern int bus_add_device(struct device * dev); extern void bus_remove_device(struct device * dev); -extern int device_make_dir(struct device * dev); -extern void device_remove_dir(struct device * dev); - -extern int bus_make_dir(struct bus_type * bus); -extern void bus_remove_dir(struct bus_type * bus); - extern int bus_add_driver(struct device_driver *); extern void bus_remove_driver(struct device_driver *); -extern int driver_make_dir(struct device_driver * drv); -extern void driver_remove_dir(struct device_driver * drv); - -extern int device_bus_link(struct device * dev); -extern void device_remove_symlink(struct driver_dir_entry * dir, const char * name); - -extern int devclass_make_dir(struct device_class *); -extern void devclass_remove_dir(struct device_class *); - -extern int devclass_drv_link(struct device_driver *); -extern void devclass_drv_unlink(struct device_driver *); - -extern int devclass_dev_link(struct device_class *, struct device *); -extern void devclass_dev_unlink(struct device_class *, struct device *); - extern int devclass_add_device(struct device *); extern void devclass_remove_device(struct device *); - -extern int intf_make_dir(struct device_interface *); -extern void intf_remove_dir(struct device_interface *); - -extern int intf_dev_link(struct intf_data *); -extern void intf_dev_unlink(struct intf_data *); extern int interface_add(struct device_class *, struct device *); extern void interface_remove(struct device_class *, struct device *); diff -Nru a/drivers/base/bus.c b/drivers/base/bus.c --- a/drivers/base/bus.c Mon Nov 4 14:31:01 2002 +++ b/drivers/base/bus.c Mon Nov 4 14:31:01 2002 @@ -12,6 +12,7 @@ #include #include #include +#include #include "base.h" static LIST_HEAD(bus_driver_list); @@ -19,6 +20,109 @@ #define to_dev(node) container_of(node,struct device,bus_list) #define to_drv(node) container_of(node,struct device_driver,bus_list) +#define to_bus_attr(_attr) container_of(_attr,struct bus_attribute,attr) +#define to_bus(obj) container_of(obj,struct bus_type,subsys.kobj) + +/* + * sysfs bindings for drivers + */ + +#define to_drv_attr(_attr) container_of(_attr,struct driver_attribute,attr) +#define to_driver(obj) container_of(obj, struct device_driver, kobj) + + +static ssize_t +drv_attr_show(struct kobject * kobj, struct attribute * attr, + char * buf, size_t count, loff_t off) +{ + struct driver_attribute * drv_attr = to_drv_attr(attr); + struct device_driver * drv = to_driver(kobj); + ssize_t ret = 0; + + if (drv_attr->show) + ret = drv_attr->show(drv,buf,count,off); + return ret; +} + +static ssize_t +drv_attr_store(struct kobject * kobj, struct attribute * attr, + const char * buf, size_t count, loff_t off) +{ + struct driver_attribute * drv_attr = to_drv_attr(attr); + struct device_driver * drv = to_driver(kobj); + ssize_t ret = 0; + + if (drv_attr->store) + ret = drv_attr->store(drv,buf,count,off); + return ret; +} + +static struct sysfs_ops driver_sysfs_ops = { + .show = drv_attr_show, + .store = drv_attr_store, +}; + + +/* + * sysfs bindings for drivers + */ + + +static ssize_t +bus_attr_show(struct kobject * kobj, struct attribute * attr, + char * buf, size_t count, loff_t off) +{ + struct bus_attribute * bus_attr = to_bus_attr(attr); + struct bus_type * bus = to_bus(kobj); + ssize_t ret = 0; + + if (bus_attr->show) + ret = bus_attr->show(bus,buf,count,off); + return ret; +} + +static ssize_t +bus_attr_store(struct kobject * kobj, struct attribute * attr, + const char * buf, size_t count, loff_t off) +{ + struct bus_attribute * bus_attr = to_bus_attr(attr); + struct bus_type * bus = to_bus(kobj); + ssize_t ret = 0; + + if (bus_attr->store) + ret = bus_attr->store(bus,buf,count,off); + return ret; +} + +static struct sysfs_ops bus_sysfs_ops = { + .show = bus_attr_show, + .store = bus_attr_store, +}; + +int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) +{ + int error; + if (get_bus(bus)) { + error = sysfs_create_file(&bus->subsys.kobj,&attr->attr); + put_bus(bus); + } else + error = -EINVAL; + return error; +} + +void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) +{ + if (get_bus(bus)) { + sysfs_remove_file(&bus->subsys.kobj,&attr->attr); + put_bus(bus); + } +} + +struct subsystem bus_subsys = { + .kobj = { .name = "bus" }, + .sysfs_ops = &bus_sysfs_ops, +}; + /** * bus_for_each_dev - walk list of devices and do something to each * @bus: bus in question @@ -92,6 +196,7 @@ pr_debug("bound device '%s' to driver '%s'\n", dev->bus_id,dev->driver->name); list_add_tail(&dev->driver_list,&dev->driver->devices); + sysfs_create_link(&dev->driver->kobj,&dev->kobj,dev->kobj.name); } static int bus_match(struct device * dev, struct device_driver * drv) @@ -162,6 +267,7 @@ static void detach(struct device * dev, struct device_driver * drv) { if (drv) { + sysfs_remove_link(&drv->kobj,dev->kobj.name); list_del_init(&dev->driver_list); devclass_remove_device(dev); if (drv->remove) @@ -206,7 +312,7 @@ list_add_tail(&dev->bus_list,&dev->bus->devices); device_attach(dev); up_write(&dev->bus->rwsem); - device_bus_link(dev); + sysfs_create_link(&bus->devsubsys.kobj,&dev->kobj,dev->bus_id); } return 0; } @@ -221,9 +327,9 @@ void bus_remove_device(struct device * dev) { if (dev->bus) { + sysfs_remove_link(&dev->bus->devsubsys.kobj,dev->bus_id); down_write(&dev->bus->rwsem); pr_debug("bus %s: remove device %s\n",dev->bus->name,dev->bus_id); - device_remove_symlink(&dev->bus->device_dir,dev->bus_id); device_detach(dev); list_del_init(&dev->bus_list); up_write(&dev->bus->rwsem); @@ -240,7 +346,6 @@ list_add_tail(&drv->bus_list,&bus->drivers); driver_attach(drv); up_write(&bus->rwsem); - driver_make_dir(drv); } return 0; } @@ -275,7 +380,6 @@ list_del_init(&bus->node); spin_unlock(&device_lock); WARN_ON(bus->present); - bus_remove_dir(bus); } int bus_register(struct bus_type * bus) @@ -286,16 +390,25 @@ atomic_set(&bus->refcount,2); bus->present = 1; + strncpy(bus->subsys.kobj.name,bus->name,KOBJ_NAME_LEN); + bus->subsys.parent = &bus_subsys; + subsystem_register(&bus->subsys); + + snprintf(bus->devsubsys.kobj.name,KOBJ_NAME_LEN,"devices"); + bus->devsubsys.parent = &bus->subsys; + subsystem_register(&bus->devsubsys); + + snprintf(bus->drvsubsys.kobj.name,KOBJ_NAME_LEN,"drivers"); + bus->drvsubsys.parent = &bus->subsys; + bus->drvsubsys.sysfs_ops = &driver_sysfs_ops; + subsystem_register(&bus->drvsubsys); + spin_lock(&device_lock); list_add_tail(&bus->node,&bus_driver_list); spin_unlock(&device_lock); pr_debug("bus type '%s' registered\n",bus->name); - - /* give it some driverfs entities */ - bus_make_dir(bus); put_bus(bus); - return 0; } @@ -306,9 +419,19 @@ spin_unlock(&device_lock); pr_debug("bus %s: unregistering\n",bus->name); + subsystem_unregister(&bus->drvsubsys); + subsystem_unregister(&bus->devsubsys); + subsystem_unregister(&bus->subsys); put_bus(bus); } +static int __init bus_subsys_init(void) +{ + return subsystem_register(&bus_subsys); +} + +core_initcall(bus_subsys_init); + EXPORT_SYMBOL(bus_for_each_dev); EXPORT_SYMBOL(bus_for_each_drv); EXPORT_SYMBOL(bus_add_device); @@ -317,3 +440,6 @@ EXPORT_SYMBOL(bus_unregister); EXPORT_SYMBOL(get_bus); EXPORT_SYMBOL(put_bus); + +EXPORT_SYMBOL(bus_create_file); +EXPORT_SYMBOL(bus_remove_file); diff -Nru a/drivers/base/class.c b/drivers/base/class.c --- a/drivers/base/class.c Mon Nov 4 14:31:03 2002 +++ b/drivers/base/class.c Mon Nov 4 14:31:03 2002 @@ -4,10 +4,98 @@ #include #include +#include #include "base.h" static LIST_HEAD(class_list); +#define to_class_attr(_attr) container_of(_attr,struct devclass_attribute,attr) +#define to_class(obj) container_of(obj,struct device_class,subsys.kobj) + +static ssize_t +devclass_attr_show(struct kobject * kobj, struct attribute * attr, + char * buf, size_t count, loff_t off) +{ + struct devclass_attribute * class_attr = to_class_attr(attr); + struct device_class * dc = to_class(kobj); + ssize_t ret = 0; + + if (class_attr->show) + ret = class_attr->show(dc,buf,count,off); + return ret; +} + +static ssize_t +devclass_attr_store(struct kobject * kobj, struct attribute * attr, + const char * buf, size_t count, loff_t off) +{ + struct devclass_attribute * class_attr = to_class_attr(attr); + struct device_class * dc = to_class(kobj); + ssize_t ret = 0; + + if (class_attr->store) + ret = class_attr->store(dc,buf,count,off); + return ret; +} + +static struct sysfs_ops class_sysfs_ops = { + show: devclass_attr_show, + store: devclass_attr_store, +}; + +static struct subsystem class_subsys = { + .kobj = { .name = "class", }, + .sysfs_ops = &class_sysfs_ops, +}; + + +static int devclass_dev_link(struct device_class * cls, struct device * dev) +{ + char linkname[16]; + snprintf(linkname,16,"%u",dev->class_num); + return sysfs_create_link(&cls->devsubsys.kobj,&dev->kobj,linkname); +} + +static void devclass_dev_unlink(struct device_class * cls, struct device * dev) +{ + char linkname[16]; + snprintf(linkname,16,"%u",dev->class_num); + sysfs_remove_link(&cls->devsubsys.kobj,linkname); +} + +static int devclass_drv_link(struct device_driver * drv) +{ + char name[KOBJ_NAME_LEN * 3]; + snprintf(name,KOBJ_NAME_LEN * 3,"%s:%s",drv->bus->name,drv->name); + return sysfs_create_link(&drv->devclass->drvsubsys.kobj,&drv->kobj,name); +} + +static void devclass_drv_unlink(struct device_driver * drv) +{ + char name[KOBJ_NAME_LEN * 3]; + snprintf(name,KOBJ_NAME_LEN * 3,"%s:%s",drv->bus->name,drv->name); + return sysfs_remove_link(&drv->devclass->drvsubsys.kobj,name); +} + + +int devclass_create_file(struct device_class * cls, struct devclass_attribute * attr) +{ + int error; + if (cls) { + error = sysfs_create_file(&cls->subsys.kobj,&attr->attr); + } else + error = -EINVAL; + return error; +} + +void devclass_remove_file(struct device_class * cls, struct devclass_attribute * attr) +{ + if (cls) + sysfs_remove_file(&cls->subsys.kobj,&attr->attr); +} + + + int devclass_add_driver(struct device_driver * drv) { struct device_class * cls = get_devclass(drv->devclass); @@ -136,7 +224,6 @@ if (atomic_dec_and_lock(&cls->refcount,&device_lock)) { list_del_init(&cls->node); spin_unlock(&device_lock); - devclass_remove_dir(cls); } } @@ -150,10 +237,21 @@ cls->present = 1; pr_debug("device class '%s': registering\n",cls->name); + strncpy(cls->subsys.kobj.name,cls->name,KOBJ_NAME_LEN); + cls->subsys.parent = &class_subsys; + subsystem_register(&cls->subsys); + + snprintf(cls->devsubsys.kobj.name,KOBJ_NAME_LEN,"devices"); + cls->devsubsys.parent = &cls->subsys; + subsystem_register(&cls->devsubsys); + + snprintf(cls->drvsubsys.kobj.name,KOBJ_NAME_LEN,"drivers"); + cls->drvsubsys.parent = &cls->subsys; + subsystem_register(&cls->drvsubsys); + spin_lock(&device_lock); list_add_tail(&cls->node,&class_list); spin_unlock(&device_lock); - devclass_make_dir(cls); put_devclass(cls); return 0; } @@ -164,8 +262,18 @@ cls->present = 0; spin_unlock(&device_lock); pr_debug("device class '%s': unregistering\n",cls->name); + subsystem_unregister(&cls->drvsubsys); + subsystem_unregister(&cls->devsubsys); + subsystem_unregister(&cls->subsys); put_devclass(cls); } + +static int __init class_subsys_init(void) +{ + return subsystem_register(&class_subsys); +} + +core_initcall(class_subsys_init); EXPORT_SYMBOL(devclass_register); EXPORT_SYMBOL(devclass_unregister); diff -Nru a/drivers/base/core.c b/drivers/base/core.c --- a/drivers/base/core.c Mon Nov 4 14:31:00 2002 +++ b/drivers/base/core.c Mon Nov 4 14:31:00 2002 @@ -23,7 +23,74 @@ spinlock_t device_lock = SPIN_LOCK_UNLOCKED; -#define to_dev(node) container_of(node,struct device,driver_list) +#define to_dev(obj) container_of(obj,struct device,kobj) + + +/* + * sysfs bindings for devices. + */ + +#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr) + +extern struct attribute * dev_default_attrs[]; + +static ssize_t +dev_attr_show(struct kobject * kobj, struct attribute * attr, + char * buf, size_t count, loff_t off) +{ + struct device_attribute * dev_attr = to_dev_attr(attr); + struct device * dev = to_dev(kobj); + ssize_t ret = 0; + + if (dev_attr->show) + ret = dev_attr->show(dev,buf,count,off); + return ret; +} + +static ssize_t +dev_attr_store(struct kobject * kobj, struct attribute * attr, + const char * buf, size_t count, loff_t off) +{ + struct device_attribute * dev_attr = to_dev_attr(attr); + struct device * dev = to_dev(kobj); + ssize_t ret = 0; + + if (dev_attr->store) + ret = dev_attr->store(dev,buf,count,off); + return ret; +} + +static struct sysfs_ops dev_sysfs_ops = { + .show = dev_attr_show, + .store = dev_attr_store, +}; + +struct subsystem device_subsys = { + .kobj = { + .name = "devices", + }, + .sysfs_ops = &dev_sysfs_ops, + .default_attrs = dev_default_attrs, +}; + + +int device_create_file(struct device * dev, struct device_attribute * attr) +{ + int error = 0; + if (get_device(dev)) { + error = sysfs_create_file(&dev->kobj,&attr->attr); + put_device(dev); + } + return error; +} + +void device_remove_file(struct device * dev, struct device_attribute * attr) +{ + if (get_device(dev)) { + sysfs_remove_file(&dev->kobj,&attr->attr); + put_device(dev); + } +} int device_add(struct device *dev) { @@ -44,7 +111,11 @@ pr_debug("DEV: registering device: ID = '%s', name = %s\n", dev->bus_id, dev->name); - if ((error = device_make_dir(dev))) + strncpy(dev->kobj.name,dev->bus_id,KOBJ_NAME_LEN); + if (dev->parent) + dev->kobj.parent = &dev->parent->kobj; + dev->kobj.subsys = &device_subsys; + if ((error = kobject_register(&dev->kobj))) goto register_done; bus_add_device(dev); @@ -69,6 +140,7 @@ void device_initialize(struct device *dev) { + kobject_init(&dev->kobj); INIT_LIST_HEAD(&dev->node); INIT_LIST_HEAD(&dev->children); INIT_LIST_HEAD(&dev->g_list); @@ -157,9 +229,6 @@ bus_remove_device(dev); - /* remove the driverfs directory */ - device_remove_dir(dev); - if (dev->release) dev->release(dev); @@ -184,10 +253,21 @@ pr_debug("DEV: Unregistering device. ID = '%s', name = '%s'\n", dev->bus_id,dev->name); + kobject_unregister(&dev->kobj); put_device(dev); } +static int __init device_subsys_init(void) +{ + return subsystem_register(&device_subsys); +} + +core_initcall(device_subsys_init); + EXPORT_SYMBOL(device_register); EXPORT_SYMBOL(device_unregister); EXPORT_SYMBOL(get_device); EXPORT_SYMBOL(put_device); + +EXPORT_SYMBOL(device_create_file); +EXPORT_SYMBOL(device_remove_file); diff -Nru a/drivers/base/cpu.c b/drivers/base/cpu.c --- a/drivers/base/cpu.c Mon Nov 4 14:31:01 2002 +++ b/drivers/base/cpu.c Mon Nov 4 14:31:01 2002 @@ -1,5 +1,5 @@ /* - * cpu.c - basic cpu class support + * drivers/base/cpu.c - basic CPU class support */ #include @@ -7,22 +7,48 @@ #include #include +#include + + static int cpu_add_device(struct device * dev) { return 0; } - struct device_class cpu_devclass = { .name = "cpu", .add_device = cpu_add_device, }; -static int __init cpu_devclass_init(void) +struct device_driver cpu_driver = { + .name = "cpu", + .bus = &system_bus_type, + .devclass = &cpu_devclass, +}; + + +/* + * register_cpu - Setup a driverfs device for a CPU. + * @num - CPU number to use when creating the device. + * + * Initialize and register the CPU device. + */ +int __init register_cpu(struct cpu *cpu, int num, struct node *root) { - return devclass_register(&cpu_devclass); + cpu->node_id = __cpu_to_node(num); + cpu->sysdev.name = "cpu"; + cpu->sysdev.id = num; + if (root) + cpu->sysdev.root = &root->sysroot; + snprintf(cpu->sysdev.dev.name, DEVICE_NAME_SIZE, "CPU %u", num); + cpu->sysdev.dev.driver = &cpu_driver; + return sys_device_register(&cpu->sysdev); } -postcore_initcall(cpu_devclass_init); -EXPORT_SYMBOL(cpu_devclass); +static int __init register_cpu_type(void) +{ + driver_register(&cpu_driver); + return devclass_register(&cpu_devclass); +} +postcore_initcall(register_cpu_type); diff -Nru a/drivers/base/driver.c b/drivers/base/driver.c --- a/drivers/base/driver.c Mon Nov 4 14:31:02 2002 +++ b/drivers/base/driver.c Mon Nov 4 14:31:02 2002 @@ -12,6 +12,29 @@ #define to_dev(node) container_of(node,struct device,driver_list) +/* + * helpers for creating driver attributes in sysfs + */ + +int driver_create_file(struct device_driver * drv, struct driver_attribute * attr) +{ + int error; + if (get_driver(drv)) { + error = sysfs_create_file(&drv->kobj,&attr->attr); + put_driver(drv); + } else + error = -EINVAL; + return error; +} + +void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr) +{ + if (get_driver(drv)) { + sysfs_remove_file(&drv->kobj,&attr->attr); + put_driver(drv); + } +} + int driver_for_each_dev(struct device_driver * drv, void * data, int (*callback)(struct device *, void * )) { @@ -65,7 +88,6 @@ return; spin_unlock(&device_lock); BUG_ON(drv->present); - bus_remove_driver(drv); if (drv->release) drv->release(drv); put_bus(bus); @@ -84,6 +106,11 @@ pr_debug("driver %s:%s: registering\n",drv->bus->name,drv->name); + kobject_init(&drv->kobj); + strncpy(drv->kobj.name,drv->name,KOBJ_NAME_LEN); + drv->kobj.subsys = &drv->bus->drvsubsys; + kobject_register(&drv->kobj); + get_bus(drv->bus); atomic_set(&drv->refcount,2); rwlock_init(&drv->lock); @@ -108,3 +135,6 @@ EXPORT_SYMBOL(driver_unregister); EXPORT_SYMBOL(get_driver); EXPORT_SYMBOL(put_driver); + +EXPORT_SYMBOL(driver_create_file); +EXPORT_SYMBOL(driver_remove_file); diff -Nru a/drivers/base/firmware.c b/drivers/base/firmware.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/base/firmware.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,32 @@ +/* + * firmware.c - firmware subsystem hoohaw. + */ + +#include +#include +#include + +static struct subsystem firmware_subsys = { + .kobj = { .name = "firmware" }, +}; + +int firmware_register(struct subsystem * s) +{ + s->parent = &firmware_subsys; + return subsystem_register(s); +} + +void firmware_unregister(struct subsystem * s) +{ + subsystem_unregister(s); +} + +static int __init firmware_init(void) +{ + return subsystem_register(&firmware_subsys); +} + +core_initcall(firmware_init); + +EXPORT_SYMBOL(firmware_register); +EXPORT_SYMBOL(firmware_unregister); diff -Nru a/drivers/base/fs/Makefile b/drivers/base/fs/Makefile --- a/drivers/base/fs/Makefile Mon Nov 4 14:31:02 2002 +++ b/drivers/base/fs/Makefile Mon Nov 4 14:31:02 2002 @@ -1,5 +1,5 @@ -obj-y := device.o bus.o driver.o class.o intf.o +obj-y := device.o -export-objs := device.o bus.o driver.o class.o +export-objs := device.o include $(TOPDIR)/Rules.make diff -Nru a/drivers/base/fs/bus.c b/drivers/base/fs/bus.c --- a/drivers/base/fs/bus.c Mon Nov 4 14:31:02 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,123 +0,0 @@ -#include -#include -#include -#include -#include "fs.h" - -static struct driver_dir_entry bus_dir; - -#define to_bus_attr(_attr) container_of(_attr,struct bus_attribute,attr) - -#define to_bus(dir) container_of(dir,struct bus_type,dir) - - -/* driverfs ops for device attribute files */ - -static int -bus_attr_open(struct driver_dir_entry * dir) -{ - struct bus_type * bus = to_bus(dir); - get_bus(bus); - return 0; -} - -static int -bus_attr_close(struct driver_dir_entry * dir) -{ - struct bus_type * bus = to_bus(dir); - put_bus(bus); - return 0; -} - -static ssize_t -bus_attr_show(struct driver_dir_entry * dir, struct attribute * attr, - char * buf, size_t count, loff_t off) -{ - struct bus_attribute * bus_attr = to_bus_attr(attr); - struct bus_type * bus = to_bus(dir); - ssize_t ret = 0; - - if (bus_attr->show) - ret = bus_attr->show(bus,buf,count,off); - return ret; -} - -static ssize_t -bus_attr_store(struct driver_dir_entry * dir, struct attribute * attr, - const char * buf, size_t count, loff_t off) -{ - struct bus_attribute * bus_attr = to_bus_attr(attr); - struct bus_type * bus = to_bus(dir); - ssize_t ret = 0; - - if (bus_attr->store) - ret = bus_attr->store(bus,buf,count,off); - return ret; -} - -static struct driverfs_ops bus_attr_ops = { - .open = bus_attr_open, - .close = bus_attr_close, - .show = bus_attr_show, - .store = bus_attr_store, -}; - -int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) -{ - int error; - if (get_bus(bus)) { - error = driverfs_create_file(&attr->attr,&bus->dir); - put_bus(bus); - } else - error = -EINVAL; - return error; -} - -void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) -{ - if (get_bus(bus)) { - driverfs_remove_file(&bus->dir,attr->attr.name); - put_bus(bus); - } -} - -int bus_make_dir(struct bus_type * bus) -{ - int error; - bus->dir.name = bus->name; - bus->dir.ops = &bus_attr_ops; - - error = device_create_dir(&bus->dir,&bus_dir); - if (!error) { - bus->device_dir.name = "devices"; - device_create_dir(&bus->device_dir,&bus->dir); - - bus->driver_dir.name = "drivers"; - device_create_dir(&bus->driver_dir,&bus->dir); - } - return error; -} - -void bus_remove_dir(struct bus_type * bus) -{ - /* remove driverfs entries */ - driverfs_remove_dir(&bus->driver_dir); - driverfs_remove_dir(&bus->device_dir); - driverfs_remove_dir(&bus->dir); -} - -static struct driver_dir_entry bus_dir = { - .name = "bus", - .mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO), -}; - -static int __init bus_init(void) -{ - /* make 'bus' driverfs directory */ - return driverfs_create_dir(&bus_dir,NULL); -} - -core_initcall(bus_init); - -EXPORT_SYMBOL(bus_create_file); -EXPORT_SYMBOL(bus_remove_file); diff -Nru a/drivers/base/fs/class.c b/drivers/base/fs/class.c --- a/drivers/base/fs/class.c Mon Nov 4 14:31:02 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,215 +0,0 @@ -/* - * class.c - driverfs bindings for device classes. - */ - -#include -#include -#include -#include -#include -#include "fs.h" - -static struct driver_dir_entry class_dir; - - -#define to_class_attr(_attr) container_of(_attr,struct devclass_attribute,attr) - -#define to_class(d) container_of(d,struct device_class,dir) - - -static ssize_t -devclass_attr_show(struct driver_dir_entry * dir, struct attribute * attr, - char * buf, size_t count, loff_t off) -{ - struct devclass_attribute * class_attr = to_class_attr(attr); - struct device_class * dc = to_class(dir); - ssize_t ret = 0; - - if (class_attr->show) - ret = class_attr->show(dc,buf,count,off); - return ret; -} - -static ssize_t -devclass_attr_store(struct driver_dir_entry * dir, struct attribute * attr, - const char * buf, size_t count, loff_t off) -{ - struct devclass_attribute * class_attr = to_class_attr(attr); - struct device_class * dc = to_class(dir); - ssize_t ret = 0; - - if (class_attr->store) - ret = class_attr->store(dc,buf,count,off); - return ret; -} - -static struct driverfs_ops devclass_attr_ops = { - show: devclass_attr_show, - store: devclass_attr_store, -}; - -int devclass_create_file(struct device_class * dc, struct devclass_attribute * attr) -{ - int error; - if (dc) { - error = driverfs_create_file(&attr->attr,&dc->dir); - } else - error = -EINVAL; - return error; -} - -void devclass_remove_file(struct device_class * dc, struct devclass_attribute * attr) -{ - if (dc) - driverfs_remove_file(&dc->dir,attr->attr.name); -} - -/** - * devclass_dev_link - create symlink to device's directory - * @cls - device class we're a part of - * @dev - device we're linking to - * - * Create a symlink in the class's devices/ directory to @dev's - * directory in the physical hierarchy. The name is the device's - * class-enumerated value (struct device::class_num). We're - * creating: - * class//devices/ -> - * root// - * So, the link looks like: - * ../../../root// - */ -int devclass_dev_link(struct device_class * cls, struct device * dev) -{ - char linkname[16]; - char * path; - int length; - int error; - - length = get_devpath_length(dev); - length += strlen("../../../root"); - - if (length > PATH_MAX) - return -ENAMETOOLONG; - - if (!(path = kmalloc(length,GFP_KERNEL))) - return -ENOMEM; - memset(path,0,length); - strcpy(path,"../../../root"); - fill_devpath(dev,path,length); - - snprintf(linkname,16,"%u",dev->class_num); - error = driverfs_create_symlink(&cls->device_dir,linkname,path); - kfree(path); - return error; -} - -void devclass_dev_unlink(struct device_class * cls, struct device * dev) -{ - char linkname[16]; - - snprintf(linkname,16,"%u",dev->class_num); - driverfs_remove_file(&cls->device_dir,linkname); -} - -/** - * devclass_drv_link - create symlink to driver's directory - * @drv: driver we're linking up - * - * Create a symlink in the class's drivers/ directory to @drv's - * directory (in the bus's directory). It's name is : - * to prevent naming conflicts. - * - * We're creating - * class//drivers/ -> - * bus//drivers// - * So, the link looks like: - * ../../../bus//drivers/ - */ -int devclass_drv_link(struct device_driver * drv) -{ - char * name; - char * path; - int namelen; - int pathlen; - int error = 0; - - namelen = strlen(drv->name) + strlen(drv->bus->name) + 2; - name = kmalloc(namelen,GFP_KERNEL); - if (!name) - return -ENOMEM; - snprintf(name,namelen,"%s:%s",drv->bus->name,drv->name); - - pathlen = strlen("../../../bus/") + - strlen(drv->bus->name) + - strlen("/drivers/") + - strlen(drv->name) + 1; - if (!(path = kmalloc(pathlen,GFP_KERNEL))) { - error = -ENOMEM; - goto Done; - } - snprintf(path,pathlen,"%s%s%s%s", - "../../../bus/", - drv->bus->name, - "/drivers/", - drv->name); - - error = driverfs_create_symlink(&drv->devclass->driver_dir,name,path); - Done: - kfree(name); - kfree(path); - return error; -} - -void devclass_drv_unlink(struct device_driver * drv) -{ - char * name; - int length; - - length = strlen(drv->name) + strlen(drv->bus->name) + 2; - if ((name = kmalloc(length,GFP_KERNEL))) { - driverfs_remove_file(&drv->devclass->driver_dir,name); - kfree(name); - } -} - -void devclass_remove_dir(struct device_class * dc) -{ - driverfs_remove_dir(&dc->device_dir); - driverfs_remove_dir(&dc->driver_dir); - driverfs_remove_dir(&dc->dir); -} - -int devclass_make_dir(struct device_class * dc) -{ - int error; - - dc->dir.name = dc->name; - dc->dir.ops = &devclass_attr_ops; - error = device_create_dir(&dc->dir,&class_dir); - if (!error) { - dc->driver_dir.name = "drivers"; - error = device_create_dir(&dc->driver_dir,&dc->dir); - if (!error) { - dc->device_dir.name = "devices"; - error = device_create_dir(&dc->device_dir,&dc->dir); - } - if (error) - driverfs_remove_dir(&dc->dir); - } - return error; -} - -static struct driver_dir_entry class_dir = { - name: "class", - mode: (S_IRWXU | S_IRUGO | S_IXUGO), -}; - -static int __init devclass_driverfs_init(void) -{ - return driverfs_create_dir(&class_dir,NULL); -} - -core_initcall(devclass_driverfs_init); - -EXPORT_SYMBOL(devclass_create_file); -EXPORT_SYMBOL(devclass_remove_file); diff -Nru a/drivers/base/fs/device.c b/drivers/base/fs/device.c --- a/drivers/base/fs/device.c Mon Nov 4 14:31:02 2002 +++ b/drivers/base/fs/device.c Mon Nov 4 14:31:02 2002 @@ -16,112 +16,6 @@ #include #include -static struct driver_dir_entry device_root_dir = { - .name = "root", - .mode = (S_IRWXU | S_IRUGO | S_IXUGO), -}; - -extern struct device_attribute * device_default_files[]; - -#define to_dev_attr(_attr) container_of(_attr,struct device_attribute,attr) - -#define to_device(d) container_of(d, struct device, dir) - - -/* driverfs ops for device attribute files */ - -static int -dev_attr_open(struct driver_dir_entry * dir) -{ - struct device * dev = to_device(dir); - get_device(dev); - return 0; -} - -static int -dev_attr_close(struct driver_dir_entry * dir) -{ - struct device * dev = to_device(dir); - put_device(dev); - return 0; -} - -static ssize_t -dev_attr_show(struct driver_dir_entry * dir, struct attribute * attr, - char * buf, size_t count, loff_t off) -{ - struct device_attribute * dev_attr = to_dev_attr(attr); - struct device * dev = to_device(dir); - ssize_t ret = 0; - - if (dev_attr->show) - ret = dev_attr->show(dev,buf,count,off); - return ret; -} - -static ssize_t -dev_attr_store(struct driver_dir_entry * dir, struct attribute * attr, - const char * buf, size_t count, loff_t off) -{ - struct device_attribute * dev_attr = to_dev_attr(attr); - struct device * dev = to_device(dir); - ssize_t ret = 0; - - if (dev_attr->store) - ret = dev_attr->store(dev,buf,count,off); - return ret; -} - -static struct driverfs_ops dev_attr_ops = { - .open = dev_attr_open, - .close = dev_attr_close, - .show = dev_attr_show, - .store = dev_attr_store, -}; - -/** - * device_create_file - create a driverfs file for a device - * @dev: device requesting file - * @entry: entry describing file - * - * Allocate space for file entry, copy descriptor, and create. - */ -int device_create_file(struct device * dev, struct device_attribute * entry) -{ - int error = -EINVAL; - - if (get_device(dev)) { - error = driverfs_create_file(&entry->attr,&dev->dir); - put_device(dev); - } - return error; -} - -/** - * device_remove_file - remove a device's file by name - * @dev: device requesting removal - * @name: name of the file - * - */ -void device_remove_file(struct device * dev, struct device_attribute * attr) -{ - if (dev) { - get_device(dev); - driverfs_remove_file(&dev->dir,attr->attr.name); - put_device(dev); - } -} - -/** - * device_remove_dir - remove a device's directory - * @dev: device in question - */ -void device_remove_dir(struct device * dev) -{ - if (dev) - driverfs_remove_dir(&dev->dir); -} - int get_devpath_length(struct device * dev) { int length = 1; @@ -153,92 +47,3 @@ pr_debug("%s: path = '%s'\n",__FUNCTION__,path); } -int device_bus_link(struct device * dev) -{ - char * path; - int length; - int error = 0; - - if (!dev->bus) - return 0; - - length = get_devpath_length(dev); - - /* now add the path from the bus directory - * It should be '../../..' (one to get to the bus's directory, - * one to get to the 'bus' directory, and one to get to the root - * of the fs.) - */ - length += strlen("../../../root"); - - if (length > PATH_MAX) - return -ENAMETOOLONG; - - if (!(path = kmalloc(length,GFP_KERNEL))) - return -ENOMEM; - memset(path,0,length); - - /* our relative position */ - strcpy(path,"../../../root"); - - fill_devpath(dev,path,length); - error = driverfs_create_symlink(&dev->bus->device_dir,dev->bus_id,path); - kfree(path); - return error; -} - -void device_remove_symlink(struct driver_dir_entry * dir, const char * name) -{ - driverfs_remove_file(dir,name); -} - -int device_create_dir(struct driver_dir_entry * dir, struct driver_dir_entry * parent) -{ - dir->mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO); - return driverfs_create_dir(dir,parent); -} - -/** - * device_make_dir - create a driverfs directory - * @name: name of directory - * @parent: dentry for the parent directory - * - * Do the initial creation of the device's driverfs directory - * and populate it with the one default file. - * - * This is just a helper for device_register(), as we - * don't export this function. (Yes, that means we don't allow - * devices to create subdirectories). - */ -int device_make_dir(struct device * dev) -{ - struct driver_dir_entry * parent; - struct device_attribute * entry; - int error; - int i; - - parent = dev->parent ? &dev->parent->dir : &device_root_dir; - dev->dir.name = dev->bus_id; - dev->dir.ops = &dev_attr_ops; - - if ((error = device_create_dir(&dev->dir,parent))) - return error; - - for (i = 0; (entry = *(device_default_files + i)); i++) { - if ((error = device_create_file(dev,entry))) { - device_remove_dir(dev); - break; - } - } - return error; -} - -static int device_driverfs_init(void) -{ - return driverfs_create_dir(&device_root_dir,NULL); -} - -core_initcall(device_driverfs_init); - -EXPORT_SYMBOL(device_create_file); -EXPORT_SYMBOL(device_remove_file); diff -Nru a/drivers/base/fs/driver.c b/drivers/base/fs/driver.c --- a/drivers/base/fs/driver.c Mon Nov 4 14:31:00 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,100 +0,0 @@ -#include -#include -#include -#include -#include "fs.h" - -#define to_drv_attr(_attr) container_of(_attr,struct driver_attribute,attr) - -#define to_drv(d) container_of(d, struct device_driver, dir) - - -/* driverfs ops for device attribute files */ - -static int -drv_attr_open(struct driver_dir_entry * dir) -{ - struct device_driver * drv = to_drv(dir); - get_driver(drv); - return 0; -} - -static int -drv_attr_close(struct driver_dir_entry * dir) -{ - struct device_driver * drv = to_drv(dir); - put_driver(drv); - return 0; -} - -static ssize_t -drv_attr_show(struct driver_dir_entry * dir, struct attribute * attr, - char * buf, size_t count, loff_t off) -{ - struct driver_attribute * drv_attr = to_drv_attr(attr); - struct device_driver * drv = to_drv(dir); - ssize_t ret = 0; - - if (drv_attr->show) - ret = drv_attr->show(drv,buf,count,off); - return ret; -} - -static ssize_t -drv_attr_store(struct driver_dir_entry * dir, struct attribute * attr, - const char * buf, size_t count, loff_t off) -{ - struct driver_attribute * drv_attr = to_drv_attr(attr); - struct device_driver * drv = to_drv(dir); - ssize_t ret = 0; - - if (drv_attr->store) - ret = drv_attr->store(drv,buf,count,off); - return ret; -} - -static struct driverfs_ops drv_attr_ops = { - .open = drv_attr_open, - .close = drv_attr_close, - .show = drv_attr_show, - .store = drv_attr_store, -}; - -int driver_create_file(struct device_driver * drv, struct driver_attribute * attr) -{ - int error; - if (get_driver(drv)) { - error = driverfs_create_file(&attr->attr,&drv->dir); - put_driver(drv); - } else - error = -EINVAL; - return error; -} - -void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr) -{ - if (get_driver(drv)) { - driverfs_remove_file(&drv->dir,attr->attr.name); - put_driver(drv); - } -} - -/** - * driver_make_dir - create a driverfs directory for a driver - * @drv: driver in question - */ -int driver_make_dir(struct device_driver * drv) -{ - drv->dir.name = drv->name; - drv->dir.ops = &drv_attr_ops; - - return device_create_dir(&drv->dir,&drv->bus->driver_dir); -} - -void driver_remove_dir(struct device_driver * drv) -{ - driverfs_remove_dir(&drv->dir); -} - -EXPORT_SYMBOL(driver_create_file); -EXPORT_SYMBOL(driver_remove_file); diff -Nru a/drivers/base/fs/fs.h b/drivers/base/fs/fs.h --- a/drivers/base/fs/fs.h Mon Nov 4 14:31:01 2002 +++ b/drivers/base/fs/fs.h Mon Nov 4 14:31:01 2002 @@ -1,6 +1,4 @@ -extern int device_create_dir(struct driver_dir_entry * dir, struct driver_dir_entry * parent); - int get_devpath_length(struct device * dev); void fill_devpath(struct device * dev, char * path, int length); diff -Nru a/drivers/base/fs/intf.c b/drivers/base/fs/intf.c --- a/drivers/base/fs/intf.c Mon Nov 4 14:31:01 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,54 +0,0 @@ -/* - * intf.c - driverfs glue for device interfaces - */ - -#include -#include -#include "fs.h" - -/** - * intf_dev_link - symlink from interface's directory to device's directory - * - */ -int intf_dev_link(struct intf_data * data) -{ - char linkname[16]; - char * path; - int length; - int error; - - length = get_devpath_length(data->dev); - length += strlen("../../../root"); - - if (length > PATH_MAX) - return -ENAMETOOLONG; - - if (!(path = kmalloc(length,GFP_KERNEL))) - return -ENOMEM; - memset(path,0,length); - strcpy(path,"../../../root"); - fill_devpath(data->dev,path,length); - - snprintf(linkname,16,"%u",data->intf_num); - error = driverfs_create_symlink(&data->intf->dir,linkname,path); - kfree(path); - return error; -} - -void intf_dev_unlink(struct intf_data * data) -{ - char linkname[16]; - snprintf(linkname,16,"%u",data->intf_num); - driverfs_remove_file(&data->intf->dir,linkname); -} - -void intf_remove_dir(struct device_interface * intf) -{ - driverfs_remove_dir(&intf->dir); -} - -int intf_make_dir(struct device_interface * intf) -{ - intf->dir.name = intf->name; - return device_create_dir(&intf->dir,&intf->devclass->dir); -} diff -Nru a/drivers/base/interface.c b/drivers/base/interface.c --- a/drivers/base/interface.c Mon Nov 4 14:31:00 2002 +++ b/drivers/base/interface.c Mon Nov 4 14:31:00 2002 @@ -88,8 +88,8 @@ static DEVICE_ATTR(power,S_IWUSR | S_IRUGO, device_read_power,device_write_power); -struct device_attribute * device_default_files[] = { - &dev_attr_name, - &dev_attr_power, +struct attribute * dev_default_attrs[] = { + &dev_attr_name.attr, + &dev_attr_power.attr, NULL, }; diff -Nru a/drivers/base/intf.c b/drivers/base/intf.c --- a/drivers/base/intf.c Mon Nov 4 14:31:02 2002 +++ b/drivers/base/intf.c Mon Nov 4 14:31:02 2002 @@ -11,6 +11,26 @@ #define to_intf(node) container_of(node,struct device_interface,node) +/** + * intf_dev_link - symlink from interface's directory to device's directory + * + */ +static int intf_dev_link(struct intf_data * data) +{ + char linkname[16]; + + snprintf(linkname,16,"%u",data->intf_num); + return sysfs_create_link(&data->intf->kobj,&data->dev->kobj,linkname); +} + +static void intf_dev_unlink(struct intf_data * data) +{ + char linkname[16]; + snprintf(linkname,16,"%u",data->intf_num); + sysfs_remove_link(&data->intf->kobj,linkname); +} + + int interface_register(struct device_interface * intf) { struct device_class * cls = intf->devclass; @@ -18,7 +38,11 @@ if (cls) { pr_debug("register interface '%s' with class '%s\n", intf->name,cls->name); - intf_make_dir(intf); + kobject_init(&intf->kobj); + strncpy(intf->kobj.name,intf->name,KOBJ_NAME_LEN); + intf->kobj.subsys = &cls->subsys; + kobject_register(&intf->kobj); + spin_lock(&device_lock); list_add_tail(&intf->node,&cls->intf_list); spin_unlock(&device_lock); @@ -31,11 +55,10 @@ { pr_debug("unregistering interface '%s' from class '%s'\n", intf->name,intf->devclass->name); + kobject_unregister(&intf->kobj); spin_lock(&device_lock); list_del_init(&intf->node); spin_unlock(&device_lock); - - intf_remove_dir(intf); } int interface_add(struct device_class * cls, struct device * dev) diff -Nru a/drivers/base/memblk.c b/drivers/base/memblk.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/base/memblk.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,55 @@ +/* + * drivers/base/memblk.c - basic Memory Block class support + */ + +#include +#include +#include +#include +#include + +#include + + +static int memblk_add_device(struct device * dev) +{ + return 0; +} +struct device_class memblk_devclass = { + .name = "memblk", + .add_device = memblk_add_device, +}; + + +struct device_driver memblk_driver = { + .name = "memblk", + .bus = &system_bus_type, + .devclass = &memblk_devclass, +}; + + +/* + * register_memblk - Setup a driverfs device for a MemBlk + * @num - MemBlk number to use when creating the device. + * + * Initialize and register the MemBlk device. + */ +int __init register_memblk(struct memblk *memblk, int num, struct node *root) +{ + memblk->node_id = __memblk_to_node(num); + memblk->sysdev.name = "memblk"; + memblk->sysdev.id = num; + if (root) + memblk->sysdev.root = &root->sysroot; + snprintf(memblk->sysdev.dev.name, DEVICE_NAME_SIZE, "Memory Block %u", num); + memblk->sysdev.dev.driver = &memblk_driver; + return sys_device_register(&memblk->sysdev); +} + + +static int __init register_memblk_type(void) +{ + driver_register(&memblk_driver); + return devclass_register(&memblk_devclass); +} +postcore_initcall(register_memblk_type); diff -Nru a/drivers/base/node.c b/drivers/base/node.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/base/node.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,99 @@ +/* + * drivers/base/node.c - basic Node class support + */ + +#include +#include +#include +#include +#include + +#include + + +static int node_add_device(struct device * dev) +{ + return 0; +} +struct device_class node_devclass = { + .name = "node", + .add_device = node_add_device, +}; + + +struct device_driver node_driver = { + .name = "node", + .bus = &system_bus_type, + .devclass = &node_devclass, +}; + + +static ssize_t node_read_cpumap(struct device * dev, char * buf, size_t count, loff_t off) +{ + struct node *node_dev = to_node(to_root(dev)); + return off ? 0 : sprintf(buf,"%lx\n",node_dev->cpumap); +} +static DEVICE_ATTR(cpumap,S_IRUGO,node_read_cpumap,NULL); + +#define K(x) ((x) << (PAGE_SHIFT - 10)) +static ssize_t node_read_meminfo(struct device * dev, char * buf, size_t count, loff_t off) +{ + struct sys_root *node = to_root(dev); + int nid = node->id; + struct sysinfo i; + si_meminfo_node(&i, nid); + return off ? 0 : sprintf(buf, "\n" + "Node %d MemTotal: %8lu kB\n" + "Node %d MemFree: %8lu kB\n" + "Node %d MemUsed: %8lu kB\n" + "Node %d HighTotal: %8lu kB\n" + "Node %d HighFree: %8lu kB\n" + "Node %d LowTotal: %8lu kB\n" + "Node %d LowFree: %8lu kB\n", + nid, K(i.totalram), + nid, K(i.freeram), + nid, K(i.totalram-i.freeram), + nid, K(i.totalhigh), + nid, K(i.freehigh), + nid, K(i.totalram-i.totalhigh), + nid, K(i.freeram-i.freehigh)); + + return 0; +} +#undef K +static DEVICE_ATTR(meminfo,S_IRUGO,node_read_meminfo,NULL); + + +/* + * register_node - Setup a driverfs device for a node. + * @num - Node number to use when creating the device. + * + * Initialize and register the node device. + */ +int __init register_node(struct node *node, int num, struct node *parent) +{ + int error; + + node->cpumap = __node_to_cpu_mask(num); + node->sysroot.id = num; + if (parent) + node->sysroot.dev.parent = &parent->sysroot.sysdev; + snprintf(node->sysroot.dev.name, DEVICE_NAME_SIZE, "Node %u", num); + snprintf(node->sysroot.dev.bus_id, BUS_ID_SIZE, "node%u", num); + node->sysroot.dev.driver = &node_driver; + node->sysroot.dev.bus = &system_bus_type; + error = sys_register_root(&node->sysroot); + if (!error){ + device_create_file(&node->sysroot.dev, &dev_attr_cpumap); + device_create_file(&node->sysroot.dev, &dev_attr_meminfo); + } + return error; +} + + +static int __init register_node_type(void) +{ + driver_register(&node_driver); + return devclass_register(&node_devclass); +} +postcore_initcall(register_node_type); diff -Nru a/drivers/base/sys.c b/drivers/base/sys.c --- a/drivers/base/sys.c Mon Nov 4 14:31:00 2002 +++ b/drivers/base/sys.c Mon Nov 4 14:31:00 2002 @@ -55,6 +55,9 @@ if (!root) return -EINVAL; + if (!root->dev.parent) + root->dev.parent = &system_bus; + pr_debug("Registering system board %d\n",root->id); error = device_register(&root->dev); diff -Nru a/drivers/block/DAC960.c b/drivers/block/DAC960.c --- a/drivers/block/DAC960.c Mon Nov 4 14:31:02 2002 +++ b/drivers/block/DAC960.c Mon Nov 4 14:31:02 2002 @@ -2019,14 +2019,9 @@ static int DAC960_revalidate(struct gendisk *disk) { - DAC960_Controller_T *p = disk->private_data; - int unit; - for (unit = 0; unit < DAC960_MaxLogicalDrives; unit++) { - if (p->disks[unit] == disk) { - set_capacity(disk, disk_size(p, unit)); - return 0; - } - } + DAC960_Controller_T *p = disk->queue->queuedata; + int unit = (int)disk->private_data; + set_capacity(disk, disk_size(p, unit)); return 0; } @@ -2205,7 +2200,7 @@ Controller->disks[i] = alloc_disk(1<disks[i]) goto Enomem; - Controller->disks[i]->private_data = Controller; + Controller->disks[i]->private_data = (void*)i; Controller->disks[i]->queue = &Controller->RequestQueue; } Controller->ControllerNumber = DAC960_ControllerCount; @@ -2855,7 +2850,7 @@ Command->CommandType = DAC960_ReadCommand; else Command->CommandType = DAC960_WriteCommand; Command->Completion = Request->waiting; - Command->LogicalDriveNumber = DAC960_LogicalDriveNumber(Request->rq_dev); + Command->LogicalDriveNumber = (int)Request->rq_disk->private_data; Command->BlockNumber = Request->sector; Command->BlockCount = Request->nr_sectors; Command->SegmentCount = Request->nr_phys_segments; diff -Nru a/drivers/block/amiflop.c b/drivers/block/amiflop.c --- a/drivers/block/amiflop.c Mon Nov 4 14:31:01 2002 +++ b/drivers/block/amiflop.c Mon Nov 4 14:31:01 2002 @@ -208,7 +208,7 @@ /* Prevent "aliased" accesses. */ static int fd_ref[4] = { 0,0,0,0 }; -static kdev_t fd_device[4] = { NODEV, NODEV, NODEV, NODEV }; +static int fd_device[4] = { 0, 0, 0, 0 }; /* * Here come the actual hardware access and helper functions. @@ -1369,7 +1369,7 @@ static void redo_fd_request(void) { unsigned int cnt, block, track, sector; - int device, drive; + int drive; struct amiga_floppy_struct *floppy; char *data; unsigned long flags; @@ -1380,19 +1380,8 @@ return; } - device = minor(CURRENT->rq_dev); - if (device < 8) { - /* manual selection */ - drive = device & 3; - } else { - /* Auto-detection */ -#ifdef DEBUG - printk("redo_fd_request: can't handle auto detect\n"); - printk("redo_fd_request: default to normal\n"); -#endif - drive = device & 3; - } floppy = CURRENT->rq_disk->private_data; + drive = floppy - unit; /* Here someone could investigate to be more efficient */ for (cnt = 0; cnt < CURRENT->current_nr_sectors; cnt++) { @@ -1594,17 +1583,16 @@ */ static int floppy_open(struct inode *inode, struct file *filp) { - int drive; - kdev_t old_dev; + int drive = minor(inode->i_rdev) & 3; + int system = (minor(inode->i_rdev) & 4) >> 2; + int old_dev; int system; unsigned long flags; - drive = minor(inode->i_rdev) & 3; old_dev = fd_device[drive]; - if (fd_ref[drive]) - if (!kdev_same(old_dev, inode->i_rdev)) - return -EBUSY; + if (fd_ref[drive] && old_dev != system) + return -EBUSY; if (filp && filp->f_mode & 3) { check_disk_change(inode->i_bdev); @@ -1625,17 +1613,16 @@ save_flags(flags); cli(); fd_ref[drive]++; - fd_device[drive] = inode->i_rdev; + fd_device[drive] = system; #ifdef MODULE if (unit[drive].motor == 0) MOD_INC_USE_COUNT; #endif restore_flags(flags); - if (!kdev_same(old_dev, NODEV) && !kdev_same(old_dev, inode->i_rdev)) - invalidate_buffers(old_dev); + if (old_dev != system) + invalidate_buffers(mk_kdev(MAJOR_NR, drive + (system << 2)); - system=(minor(inode->i_rdev) & 4)>>2; unit[drive].dtype=&data_types[system]; unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks* data_types[system].sects*unit[drive].type->sect_mult; diff -Nru a/drivers/block/ataflop.c b/drivers/block/ataflop.c --- a/drivers/block/ataflop.c Mon Nov 4 14:31:01 2002 +++ b/drivers/block/ataflop.c Mon Nov 4 14:31:01 2002 @@ -1438,8 +1438,9 @@ static void redo_fd_request(void) { - int device, drive, type; - + int drive, type; + struct atari_floppy_struct *floppy; + DPRINT(("redo_fd_request: CURRENT=%p dev=%s CURRENT->sector=%ld\n", CURRENT, !blk_queue_empty(QUEUE) ? CURRENT->rq_disk->disk_name : "", !blk_queue_empty(QUEUE) ? CURRENT->sector : 0 )); @@ -1451,9 +1452,9 @@ if (blk_queue_empty(QUEUE)) goto the_end; - device = minor(CURRENT->rq_dev); - drive = device & 3; - type = device >> 2; + floppy = CURRENT->rq_disk->private_data; + drive = floppy - unit; + type = fd_device[drive]; if (!UD.connected) { /* drive not connected */ @@ -1857,7 +1858,7 @@ int old_dev = fd_device[drive]; DPRINT(("fd_open: type=%d\n",type)); - if (fd_ref[drive] && old_dev != minor(inode->i_rdev)) + if (fd_ref[drive] && old_dev != type) return -EBUSY; if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL)) @@ -1868,10 +1869,10 @@ else fd_ref[drive]++; - fd_device[drive] = minor(inode->i_rdev); + fd_device[drive] = type; - if (old_dev && old_dev != minor(inode->i_rdev)) - invalidate_buffers(mk_kdev(FLOPPY_MAJOR, old_dev)); + if (old_dev && old_dev != type) + invalidate_buffers(mk_kdev(FLOPPY_MAJOR, drive + (type<<2))); if (filp->f_flags & O_NDELAY) return 0; diff -Nru a/drivers/block/elevator.c b/drivers/block/elevator.c --- a/drivers/block/elevator.c Mon Nov 4 14:31:02 2002 +++ b/drivers/block/elevator.c Mon Nov 4 14:31:02 2002 @@ -69,7 +69,7 @@ * if the device is different (not a normal case) just check if * bio is after rq */ - if (!kdev_same(next_rq->rq_dev, rq->rq_dev)) + if (next_rq->rq_disk != rq->rq_disk) return bio->bi_sector > rq->sector; /* @@ -112,7 +112,7 @@ /* * same device and no special stuff set, merge is ok */ - if (kdev_same(rq->rq_dev, to_kdev_t(bio->bi_bdev->bd_dev)) && + if (rq->rq_disk == bio->bi_bdev->bd_disk && !rq->waiting && !rq->special) return 1; diff -Nru a/drivers/block/floppy.c b/drivers/block/floppy.c --- a/drivers/block/floppy.c Mon Nov 4 14:31:01 2002 +++ b/drivers/block/floppy.c Mon Nov 4 14:31:01 2002 @@ -2158,12 +2158,13 @@ DRS->track = NEED_2_RECAL; } -static void set_floppy(kdev_t device) +static void set_floppy(int drive) { - if (TYPE(device)) - _floppy = TYPE(device) + floppy_type; + int type = ITYPE(UDRS->fd_device); + if (type) + _floppy = floppy_type + type; else - _floppy = current_type[ DRIVE(device) ]; + _floppy = current_type[ drive ]; } /* @@ -2269,7 +2270,7 @@ int drive=DRIVE(device); LOCK_FDC(drive,1); - set_floppy(device); + set_floppy(drive); if (!_floppy || _floppy->track > DP->tracks || tmp_format_req->track >= _floppy->track || @@ -2631,7 +2632,7 @@ return 0; } - set_fdc(DRIVE(current_req->rq_dev)); + set_fdc((int)current_req->rq_disk->private_data); raw_cmd = &default_raw_cmd; raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK | @@ -2902,7 +2903,7 @@ static void redo_fd_request(void) { #define REPEAT {request_done(0); continue; } - kdev_t device; + int drive; int tmp; lastredo = jiffies; @@ -2919,11 +2920,11 @@ } current_req = req; } - device = current_req->rq_dev; - set_fdc(DRIVE(device)); + drive = (int)current_req->rq_disk->private_data; + set_fdc(drive); reschedule_timeout(current_reqD, "redo fd request", 0); - set_floppy(device); + set_floppy(drive); raw_cmd = & default_raw_cmd; raw_cmd->flags = 0; if (start_motor(redo_fd_request)) return; @@ -3594,7 +3595,7 @@ if (type) return -EINVAL; LOCK_FDC(drive,1); - set_floppy(device); + set_floppy(drive); CALL(i = raw_cmd_ioctl(cmd,(void *) param)); process_fd_request(); return i; diff -Nru a/drivers/block/genhd.c b/drivers/block/genhd.c --- a/drivers/block/genhd.c Mon Nov 4 14:31:01 2002 +++ b/drivers/block/genhd.c Mon Nov 4 14:31:01 2002 @@ -252,14 +252,6 @@ extern int blk_dev_init(void); -struct device_class disk_devclass = { - .name = "disk", -}; - -static struct bus_type disk_bus = { - name: "block", -}; - static struct gendisk *base_probe(dev_t dev, int *part, void *data) { char name[20]; @@ -268,6 +260,8 @@ return NULL; } +struct subsystem block_subsys; + int __init device_init(void) { struct blk_probe *base = kmalloc(sizeof(struct blk_probe), GFP_KERNEL); @@ -280,23 +274,116 @@ for (i = 1; i < MAX_BLKDEV; i++) probes[i] = base; blk_dev_init(); - devclass_register(&disk_devclass); - bus_register(&disk_bus); + subsystem_register(&block_subsys); return 0; } -__initcall(device_init); +subsys_initcall(device_init); + + + +/* + * kobject & sysfs bindings for block devices + */ + +#define to_disk(obj) container_of(obj,struct gendisk,kobj) + +struct disk_attribute { + struct attribute attr; + ssize_t (*show)(struct gendisk *, char *, size_t, loff_t); +}; + +static ssize_t disk_attr_show(struct kobject * kobj, struct attribute * attr, + char * page, size_t count, loff_t off) +{ + struct gendisk * disk = to_disk(kobj); + struct disk_attribute * disk_attr = container_of(attr,struct disk_attribute,attr); + ssize_t ret = 0; + if (disk_attr->show) + ret = disk_attr->show(disk,page,count,off); + return ret; +} + +static struct sysfs_ops disk_sysfs_ops = { + .show = &disk_attr_show, +}; + +static ssize_t disk_dev_read(struct gendisk * disk, + char *page, size_t count, loff_t off) +{ + dev_t base = MKDEV(disk->major, disk->first_minor); + return off ? 0 : sprintf(page, "%04x\n",base); +} +static ssize_t disk_range_read(struct gendisk * disk, + char *page, size_t count, loff_t off) +{ + return off ? 0 : sprintf(page, "%d\n",disk->minors); +} +static ssize_t disk_size_read(struct gendisk * disk, + char *page, size_t count, loff_t off) +{ + return off ? 0 : sprintf(page, "%llu\n",(unsigned long long)get_capacity(disk)); +} +static inline unsigned MSEC(unsigned x) +{ + return x * 1000 / HZ; +} +static ssize_t disk_stat_read(struct gendisk * disk, + char *page, size_t count, loff_t off) +{ + disk_round_stats(disk); + return off ? 0 : sprintf(page, + "%8u %8u %8llu %8u " + "%8u %8u %8llu %8u " + "%8u %8u %8u" + "\n", + disk->reads, disk->read_merges, (u64)disk->read_sectors, + MSEC(disk->read_ticks), + disk->writes, disk->write_merges, (u64)disk->write_sectors, + MSEC(disk->write_ticks), + disk->in_flight, MSEC(disk->io_ticks), + MSEC(disk->time_in_queue)); +} +static struct disk_attribute disk_attr_dev = { + .attr = {.name = "dev", .mode = S_IRUGO }, + .show = disk_dev_read +}; +static struct disk_attribute disk_attr_range = { + .attr = {.name = "range", .mode = S_IRUGO }, + .show = disk_range_read +}; +static struct disk_attribute disk_attr_size = { + .attr = {.name = "size", .mode = S_IRUGO }, + .show = disk_size_read +}; +static struct disk_attribute disk_attr_stat = { + .attr = {.name = "stat", .mode = S_IRUGO }, + .show = disk_stat_read +}; -EXPORT_SYMBOL(disk_devclass); +static struct attribute * default_attrs[] = { + &disk_attr_dev.attr, + &disk_attr_range.attr, + &disk_attr_size.attr, + &disk_attr_stat.attr, + NULL, +}; -static void disk_release(struct device *dev) +static void disk_release(struct kobject * kobj) { - struct gendisk *disk = dev->driver_data; + struct gendisk *disk = to_disk(kobj); kfree(disk->random); kfree(disk->part); kfree(disk); } +struct subsystem block_subsys = { + .kobj = { .name = "block" }, + .release = disk_release, + .sysfs_ops = &disk_sysfs_ops, + .default_attrs = default_attrs, +}; + struct gendisk *alloc_disk(int minors) { struct gendisk *disk = kmalloc(sizeof(struct gendisk), GFP_KERNEL); @@ -314,11 +401,9 @@ disk->minors = minors; while (minors >>= 1) disk->minor_shift++; + kobject_init(&disk->kobj); + disk->kobj.subsys = &block_subsys; INIT_LIST_HEAD(&disk->full_list); - disk->disk_dev.bus = &disk_bus; - disk->disk_dev.release = disk_release; - disk->disk_dev.driver_data = disk; - device_initialize(&disk->disk_dev); } rand_initialize_disk(disk); return disk; @@ -332,14 +417,13 @@ owner = disk->fops->owner; if (owner && !try_inc_mod_count(owner)) return NULL; - atomic_inc(&disk->disk_dev.refcount); - return disk; + return to_disk(kobject_get(&disk->kobj)); } void put_disk(struct gendisk *disk) { if (disk) - put_device(&disk->disk_dev); + kobject_put(&disk->kobj); } EXPORT_SYMBOL(alloc_disk); diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c --- a/drivers/block/ll_rw_blk.c Mon Nov 4 14:31:00 2002 +++ b/drivers/block/ll_rw_blk.c Mon Nov 4 14:31:00 2002 @@ -27,6 +27,10 @@ #include #include +/* + * Disk stats + */ +struct disk_stat dkstat; /* * For the allocated request tables @@ -580,8 +584,8 @@ if (unlikely((rq->flags & REQ_QUEUED))) { printk(KERN_ERR - "request %p for device [02%x:02%x] already tagged %d", - rq, major(rq->rq_dev), minor(rq->rq_dev), rq->tag); + "request %p for device [%s] already tagged %d", + rq, rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->tag); BUG(); } @@ -661,7 +665,8 @@ { int bit; - printk("%s: dev %02x:%02x: flags = ", msg, major(rq->rq_dev), minor(rq->rq_dev)); + printk("%s: dev %s: flags = ", msg, + rq->rq_disk ? rq->rq_disk->disk_name : "?"); bit = 0; do { if (rq->flags & (1 << bit)) @@ -1406,9 +1411,8 @@ void drive_stat_acct(struct request *rq, int nr_sectors, int new_io) { - unsigned int major = major(rq->rq_dev); int rw = rq_data_dir(rq); - unsigned int index; + unsigned int major, index; if (!rq->rq_disk) return; @@ -1427,18 +1431,19 @@ rq->rq_disk->in_flight++; } + major = rq->rq_disk->major; index = rq->rq_disk->first_minor >> rq->rq_disk->minor_shift; if ((index >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR)) return; - kstat.dk_drive[major][index] += new_io; + dkstat.drive[major][index] += new_io; if (rw == READ) { - kstat.dk_drive_rio[major][index] += new_io; - kstat.dk_drive_rblk[major][index] += nr_sectors; + dkstat.drive_rio[major][index] += new_io; + dkstat.drive_rblk[major][index] += nr_sectors; } else if (rw == WRITE) { - kstat.dk_drive_wio[major][index] += new_io; - kstat.dk_drive_wblk[major][index] += nr_sectors; + dkstat.drive_wio[major][index] += new_io; + dkstat.drive_wblk[major][index] += nr_sectors; } else printk(KERN_ERR "drive_stat_acct: cmd not R/W?\n"); } @@ -1582,7 +1587,7 @@ return; if (rq_data_dir(req) != rq_data_dir(next) - || !kdev_same(req->rq_dev, next->rq_dev) + || req->rq_disk != next->rq_disk || next->waiting || next->special) return; @@ -1794,7 +1799,6 @@ req->buffer = bio_data(bio); /* see ->buffer comment above */ req->waiting = NULL; req->bio = req->biotail = bio; - req->rq_dev = to_kdev_t(bio->bi_bdev->bd_dev); req->rq_disk = bio->bi_bdev->bd_disk; req->start_time = jiffies; add_request(q, req, insert_here); @@ -2014,7 +2018,7 @@ error = -EIO; if (!(req->flags & REQ_QUIET)) printk("end_request: I/O error, dev %s, sector %llu\n", - kdevname(req->rq_dev), + req->rq_disk ? req->rq_disk->disk_name : "?", (unsigned long long)req->sector); } diff -Nru a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c --- a/drivers/block/ps2esdi.c Mon Nov 4 14:31:00 2002 +++ b/drivers/block/ps2esdi.c Mon Nov 4 14:31:00 2002 @@ -74,7 +74,7 @@ static void do_ps2esdi_request(request_queue_t * q); -static void ps2esdi_readwrite(int cmd, u_char drive, u_int block, u_int count); +static void ps2esdi_readwrite(int cmd, struct request *req); static void ps2esdi_fill_cmd_block(u_short * cmd_blk, u_short cmd, u_short cyl, u_short head, u_short sector, u_short length, u_char drive); @@ -567,7 +567,7 @@ struct ps2esdi_i_struct *p = req->rq_disk->private_data; unsigned block = req->sector; unsigned count = req->current_nr_sectors; - int drive = DEVICE_NR(req->rq_dev); + int drive = p - ps2esdi_info; u_short track, head, cylinder, sector; u_short cmd_blk[TYPE_1_CMD_BLK_LENGTH]; diff -Nru a/drivers/block/rd.c b/drivers/block/rd.c --- a/drivers/block/rd.c Mon Nov 4 14:31:02 2002 +++ b/drivers/block/rd.c Mon Nov 4 14:31:02 2002 @@ -204,7 +204,7 @@ kunmap(vec->bv_page); if (rw == READ) { - flush_dcache_page(sbh->b_page); + flush_dcache_page(vec->bv_page); } else { SetPageDirty(page); } @@ -300,6 +300,8 @@ { extern void free_initrd_mem(unsigned long, unsigned long); + blkdev_put(inode->i_bdev, BDEV_FILE); + spin_lock(&initrd_users_lock); if (!--initrd_users) { spin_unlock(&initrd_users_lock); @@ -309,8 +311,6 @@ } else { spin_unlock(&initrd_users_lock); } - - blkdev_put(inode->i_bdev, BDEV_FILE); return 0; } @@ -348,6 +348,7 @@ */ if (rd_bdev[unit] == NULL) { struct block_device *bdev = inode->i_bdev; + atomic_inc(&bdev->bd_count); rd_bdev[unit] = bdev; bdev->bd_openers++; bdev->bd_block_size = rd_blocksize; diff -Nru a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c --- a/drivers/block/scsi_ioctl.c Mon Nov 4 14:31:03 2002 +++ b/drivers/block/scsi_ioctl.c Mon Nov 4 14:31:03 2002 @@ -51,7 +51,6 @@ DECLARE_COMPLETION(wait); int err = 0; - rq->rq_dev = to_kdev_t(bdev->bd_dev); rq->rq_disk = bdev->bd_disk; /* @@ -227,6 +226,7 @@ /* * fill in request structure */ + rq->cmd_len = hdr.cmd_len; copy_from_user(rq->cmd, hdr.cmdp, hdr.cmd_len); if (sizeof(rq->cmd) != hdr.cmd_len) memset(rq->cmd + hdr.cmd_len, 0, sizeof(rq->cmd) - hdr.cmd_len); @@ -349,6 +349,7 @@ * get command and data to send to device, if any */ err = -EFAULT; + rq->cmd_len = cmdlen; if (copy_from_user(rq->cmd, sic->data, cmdlen)) goto error; @@ -463,6 +464,7 @@ memset(rq->cmd, 0, sizeof(rq->cmd)); rq->cmd[0] = GPCMD_START_STOP_UNIT; rq->cmd[4] = 0x02 + (close != 0); + rq->cmd_len = 6; err = blk_do_rq(q, bdev, rq); blk_put_request(rq); break; diff -Nru a/drivers/block/z2ram.c b/drivers/block/z2ram.c --- a/drivers/block/z2ram.c Mon Nov 4 14:31:02 2002 +++ b/drivers/block/z2ram.c Mon Nov 4 14:31:02 2002 @@ -295,7 +295,7 @@ current_device = device; z2ram_size <<= Z2RAM_CHUNKSHIFT; - set_capacity(z2ram_gendisk, z2ram_size >> 9; + set_capacity(z2ram_gendisk, z2ram_size >> 9); } return 0; diff -Nru a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c --- a/drivers/bluetooth/hci_bcsp.c Mon Nov 4 14:31:02 2002 +++ b/drivers/bluetooth/hci_bcsp.c Mon Nov 4 14:31:02 2002 @@ -701,7 +701,13 @@ int bcsp_init(void) { - return hci_uart_register_proto(&bcsp); + int err = hci_uart_register_proto(&bcsp); + if (!err) + BT_INFO("HCI BCSP protocol initialized"); + else + BT_ERR("HCI BCSP protocol registration failed"); + + return err; } int bcsp_deinit(void) diff -Nru a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c --- a/drivers/bluetooth/hci_h4.c Mon Nov 4 14:31:01 2002 +++ b/drivers/bluetooth/hci_h4.c Mon Nov 4 14:31:01 2002 @@ -269,7 +269,13 @@ int h4_init(void) { - return hci_uart_register_proto(&h4p); + int err = hci_uart_register_proto(&h4p); + if (!err) + BT_INFO("HCI H4 protocol initialized"); + else + BT_ERR("HCI H4 protocol registration failed"); + + return err; } int h4_deinit(void) diff -Nru a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c --- a/drivers/bluetooth/hci_ldisc.c Mon Nov 4 14:31:02 2002 +++ b/drivers/bluetooth/hci_ldisc.c Mon Nov 4 14:31:02 2002 @@ -344,7 +344,8 @@ if (tty != hu->tty) return; - hci_uart_tx_wakeup(hu); + if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) + hci_uart_tx_wakeup(hu); } /* hci_uart_tty_room() @@ -521,9 +522,7 @@ static struct tty_ldisc hci_uart_ldisc; int err; - BT_INFO("Bluetooth HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", - VERSION); - BT_INFO("Written 2000,2001 by Maxim Krasnyansky "); + BT_INFO("HCI UART driver ver %s", VERSION); /* Register the tty discipline */ @@ -541,7 +540,7 @@ hci_uart_ldisc.write_wakeup= hci_uart_tty_wakeup; if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) { - BT_ERR("Can't register HCI line discipline (%d)", err); + BT_ERR("HCI line discipline registration failed. (%d)", err); return err; } diff -Nru a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h --- a/drivers/bluetooth/hci_uart.h Mon Nov 4 14:31:00 2002 +++ b/drivers/bluetooth/hci_uart.h Mon Nov 4 14:31:00 2002 @@ -68,7 +68,7 @@ }; /* HCI_UART flag bits */ -#define HCI_UART_PROTO_SET 0x00 +#define HCI_UART_PROTO_SET 0 /* TX states */ #define HCI_UART_SENDING 1 diff -Nru a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c --- a/drivers/bluetooth/hci_usb.c Mon Nov 4 14:31:02 2002 +++ b/drivers/bluetooth/hci_usb.c Mon Nov 4 14:31:02 2002 @@ -805,9 +805,7 @@ { int err; - BT_INFO("Bluetooth HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", - VERSION); - BT_INFO("Written 2000,2001 by Maxim Krasnyansky "); + BT_INFO("HCI USB driver ver %s", VERSION); if ((err = usb_register(&hci_usb_driver)) < 0) BT_ERR("Failed to register HCI USB driver"); diff -Nru a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c --- a/drivers/bluetooth/hci_vhci.c Mon Nov 4 14:31:02 2002 +++ b/drivers/bluetooth/hci_vhci.c Mon Nov 4 14:31:02 2002 @@ -331,9 +331,7 @@ int __init hci_vhci_init(void) { - BT_INFO("Bluetooth VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", - VERSION); - BT_INFO("Written 2000,2001 by Maxim Krasnyansky "); + BT_INFO("VHCI driver ver %s", VERSION); if (misc_register(&hci_vhci_miscdev)) { BT_ERR("Can't register misc device %d\n", VHCI_MINOR); diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile --- a/drivers/char/Makefile Mon Nov 4 14:31:02 2002 +++ b/drivers/char/Makefile Mon Nov 4 14:31:02 2002 @@ -7,14 +7,14 @@ # FONTMAPFILE = cp437.uni -obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o pty.o misc.o random.o eventpoll.o +obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o pty.o misc.o random.o # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. export-objs := busmouse.o vt.o generic_serial.o ip2main.o \ ite_gpio.o keyboard.o misc.o nvram.o random.o rtc.o \ - selection.o sonypi.o sysrq.o tty_io.o tty_ioctl.o eventpoll.o + selection.o sonypi.o sysrq.o tty_io.o tty_ioctl.o obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o consolemap.o consolemap_deftbl.o selection.o keyboard.o obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o @@ -57,7 +57,6 @@ obj-$(CONFIG_R3964) += n_r3964.o obj-$(CONFIG_APPLICOM) += applicom.o obj-$(CONFIG_SONYPI) += sonypi.o -obj-$(CONFIG_ATARIMOUSE) += atarimouse.o obj-$(CONFIG_RTC) += rtc.o obj-$(CONFIG_GEN_RTC) += genrtc.o obj-$(CONFIG_EFI_RTC) += efirtc.o diff -Nru a/drivers/char/amiserial.c b/drivers/char/amiserial.c --- a/drivers/char/amiserial.c Mon Nov 4 14:31:03 2002 +++ b/drivers/char/amiserial.c Mon Nov 4 14:31:03 2002 @@ -2054,8 +2054,8 @@ return ret; } -int rs_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) +static int rs_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) { int len = 0, l; off_t begin = 0; diff -Nru a/drivers/char/eventpoll.c b/drivers/char/eventpoll.c --- a/drivers/char/eventpoll.c Mon Nov 4 14:31:01 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1438 +0,0 @@ -/* - * drivers/char/eventpoll.c ( Efficent event polling implementation ) - * Copyright (C) 2001,...,2002 Davide Libenzi - * - * 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. - * - * Davide Libenzi - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -#define EVENTPOLLFS_MAGIC 0x03111965 /* My birthday should work for this :) */ - -#define DEBUG_EPOLL 0 - -#if DEBUG_EPOLL > 0 -#define DPRINTK(x) printk x -#define DNPRINTK(n, x) do { if ((n) <= DEBUG_EPOLL) printk x; } while (0) -#else /* #if DEBUG_EPOLL > 0 */ -#define DPRINTK(x) (void) 0 -#define DNPRINTK(n, x) (void) 0 -#endif /* #if DEBUG_EPOLL > 0 */ - -#define DEBUG_DPI 0 - -#if DEBUG_DPI != 0 -#define DPI_SLAB_DEBUG (SLAB_DEBUG_FREE | SLAB_RED_ZONE /* | SLAB_POISON */) -#else /* #if DEBUG_DPI != 0 */ -#define DPI_SLAB_DEBUG 0 -#endif /* #if DEBUG_DPI != 0 */ - -#define INITIAL_HASH_BITS 7 -#define MAX_HASH_BITS 18 -#define RESIZE_LENGTH 2 - -#define DPI_MEM_ALLOC() (struct epitem *) kmem_cache_alloc(dpi_cache, SLAB_KERNEL) -#define DPI_MEM_FREE(p) kmem_cache_free(dpi_cache, p) -#define IS_FILE_EPOLL(f) ((f)->f_op == &eventpoll_fops) - - -/* - * Type used for versioning events snapshots inside the double buffer. - */ -typedef unsigned long long event_version_t; - -/* - * This structure is stored inside the "private_data" member of the file - * structure and rapresent the main data sructure for the eventpoll - * interface. - */ -struct eventpoll { - /* - * Protect the evenpoll interface from sys_epoll_ctl(2), ioctl(EP_POLL) - * and ->write() concurrency. It basically serialize the add/remove/edit - * of items in the interest set. - */ - struct rw_semaphore acsem; - - /* - * Protect the this structure access. When the "acsem" is acquired - * togheter with this one, "acsem" should be acquired first. Or, - * "lock" nests inside "acsem". - */ - rwlock_t lock; - - /* Wait queue used by sys_epoll_wait() and ioctl(EP_POLL) */ - wait_queue_head_t wq; - - /* Wait queue used by file->poll() */ - wait_queue_head_t poll_wait; - - /* This is the hash used to store the "struct epitem" elements */ - struct list_head *hash; - - unsigned int hbits; - unsigned int hmask; - atomic_t hents; - atomic_t resize; - - /* Number of pages currently allocated in each side of the double buffer */ - int numpages; - - /* - * Current page set pointer, switched from "pages0" and "pages1" each time - * ep_poll() returns events to the caller. - */ - char **pages; - - /* Each one of these contains the pages allocated for each side of - * the double buffer. - */ - char *pages0[MAX_EVENTPOLL_PAGES]; - char *pages1[MAX_EVENTPOLL_PAGES]; - - /* - * Variable containing the vma base address where the double buffer - * pages are mapped onto. - */ - unsigned long vmabase; - - /* - * Certain functions cannot be called if the double buffer pages are - * not allocated and if the memory mapping is not in place. This tells - * us that everything is setup to fully use the interface. - */ - atomic_t mmapped; - - /* Number of events currently available inside the current snapshot */ - int eventcnt; - - /* - * Variable storing the current "version" of the snapshot. It is used - * to validate the validity of the current slot pointed by the "index" - * member of a "struct epitem". - */ - event_version_t ver; -}; - -/* - * Each file descriptor added to the eventpoll interface will - * have an entry of this type linked to the hash. - */ -struct epitem { - /* List header used to link this structure to the eventpoll hash */ - struct list_head llink; - - /* The "container" of this item */ - struct eventpoll *ep; - - /* The file this item refers to */ - struct file *file; - - /* The structure that describe the interested events and the source fd */ - struct pollfd pfd; - - /* - * The index inside the current double buffer that stores the active - * event slot for this item ( file ). - */ - int index; - - /* - * The version that is used to validate if the current slot is still - * valid or if it refers to an old snapshot. It is matches togheter - * with the one inside the eventpoll structure. - */ - event_version_t ver; -}; - - - - -static int ep_getfd(int *efd, struct inode **einode, struct file **efile); -static int ep_alloc_pages(char **pages, int numpages); -static int ep_free_pages(char **pages, int numpages); -static int ep_init(struct eventpoll *ep); -static void ep_free(struct eventpoll *ep); -static struct epitem *ep_find_nl(struct eventpoll *ep, int fd); -static struct epitem *ep_find(struct eventpoll *ep, int fd); -static int ep_hashresize(struct eventpoll *ep, unsigned long *kflags); -static int ep_insert(struct eventpoll *ep, struct pollfd *pfd); -static int ep_remove(struct eventpoll *ep, struct epitem *dpi); -static void notify_proc(struct file *file, void *data, unsigned long *local, - long *event); -static int open_eventpoll(struct inode *inode, struct file *file); -static int close_eventpoll(struct inode *inode, struct file *file); -static unsigned int poll_eventpoll(struct file *file, poll_table *wait); -static int write_eventpoll(struct file *file, const char *buffer, size_t count, - loff_t *ppos); -static int ep_poll(struct eventpoll *ep, struct evpoll *dvp); -static int ep_do_alloc_pages(struct eventpoll *ep, int numpages); -static int ioctl_eventpoll(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); -static void eventpoll_mm_open(struct vm_area_struct * vma); -static void eventpoll_mm_close(struct vm_area_struct * vma); -static int mmap_eventpoll(struct file *file, struct vm_area_struct *vma); -static int eventpollfs_delete_dentry(struct dentry *dentry); -static struct inode *get_eventpoll_inode(void); -static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data); - - - -/* Slab cache used to allocate "struct epitem" */ -static kmem_cache_t *dpi_cache; - -/* Virtual fs used to allocate inodes for eventpoll files */ -static struct vfsmount *eventpoll_mnt; - -/* File callbacks that implement the eventpoll file behaviour */ -static struct file_operations eventpoll_fops = { - .write = write_eventpoll, - .ioctl = ioctl_eventpoll, - .mmap = mmap_eventpoll, - .open = open_eventpoll, - .release = close_eventpoll, - .poll = poll_eventpoll -}; - -/* Memory mapping callbacks for the eventpoll file */ -static struct vm_operations_struct eventpoll_mmap_ops = { - .open = eventpoll_mm_open, - .close = eventpoll_mm_close, -}; - -/* - * The "struct miscdevice" is used to register the eventpoll device - * to make it suitable to be openend from a /dev file. - */ -static struct miscdevice eventpoll_miscdev = { - EVENTPOLL_MINOR, "eventpoll", &eventpoll_fops -}; - -/* - * This is used to register the virtual file system from where - * eventpoll inodes are allocated. - */ -static struct file_system_type eventpoll_fs_type = { - .name = "eventpollfs", - .get_sb = eventpollfs_get_sb, - .kill_sb = kill_anon_super, -}; - -/* Very basic directory entry operations for the eventpoll virtual file system */ -static struct dentry_operations eventpollfs_dentry_operations = { - .d_delete = eventpollfs_delete_dentry, -}; - - - -/* - * It opens an eventpoll file descriptor by allocating space for "maxfds" - * file descriptors. It is the kernel part of the userspace epoll_create(2). - */ -asmlinkage int sys_epoll_create(int maxfds) -{ - int error = -EINVAL, fd; - unsigned long addr; - struct inode *inode; - struct file *file; - struct eventpoll *ep; - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n", - current, maxfds)); - - /* - * It is not possible to store more than MAX_FDS_IN_EVENTPOLL file - * descriptors inside the eventpoll interface. - */ - if (maxfds > MAX_FDS_IN_EVENTPOLL) - goto eexit_1; - - /* - * Creates all the items needed to setup an eventpoll file. That is, - * a file structure, and inode and a free file descriptor. - */ - error = ep_getfd(&fd, &inode, &file); - if (error) - goto eexit_1; - - /* - * Calls the code to initialize the eventpoll file. This code is - * the same as the "open" file operation callback because inside - * ep_getfd() we did what the kernel usually does before invoking - * corresponding file "open" callback. - */ - error = open_eventpoll(inode, file); - if (error) - goto eexit_2; - - /* The "private_data" member is setup by open_eventpoll() */ - ep = file->private_data; - - /* Alloc pages for the event double buffer */ - error = ep_do_alloc_pages(ep, EP_FDS_PAGES(maxfds + 1)); - if (error) - goto eexit_2; - - /* - * Create a user space mapping of the event double buffer to - * avoid kernel to user space memory copy when returning events - * to the caller. - */ - down_write(¤t->mm->mmap_sem); - addr = do_mmap_pgoff(file, 0, EP_MAP_SIZE(maxfds + 1), PROT_READ, - MAP_PRIVATE, 0); - up_write(¤t->mm->mmap_sem); - error = PTR_ERR((void *) addr); - if (IS_ERR((void *) addr)) - goto eexit_2; - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", - current, maxfds, fd)); - - return fd; - -eexit_2: - sys_close(fd); -eexit_1: - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", - current, maxfds, error)); - return error; -} - - -/* - * The following function implement the controller interface for the eventpoll - * file that enable the insertion/removal/change of file descriptors inside - * the interest set. It rapresents the kernel part of the user spcae epoll_ctl(2). - */ -asmlinkage int sys_epoll_ctl(int epfd, int op, int fd, unsigned int events) -{ - int error = -EBADF; - struct file *file; - struct eventpoll *ep; - struct epitem *dpi; - struct pollfd pfd; - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %u)\n", - current, epfd, op, fd, events)); - - file = fget(epfd); - if (!file) - goto eexit_1; - - /* - * We have to check that the file structure underneath the file descriptor - * the user passed to us _is_ an eventpoll file. - */ - error = -EINVAL; - if (!IS_FILE_EPOLL(file)) - goto eexit_2; - - /* - * At this point it is safe to assume that the "private_data" contains - * our own data structure. - */ - ep = file->private_data; - - down_write(&ep->acsem); - - pfd.fd = fd; - pfd.events = events | POLLERR | POLLHUP; - pfd.revents = 0; - - dpi = ep_find(ep, fd); - - error = -EINVAL; - switch (op) { - case EP_CTL_ADD: - if (!dpi) - error = ep_insert(ep, &pfd); - else - error = -EEXIST; - break; - case EP_CTL_DEL: - if (dpi) - error = ep_remove(ep, dpi); - else - error = -ENOENT; - break; - case EP_CTL_MOD: - if (dpi) { - dpi->pfd.events = events; - error = 0; - } else - error = -ENOENT; - break; - } - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %u) = %d\n", - current, epfd, op, fd, events, error)); - - up_write(&ep->acsem); - -eexit_2: - fput(file); -eexit_1: - return error; -} - - -/* - * Implement the event wait interface for the eventpoll file. It is the kernel - * part of the user space epoll_wait(2). - */ -asmlinkage int sys_epoll_wait(int epfd, struct pollfd const **events, int timeout) -{ - int error = -EBADF; - void *eaddr; - struct file *file; - struct eventpoll *ep; - struct evpoll dvp; - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d)\n", - current, epfd, events, timeout)); - - file = fget(epfd); - if (!file) - goto eexit_1; - - /* - * We have to check that the file structure underneath the file descriptor - * the user passed to us _is_ an eventpoll file. - */ - error = -EINVAL; - if (!IS_FILE_EPOLL(file)) - goto eexit_2; - - /* - * At this point it is safe to assume that the "private_data" contains - * our own data structure. - */ - ep = file->private_data; - - /* - * It is possible that the user created an eventpoll file by open()ing - * the corresponding /dev/ file and he did not perform the correct - * initialization required by the old /dev/epoll interface. This test - * protect us from this scenario. - */ - error = -EINVAL; - if (!atomic_read(&ep->mmapped)) - goto eexit_2; - - dvp.ep_timeout = timeout; - error = ep_poll(ep, &dvp); - if (error > 0) { - eaddr = (void *) (ep->vmabase + dvp.ep_resoff); - if (copy_to_user(events, &eaddr, sizeof(struct pollfd *))) - error = -EFAULT; - } - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d) = %d\n", - current, epfd, events, timeout, error)); - -eexit_2: - fput(file); -eexit_1: - return error; -} - - -/* - * Creates the file descriptor to be used by the epoll interface. - */ -static int ep_getfd(int *efd, struct inode **einode, struct file **efile) -{ - struct qstr this; - char name[32]; - struct dentry *dentry; - struct inode *inode; - struct file *file; - int error, fd; - - /* Get an ready to use file */ - error = -ENFILE; - file = get_empty_filp(); - if (!file) - goto eexit_1; - - /* Allocates an inode from the eventpoll file system */ - inode = get_eventpoll_inode(); - error = PTR_ERR(inode); - if (IS_ERR(inode)) - goto eexit_2; - - /* Allocates a free descriptor to plug the file onto */ - error = get_unused_fd(); - if (error < 0) - goto eexit_3; - fd = error; - - /* - * Link the inode to a directory entry by creating a unique name - * using the inode number. - */ - error = -ENOMEM; - sprintf(name, "[%lu]", inode->i_ino); - this.name = name; - this.len = strlen(name); - this.hash = inode->i_ino; - dentry = d_alloc(eventpoll_mnt->mnt_sb->s_root, &this); - if (!dentry) - goto eexit_4; - dentry->d_op = &eventpollfs_dentry_operations; - d_add(dentry, inode); - file->f_vfsmnt = mntget(eventpoll_mnt); - file->f_dentry = dget(dentry); - - /* - * Initialize the file as read/write because it could be used - * with write() to add/remove/change interest sets. - */ - file->f_pos = 0; - file->f_flags = O_RDWR; - file->f_op = &eventpoll_fops; - file->f_mode = FMODE_READ | FMODE_WRITE; - file->f_version = 0; - file->private_data = NULL; - - /* Install the new setup file into the allocated fd. */ - fd_install(fd, file); - - *efd = fd; - *einode = inode; - *efile = file; - return 0; - -eexit_4: - put_unused_fd(fd); -eexit_3: - iput(inode); -eexit_2: - put_filp(file); -eexit_1: - return error; -} - - -static int ep_alloc_pages(char **pages, int numpages) -{ - int ii; - - for (ii = 0; ii < numpages; ii++) { - pages[ii] = (char *) __get_free_pages(GFP_KERNEL, 0); - if (!pages[ii]) { - for (--ii; ii >= 0; ii--) { - ClearPageReserved(virt_to_page(pages[ii])); - free_pages((unsigned long) pages[ii], 0); - } - return -ENOMEM; - } - SetPageReserved(virt_to_page(pages[ii])); - } - return 0; -} - - -static int ep_free_pages(char **pages, int numpages) -{ - int ii; - - for (ii = 0; ii < numpages; ii++) { - ClearPageReserved(virt_to_page(pages[ii])); - free_pages((unsigned long) pages[ii], 0); - } - return 0; -} - - -static int ep_init(struct eventpoll *ep) -{ - int ii, hentries; - - init_rwsem(&ep->acsem); - rwlock_init(&ep->lock); - init_waitqueue_head(&ep->wq); - init_waitqueue_head(&ep->poll_wait); - ep->hbits = INITIAL_HASH_BITS; - ep->hmask = (1 << ep->hbits) - 1; - atomic_set(&ep->hents, 0); - atomic_set(&ep->resize, 0); - atomic_set(&ep->mmapped, 0); - ep->numpages = 0; - ep->vmabase = 0; - ep->pages = ep->pages0; - ep->eventcnt = 0; - ep->ver = 1; - - hentries = ep->hmask + 1; - if (!(ep->hash = (struct list_head *) vmalloc(hentries * sizeof(struct list_head)))) - return -ENOMEM; - - for (ii = 0; ii < hentries; ii++) - INIT_LIST_HEAD(&ep->hash[ii]); - - return 0; -} - - -static void ep_free(struct eventpoll *ep) -{ - int ii; - struct list_head *lsthead; - - /* - * Walks through the whole hash by unregistering file callbacks and - * freeing each "struct epitem". - */ - for (ii = 0; ii <= ep->hmask; ii++) { - lsthead = &ep->hash[ii]; - while (!list_empty(lsthead)) { - struct epitem *dpi = list_entry(lsthead->next, struct epitem, llink); - - file_notify_delcb(dpi->file, notify_proc); - list_del(lsthead->next); - DPI_MEM_FREE(dpi); - } - } - /* - * At this point we can free the hash and the pages used for the event - * double buffer. The ep_free() function is called from the "close" - * file operations callback, and this garanties us that the pages are - * already unmapped. - */ - vfree(ep->hash); - if (ep->numpages > 0) { - ep_free_pages(ep->pages0, ep->numpages); - ep_free_pages(ep->pages1, ep->numpages); - } -} - - -/* - * No lock version of ep_find(), used when the code had to acquire the lock - * before calling the function. - */ -static struct epitem *ep_find_nl(struct eventpoll *ep, int fd) -{ - struct epitem *dpi = NULL; - struct list_head *lsthead, *lnk; - - lsthead = &ep->hash[fd & ep->hmask]; - list_for_each(lnk, lsthead) { - dpi = list_entry(lnk, struct epitem, llink); - - if (dpi->pfd.fd == fd) break; - dpi = NULL; - } - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_find(%d) -> %p\n", - current, fd, dpi)); - - return dpi; -} - - -static struct epitem *ep_find(struct eventpoll *ep, int fd) -{ - struct epitem *dpi; - unsigned long flags; - - read_lock_irqsave(&ep->lock, flags); - - dpi = ep_find_nl(ep, fd); - - read_unlock_irqrestore(&ep->lock, flags); - - return dpi; -} - - -static int ep_hashresize(struct eventpoll *ep, unsigned long *kflags) -{ - struct list_head *hash, *oldhash; - unsigned int hbits = ep->hbits + 1; - unsigned int hmask = (1 << hbits) - 1; - int ii, res, hentries = hmask + 1; - unsigned long flags = *kflags; - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_hashresize(%p) bits=%u\n", - current, ep, hbits)); - - write_unlock_irqrestore(&ep->lock, flags); - - res = -ENOMEM; - if (!(hash = (struct list_head *) vmalloc(hentries * sizeof(struct list_head)))) { - write_lock_irqsave(&ep->lock, flags); - goto eexit_1; - } - - for (ii = 0; ii < hentries; ii++) - INIT_LIST_HEAD(&hash[ii]); - - write_lock_irqsave(&ep->lock, flags); - - oldhash = ep->hash; - for (ii = 0; ii <= ep->hmask; ii++) { - struct list_head *oldhead = &oldhash[ii], *lnk; - - while (!list_empty(oldhead)) { - struct epitem *dpi = list_entry(lnk = oldhead->next, struct epitem, llink); - - list_del(lnk); - list_add(lnk, &hash[dpi->pfd.fd & hmask]); - } - } - - ep->hash = hash; - ep->hbits = hbits; - ep->hmask = hmask; - - write_unlock_irqrestore(&ep->lock, flags); - vfree(oldhash); - write_lock_irqsave(&ep->lock, flags); - - res = 0; -eexit_1: - *kflags = flags; - atomic_dec(&ep->resize); - return res; -} - - -static int ep_insert(struct eventpoll *ep, struct pollfd *pfd) -{ - int error; - struct epitem *dpi; - struct file *file; - unsigned long flags; - - if (atomic_read(&ep->hents) >= (ep->numpages * POLLFD_X_PAGE)) - return -E2BIG; - - file = fget(pfd->fd); - if (!file) - return -EBADF; - - error = -ENOMEM; - if (!(dpi = DPI_MEM_ALLOC())) - goto eexit_1; - - INIT_LIST_HEAD(&dpi->llink); - dpi->ep = ep; - dpi->file = file; - dpi->pfd = *pfd; - dpi->index = -1; - dpi->ver = ep->ver - 1; - - write_lock_irqsave(&ep->lock, flags); - - list_add(&dpi->llink, &ep->hash[pfd->fd & ep->hmask]); - atomic_inc(&ep->hents); - - if (!atomic_read(&ep->resize) && - (atomic_read(&ep->hents) >> ep->hbits) > RESIZE_LENGTH && - ep->hbits < MAX_HASH_BITS) { - atomic_inc(&ep->resize); - ep_hashresize(ep, &flags); - } - - write_unlock_irqrestore(&ep->lock, flags); - - file_notify_addcb(file, notify_proc, dpi); - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_insert(%p, %d)\n", - current, ep, pfd->fd)); - - error = 0; -eexit_1: - fput(file); - - return error; -} - - -/* - * Removes a "struct epitem" from the eventpoll hash and deallocates - * all the associated resources. - */ -static int ep_remove(struct eventpoll *ep, struct epitem *dpi) -{ - unsigned long flags; - struct pollfd *pfd, *lpfd; - struct epitem *ldpi; - - /* First, removes the callback from the file callback list */ - file_notify_delcb(dpi->file, notify_proc); - - write_lock_irqsave(&ep->lock, flags); - - list_del(&dpi->llink); - atomic_dec(&ep->hents); - - /* - * This is to remove stale events. We don't want that the removed file - * has a pending event that might be associated with a file inserted - * at a later time inside the eventpoll interface. this code checks - * if the currently removed file has a valid pending event and, if it does, - * manages things to remove it and decrement the currently available - * event count. - */ - if (dpi->index >= 0 && dpi->ver == ep->ver && dpi->index < ep->eventcnt) { - pfd = (struct pollfd *) (ep->pages[EVENT_PAGE_INDEX(dpi->index)] + - EVENT_PAGE_OFFSET(dpi->index)); - if (pfd->fd == dpi->pfd.fd && dpi->index < --ep->eventcnt) { - lpfd = (struct pollfd *) (ep->pages[EVENT_PAGE_INDEX(ep->eventcnt)] + - EVENT_PAGE_OFFSET(ep->eventcnt)); - *pfd = *lpfd; - - if ((ldpi = ep_find_nl(ep, pfd->fd))) ldpi->index = dpi->index; - } - } - - write_unlock_irqrestore(&ep->lock, flags); - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %d)\n", - current, ep, dpi->pfd.fd)); - - /* At this point it is safe to free the eventpoll item */ - DPI_MEM_FREE(dpi); - - return 0; -} - - -/* - * This is the event notify callback that is called from fs/fcblist.c because - * of the registration ( file_notify_addcb() ) done in ep_insert(). - */ -static void notify_proc(struct file *file, void *data, unsigned long *local, - long *event) -{ - struct epitem *dpi = data; - struct eventpoll *ep = dpi->ep; - struct pollfd *pfd; - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: notify(%p, %p, %ld, %ld) ep=%p\n", - current, file, data, event[0], event[1], ep)); - - /* - * We don't need to disable IRQs here because the callback dispatch - * routine inside fs/fcblist.c already call us with disabled IRQ. - */ - write_lock(&ep->lock); - - /* We're not expecting any of those events. Jump out soon ... */ - if (!(dpi->pfd.events & event[1])) - goto out; - - /* - * This logic determins if an active even slot is available for the - * currently signaled file, or if we have to make space for a new one - * and increment the number of ready file descriptors ( ep->eventcnt ). - */ - if (dpi->index < 0 || dpi->ver != ep->ver) { - if (ep->eventcnt >= (ep->numpages * POLLFD_X_PAGE)) - goto out; - dpi->index = ep->eventcnt++; - dpi->ver = ep->ver; - pfd = (struct pollfd *) (ep->pages[EVENT_PAGE_INDEX(dpi->index)] + - EVENT_PAGE_OFFSET(dpi->index)); - *pfd = dpi->pfd; - } else { - pfd = (struct pollfd *) (ep->pages[EVENT_PAGE_INDEX(dpi->index)] + - EVENT_PAGE_OFFSET(dpi->index)); - if (pfd->fd != dpi->pfd.fd) { - if (ep->eventcnt >= (ep->numpages * POLLFD_X_PAGE)) - goto out; - dpi->index = ep->eventcnt++; - pfd = (struct pollfd *) (ep->pages[EVENT_PAGE_INDEX(dpi->index)] + - EVENT_PAGE_OFFSET(dpi->index)); - *pfd = dpi->pfd; - } - } - - /* - * Merge event bits into the corresponding event slot inside the - * double buffer. - */ - pfd->revents |= (pfd->events & event[1]); - - /* - * Wake up ( if active ) both the eventpoll wait list and the ->poll() - * wait list. - */ - if (waitqueue_active(&ep->wq)) - wake_up(&ep->wq); - if (waitqueue_active(&ep->poll_wait)) - wake_up(&ep->poll_wait); -out: - write_unlock(&ep->lock); -} - - -static int open_eventpoll(struct inode *inode, struct file *file) -{ - int res; - struct eventpoll *ep; - - if (!(ep = kmalloc(sizeof(struct eventpoll), GFP_KERNEL))) - return -ENOMEM; - - memset(ep, 0, sizeof(*ep)); - if ((res = ep_init(ep))) { - kfree(ep); - return res; - } - - file->private_data = ep; - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: open() ep=%p\n", current, ep)); - return 0; -} - - -static int close_eventpoll(struct inode *inode, struct file *file) -{ - struct eventpoll *ep = file->private_data; - - if (ep) { - ep_free(ep); - kfree(ep); - } - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: close() ep=%p\n", current, ep)); - return 0; -} - - -static unsigned int poll_eventpoll(struct file *file, poll_table *wait) -{ - struct eventpoll *ep = file->private_data; - - poll_wait(file, &ep->poll_wait, wait); - if (ep->eventcnt) - return POLLIN | POLLRDNORM; - - return 0; -} - - -static int write_eventpoll(struct file *file, const char *buffer, size_t count, - loff_t *ppos) -{ - int rcount; - struct eventpoll *ep = file->private_data; - struct epitem *dpi; - struct pollfd pfd; - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: write(%p, %d)\n", current, ep, count)); - - /* The size of the write must be a multiple of sizeof(struct pollfd) */ - rcount = -EINVAL; - if (count % sizeof(struct pollfd)) - goto eexit_1; - - /* - * And we have also to verify that that area is correctly accessible - * for the user. - */ - if ((rcount = verify_area(VERIFY_READ, buffer, count))) - goto eexit_1; - - down_write(&ep->acsem); - - rcount = 0; - - while (count > 0) { - if (__copy_from_user(&pfd, buffer, sizeof(pfd))) { - rcount = -EFAULT; - goto eexit_2; - } - - dpi = ep_find(ep, pfd.fd); - - if (pfd.fd >= current->files->max_fds || !current->files->fd[pfd.fd]) - pfd.events = POLLREMOVE; - if (pfd.events & POLLREMOVE) { - if (dpi) { - ep_remove(ep, dpi); - rcount += sizeof(pfd); - } - } - else if (dpi) { - dpi->pfd.events = pfd.events; - rcount += sizeof(pfd); - } else { - pfd.revents = 0; - if (!ep_insert(ep, &pfd)) - rcount += sizeof(pfd); - } - - buffer += sizeof(pfd); - count -= sizeof(pfd); - } - -eexit_2: - up_write(&ep->acsem); -eexit_1: - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: write(%p, %d) = %d\n", - current, ep, count, rcount)); - - return rcount; -} - - -static int ep_poll(struct eventpoll *ep, struct evpoll *dvp) -{ - int res = 0; - long timeout; - unsigned long flags; - wait_queue_t wait; - - /* - * We don't want ep_poll() to be called if the correct sequence - * of operations are performed to initialize it. This won't happen - * for the system call interface but it could happen using the - * old /dev/epoll interface, that is maintained for compatibility. - */ - if (!atomic_read(&ep->mmapped)) - return -EINVAL; - - write_lock_irqsave(&ep->lock, flags); - - res = 0; - if (!ep->eventcnt) { - /* - * We don't have any available event to return to the caller. - * We need to sleep here, and we will be wake up by - * notify_proc() when events will become available. - */ - init_waitqueue_entry(&wait, current); - add_wait_queue(&ep->wq, &wait); - - /* - * Calculate the timeout by checking for the "infinite" value ( -1 ) - * and the overflow condition ( > MAX_SCHEDULE_TIMEOUT / HZ ). The - * passed timeout is in milliseconds, that why (t * HZ) / 1000. - */ - timeout = dvp->ep_timeout == -1 || dvp->ep_timeout > MAX_SCHEDULE_TIMEOUT / HZ ? - MAX_SCHEDULE_TIMEOUT: (dvp->ep_timeout * HZ) / 1000; - - for (;;) { - /* - * We don't want to sleep if the notify_proc() sends us - * a wakeup in between. That's why we set the task state - * to TASK_INTERRUPTIBLE before doing the checks. - */ - set_current_state(TASK_INTERRUPTIBLE); - if (ep->eventcnt || !timeout) - break; - if (signal_pending(current)) { - res = -EINTR; - break; - } - - write_unlock_irqrestore(&ep->lock, flags); - timeout = schedule_timeout(timeout); - write_lock_irqsave(&ep->lock, flags); - } - remove_wait_queue(&ep->wq, &wait); - - set_current_state(TASK_RUNNING); - } - - /* - * If we've been wake up because of events became available, we need to: - * - * 1) null the number of available ready file descriptors - * 2) increment the version of the current ( next ) snapshot - * 3) swap the double buffer to return the current one to the caller - * 4) set the current ( for the user, previous for the interface ) offset - */ - if (!res && ep->eventcnt) { - res = ep->eventcnt; - ep->eventcnt = 0; - ++ep->ver; - if (ep->pages == ep->pages0) { - ep->pages = ep->pages1; - dvp->ep_resoff = 0; - } else { - ep->pages = ep->pages0; - dvp->ep_resoff = ep->numpages * PAGE_SIZE; - } - } - - write_unlock_irqrestore(&ep->lock, flags); - - return res; -} - - -static int ep_do_alloc_pages(struct eventpoll *ep, int numpages) -{ - int res, pgalloc, pgcpy; - unsigned long flags; - char **pages, **pages0, **pages1; - - if (atomic_read(&ep->mmapped)) - return -EBUSY; - if (numpages > MAX_EVENTPOLL_PAGES) - return -EINVAL; - - pgalloc = numpages - ep->numpages; - if ((pages = (char **) vmalloc(2 * (pgalloc + 1) * sizeof(char *))) == NULL) - return -ENOMEM; - pages0 = &pages[0]; - pages1 = &pages[pgalloc + 1]; - - if ((res = ep_alloc_pages(pages0, pgalloc))) - goto eexit_1; - - if ((res = ep_alloc_pages(pages1, pgalloc))) { - ep_free_pages(pages0, pgalloc); - goto eexit_1; - } - - write_lock_irqsave(&ep->lock, flags); - pgcpy = (ep->numpages + pgalloc) > numpages ? numpages - ep->numpages: pgalloc; - if (pgcpy > 0) { - memcpy(&ep->pages0[ep->numpages], pages0, pgcpy * sizeof(char *)); - memcpy(&ep->pages1[ep->numpages], pages1, pgcpy * sizeof(char *)); - ep->numpages += pgcpy; - } - write_unlock_irqrestore(&ep->lock, flags); - - if (pgcpy < pgalloc) { - if (pgcpy < 0) - pgcpy = 0; - ep_free_pages(&pages0[pgcpy], pgalloc - pgcpy); - ep_free_pages(&pages1[pgcpy], pgalloc - pgcpy); - } - -eexit_1: - vfree(pages); - return res; -} - - -static int ioctl_eventpoll(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int res; - struct eventpoll *ep = file->private_data; - struct epitem *dpi; - unsigned long flags; - struct pollfd pfd; - struct evpoll dvp; - - switch (cmd) { - case EP_ALLOC: - res = ep_do_alloc_pages(ep, EP_FDS_PAGES(arg)); - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ioctl(%p, EP_ALLOC, %lu) == %d\n", - current, ep, arg, res)); - return res; - - case EP_FREE: - if (atomic_read(&ep->mmapped)) - return -EBUSY; - - res = -EINVAL; - write_lock_irqsave(&ep->lock, flags); - if (ep->numpages > 0) { - ep_free_pages(ep->pages0, ep->numpages); - ep_free_pages(ep->pages1, ep->numpages); - ep->numpages = 0; - ep->pages = ep->pages0; - res = 0; - } - write_unlock_irqrestore(&ep->lock, flags); - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ioctl(%p, EP_FREE) == %d\n", - current, ep, res)); - return res; - - case EP_POLL: - if (copy_from_user(&dvp, (void *) arg, sizeof(struct evpoll))) - return -EFAULT; - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ioctl(%p, EP_POLL, %d)\n", - current, ep, dvp.ep_timeout)); - - res = ep_poll(ep, &dvp); - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ioctl(%p, EP_POLL, %d) == %d\n", - current, ep, dvp.ep_timeout, res)); - - if (res > 0 && copy_to_user((void *) arg, &dvp, sizeof(struct evpoll))) - res = -EFAULT; - - return res; - - case EP_ISPOLLED: - if (copy_from_user(&pfd, (void *) arg, sizeof(struct pollfd))) - return 0; - - read_lock_irqsave(&ep->lock, flags); - - res = 0; - if (!(dpi = ep_find_nl(ep, pfd.fd))) - goto is_not_polled; - - pfd = dpi->pfd; - res = 1; - - is_not_polled: - read_unlock_irqrestore(&ep->lock, flags); - - if (res) - copy_to_user((void *) arg, &pfd, sizeof(struct pollfd)); - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ioctl(%p, EP_ISPOLLED, %d) == %d\n", - current, ep, pfd.fd, res)); - return res; - } - - return -EINVAL; -} - - -static void eventpoll_mm_open(struct vm_area_struct * vma) -{ - struct file *file = vma->vm_file; - struct eventpoll *ep = file->private_data; - - if (ep) atomic_inc(&ep->mmapped); - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: mm_open(%p)\n", current, ep)); -} - - -static void eventpoll_mm_close(struct vm_area_struct * vma) -{ - struct file *file = vma->vm_file; - struct eventpoll *ep = file->private_data; - - if (ep && atomic_dec_and_test(&ep->mmapped)) - ep->vmabase = 0; - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: mm_close(%p)\n", current, ep)); -} - - -static int mmap_eventpoll(struct file *file, struct vm_area_struct *vma) -{ - struct eventpoll *ep = file->private_data; - unsigned long start; - int ii, res, numpages; - size_t mapsize; - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: mmap(%p, %lx, %lx)\n", - current, ep, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT)); - - /* - * We need the eventpoll file to be RW but we don't want it to be - * mapped RW. This test perform the test and reject RW mmaping. - */ - if (vma->vm_flags & VM_WRITE) - return -EACCES; - - if ((vma->vm_pgoff << PAGE_SHIFT) != 0) - return -EINVAL; - - /* - * We need to verify that the mapped area covers all the allocated - * double buffer. - */ - mapsize = PAGE_ALIGN(vma->vm_end - vma->vm_start); - numpages = mapsize >> PAGE_SHIFT; - - res = -EINVAL; - if (numpages != (2 * ep->numpages)) - goto eexit_1; - - /* - * Map the double buffer starting from "vma->vm_start" up to - * "vma->vm_start + ep->numpages * PAGE_SIZE". - */ - start = vma->vm_start; - for (ii = 0; ii < ep->numpages; ii++) { - if ((res = remap_page_range(vma, start, __pa(ep->pages0[ii]), - PAGE_SIZE, vma->vm_page_prot))) - goto eexit_1; - start += PAGE_SIZE; - } - for (ii = 0; ii < ep->numpages; ii++) { - if ((res = remap_page_range(vma, start, __pa(ep->pages1[ii]), - PAGE_SIZE, vma->vm_page_prot))) - goto eexit_1; - start += PAGE_SIZE; - } - vma->vm_ops = &eventpoll_mmap_ops; - - /* Saves the base mapping address for later use in sys_epoll_wait(2) */ - ep->vmabase = vma->vm_start; - - /* - * Ok, mapping has been done. We can open the door to functions that - * requires the mapping to be in place. - */ - atomic_set(&ep->mmapped, 1); - - res = 0; -eexit_1: - - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: mmap(%p, %lx, %lx) == %d\n", - current, ep, vma->vm_start, vma->vm_pgoff << PAGE_SHIFT, res)); - return res; -} - - -static int eventpollfs_delete_dentry(struct dentry *dentry) -{ - - return 1; -} - - -static struct inode *get_eventpoll_inode(void) -{ - int error = -ENOMEM; - struct inode *inode = new_inode(eventpoll_mnt->mnt_sb); - - if (!inode) - goto eexit_1; - - inode->i_fop = &eventpoll_fops; - - /* - * Mark the inode dirty from the very beginning, - * that way it will never be moved to the dirty - * list because "mark_inode_dirty()" will think - * that it already _is_ on the dirty list. - */ - inode->i_state = I_DIRTY; - inode->i_mode = S_IRUSR | S_IWUSR; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inode->i_blksize = PAGE_SIZE; - return inode; - -eexit_1: - return ERR_PTR(error); -} - - -static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) -{ - - return get_sb_pseudo(fs_type, "eventpoll:", NULL, EVENTPOLLFS_MAGIC); -} - - -static int __init eventpoll_init(void) -{ - int error; - - /* Allocates slab cache used to allocate "struct epitem" items */ - error = -ENOMEM; - dpi_cache = kmem_cache_create("eventpoll", - sizeof(struct epitem), - __alignof__(struct epitem), - DPI_SLAB_DEBUG, NULL, NULL); - if (!dpi_cache) - goto eexit_1; - - /* - * Register the virtual file system that will be the source of inodes - * for the eventpoll files - */ - error = register_filesystem(&eventpoll_fs_type); - if (error) - goto eexit_2; - - /* Mount the above commented virtual file system */ - eventpoll_mnt = kern_mount(&eventpoll_fs_type); - error = PTR_ERR(eventpoll_mnt); - if (IS_ERR(eventpoll_mnt)) - goto eexit_3; - - /* - * This is to maintain compatibility with the old /dev/epoll interface. - * We need to register a misc device so that the caller can open(2) it - * through a file inside /dev. - */ - error = misc_register(&eventpoll_miscdev); - if (error) - goto eexit_4; - - printk(KERN_INFO "[%p] eventpoll: driver installed.\n", current); - - return error; - -eexit_4: - mntput(eventpoll_mnt); -eexit_3: - unregister_filesystem(&eventpoll_fs_type); -eexit_2: - kmem_cache_destroy(dpi_cache); -eexit_1: - - return error; -} - - -static void __exit eventpoll_exit(void) -{ - /* Undo all operations done inside eventpoll_init() */ - unregister_filesystem(&eventpoll_fs_type); - mntput(eventpoll_mnt); - misc_deregister(&eventpoll_miscdev); - kmem_cache_destroy(dpi_cache); -} - -module_init(eventpoll_init); -module_exit(eventpoll_exit); - -MODULE_LICENSE("GPL"); - diff -Nru a/drivers/char/nvram.c b/drivers/char/nvram.c --- a/drivers/char/nvram.c Mon Nov 4 14:31:01 2002 +++ b/drivers/char/nvram.c Mon Nov 4 14:31:01 2002 @@ -98,6 +98,8 @@ #define RTC_PORT(x) (TT_RTC_BAS + 2*(x)) #define CHECK_DRIVER_INIT() (MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK)) +#define NVRAM_BYTES 50 + /* On Ataris, the checksum is over all bytes except the checksum bytes * themselves; these are at the very end */ #define ATARI_CKS_RANGE_START 0 diff -Nru a/drivers/char/raw.c b/drivers/char/raw.c --- a/drivers/char/raw.c Mon Nov 4 14:31:02 2002 +++ b/drivers/char/raw.c Mon Nov 4 14:31:02 2002 @@ -56,9 +56,15 @@ bdev = raw_devices[minor].binding; err = -ENODEV; if (bdev) { + err = bd_claim(bdev, raw_open); + if (err) + goto out; atomic_inc(&bdev->bd_count); err = blkdev_get(bdev, filp->f_mode, 0, BDEV_RAW); - if (!err) { + if (err) { + bd_release(bdev); + goto out; + } else { err = set_blocksize(bdev, bdev_hardsect_size(bdev)); if (err == 0) { raw_devices[minor].inuse++; @@ -69,6 +75,7 @@ } } filp->private_data = bdev; +out: up(&raw_mutex); return err; } @@ -82,6 +89,7 @@ bdev = raw_devices[minor].binding; raw_devices[minor].inuse--; up(&raw_mutex); + bd_release(bdev); blkdev_put(bdev, BDEV_RAW); return 0; } diff -Nru a/drivers/char/sysrq.c b/drivers/char/sysrq.c --- a/drivers/char/sysrq.c Mon Nov 4 14:31:02 2002 +++ b/drivers/char/sysrq.c Mon Nov 4 14:31:02 2002 @@ -35,6 +35,10 @@ #include +#ifdef CONFIG_VOYAGER +#include +#endif + extern void reset_vc(unsigned int); extern struct list_head super_blocks; @@ -319,6 +323,14 @@ action_msg: "Terminate All Tasks", }; +#ifdef CONFIG_VOYAGER +static struct sysrq_key_op sysrq_voyager_dump_op = { + handler: voyager_dump, + help_msg: "voyager", + action_msg: "Dump Voyager Status\n", +}; +#endif + static void sysrq_handle_kill(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { @@ -352,7 +364,11 @@ it is handled specially on the sparc and will never arrive */ /* b */ &sysrq_reboot_op, +#ifdef CONFIG_VOYAGER +/* c */ &sysrq_voyager_dump_op, +#else /* c */ NULL, +#endif /* d */ NULL, /* e */ &sysrq_term_op, /* f */ NULL, diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c --- a/drivers/ide/ide-cd.c Mon Nov 4 14:31:01 2002 +++ b/drivers/ide/ide-cd.c Mon Nov 4 14:31:01 2002 @@ -878,10 +878,12 @@ * changed 5 parameters to 3 for dvd-ram * struct packet_command *pc; now packet_command_t *pc; */ +#define ATAPI_MIN_CDB_BYTES 12 static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive, struct request *rq, ide_handler_t *handler) { + int cmd_len; struct cdrom_info *info = drive->driver_data; ide_startstop_t startstop; @@ -905,8 +907,13 @@ /* Arm the interrupt handler. */ ide_set_handler(drive, handler, rq->timeout, cdrom_timer_expiry); + /* ATAPI commands get padded out to 12 bytes minimum */ + cmd_len = rq->cmd_len; + if (cmd_len < ATAPI_MIN_CDB_BYTES) + cmd_len = ATAPI_MIN_CDB_BYTES; + /* Send the command to the device. */ - HWIF(drive)->atapi_output_bytes(drive, rq->cmd, sizeof(rq->cmd)); + HWIF(drive)->atapi_output_bytes(drive, rq->cmd, cmd_len); /* Start the DMA if need be */ if (info->dma) @@ -3004,6 +3011,7 @@ */ rq->cmd[7] = (blocks >> 8) & 0xff; rq->cmd[8] = blocks & 0xff; + rq->cmd_len = 10; return BLKPREP_OK; } @@ -3026,6 +3034,7 @@ c[2] = 0; c[1] &= 0xe0; c[0] += (READ_10 - READ_6); + rq->cmd_len = 10; return BLKPREP_OK; } diff -Nru a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h --- a/drivers/ide/ide-cd.h Mon Nov 4 14:31:03 2002 +++ b/drivers/ide/ide-cd.h Mon Nov 4 14:31:03 2002 @@ -104,9 +104,6 @@ #define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags)) -struct packet_command { -}; - /* Structure of a MSF cdrom address. */ struct atapi_msf { byte reserved; @@ -472,7 +469,6 @@ struct request_sense sense_data; struct request request_sense_request; - struct packet_command request_sense_pc; int dma; int cmd; unsigned long last_block; diff -Nru a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c --- a/drivers/ide/ide-floppy.c Mon Nov 4 14:31:01 2002 +++ b/drivers/ide/ide-floppy.c Mon Nov 4 14:31:01 2002 @@ -1263,8 +1263,8 @@ unsigned long block = (unsigned long)block_s; #if IDEFLOPPY_DEBUG_LOG - printk(KERN_INFO "rq_status: %d, rq_dev: %u, flags: %lx, errors: %d\n", - rq->rq_status, (unsigned int) rq->rq_dev, + printk(KERN_INFO "rq_status: %d, dev: %s, flags: %lx, errors: %d\n", + rq->rq_status, rq->rq_disk->disk_name, rq->flags, rq->errors); printk(KERN_INFO "sector: %ld, nr_sectors: %ld, " "current_nr_sectors: %ld\n", (long)rq->sector, diff -Nru a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c --- a/drivers/ide/ide-lib.c Mon Nov 4 14:31:02 2002 +++ b/drivers/ide/ide-lib.c Mon Nov 4 14:31:02 2002 @@ -171,7 +171,7 @@ BUG(); return min(speed, speed_max[mode]); #else /* !CONFIG_BLK_DEV_IDEDMA */ - return min(speed, XFER_PIO_4); + return min(speed, (u8)XFER_PIO_4); #endif /* CONFIG_BLK_DEV_IDEDMA */ } diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c --- a/drivers/ide/ide-tape.c Mon Nov 4 14:31:01 2002 +++ b/drivers/ide/ide-tape.c Mon Nov 4 14:31:01 2002 @@ -2591,8 +2591,8 @@ #if 0 if (tape->debug_level >= 5) printk(KERN_INFO "ide-tape: rq_status: %d, " - "rq_dev: %u, cmd: %ld, errors: %d\n", rq->rq_status, - (unsigned int) rq->rq_dev, rq->flags, rq->errors); + "dev: %s, cmd: %ld, errors: %d\n", rq->rq_status, + rq->rq_disk->disk_name, rq->flags, rq->errors); #endif if (tape->debug_level >= 2) printk(KERN_INFO "ide-tape: sector: %ld, " diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c --- a/drivers/ide/ide-taskfile.c Mon Nov 4 14:31:00 2002 +++ b/drivers/ide/ide-taskfile.c Mon Nov 4 14:31:00 2002 @@ -1356,7 +1356,6 @@ rq->special = args; rq->errors = 0; rq->rq_status = RQ_ACTIVE; - rq->rq_dev = mk_kdev(disk->major, disk->first_minor); rq->rq_disk = drive->disk; rq->waiting = &wait; diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c --- a/drivers/ide/ide.c Mon Nov 4 14:31:01 2002 +++ b/drivers/ide/ide.c Mon Nov 4 14:31:01 2002 @@ -181,13 +181,13 @@ static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */ -#if defined(__mc68000__) || defined(CONFIG_APUS) +#ifdef IDE_ARCH_LOCK /* * ide_lock is used by the Atari code to obtain access to the IDE interrupt, * which is shared between several drivers. */ static int ide_intr_lock; -#endif /* __mc68000__ || CONFIG_APUS */ +#endif /* IDE_ARCH_LOCK */ #ifdef CONFIG_IDEDMA_AUTO int noautodma = 0; @@ -1092,7 +1092,7 @@ */ /* for atari only */ - ide_release_lock(&ide_lock); + ide_release_lock(&ide_intr_lock); hwgroup->busy = 0; } @@ -1530,7 +1530,6 @@ rq->errors = 0; rq->rq_status = RQ_ACTIVE; - rq->rq_dev = mk_kdev(drive->disk->major, drive->disk->first_minor); rq->rq_disk = drive->disk; /* diff -Nru a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c --- a/drivers/input/keyboard/amikbd.c Mon Nov 4 14:31:02 2002 +++ b/drivers/input/keyboard/amikbd.c Mon Nov 4 14:31:02 2002 @@ -112,7 +112,7 @@ if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb")) return -EBUSY; - init_input_dev(&amibkd_dev); + init_input_dev(&amikbd_dev); amikbd_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); amikbd_dev.keycode = amikbd_keycode; diff -Nru a/drivers/macintosh/mac_keyb.c b/drivers/macintosh/mac_keyb.c --- a/drivers/macintosh/mac_keyb.c Mon Nov 4 14:31:01 2002 +++ b/drivers/macintosh/mac_keyb.c Mon Nov 4 14:31:01 2002 @@ -247,14 +247,6 @@ static void init_microspeed(int id); static void init_ms_a3(int id); -#ifdef CONFIG_ADBMOUSE -/* XXX: Hook for mouse driver */ -void (*adb_mouse_interrupt_hook)(unsigned char *, int); -int adb_emulate_buttons = 0; -int adb_button2_keycode = 0x7d; /* right control key */ -int adb_button3_keycode = 0x7c; /* right option key */ -#endif - extern struct kbd_struct kbd_table[]; extern void handle_scancode(unsigned char, int); @@ -342,38 +334,6 @@ if (!repeat) del_timer(&repeat_timer); -#ifdef CONFIG_ADBMOUSE - /* - * XXX: Add mouse button 2+3 fake codes here if mouse open. - * Keep track of 'button' states here as we only send - * single up/down events! - * Really messy; might need to check if keyboard is in - * VC_RAW mode. - * Might also want to know how many buttons need to be emulated. - * -> hide this as function in arch/m68k/mac ? - */ - if (adb_emulate_buttons - && (keycode == adb_button2_keycode - || keycode == adb_button3_keycode) - && (adb_mouse_interrupt_hook || console_loglevel == 10)) { - int button; - /* faked ADB packet */ - static unsigned char data[4] = { 0, 0x80, 0x80, 0x80 }; - - button = keycode == adb_button2_keycode? 2: 3; - if (data[button] != up_flag) { - /* send a fake mouse packet */ - data[button] = up_flag; - if (console_loglevel >= 8) - printk("fake mouse event: %x %x %x\n", - data[1], data[2], data[3]); - if (adb_mouse_interrupt_hook) - adb_mouse_interrupt_hook(data, 4); - } - return; - } -#endif /* CONFIG_ADBMOUSE */ - if (kbd->kbdmode != VC_RAW) { if (!up_flag && !dont_repeat[keycode]) { last_keycode = keycode; @@ -428,163 +388,6 @@ } } -#ifdef CONFIG_ADBMOUSE -static void -mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) -{ - /* [ACA:23-Mar-97] Three button mouse support. This is designed to - function with MkLinux DR-2.1 style X servers. It only works with - three-button mice that conform to Apple's multi-button mouse - protocol. */ - - /* - The X server for MkLinux DR2.1 uses the following unused keycodes to - read the mouse: - - 0x7e This indicates that the next two keycodes should be interpreted - as mouse information. The first following byte's high bit - represents the state of the left button. The lower seven bits - represent the x-axis acceleration. The lower seven bits of the - second byte represent y-axis acceleration. - - 0x3f The x server interprets this keycode as a middle button - release. - - 0xbf The x server interprets this keycode as a middle button - depress. - - 0x40 The x server interprets this keycode as a right button - release. - - 0xc0 The x server interprets this keycode as a right button - depress. - - NOTES: There should be a better way of handling mice in the X server. - The MOUSE_ESCAPE code (0x7e) should be followed by three bytes instead - of two. The three mouse buttons should then, in the X server, be read - as the high-bits of all three bytes. The x and y motions can still be - in the first two bytes. Maybe I'll do this... - */ - - /* - Handler 1 -- 100cpi original Apple mouse protocol. - Handler 2 -- 200cpi original Apple mouse protocol. - - For Apple's standard one-button mouse protocol the data array will - contain the following values: - - BITS COMMENTS - data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. - data[1] = bxxx xxxx First button and x-axis motion. - data[2] = byyy yyyy Second button and y-axis motion. - - Handler 4 -- Apple Extended mouse protocol. - - For Apple's 3-button mouse protocol the data array will contain the - following values: - - BITS COMMENTS - data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. - data[1] = bxxx xxxx Left button and x-axis motion. - data[2] = byyy yyyy Second button and y-axis motion. - data[3] = byyy bxxx Third button and fourth button. Y is additional - high bits of y-axis motion. XY is additional - high bits of x-axis motion. - - MacAlly 2-button mouse protocol. - - For MacAlly 2-button mouse protocol the data array will contain the - following values: - - BITS COMMENTS - data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. - data[1] = bxxx xxxx Left button and x-axis motion. - data[2] = byyy yyyy Right button and y-axis motion. - data[3] = ???? ???? unknown - data[4] = ???? ???? unknown - - */ - struct kbd_struct *kbd; - - /* If it's a trackpad, we alias the second button to the first. - NOTE: Apple sends an ADB flush command to the trackpad when - the first (the real) button is released. We could do - this here using async flush requests. - */ - switch (adb_mouse_kinds[(data[0]>>4) & 0xf]) - { - case ADBMOUSE_TRACKPAD: - data[1] = (data[1] & 0x7f) | ((data[1] & data[2]) & 0x80); - data[2] = data[2] | 0x80; - break; - case ADBMOUSE_MICROSPEED: - data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7); - data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6); - data[3] = (data[3] & 0x77) | ((data[3] & 0x04) << 5) - | (data[3] & 0x08); - break; - case ADBMOUSE_TRACKBALLPRO: - data[1] = (data[1] & 0x7f) | (((data[3] & 0x04) << 5) - & ((data[3] & 0x08) << 4)); - data[2] = (data[2] & 0x7f) | ((data[3] & 0x01) << 7); - data[3] = (data[3] & 0x77) | ((data[3] & 0x02) << 6); - break; - case ADBMOUSE_MS_A3: - data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7); - data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6); - data[3] = ((data[3] & 0x04) << 5); - break; - case ADBMOUSE_MACALLY2: - data[3] = (data[2] & 0x80) ? 0x80 : 0x00; - data[2] |= 0x80; /* Right button is mapped as button 3 */ - nb=4; - break; - } - - if (adb_mouse_interrupt_hook) - adb_mouse_interrupt_hook(data, nb); - - kbd = kbd_table + fg_console; - - /* Only send mouse codes when keyboard is in raw mode. */ - if (kbd->kbdmode == VC_RAW) { - static unsigned char uch_ButtonStateSecond = 0x80; - unsigned char uchButtonSecond; - - /* Send first button, second button and movement. */ - mac_put_queue(0x7e); - mac_put_queue(data[1]); - mac_put_queue(data[2]); - - /* [ACA: Are there any two-button ADB mice that use handler 1 or 2?] */ - - /* Store the button state. */ - uchButtonSecond = (data[2] & 0x80); - - /* Send second button. */ - if (uchButtonSecond != uch_ButtonStateSecond) { - mac_put_queue(0x3f | uchButtonSecond); - uch_ButtonStateSecond = uchButtonSecond; - } - - /* Macintosh 3-button mouse (handler 4). */ - if (nb >= 4) { - static unsigned char uch_ButtonStateThird = 0x80; - unsigned char uchButtonThird; - - /* Store the button state for speed. */ - uchButtonThird = (data[3] & 0x80); - - /* Send third button. */ - if (uchButtonThird != uch_ButtonStateThird) { - mac_put_queue(0x40 | uchButtonThird); - uch_ButtonStateThird = uchButtonThird; - } - } - } -} -#endif /* CONFIG_ADBMOUSE */ - static void buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) { @@ -708,11 +511,6 @@ memcpy(key_maps[8], macalt_map, sizeof(plain_map)); memcpy(key_maps[12], macctrl_alt_map, sizeof(plain_map)); -#ifdef CONFIG_ADBMOUSE - /* initialize mouse interrupt hook */ - adb_mouse_interrupt_hook = NULL; -#endif - led_request.complete = 1; mackeyb_probe(); @@ -751,10 +549,6 @@ { struct adb_request req; int i; - -#ifdef CONFIG_ADBMOUSE - adb_register(ADB_MOUSE, 0, &mouse_ids, mouse_input); -#endif /* CONFIG_ADBMOUSE */ adb_register(ADB_KEYBOARD, 0, &keyboard_ids, keyboard_input); adb_register(0x07, 0x1F, &buttons_ids, buttons_input); diff -Nru a/drivers/media/Kconfig b/drivers/media/Kconfig --- a/drivers/media/Kconfig Mon Nov 4 14:31:01 2002 +++ b/drivers/media/Kconfig Mon Nov 4 14:31:01 2002 @@ -12,9 +12,14 @@ this are available from . - If you are interested in writing a driver for such an audio/video - device or user software interacting with such a driver, please read - the file . + This kernel includes support for the new Video for Linux Two API, + (V4L2) as well as the original system. Drivers and applications + need to be rewritten to use V4L2, but drivers for popular cards + and applications for most video capture functions already exist. + + Documentation for the original API is included in the file + Documentation/video4linux/API.html. Documentation for V4L2 is + available on the web at http://bytesex.org/v4l/ This driver is also available as a module called videodev.o ( = code which can be inserted in and removed from the running kernel diff -Nru a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig --- a/drivers/media/video/Kconfig Mon Nov 4 14:31:02 2002 +++ b/drivers/media/video/Kconfig Mon Nov 4 14:31:02 2002 @@ -212,5 +212,17 @@ whenever you want). If you want to compile it as a module, say M here and read . +config VIDEO_SAA7134 + tristate "Philips SAA7134 support" + depends on VIDEO_DEV && PCI && I2C + ---help--- + This is a video4linux driver for Philips SAA7130/7134 based + TV cards. + + This driver is available as a module called saa7134.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read . + endmenu diff -Nru a/drivers/media/video/Makefile b/drivers/media/video/Makefile --- a/drivers/media/video/Makefile Mon Nov 4 14:31:01 2002 +++ b/drivers/media/video/Makefile Mon Nov 4 14:31:01 2002 @@ -5,13 +5,14 @@ # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. -export-objs := videodev.o bttv-if.o cpia.o video-buf.o +export-objs := videodev.o v4l2-common.o \ + bttv-if.o cpia.o video-buf.o bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ bttv-risc.o bttv-vbi.o zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o -obj-$(CONFIG_VIDEO_DEV) += videodev.o +obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \ tda7432.o tda9875.o tuner.o video-buf.o @@ -34,6 +35,7 @@ obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o obj-$(CONFIG_VIDEO_MEYE) += meye.o +obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ tuner.o tda9887.o obj-$(CONFIG_TUNER_3036) += tuner-3036.o include $(TOPDIR)/Rules.make diff -Nru a/drivers/media/video/bt848.h b/drivers/media/video/bt848.h --- a/drivers/media/video/bt848.h Mon Nov 4 14:31:01 2002 +++ b/drivers/media/video/bt848.h Mon Nov 4 14:31:01 2002 @@ -347,6 +347,8 @@ #define BT848_PLL_X (1<<7) #define BT848_PLL_C (1<<6) +#define BT848_DVSIF 0x0FC + /* Bt878 register */ #define BT878_DEVCTRL 0x40 diff -Nru a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c --- a/drivers/media/video/bttv-cards.c Mon Nov 4 14:31:01 2002 +++ b/drivers/media/video/bttv-cards.c Mon Nov 4 14:31:01 2002 @@ -37,15 +37,16 @@ #include "bttvp.h" #include "tuner.h" +#if 0 +# include "bt832.h" +#endif /* fwd decl */ static void boot_msp34xx(struct bttv *btv, int pin); static void hauppauge_eeprom(struct bttv *btv); static void avermedia_eeprom(struct bttv *btv); +static void osprey_eeprom(struct bttv *btv); static void init_PXC200(struct bttv *btv); -#if 0 -static void init_tea5757(struct bttv *btv); -#endif static void winview_audio(struct bttv *btv, struct video_audio *v, int set); static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set); @@ -58,6 +59,12 @@ static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set); static void windvr_audio(struct bttv *btv, struct video_audio *v, int set); static void rv605_muxsel(struct bttv *btv, unsigned int input); +static void eagle_muxsel(struct bttv *btv, unsigned int input); + +static int terratec_active_radio_upgrade(struct bttv *btv); +static int tea5757_read(struct bttv *btv); +static int tea5757_write(struct bttv *btv, int value); + /* config variables */ static int triton1=0; @@ -83,11 +90,11 @@ MODULE_PARM_DESC(vsfx,"set VSFX pci config bit " "[yet another chipset flaw workaround]"); MODULE_PARM(no_overlay,"i"); -MODULE_PARM(card,"1-" __MODULE_STRING(BTTV_MAX) "i"); +MODULE_PARM(card,"1-" __stringify(BTTV_MAX) "i"); MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list"); -MODULE_PARM(pll,"1-" __MODULE_STRING(BTTV_MAX) "i"); +MODULE_PARM(pll,"1-" __stringify(BTTV_MAX) "i"); MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)"); -MODULE_PARM(tuner,"1-" __MODULE_STRING(BTTV_MAX) "i"); +MODULE_PARM(tuner,"1-" __stringify(BTTV_MAX) "i"); MODULE_PARM_DESC(tuner,"specify installed tuner type"); MODULE_PARM(autoload,"i"); MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)"); @@ -127,24 +134,29 @@ } cards[] __devinitdata = { { 0x13eb0070, BTTV_HAUPPAUGE878, "Hauppauge WinTV" }, { 0x39000070, BTTV_HAUPPAUGE878, "Hauppauge WinTV-D" }, - { 0x45000070, BTTV_HAUPPAUGE878, "Hauppauge WinTV/PVR" }, - { 0xff000070, BTTV_HAUPPAUGE878, "Osprey-100" }, - { 0xff010070, BTTV_HAUPPAUGE878, "Osprey-200" }, + { 0x45000070, BTTV_HAUPPAUGEPVR, "Hauppauge WinTV/PVR" }, + { 0xff000070, BTTV_OSPREY1x0, "Osprey-100" }, + { 0xff010070, BTTV_OSPREY2x0_SVID,"Osprey-200" }, + { 0xff020070, BTTV_OSPREY500, "Osprey-500" }, + { 0xff030070, BTTV_OSPREY2000, "Osprey-2000" }, + { 0xff040070, BTTV_OSPREY540, "Osprey-540" }, { 0x00011002, BTTV_ATI_TVWONDER, "ATI TV Wonder" }, { 0x00031002, BTTV_ATI_TVWONDERVE,"ATI TV Wonder/VE" }, { 0x6606107d, BTTV_WINFAST2000, "Leadtek WinFast TV 2000" }, { 0x6607107d, BTTV_WINFAST2000, "Leadtek WinFast VC 100" }, - { 0x263610b4, BTTV_STB2, "STB TV PCI FM, P/N 6000704" }, + { 0x263610b4, BTTV_STB2, "STB TV PCI FM, Gateway P/N 6000704" }, { 0x402010fc, BTTV_GVBCTV3PCI, "I-O Data Co. GV-BCTV3/PCI" }, { 0x405010fc, BTTV_GVBCTV4PCI, "I-O Data Co. GV-BCTV4/PCI" }, + { 0x407010fc, BTTV_GVBCTV5PCI, "I-O Data Co. GV-BCTV5/PCI" }, { 0x1200bd11, BTTV_PINNACLE, "Pinnacle PCTV" }, { 0x001211bd, BTTV_PINNACLE, "Pinnacle PCTV" }, { 0x001c11bd, BTTV_PINNACLE, "Pinnacle PCTV Sat" }, { 0x3000121a, BTTV_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" }, + { 0x3060121a, BTTV_STB2, "3Dfx VoodooTV 100/ STB OEM" }, { 0x3000144f, BTTV_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" }, { 0x3002144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" }, @@ -170,6 +182,7 @@ { 0x1135153b, BTTV_TERRATVALUER, "Terratec TValue Radio" }, { 0x5018153b, BTTV_TERRATVALUE, "Terratec TValue" }, + { 0x400015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, { 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" }, { 0x400d15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, { 0x401015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" }, @@ -225,7 +238,7 @@ needs_tvaudio: 1, tuner_type: -1, },{ - name: "STB", + name: "STB, Gateway P/N 6000699 (bt848)", video_inputs: 3, audio_inputs: 1, tuner: 0, @@ -235,7 +248,9 @@ audiomux: { 4, 0, 2, 3, 1}, no_msp34xx: 1, needs_tvaudio: 1, - tuner_type: -1, + tuner_type: TUNER_PHILIPS_NTSC, + pll: PLL_28, + has_radio: 1, },{ /* ---- card 0x04 ---------------------------------- */ @@ -357,7 +372,7 @@ audiomux: { 13, 14, 11, 7, 0, 0}, needs_tvaudio: 1, pll: PLL_28, - tuner_type: -1, + tuner_type: TUNER_PHILIPS_PAL, },{ name: "Aimslab Video Highway Xtreme (VHX)", video_inputs: 3, @@ -490,16 +505,17 @@ pll: PLL_28, tuner_type: -1, },{ - name: "Terratec Terra TV+ Version 1.0 (Bt848)/Vobis TV-Boostar", + name: "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar", video_inputs: 3, audio_inputs: 1, tuner: 0, svhs: 2, - gpiomask: 16777215, + gpiomask: 0x1f0fff, muxsel: { 2, 3, 1, 1}, - audiomux: { 131072, 1, 1638400, 3,4}, - needs_tvaudio: 1, - tuner_type: -1, + audiomux: { 0x20000, 0x30000, 0x10000, 0, 0x40000}, + needs_tvaudio: 0, + tuner_type: TUNER_PHILIPS_PAL, + audio_hook: terratv_audio, },{ name: "Hauppauge WinCam newer (bt878)", video_inputs: 4, @@ -525,17 +541,48 @@ },{ /* ---- card 0x1c ---------------------------------- */ - name: "Terratec TerraTV+", + name: "Terratec TerraTV+ Version 1.1 (bt878)", video_inputs: 3, audio_inputs: 1, tuner: 0, svhs: 2, - gpiomask: 0x70000, + gpiomask: 0x1f0fff, muxsel: { 2, 3, 1, 1}, audiomux: { 0x20000, 0x30000, 0x10000, 0x00000, 0x40000}, - needs_tvaudio: 1, + needs_tvaudio: 0, tuner_type: TUNER_PHILIPS_PAL, audio_hook: terratv_audio, + /* GPIO wiring: + External 20 pin connector (for Active Radio Upgrade board) + gpio00: i2c-sda + gpio01: i2c-scl + gpio02: om5610-data + gpio03: om5610-clk + gpio04: om5610-wre + gpio05: om5610-stereo + gpio06: rds6588-davn + gpio07: Pin 7 n.c. + gpio08: nIOW + gpio09+10: nIOR, nSEL ?? (bt878) + gpio09: nIOR (bt848) + gpio10: nSEL (bt848) + Sound Routing: + gpio16: u2-A0 (1st 4052bt) + gpio17: u2-A1 + gpio18: u2-nEN + gpio19: u4-A0 (2nd 4052) + gpio20: u4-A1 + u4-nEN - GND + Btspy: + 00000 : Cdrom (internal audio input) + 10000 : ext. Video audio input + 20000 : TV Mono + a0000 : TV Mono/2 + 1a0000 : TV Stereo + 30000 : Radio + 40000 : Mute + */ + },{ /* Jannik Fritsch */ name: "Imagenation PXC200", @@ -583,7 +630,7 @@ needs_tvaudio: 0, tuner_type: 4, },{ - name: "Terratec TerraTValue", + name: "Terratec TerraTValue Version Bt878", video_inputs: 3, audio_inputs: 1, tuner: 0, @@ -595,17 +642,29 @@ pll: PLL_28, tuner_type: TUNER_PHILIPS_PAL, },{ - name: "Leadtek WinFast 2000", - video_inputs: 3, + name: "Leadtek WinFast 2000/ WinFast 2000 XP", + video_inputs: 4, audio_inputs: 1, tuner: 0, svhs: 2, gpiomask: 0xc33000, - muxsel: { 2, 3, 1, 1,0}, - audiomux: { 0x422000,0x001000,0x621100,0x620000,0x800000,0x620000}, + muxsel: { 2, 3, 1, 1, 0}, // TV, CVid, SVid, CVid over SVid connector + audiomux: { 0x422000,0x1000,0x0000,0x620000,0x800000}, + /* Audio Routing for "WinFast 2000 XP" (no tv stereo !) + gpio23 -- hef4052:nEnable (0x800000) + gpio12 -- hef4052:A1 + gpio13 -- hef4052:A0 + 0x0000: external audio + 0x1000: FM + 0x2000: TV + 0x3000: n.c. + Note: There exists another variant "Winfast 2000" with tv stereo !? + Note: eeprom only contains FF and pci subsystem id 107d:6606 + */ needs_tvaudio: 0, pll: PLL_28, - tuner_type: -1, + has_radio: 1, + tuner_type: 5, // default for now, gpio reads BFFF06 for Pal bg+dk audio_hook: winfast2000_audio, },{ name: "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II", @@ -671,7 +730,7 @@ },{ /* ---- card 0x28 ---------------------------------- */ - name: "STB2", + name: "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100", video_inputs: 3, audio_inputs: 1, tuner: 0, @@ -681,7 +740,9 @@ audiomux: { 4, 0, 2, 3, 1}, no_msp34xx: 1, needs_tvaudio: 1, - tuner_type: -1, + tuner_type: TUNER_PHILIPS_NTSC, + pll: PLL_28, + has_radio: 1, },{ name: "AVerMedia TVPhone 98", video_inputs: 3, @@ -810,6 +871,15 @@ no_msp34xx: 1, pll: PLL_28, tuner_type: TUNER_PHILIPS_PAL_I, + /* GPIO wiring: (different from Rev.4C !) + GPIO17: U4.A0 (first hef4052bt) + GPIO19: U4.A1 + GPIO20: U5.A1 (second hef4052bt) + GPIO21: U4.nEN + GPIO22: BT832 Reset Line + GPIO23: A5,A0, U5,nEN + Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22 + */ },{ name: "Eagle Wireless Capricorn2 (bt878A)", video_inputs: 4, @@ -1105,10 +1175,17 @@ svhs: 2, gpiomask: 15, muxsel: { 2, 3, 1, 1}, - audiomux: { 0, 0, 11, 7, 13, 0}, + audiomux: { 0, 0, 11, 7, 13, 0}, // TV and Radio with same GPIO ! needs_tvaudio: 1, pll: PLL_28, tuner_type: 25, + /* GPIO wiring: + GPIO0: U4.A0 (hef4052bt) + GPIO1: U4.A1 + GPIO2: U4.A1 (second hef4052bt) + GPIO3: U4.nEN, U5.A0, A5.nEN + GPIO8-15: vrd866b ? + */ },{ name: "Lifeview FlyVideo 98EZ (capture only) LR51", video_inputs: 4, @@ -1123,20 +1200,27 @@ /* ---- card 0x48 ---------------------------------- */ /* Dariusz Kowalewski */ name: "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)", - video_inputs: 3, + video_inputs: 4, audio_inputs: 1, tuner: 0, svhs: 2, gpiomask: 0x3f, - muxsel: { 2, 3, 0, 1 }, + muxsel: { 2, 3, 1, 1 }, audiomux: { 0x01, 0x00, 0x03, 0x03, 0x09, 0x02 }, needs_tvaudio: 1, no_msp34xx: 1, no_tda9875: 1, pll: PLL_28, - tuner_type: -1, - audio_hook: pvbt878p9b_audio, - has_radio: 1, + tuner_type: 5, + audio_hook: pvbt878p9b_audio, // Note: not all cards have stereo + has_radio: 1, // Note: not all cards have radio + /* GPIO wiring: + GPIO0: A0 hef4052 + GPIO1: A1 hef4052 + GPIO3: nEN hef4052 + GPIO8-15: vrd866b + GPIO20,22,23: R30,R29,R28 + */ },{ /* Clay Kunz */ /* you must jumper JP5 for the card to work */ @@ -1242,6 +1326,193 @@ muxsel: { 2, 3, 1, 0}, pll: PLL_28, tuner_type: -1, +},{ + + /* ---- card 0x50 ---------------------------------- */ + name: "Hauppauge WinTV PVR", + video_inputs: 4, + audio_inputs: 1, + tuner: 0, + svhs: 2, + muxsel: { 2, 0, 1, 1}, + needs_tvaudio: 1, + pll: PLL_28, + tuner_type: -1, + + gpiomask: 7, + audiomux: {7}, +},{ + name: "GV-BCTV5/PCI", + video_inputs: 3, + audio_inputs: 1, + tuner: 0, + svhs: 2, + gpiomask: 0x010f00, + muxsel: {2, 3, 1, 0}, + audiomux: {0x10000, 0, 0x10000, 0, 0, 0}, + no_msp34xx: 1, + pll: PLL_28, + tuner_type: TUNER_PHILIPS_NTSC_M, + audio_hook: gvbctv3pci_audio, +},{ + name: "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */ + video_inputs: 4, /* id-inputs-clock */ + audio_inputs: 0, + tuner: -1, + svhs: 3, + muxsel: { 3, 2, 0, 1 }, + pll: PLL_28, + tuner_type: -1, + no_msp34xx: 1, + no_tda9875: 1, + no_tda7432: 1, +},{ + name: "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */ + video_inputs: 3, + audio_inputs: 0, + tuner: -1, + svhs: 2, + muxsel: { 2, 3, 1 }, + pll: PLL_28, + tuner_type: -1, + no_msp34xx: 1, + no_tda9875: 1, + no_tda7432: 1, +},{ + + /* ---- card 0x54 ---------------------------------- */ + name: "Osprey 101 (848)", /* 0x05-40C0-C1 */ + video_inputs: 2, + audio_inputs: 0, + tuner: -1, + svhs: 1, + muxsel: { 3, 1 }, + pll: PLL_28, + tuner_type: -1, + no_msp34xx: 1, + no_tda9875: 1, + no_tda7432: 1, +},{ + name: "Osprey 101/151", /* 0x1(4|5)-0004-C4 */ + video_inputs: 1, + audio_inputs: 0, + tuner: -1, + svhs: -1, + muxsel: { 0 }, + pll: PLL_28, + tuner_type: -1, + no_msp34xx: 1, + no_tda9875: 1, + no_tda7432: 1, +},{ + name: "Osprey 101/151 w/ svid", /* 0x(16|17|20)-00C4-C1 */ + video_inputs: 2, + audio_inputs: 0, + tuner: -1, + svhs: 1, + muxsel: { 0, 1 }, + pll: PLL_28, + tuner_type: -1, + no_msp34xx: 1, + no_tda9875: 1, + no_tda7432: 1, +},{ + name: "Osprey 200/201/250/251", /* 0x1(8|9|E|F)-0004-C4 */ + video_inputs: 1, + audio_inputs: 1, + tuner: -1, + svhs: -1, + muxsel: { 0 }, + pll: PLL_28, + tuner_type: -1, + no_msp34xx: 1, + no_tda9875: 1, + no_tda7432: 1, +},{ + + /* ---- card 0x58 ---------------------------------- */ + name: "Osprey 200/250", /* 0x1(A|B)-00C4-C1 */ + video_inputs: 2, + audio_inputs: 1, + tuner: -1, + svhs: 1, + muxsel: { 0, 1 }, + pll: PLL_28, + tuner_type: -1, + no_msp34xx: 1, + no_tda9875: 1, + no_tda7432: 1, +},{ + name: "Osprey 210/220", /* 0x1(A|B)-04C0-C1 */ + video_inputs: 2, + audio_inputs: 1, + tuner: -1, + svhs: 1, + muxsel: { 2, 3 }, + pll: PLL_28, + tuner_type: -1, + no_msp34xx: 1, + no_tda9875: 1, + no_tda7432: 1, +},{ + name: "Osprey 500", /* 500 */ + video_inputs: 2, + audio_inputs: 1, + tuner: -1, + svhs: 1, + muxsel: { 2, 3 }, + pll: PLL_28, + tuner_type: -1, + no_msp34xx: 1, + no_tda9875: 1, + no_tda7432: 1, +},{ + name: "Osprey 540", /* 540 */ + video_inputs: 4, + audio_inputs: 1, + tuner: -1, +#if 0 /* TODO ... */ + svhs: OSPREY540_SVID_ANALOG, + muxsel: { [OSPREY540_COMP_ANALOG] = 2, + [OSPREY540_SVID_ANALOG] = 3, }, +#endif + pll: PLL_28, + tuner_type: -1, + no_msp34xx: 1, + no_tda9875: 1, + no_tda7432: 1, +#if 0 /* TODO ... */ + muxsel_hook: osprey_540_muxsel, + picture_hook: osprey_540_set_picture, +#endif +},{ + + /* ---- card 0x5C ---------------------------------- */ + name: "Osprey 2000", /* 2000 */ + video_inputs: 2, + audio_inputs: 1, + tuner: -1, + svhs: 1, + muxsel: { 2, 3 }, + pll: PLL_28, + tuner_type: -1, + no_msp34xx: 1, + no_tda9875: 1, + no_tda7432: 1, /* must avoid, conflicts with the bt860 */ +},{ + /* M G Berberich */ + name: "IDS Eagle", + video_inputs: 4, + audio_inputs: 0, + tuner: -1, + tuner_type: -1, + svhs: -1, + gpiomask: 0, + muxsel: { 0, 1, 2, 3 }, + muxsel_hook: eagle_muxsel, + no_msp34xx: 1, + no_tda9875: 1, + pll: PLL_28, }}; const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard)); @@ -1355,11 +1626,13 @@ switch(ttype) { case 0x0: tuner=4; // None break; - case 0x4: tuner=5; // Philips PAL + case 0x2: tuner=39;// LG NTSC (newer TAPC series) TAPC-H701P + break; + case 0x4: tuner=5; // Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 break; - case 0x6: tuner=37; // LG PAL (newer TAPC series) + case 0x6: tuner=37; // LG PAL (newer TAPC series) TAPC-G702P break; - case 0xC: tuner=3; // Philips SECAM(+PAL) + case 0xC: tuner=3; // Philips SECAM(+PAL) FQ1216ME or FI1216MF break; default: printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->nr); @@ -1394,48 +1667,148 @@ int miro_tunermap[] = { 0,6,2,3, 4,5,6,0, 3,0,4,5, 5,2,16,1, 14,2,17,1, 4,1,4,3, 1,2,16,1, 4,4,4,4 }; int miro_fmtuner[] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, - 1,1,1,1, 1,1,1,0, 0,0,0,0, 0,0,0,0 }; + 1,1,1,1, 1,1,1,0, 0,0,0,0, 0,1,0,0 }; static void miro_pinnacle_gpio(struct bttv *btv) { - int id,msp; - - id = ((btread(BT848_GPIO_DATA)>>10) & 31) -1; - msp = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx"); - btv->tuner_type = miro_tunermap[id]; - if (0 == (btread(BT848_GPIO_DATA) & 0x20)) { - btv->has_radio = 1; - if (!miro_fmtuner[id]) { - btv->has_matchbox = 1; - btv->mbox_we = (1<<6); - btv->mbox_most = (1<<7); - btv->mbox_clk = (1<<8); - btv->mbox_data = (1<<9); - btv->mbox_mask = (1<<6)|(1<<7)|(1<<8)|(1<<9); + int id,msp,gpio; + char *info; + + btwrite(0,BT848_GPIO_OUT_EN); + gpio = btread(BT848_GPIO_DATA); + id = ((gpio>>10) & 63) -1; + msp = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx"); + if (id < 32) { + btv->tuner_type = miro_tunermap[id]; + if (0 == (gpio & 0x20)) { + btv->has_radio = 1; + if (!miro_fmtuner[id]) { + btv->has_matchbox = 1; + btv->mbox_we = (1<<6); + btv->mbox_most = (1<<7); + btv->mbox_clk = (1<<8); + btv->mbox_data = (1<<9); + btv->mbox_mask = (1<<6)|(1<<7)|(1<<8)|(1<<9); + } + } else { + btv->has_radio = 0; + } + if (-1 != msp) { + if (btv->type == BTTV_MIRO) + btv->type = BTTV_MIROPRO; + if (btv->type == BTTV_PINNACLE) + btv->type = BTTV_PINNACLEPRO; } + printk(KERN_INFO "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n", + btv->nr, id+1, btv->tuner_type, + !btv->has_radio ? "no" : + (btv->has_matchbox ? "matchbox" : "fmtuner"), + (-1 == msp) ? "no" : "yes"); } else { + /* new cards with microtune tuner */ + id = 63 - id; btv->has_radio = 0; + switch (id) { + case 1: + info = "PAL / mono"; + break; + case 2: + info = "PAL+SECAM / stereo"; + btv->has_radio = 1; + break; + case 3: + info = "NTSC / stereo"; + btv->has_radio = 1; + break; + case 4: + info = "PAL+SECAM / mono"; + break; + case 5: + info = "NTSC / mono"; + break; + case 6: + info = "NTSC / stereo"; + break; + default: + info = "oops: unknown card"; + break; + } + printk(KERN_INFO + "bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n", + btv->nr, id, info, btv->has_radio ? "yes" : "no"); + btv->tuner_type = 33; + if (autoload) + request_module("tda9887"); + bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE,&id); } - if (-1 != msp) { - if (btv->type == BTTV_MIRO) - btv->type = BTTV_MIROPRO; - if (btv->type == BTTV_PINNACLE) - btv->type = BTTV_PINNACLEPRO; - } - printk(KERN_INFO "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n", - btv->nr, id+1, btv->tuner_type, - !btv->has_radio ? "no" : - (btv->has_matchbox ? "matchbox" : "fmtuner"), - (-1 == msp) ? "no" : "yes"); } +/* GPIO21 L: Buffer aktiv, H: Buffer inaktiv */ +#define LM1882_SYNC_DRIVE 0x200000L + +static void init_ids_eagle(struct bttv *btv) +{ + btwrite(0xFFFF37, BT848_GPIO_OUT_EN); + btwrite(0x000000, BT848_GPIO_REG_INP); + + btwrite(0x200020, BT848_GPIO_DATA); + + /* flash strobe inverter ?! */ + btwrite(0x200024, BT848_GPIO_DATA); + + /* switch sync drive off */ + btor(LM1882_SYNC_DRIVE, BT848_GPIO_DATA); + + /* set BT848 muxel to 2 */ + btaor((2)<<5, ~(2<<5), BT848_IFORM); +} + +/* Muxsel helper for the IDS Eagle. + * the eagles does not use the standard muxsel-bits but + * has its own multiplexer */ +static void eagle_muxsel(struct bttv *btv, unsigned int input) +{ + btaor((2)<<5, ~(3<<5), BT848_IFORM); + btaor((bttv_tvcards[btv->type].muxsel[input&7]&3), + ~3, BT848_GPIO_DATA); + +#if 0 + /* svhs */ + /* wake chroma ADC */ + btand(~BT848_ADC_C_SLEEP, BT848_ADC); + /* set to YC video */ + btor(BT848_CONTROL_COMP, BT848_E_CONTROL); + btor(BT848_CONTROL_COMP, BT848_O_CONTROL); +#else + /* composite */ + /* set chroma ADC to sleep */ + btor(BT848_ADC_C_SLEEP, BT848_ADC); + /* set to composite video */ + btand(~BT848_CONTROL_COMP, BT848_E_CONTROL); + btand(~BT848_CONTROL_COMP, BT848_O_CONTROL); +#endif + + /* switch sync drive off */ + btor(LM1882_SYNC_DRIVE, BT848_GPIO_DATA); +} + +/* ----------------------------------------------------------------------- */ + /* initialization part one -- before registering i2c bus */ void __devinit bttv_init_card1(struct bttv *btv) { - if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) + switch (btv->type) { + case BTTV_HAUPPAUGE: + case BTTV_HAUPPAUGE878: boot_msp34xx(btv,5); - if (btv->type == BTTV_VOODOOTV_FM) + break; + case BTTV_VOODOOTV_FM: boot_msp34xx(btv,20); + break; + case BTTV_HAUPPAUGEPVR: + pvr_boot(btv); + break; + } } /* initialization part two -- after registering i2c bus */ @@ -1443,40 +1816,43 @@ { btv->tuner_type = -1; - /* miro/pinnacle */ - if (btv->type == BTTV_MIRO || - btv->type == BTTV_MIROPRO || - btv->type == BTTV_PINNACLE || - btv->type == BTTV_PINNACLEPRO) + switch (btv->type) { + case BTTV_MIRO: + case BTTV_MIROPRO: + case BTTV_PINNACLE: + case BTTV_PINNACLEPRO: + /* miro/pinnacle */ miro_pinnacle_gpio(btv); - - if (btv->type == BTTV_FLYVIDEO_98 || - btv->type == BTTV_LIFE_FLYKIT || - btv->type == BTTV_FLYVIDEO || - btv->type == BTTV_TYPHOON_TVIEW || - btv->type == BTTV_CHRONOS_VS2 || - btv->type == BTTV_FLYVIDEO_98FM || - btv->type == BTTV_FLYVIDEO2000 || - btv->type == BTTV_FLYVIDEO98EZ || - btv->type == BTTV_CONFERENCETV || - btv->type == BTTV_LIFETEC_9415) + break; + case BTTV_FLYVIDEO_98: + case BTTV_MAXI: + case BTTV_LIFE_FLYKIT: + case BTTV_FLYVIDEO: + case BTTV_TYPHOON_TVIEW: + case BTTV_CHRONOS_VS2: + case BTTV_FLYVIDEO_98FM: + case BTTV_FLYVIDEO2000: + case BTTV_FLYVIDEO98EZ: + case BTTV_CONFERENCETV: + case BTTV_LIFETEC_9415: flyvideo_gpio(btv); - - if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) { + break; + case BTTV_HAUPPAUGE: + case BTTV_HAUPPAUGE878: + case BTTV_HAUPPAUGEPVR: /* pick up some config infos from the eeprom */ bttv_readee(btv,eeprom_data,0xa0); hauppauge_eeprom(btv); - } - - if (btv->type == BTTV_AVERMEDIA98 || btv->type == BTTV_AVPHONE98) { + break; + case BTTV_AVERMEDIA98: + case BTTV_AVPHONE98: bttv_readee(btv,eeprom_data,0xa0); avermedia_eeprom(btv); - } - - if (btv->type == BTTV_PXC200) + break; + case BTTV_PXC200: init_PXC200(btv); - - if (btv->type == BTTV_VHX) { + break; + case BTTV_VHX: btv->has_radio = 1; btv->has_matchbox = 1; btv->mbox_we = 0x20; @@ -1484,13 +1860,42 @@ btv->mbox_clk = 0x08; btv->mbox_data = 0x10; btv->mbox_mask = 0x38; - } - - if (btv->type == BTTV_MAGICTVIEW061) { - if(btv->cardid == 0x4002144f) { + break; + case BTTV_VOBIS_BOOSTAR: + case BTTV_TERRATV: + terratec_active_radio_upgrade(btv); + break; + case BTTV_MAGICTVIEW061: + if (btv->cardid == 0x3002144f) { btv->has_radio=1; printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->nr); } + break; + case BTTV_STB2: + if (btv->cardid == 0x3060121a) { + /* Fix up entry for 3DFX VoodooTV 100, + which is an OEM STB card variant. */ + btv->has_radio=0; + btv->tuner_type=TUNER_TEMIC_NTSC; + } + break; + case BTTV_OSPREY1x0: + case BTTV_OSPREY1x0_848: + case BTTV_OSPREY101_848: + case BTTV_OSPREY1x1: + case BTTV_OSPREY1x1_SVID: + case BTTV_OSPREY2xx: + case BTTV_OSPREY2x0_SVID: + case BTTV_OSPREY2x0: + case BTTV_OSPREY500: + case BTTV_OSPREY540: + case BTTV_OSPREY2000: + bttv_readee(btv,eeprom_data,0xa0); + osprey_eeprom(btv); + break; + case BTTV_IDS_EAGLE: + init_ids_eagle(btv); + break; } /* pll configuration */ @@ -1542,6 +1947,34 @@ if (bttv_tvcards[btv->type].audio_hook) btv->audio_hook=bttv_tvcards[btv->type].audio_hook; +#if 0 + /* detect Bt832 chip for quartzsight digital camera */ + if((bttv_I2CRead(btv, I2C_BT832_ALT1, "Bt832") >=0) || + (bttv_I2CRead(btv, I2C_BT832_ALT2, "Bt832") >=0)) { + int outbits,databits; + request_module("bt832"); + + bttv_call_i2c_clients(btv, BT832_HEXDUMP, NULL); + + printk("Reset Bt832 (0x400000 for Pixelview 4E)\n"); + btwrite(0, BT848_GPIO_DATA); + outbits = btread(BT848_GPIO_OUT_EN); + databits= btread(BT848_GPIO_DATA); + btwrite(0x400000, BT848_GPIO_OUT_EN); + udelay(5); + btwrite(0x400000, BT848_GPIO_DATA); + udelay(5); + btwrite(0, BT848_GPIO_DATA); + udelay(5); + btwrite(outbits, BT848_GPIO_OUT_EN); + btwrite(databits, BT848_GPIO_DATA); + + // bt832 on pixelview changes from i2c 0x8a to 0x88 after + // being reset as above. So we must follow by this: + bttv_call_i2c_clients(btv, BT832_REATTACH, NULL); + } +#endif + /* try to detect audio/fader chips */ if (!bttv_tvcards[btv->type].no_msp34xx && bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) { @@ -1555,7 +1988,8 @@ request_module("tda9875"); } - if (bttv_I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) { + if (!bttv_tvcards[btv->type].no_tda7432 && + bttv_I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) { if (autoload) request_module("tda7432"); } @@ -1663,6 +2097,220 @@ btv->tuner_type, radio ? "yes" : "no"); } +static int terratec_active_radio_upgrade(struct bttv *btv) +{ + int freq; + + btv->has_radio = 1; + btv->has_matchbox = 1; + btv->mbox_we = 0x10; + btv->mbox_most = 0x20; + btv->mbox_clk = 0x08; + btv->mbox_data = 0x04; + btv->mbox_mask = 0x3c; + + btv->mbox_iow = 1 << 8; + btv->mbox_ior = 1 << 9; + btv->mbox_csel = 1 << 10; + + freq=88000/62.5; + tea5757_write(btv, 5 * freq + 0x358); // write 0x1ed8 + if (0x1ed8 == tea5757_read(btv)) { + printk("bttv%d: Terratec Active Radio Upgrade found.\n", + btv->nr); + btv->has_radio = 1; + btv->has_matchbox = 1; + } else { + btv->has_radio = 0; + btv->has_matchbox = 0; + } + return 0; +} + + +/* ----------------------------------------------------------------------- */ + +/* + * minimal bootstrap for the WinTV/PVR -- upload altera firmware. + * + * The hcwamc.rbf firmware file is on the Hauppauge driver CD. Have + * a look at Pvr/pvr45xxx.EXE (self-extracting zip archive, can be + * unpacked with unzip). + */ +static char *firm_altera = "/usr/lib/video4linux/hcwamc.rbf"; +MODULE_PARM(firm_altera,"s"); +MODULE_PARM_DESC(firm_altera,"WinTV/PVR firmware " + "(driver CD => unzip pvr45xxx.exe => hcwamc.rbf)"); + +/* drivers/sound/sound_firmware.c => soundcore.o */ +extern int mod_firmware_load(const char *fn, char **fp); + +#define PVR_GPIO_DELAY 10 + +#define BTTV_ALT_DATA 0x000001 +#define BTTV_ALT_DCLK 0x100000 +#define BTTV_ALT_NCONFIG 0x800000 + +static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen) +{ + u32 n; + u8 bits; + int i; + + btwrite(BTTV_ALT_DATA|BTTV_ALT_DCLK|BTTV_ALT_NCONFIG, + BT848_GPIO_OUT_EN); + btwrite(0,BT848_GPIO_DATA); + udelay(PVR_GPIO_DELAY); + + btwrite(BTTV_ALT_NCONFIG,BT848_GPIO_DATA); + udelay(PVR_GPIO_DELAY); + + for (n = 0; n < microlen; n++) { + bits = micro[n]; + for ( i = 0 ; i < 8 ; i++ ) { + btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA); + if (bits & 0x01) + btor(BTTV_ALT_DATA,BT848_GPIO_DATA); + else + btand(~BTTV_ALT_DATA,BT848_GPIO_DATA); + btor(BTTV_ALT_DCLK,BT848_GPIO_DATA); + bits >>= 1; + } + } + btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA); + udelay(PVR_GPIO_DELAY); + + /* begin Altera init loop (Not necessary,but doesn't hurt) */ + for (i = 0 ; i < 30 ; i++) { + btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA); + btor(BTTV_ALT_DCLK,BT848_GPIO_DATA); + } + btand(~BTTV_ALT_DCLK,BT848_GPIO_DATA); + return 0; +} + +int __devinit pvr_boot(struct bttv *btv) +{ + u32 microlen; + u8 *micro; + int result; + + microlen = mod_firmware_load(firm_altera, (char**) µ); + if (!microlen) + return -1; + + printk(KERN_INFO "bttv%d: uploading altera firmware [%s] ...\n", + btv->nr, firm_altera); + result = pvr_altera_load(btv, micro, microlen); + printk(KERN_INFO "bttv%d: ... upload %s\n", + btv->nr, (result < 0) ? "failed" : "ok"); + vfree(micro); + return result; +} + +/* ----------------------------------------------------------------------- */ +/* some osprey specific stuff */ + +static void __devinit osprey_eeprom(struct bttv *btv) +{ + int i = 0; + unsigned char *ee = eeprom_data; + unsigned long serial = 0; + + if (btv->type == 0) { + /* this might be an antique... check for MMAC label in eeprom */ + if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) { + unsigned char checksum = 0; + for (i =0; i<21; i++) + checksum += ee[i]; + if (checksum != ee[21]) + return; + btv->type = BTTV_OSPREY1x0_848; + for (i = 12; i < 21; i++) + serial *= 10, serial += ee[i] - '0'; + } + } else { + unsigned short type; + int offset = 4*16; + + for(; offset < 8*16; offset += 16) { + unsigned short checksum = 0; + /* verify the checksum */ + for(i = 0; i<14; i++) checksum += ee[i+offset]; + checksum = ~checksum; /* no idea why */ + if ((((checksum>>8)&0x0FF) == ee[offset+14]) && + ((checksum & 0x0FF) == ee[offset+15])) { + break; + } + } + + if (offset >= 8*16) + return; + + /* found a valid descriptor */ + type = (ee[offset+4]<<8) | (ee[offset+5]); + + switch(type) { + + /* 848 based */ + case 0x0004: + btv->type = BTTV_OSPREY1x0_848; + break; + case 0x0005: + btv->type = BTTV_OSPREY101_848; + break; + + /* 878 based */ + case 0x0012: + case 0x0013: + btv->type = BTTV_OSPREY1x0; + break; + case 0x0014: + case 0x0015: + btv->type = BTTV_OSPREY1x1; + break; + case 0x0016: + case 0x0017: + case 0x0020: + btv->type = BTTV_OSPREY1x1_SVID; + break; + case 0x0018: + case 0x0019: + case 0x001E: + case 0x001F: + btv->type = BTTV_OSPREY2xx; + break; + case 0x001A: + case 0x001B: + btv->type = BTTV_OSPREY2x0_SVID; + break; + case 0x0040: + btv->type = BTTV_OSPREY500; + break; + case 0x0050: + case 0x0056: + btv->type = BTTV_OSPREY540; + /* bttv_osprey_540_init(btv); */ + break; + case 0x0060: + case 0x0070: + btv->type = BTTV_OSPREY2x0; + //enable output on select control lines + btwrite(0x000303, BT848_GPIO_OUT_EN); + break; + default: + /* unknown...leave generic, but get serial # */ + break; + } + serial = (ee[offset+6] << 24) + | (ee[offset+7] << 16) + | (ee[offset+8] << 8) + | (ee[offset+9]); + } + + printk(KERN_INFO "bttv%d: osprey eeprom: card=%d name=%s serial=%ld\n", + btv->nr, btv->type, bttv_tvcards[btv->type].name,serial); +} /* ----------------------------------------------------------------------- */ /* AVermedia specific stuff, from bktr_card.c */ @@ -1822,17 +2470,55 @@ * Brutally hacked by Dan Sheridan djs52 8/3/00 */ -#if 0 -/* bus bits on the GPIO port */ -#define TEA_WE 6 -#define TEA_DATA 9 -#define TEA_CLK 8 -#define TEA_MOST 7 -#endif +void bus_low(struct bttv *btv, int bit) +{ + if (btv->mbox_ior) { + btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + BT848_GPIO_DATA); + udelay(5); + } + + btand(~(bit), BT848_GPIO_DATA); + udelay(5); + + if (btv->mbox_ior) { + btand(~(btv->mbox_iow | btv->mbox_csel), + BT848_GPIO_DATA); + udelay(5); + } +} + +void bus_high(struct bttv *btv, int bit) +{ + if (btv->mbox_ior) { + btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + BT848_GPIO_DATA); + udelay(5); + } + + btor((bit), BT848_GPIO_DATA); + udelay(5); -#define BUS_LOW(bit) btand(~(bit), BT848_GPIO_DATA) -#define BUS_HIGH(bit) btor((bit), BT848_GPIO_DATA) -#define BUS_IN(bit) (btread(BT848_GPIO_DATA) & (bit)) + if (btv->mbox_ior) { + btand(~(btv->mbox_iow | btv->mbox_csel), + BT848_GPIO_DATA); + udelay(5); + } +} + +int bus_in(struct bttv *btv, int bit) +{ + if (btv->mbox_ior) { + btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + BT848_GPIO_DATA); + udelay(5); + + btand(~(btv->mbox_ior | btv->mbox_csel), + BT848_GPIO_DATA); + udelay(5); + } + return btread(BT848_GPIO_DATA) & (bit); +} /* TEA5757 register bits */ #define TEA_FREQ 0:14 @@ -1871,34 +2557,41 @@ /* better safe than sorry */ btaor((btv->mbox_clk | btv->mbox_we), ~btv->mbox_mask, BT848_GPIO_OUT_EN); + + if (btv->mbox_ior) { + btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + BT848_GPIO_DATA); + udelay(5); + } + if (bttv_gpio) bttv_gpio_tracking(btv,"tea5757 read"); - BUS_LOW(btv->mbox_we); - BUS_LOW(btv->mbox_clk); + bus_low(btv,btv->mbox_we); + bus_low(btv,btv->mbox_clk); udelay(10); - for(timeout = jiffies + 10 * HZ; - BUS_IN(btv->mbox_data) && time_before(jiffies, timeout); - schedule()); /* 10 s */ - if (BUS_IN(btv->mbox_data)) { + timeout= jiffies + HZ; + + // wait for DATA line to go low; error if it doesn't + while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout)) + schedule(); + if (bus_in(btv,btv->mbox_data)) { printk(KERN_WARNING "bttv%d: tea5757: read timeout\n",btv->nr); return -1; } - for(timeout = jiffies + HZ/5; - BUS_IN(btv->mbox_data) == 1 && time_before(jiffies, timeout); - schedule()); /* 0.2 s */ + dprintk("bttv%d: tea5757:",btv->nr); for(i = 0; i < 24; i++) { udelay(5); - BUS_HIGH(btv->mbox_clk); + bus_high(btv,btv->mbox_clk); udelay(5); - dprintk("%c",(BUS_IN(btv->mbox_most) == 0)?'T':'-'); - BUS_LOW(btv->mbox_clk); + dprintk("%c",(bus_in(btv,btv->mbox_most) == 0)?'T':'-'); + bus_low(btv,btv->mbox_clk); value <<= 1; - value |= (BUS_IN(btv->mbox_data) == 0)?0:1; /* MSB first */ - dprintk("%c", (BUS_IN(btv->mbox_most) == 0)?'S':'M'); + value |= (bus_in(btv,btv->mbox_data) == 0)?0:1; /* MSB first */ + dprintk("%c", (bus_in(btv,btv->mbox_most) == 0)?'S':'M'); } dprintk("\nbttv%d: tea5757: read 0x%X\n", btv->nr, value); return value; @@ -1911,32 +2604,42 @@ btaor(btv->mbox_clk | btv->mbox_we | btv->mbox_data, ~btv->mbox_mask, BT848_GPIO_OUT_EN); + + if (btv->mbox_ior) { + btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel, + BT848_GPIO_DATA); + udelay(5); + } if (bttv_gpio) bttv_gpio_tracking(btv,"tea5757 write"); + dprintk("bttv%d: tea5757: write 0x%X\n", btv->nr, value); - BUS_LOW(btv->mbox_clk); - BUS_HIGH(btv->mbox_we); + bus_low(btv,btv->mbox_clk); + bus_high(btv,btv->mbox_we); for(i = 0; i < 25; i++) { if (reg & 0x1000000) - BUS_HIGH(btv->mbox_data); + bus_high(btv,btv->mbox_data); else - BUS_LOW(btv->mbox_data); + bus_low(btv,btv->mbox_data); reg <<= 1; - BUS_HIGH(btv->mbox_clk); + bus_high(btv,btv->mbox_clk); udelay(10); - BUS_LOW(btv->mbox_clk); + bus_low(btv,btv->mbox_clk); udelay(10); } - BUS_LOW(btv->mbox_we); /* unmute !!! */ + bus_low(btv,btv->mbox_we); /* unmute !!! */ return 0; } void tea5757_set_freq(struct bttv *btv, unsigned short freq) { + int value; + + dprintk("tea5757_set_freq %d\n",freq); tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */ - if (bttv_debug) - tea5757_read(btv); + value = tea5757_read(btv); + dprintk("bttv%d: tea5757 readback =0x%x\n",btv->nr,value); } @@ -2076,7 +2779,7 @@ } } - +// TDA9821 on TerraTV+ Bt848, Bt878 static void terratv_audio(struct bttv *btv, struct video_audio *v, int set) { @@ -2127,6 +2830,9 @@ * Dariusz Kowalewski * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM * revision 9B has on-board TDA9874A sound decoder). + * + * Note: There are card variants without tda9874a. Forcing the "stereo sound route" + * will mute this cards. */ static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set) diff -Nru a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c --- a/drivers/media/video/bttv-driver.c Mon Nov 4 14:31:02 2002 +++ b/drivers/media/video/bttv-driver.c Mon Nov 4 14:31:02 2002 @@ -23,6 +23,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include @@ -31,7 +32,6 @@ #include #include #include -#include #include #include @@ -74,14 +74,11 @@ /* API features (turn on/off stuff for testing) */ static unsigned int sloppy = 0; -static unsigned int mmap = 1; -#ifdef HAVE_V4L2 static unsigned int v4l2 = 1; -#endif /* insmod args */ -MODULE_PARM(radio,"1-" __MODULE_STRING(BTTV_MAX) "i"); +MODULE_PARM(radio,"1-" __stringify(BTTV_MAX) "i"); MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)"); MODULE_PARM(bigendian,"i"); MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian"); @@ -115,10 +112,7 @@ MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)"); MODULE_PARM(sloppy,"i"); -MODULE_PARM(mmap,"i"); -#ifdef HAVE_V4L2 MODULE_PARM(v4l2,"i"); -#endif MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards"); MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); @@ -130,74 +124,148 @@ __setup("bttv.radio=", p_radio); #endif -#ifndef HAVE_V4L2 -/* some dummy defines to avoid cluttering up the source code with - a huge number of ifdef's for V4L2 */ -# define V4L2_STD_PAL -1 -# define V4L2_STD_NTSC -1 -# define V4L2_STD_SECAM -1 -# define V4L2_STD_PAL_60 -1 -# define V4L2_STD_PAL_M -1 -# define V4L2_STD_PAL_N -1 -# define V4L2_STD_NTSC_N -1 -# define V4L2_PIX_FMT_GREY -1 -# define V4L2_PIX_FMT_HI240 -1 -# define V4L2_PIX_FMT_RGB555 -1 -# define V4L2_PIX_FMT_RGB555X -1 -# define V4L2_PIX_FMT_RGB565 -1 -# define V4L2_PIX_FMT_RGB565X -1 -# define V4L2_PIX_FMT_BGR24 -1 -# define V4L2_PIX_FMT_BGR32 -1 -# define V4L2_PIX_FMT_RGB32 -1 -# define V4L2_PIX_FMT_YUYV -1 -# define V4L2_PIX_FMT_UYVY -1 -# define V4L2_PIX_FMT_YUV422P -1 -# define V4L2_PIX_FMT_YUV420 -1 -# define V4L2_PIX_FMT_YVU420 -1 -# define V4L2_PIX_FMT_YUV411P -1 -# define V4L2_PIX_FMT_YUV410 -1 -# define V4L2_PIX_FMT_YVU410 -1 -# define V4L2_BUF_TYPE_CAPTURE -1 -# define V4L2_BUF_TYPE_VBI -1 -# define BTTV_APIS "[v4l]" -#else -# define BTTV_APIS "[v4l/v4l2]" -#endif - /* ----------------------------------------------------------------------- */ /* static data */ +/* special timing tables from conexant... */ +static u8 SRAM_Table[][60] = +{ + /* PAL digital input over GPIO[7:0] */ + { + 0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16, + 0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00, + 0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00, + 0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37, + 0x37,0x00,0xAF,0x21,0x00 + }, + /* NTSC digital input over GPIO[7:0] */ + { + 0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06, + 0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00, + 0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07, + 0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6, + 0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21, + 0x00, + }, +}; + const struct bttv_tvnorm bttv_tvnorms[] = { /* PAL-BDGHI */ - { V4L2_STD_PAL, 35468950, - 922, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), - 1135, 186, 922, 0x20, 255}, - /* NTSC */ - { V4L2_STD_NTSC, 28636363, - 754, 480, 910, 0x70, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0), - 910, 135, 754, 0x1a, 144}, - /* SECAM */ - { V4L2_STD_SECAM, 35468950, - 922, 576, 1135, 0x7f, 0xa0, (BT848_IFORM_SECAM|BT848_IFORM_XT1), - 1135, 186, 922, 0x20, 255}, - - /* these ones are bttv specific (for v4l1) */ - /* PAL-NC */ - { V4L2_STD_PAL_60, 28636363, - 640, 576, 910, 0x7f, 0x72, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0), - 780, 130, 734, 0x1a, 144}, - /* PAL-M */ - { V4L2_STD_PAL_M, 28636363, - 640, 480, 910, 0x70, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0), - 780, 135, 754, 0x1a, 144}, - /* PAL-N */ - { V4L2_STD_PAL_N, 35468950, - 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT0), - 944, 186, 922, 0x20, 144}, - /* NTSC-Japan */ - { V4L2_STD_NTSC_N, 28636363, - 640, 480, 910, 0x70, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0), - 780, 135, 754, 0x16, 144}, + /* max. active video is actually 922, but 924 is divisible by 4 and 3! */ + /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */ + { + .v4l2_id = V4L2_STD_PAL, + .name = "PAL", + .Fsc = 35468950, + .swidth = 924, + .sheight = 576, + .totalwidth = 1135, + .adelay = 0x7f, + .bdelay = 0x72, + .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), + .scaledtwidth = 1135, + .hdelayx1 = 186, + .hactivex1 = 924, + .vdelay = 0x20, + .vbipack = 255, + .sram = 0, + },{ + .v4l2_id = V4L2_STD_NTSC, + .name = "NTSC", + .Fsc = 28636363, + .swidth = 768, + .sheight = 480, + .totalwidth = 910, + .adelay = 0x68, + .bdelay = 0x5d, + .iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0), + .scaledtwidth = 910, + .hdelayx1 = 128, + .hactivex1 = 910, + .vdelay = 0x1a, + .vbipack = 144, + .sram = 1, + },{ + .v4l2_id = V4L2_STD_SECAM, + .name = "SECAM", + .Fsc = 35468950, + .swidth = 924, + .sheight = 576, + .totalwidth = 1135, + .adelay = 0x7f, + .bdelay = 0xb0, + .iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1), + .scaledtwidth = 1135, + .hdelayx1 = 186, + .hactivex1 = 922, + .vdelay = 0x20, + .vbipack = 255, + .sram = 0, /* like PAL, correct? */ + },{ + .v4l2_id = V4L2_STD_PAL_Nc, + .name = "PAL-Nc", + .Fsc = 28636363, + .swidth = 640, + .sheight = 576, + .totalwidth = 910, + .adelay = 0x68, + .bdelay = 0x5d, + .iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0), + .scaledtwidth = 780, + .hdelayx1 = 130, + .hactivex1 = 734, + .vdelay = 0x1a, + .vbipack = 144, + .sram = -1, + },{ + .v4l2_id = V4L2_STD_PAL_M, + .name = "PAL-M", + .Fsc = 28636363, + .swidth = 640, + .sheight = 480, + .totalwidth = 910, + .adelay = 0x68, + .bdelay = 0x5d, + .iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0), + .scaledtwidth = 780, + .hdelayx1 = 135, + .hactivex1 = 754, + .vdelay = 0x1a, + .vbipack = 144, + .sram = -1, + },{ + .v4l2_id = V4L2_STD_PAL_N, + .name = "PAL-N", + .Fsc 35468950, + .swidth = 768, + .sheight = 576, + .totalwidth = 1135, + .adelay = 0x7f, + .bdelay = 0x72, + .iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1), + .scaledtwidth = 944, + .hdelayx1 = 186, + .hactivex1 = 922, + .vdelay = 0x20, + .vbipack = 144, + .sram = -1, + },{ + .v4l2_id = V4L2_STD_NTSC_M_JP, + .name = "NTSC-JP", + .Fsc = 28636363, + .swidth = 640, + .sheight = 480, + .totalwidth = 910, + .adelay = 0x68, + .bdelay = 0x5d, + .iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0), + .scaledtwidth = 780, + .hdelayx1 = 135, + .hactivex1 = 754, + .vdelay = 0x16, + .vbipack = 144, + .sram = -1, + } }; const int BTTV_TVNORMS = (sizeof(bttv_tvnorms)/sizeof(struct bttv_tvnorm)); @@ -360,7 +428,6 @@ /* ----------------------------------------------------------------------- */ -#ifdef HAVE_V4L2 #define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0) #define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1) #define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2) @@ -382,8 +449,6 @@ step: 256, default_value: 32768, type: V4L2_CTRL_TYPE_INTEGER, - category: V4L2_CTRL_CAT_VIDEO, - group: "Video", },{ id: V4L2_CID_CONTRAST, name: "Contrast", @@ -392,8 +457,6 @@ step: 128, default_value: 32768, type: V4L2_CTRL_TYPE_INTEGER, - category: V4L2_CTRL_CAT_VIDEO, - group: "Video", },{ id: V4L2_CID_SATURATION, name: "Saturation", @@ -402,8 +465,6 @@ step: 128, default_value: 32768, type: V4L2_CTRL_TYPE_INTEGER, - category: V4L2_CTRL_CAT_VIDEO, - group: "Video", },{ id: V4L2_CID_HUE, name: "Hue", @@ -412,8 +473,6 @@ step: 256, default_value: 32768, type: V4L2_CTRL_TYPE_INTEGER, - category: V4L2_CTRL_CAT_VIDEO, - group: "Video", }, /* --- audio --- */ { @@ -422,8 +481,6 @@ minimum: 0, maximum: 1, type: V4L2_CTRL_TYPE_BOOLEAN, - category: V4L2_CTRL_CAT_AUDIO, - group: "Audio", },{ id: V4L2_CID_AUDIO_VOLUME, name: "Volume", @@ -432,8 +489,6 @@ step: 65535/100, default_value: 65535, type: V4L2_CTRL_TYPE_INTEGER, - category: V4L2_CTRL_CAT_AUDIO, - group: "Audio", },{ id: V4L2_CID_AUDIO_BALANCE, name: "Balance", @@ -442,8 +497,6 @@ step: 65535/100, default_value: 32768, type: V4L2_CTRL_TYPE_INTEGER, - category: V4L2_CTRL_CAT_AUDIO, - group: "Audio", },{ id: V4L2_CID_AUDIO_BASS, name: "Bass", @@ -452,8 +505,6 @@ step: 65535/100, default_value: 32768, type: V4L2_CTRL_TYPE_INTEGER, - category: V4L2_CTRL_CAT_AUDIO, - group: "Audio", },{ id: V4L2_CID_AUDIO_TREBLE, name: "Treble", @@ -462,8 +513,6 @@ step: 65535/100, default_value: 32768, type: V4L2_CTRL_TYPE_INTEGER, - category: V4L2_CTRL_CAT_AUDIO, - group: "Audio", }, /* --- private --- */ { @@ -472,39 +521,33 @@ minimum: 0, maximum: 1, type: V4L2_CTRL_TYPE_BOOLEAN, - group: "Private", },{ id: V4L2_CID_PRIVATE_COMBFILTER, name: "combfilter", minimum: 0, maximum: 1, type: V4L2_CTRL_TYPE_BOOLEAN, - group: "Private", },{ id: V4L2_CID_PRIVATE_AUTOMUTE, name: "automute", minimum: 0, maximum: 1, type: V4L2_CTRL_TYPE_BOOLEAN, - group: "Private", },{ id: V4L2_CID_PRIVATE_LUMAFILTER, name: "luma decimation filter", minimum: 0, maximum: 1, type: V4L2_CTRL_TYPE_BOOLEAN, - group: "Private", },{ id: V4L2_CID_PRIVATE_AGC_CRUSH, name: "agc crush", minimum: 0, maximum: 1, type: V4L2_CTRL_TYPE_BOOLEAN, - group: "Private", } }; const int BTTV_CTLS = (sizeof(bttv_ctls)/sizeof(struct v4l2_queryctrl)); -#endif /* HAVE_V4L2 */ /* ----------------------------------------------------------------------- */ /* resource management */ @@ -558,57 +601,6 @@ } /* ----------------------------------------------------------------------- */ -/* - * sanity check for video framebuffer address ranges (overlay). - * let's see if that address range actually belongs to some - * pci display adapter. - * - * FIXME: stuff isn't portable. It's also a v4l API bug, pass a - * physical address in VIDIOCSFBUF isn't portable too ... - */ - -static int -find_videomem(unsigned long from, unsigned long to) -{ -#if PCI_DMA_BUS_IS_PHYS - struct pci_dev *dev = NULL; - int i,match,found; - - found = 0; - dprintk(KERN_DEBUG "bttv: checking video framebuffer address" - " (%lx-%lx)\n",from,to); - pci_for_each_dev(dev) { - if (dev->class != PCI_CLASS_NOT_DEFINED_VGA && - dev->class >> 16 != PCI_BASE_CLASS_DISPLAY) - continue; - dprintk(KERN_DEBUG - " pci display adapter %04x:%04x at %02x:%02x.%x\n", - dev->vendor,dev->device,dev->bus->number, - PCI_SLOT(dev->devfn),PCI_FUNC(dev->devfn)); - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - if (!(dev->resource[i].flags & IORESOURCE_MEM)) - continue; - if (dev->resource[i].flags & IORESOURCE_READONLY) - continue; - match = (from >= dev->resource[i].start) && - (to-1 <= dev->resource[i].end); - if (match) - found = 1; - dprintk(KERN_DEBUG " memory at %08lx-%08lx%s\n", - dev->resource[i].start, - dev->resource[i].end, - match ? " (check passed)" : ""); - } - } - return found; -#else - /* Hmm, the physical address passed to us is probably bogous */ - dprintk(KERN_DEBUG "bttv: no overlay for this arch, sorry\n"); - return 0; -#endif -} - -/* ----------------------------------------------------------------------- */ /* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */ /* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C @@ -688,6 +680,34 @@ return -1; } +/* used to switch between the bt848's analog/digital video capture modes */ +void bt848A_set_timing(struct bttv *btv) +{ + u8 dvsif_val = 0; + int table_idx = bttv_tvnorms[btv->tvnorm].sram; + int i; + + /* timing change...reset timing generator address */ + btwrite(0x00, BT848_TGCTRL); + btwrite(0x02, BT848_TGCTRL); + btwrite(0x00, BT848_TGCTRL); + + if (btv->digital_video && -1 != table_idx) { + dprintk("bttv%d: load digital timing table (table_idx=%d)\n", + btv->nr,table_idx); + dvsif_val = 0x41; + for(i = 0; i < 51; i++) + btwrite(SRAM_Table[table_idx][i],BT848_TGLB); + + btwrite(0x75,BT848_PLL_F_LO); + btwrite(0x50,BT848_PLL_F_HI); + btwrite(0x8B,BT848_PLL_XCI); + btwrite(0x11,BT848_TGCTRL); + btv->pll.pll_current = 0; + } + btwrite(dvsif_val,BT848_DVSIF); +} + /* ----------------------------------------------------------------------- */ static void bt848_bright(struct bttv *btv, int bright) @@ -813,9 +833,11 @@ i2c_mux = mux = (btv->audio & AUDIO_MUTE) ? AUDIO_OFF : btv->audio; if (btv->opt_automute && !signal && !btv->radio_user) mux = AUDIO_OFF; +#if 0 printk("bttv%d: amux: mode=%d audio=%d signal=%s mux=%d/%d irq=%s\n", btv->nr, mode, btv->audio, signal ? "yes" : "no", mux, i2c_mux, in_interrupt() ? "yes" : "no"); +#endif val = bttv_tvcards[btv->type].audiomux[mux]; btaor(val,~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA); @@ -856,9 +878,24 @@ BT848_IFORM); btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE); btwrite(1, BT848_VBI_PACK_DEL); - - btv->pll.pll_ofreq = tvnorm->Fsc; - set_pll(btv); + + if (btv->digital_video) { + bt848A_set_timing(btv); + } else { + btv->pll.pll_ofreq = tvnorm->Fsc; + set_pll(btv); + } + + switch (btv->type) { + case BTTV_VOODOOTV_FM: + bttv_tda9880_setnorm(btv,norm); + break; +#if 0 + case BTTV_OSPREY540: + osprey_540_set_norm(btv,norm); + break; +#endif + } return 0; } @@ -924,7 +961,6 @@ set_input(btv,btv->input); } -#ifdef HAVE_V4L2 static int get_control(struct bttv *btv, struct v4l2_control *c) { struct video_audio va; @@ -935,7 +971,7 @@ break; if (i == BTTV_CTLS) return -EINVAL; - if (bttv_ctls[i].category == V4L2_CTRL_CAT_AUDIO) { + if (i >= 4 && i <= 8) { memset(&va,0,sizeof(va)); bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va); if (btv->audio_hook) @@ -1002,7 +1038,7 @@ break; if (i == BTTV_CTLS) return -EINVAL; - if (bttv_ctls[i].category == V4L2_CTRL_CAT_AUDIO) { + if (i >= 4 && i <= 8) { memset(&va,0,sizeof(va)); bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va); if (btv->audio_hook) @@ -1074,14 +1110,13 @@ default: return -EINVAL; } - if (bttv_ctls[i].category == V4L2_CTRL_CAT_AUDIO) { + if (i >= 4 && i <= 8) { bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va); if (btv->audio_hook) btv->audio_hook(btv,&va,1); } return 0; } -#endif /* HAVE_V4L2 */ /* ----------------------------------------------------------------------- */ @@ -1098,9 +1133,9 @@ { int need_count = 0; - if (locked_btres(btv,RESOURCE_STREAMING)) + if (locked_btres(btv,RESOURCE_VIDEO)) need_count++; - if (btv->vbi.users) + if (locked_btres(btv,RESOURCE_VBI)) need_count++; if (need_count) { @@ -1127,7 +1162,6 @@ return NULL; } -#ifdef HAVE_V4L2 static const struct bttv_format* format_by_fourcc(int fourcc) { @@ -1141,7 +1175,6 @@ } return NULL; } -#endif /* ----------------------------------------------------------------------- */ /* misc helpers */ @@ -1173,7 +1206,8 @@ static int bttv_prepare_buffer(struct bttv *btv, struct bttv_buffer *buf, const struct bttv_format *fmt, - int width, int height, int field) + int width, int height, + enum v4l2_field field) { int redo_dma_risc = 0; int rc; @@ -1196,8 +1230,6 @@ buf->vb.size = (width * height * fmt->depth) >> 3; if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) return -EINVAL; - field = bttv_buffer_field(btv, field, VBUF_FIELD_EVEN, - btv->tvnorm, height); } /* alloc + fill struct bttv_buffer (if changed) */ @@ -1252,13 +1284,14 @@ } static int -buffer_prepare(struct file *file, struct videobuf_buffer *vb, int field) +buffer_prepare(struct file *file, struct videobuf_buffer *vb) { struct bttv_buffer *buf = (struct bttv_buffer*)vb; struct bttv_fh *fh = file->private_data; return bttv_prepare_buffer(fh->btv,buf,fh->buf.fmt, - fh->buf.vb.width,fh->buf.vb.height,field); + fh->buf.vb.width,fh->buf.vb.height, + fh->buf.vb.field); } static void @@ -1280,7 +1313,7 @@ bttv_dma_free(fh->btv,buf); } -static struct videobuf_queue_ops bttv_qops = { +static struct videobuf_queue_ops bttv_video_qops = { buf_setup: buffer_setup, buf_prepare: buffer_prepare, buf_queue: buffer_queue, @@ -1295,20 +1328,6 @@ "SMICROCODE", "GVBIFMT", "SVBIFMT" }; #define V4L1_IOCTLS (sizeof(v4l1_ioctls)/sizeof(char*)) -static const char *v4l2_ioctls[] = { - "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT", - "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF", - "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON", - "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD", - "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER", - "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL", - "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43", - "44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT", - "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR", - "S_MODULATOR" -}; -#define V4L2_IOCTLS (sizeof(v4l2_ioctls)/sizeof(char*)) - int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) { switch (cmd) { @@ -1317,18 +1336,12 @@ /* *** v4l1 *** ************************************************ */ case VIDIOCGFREQ: -#ifdef HAVE_V4L2 - case VIDIOC_G_FREQ: -#endif { unsigned long *freq = arg; *freq = btv->freq; return 0; } case VIDIOCSFREQ: -#ifdef HAVE_V4L2 - case VIDIOC_S_FREQ: -#endif { unsigned long *freq = arg; down(&btv->lock); @@ -1456,32 +1469,30 @@ return 0; } -#ifdef HAVE_V4L2 /* *** v4l2 *** ************************************************ */ case VIDIOC_ENUMSTD: { - struct v4l2_enumstd *e = arg; - + struct v4l2_standard *e = arg; + if (e->index < 0 || e->index >= BTTV_TVNORMS) return -EINVAL; - v4l2_video_std_construct(&e->std, bttv_tvnorms[e->index].v4l2_id, 0); - e->inputs = 0x0f; - e->outputs = 0x00; + v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id, + bttv_tvnorms[e->index].name); return 0; } case VIDIOC_G_STD: { - struct v4l2_standard *s = arg; - v4l2_video_std_construct(s,bttv_tvnorms[btv->tvnorm].v4l2_id,0); + v4l2_std_id *id = arg; + *id = bttv_tvnorms[btv->tvnorm].v4l2_id; return 0; } case VIDIOC_S_STD: { - struct v4l2_standard *s = arg; - int i, id = v4l2_video_std_confirm(s); + v4l2_std_id *id = arg; + int i; - for(i = 0; i < BTTV_TVNORMS; i++) - if (id == bttv_tvnorms[i].v4l2_id) + for (i = 0; i < BTTV_TVNORMS; i++) + if (*id & bttv_tvnorms[i].v4l2_id) break; if (i == BTTV_TVNORMS) return -EINVAL; @@ -1492,6 +1503,16 @@ up(&btv->lock); return 0; } + case VIDIOC_QUERYSTD: + { + v4l2_std_id *id = arg; + + if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML) + *id = V4L2_STD_625_50; + else + *id = V4L2_STD_525_60; + return 0; + } case VIDIOC_ENUMINPUT: { @@ -1500,12 +1521,10 @@ if (i->index >= bttv_tvcards[btv->type].video_inputs) return -EINVAL; i->type = V4L2_INPUT_TYPE_CAMERA; - i->capability = 0; - i->assoc_audio = 0; if (i->index == bttv_tvcards[btv->type].tuner) { sprintf(i->name, "Television"); - i->type = V4L2_INPUT_TYPE_TUNER; - i->capability = V4L2_INPUT_CAP_AUDIO; + i->type = V4L2_INPUT_TYPE_TUNER; + i->tuner = 0; } else if (i->index==bttv_tvcards[btv->type].svhs) { sprintf(i->name, "S-Video"); } else { @@ -1532,14 +1551,17 @@ return 0; } - case VIDIOC_G_TUNER: { + case VIDIOC_G_TUNER: + { struct v4l2_tuner *t = arg; + if (-1 == bttv_tvcards[btv->type].tuner) + return -EINVAL; + if (0 != t->index) + return -EINVAL; down(&btv->lock); memset(t,0,sizeof(*t)); - t->input = bttv_tvcards[btv->type].tuner; strcpy(t->name, "Television"); - v4l2_video_std_construct(&t->std, bttv_tvnorms[btv->tvnorm].v4l2_id, 0); t->capability = V4L2_TUNER_CAP_NORM; t->rangehigh = 0xffffffffUL; t->rxsubchans = V4L2_TUNER_SUB_MONO; @@ -1563,10 +1585,13 @@ up(&btv->lock); return 0; } - case VIDIOC_S_TUNER: { + case VIDIOC_S_TUNER: + { struct v4l2_tuner *t = arg; - - if(t->input!=bttv_tvcards[btv->type].tuner) + + if (-1 == bttv_tvcards[btv->type].tuner) + return -EINVAL; + if (0 != t->index) return -EINVAL; down(&btv->lock); { @@ -1587,7 +1612,32 @@ up(&btv->lock); return 0; } -#endif /* HAVE_V4L2 */ + + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + memset(f,0,sizeof(*f)); + f->type = V4L2_TUNER_ANALOG_TV; + f->frequency = btv->freq; + return 0; + } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + if (unlikely(f->tuner != 0)) + return -EINVAL; + if (unlikely(f->type != V4L2_TUNER_ANALOG_TV)) + return -EINVAL; + down(&btv->lock); + btv->freq = f->frequency; + bttv_call_i2c_clients(btv,VIDIOCSFREQ,&btv->freq); + if (btv->has_matchbox && btv->radio_user) + tea5757_set_freq(btv,btv->freq); + up(&btv->lock); + return 0; + } default: return -ENOIOCTLCMD; @@ -1596,55 +1646,88 @@ return 0; } -static int setup_window(struct bttv_fh *fh, struct bttv *btv, - int x, int y, int width, int height, - struct video_clip *user_clips, int nclips) +static int verify_window(const struct bttv_tvnorm *tvn, + struct v4l2_window *win, int fixup) { - struct video_clip *clips = NULL; - int n,size,retval = 0; + enum v4l2_field field; + int maxw, maxh; - if (width < 48 || - height < 32 || - width > bttv_tvnorms[btv->tvnorm].swidth || - height > bttv_tvnorms[btv->tvnorm].sheight || - NULL == fh->ovfmt) + if (win->w.width < 48 || win->w.height < 32) return -EINVAL; - if (nclips > 2048) + if (win->clipcount > 2048) + return -EINVAL; + + field = win->field; + maxw = tvn->swidth; + maxh = tvn->sheight; + + if (V4L2_FIELD_ANY == field) { + field = (win->w.height > maxh/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_TOP; + } + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; + default: return -EINVAL; + } + + if (!fixup && (win->w.width > maxw || win->w.height > maxh)) + return -EINVAL; + + if (win->w.width > maxw) + win->w.width = maxw; + if (win->w.height > maxh) + win->w.height = maxh; + win->field = field; + return 0; +} + +static int setup_window(struct bttv_fh *fh, struct bttv *btv, + struct v4l2_window *win, int fixup) +{ + struct v4l2_clip *clips = NULL; + int n,size,retval = 0; + + retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup); + if (0 != retval) + return retval; /* copy clips -- luckily v4l1 + v4l2 are binary compatible here ...*/ - n = nclips; + n = win->clipcount; size = sizeof(struct video_clip)*(n+4); clips = kmalloc(size,GFP_KERNEL); if (NULL == clips) return -ENOMEM; if (n > 0) { - if (copy_from_user(clips,user_clips, - sizeof(struct video_clip)*nclips)) { + if (copy_from_user(clips,win->clips, + sizeof(struct v4l2_clip)*win->clipcount)) { kfree(clips); return -EFAULT; } } /* clip against screen */ if (NULL != btv->fbuf.base) - n = bttv_screen_clips(&btv->fbuf, x, y, - width, height, - clips, n); - bttv_sort_clips(clips,nclips); + n = bttv_screen_clips(btv->fbuf.width, btv->fbuf.width, + &win->w, clips, n); + bttv_sort_clips(clips,n); - down(&fh->q.lock); + down(&fh->cap.lock); if (fh->ov.clips) kfree(fh->ov.clips); fh->ov.clips = clips; - fh->ov.nclips = nclips; + fh->ov.nclips = n; - fh->ov.x = x; - fh->ov.y = y; - fh->ov.width = width; - fh->ov.height = height; - btv->init.ov.width = width; - btv->init.ov.height = height; + fh->ov.w = win->w; + fh->ov.field = win->field; + btv->init.ov.w.width = win->w.width; + btv->init.ov.w.height = win->w.height; /* update overlay if needed */ retval = 0; @@ -1655,10 +1738,205 @@ bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); retval = bttv_switch_overlay(btv,fh,new); } - up(&fh->q.lock); + up(&fh->cap.lock); return retval; } +/* ----------------------------------------------------------------------- */ + +static struct videobuf_queue* bttv_queue(struct bttv_fh *fh) +{ + struct videobuf_queue* q = NULL; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + q = &fh->cap; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + q = &fh->vbi; + break; + default: + BUG(); + } + return q; +} + +static int bttv_resource(struct bttv_fh *fh) +{ + int res = 0; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + res = RESOURCE_VIDEO; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + res = RESOURCE_VBI; + break; + default: + BUG(); + } + return res; +} + +static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type) +{ + struct videobuf_queue *q = bttv_queue(fh); + int res = bttv_resource(fh); + + if (check_btres(fh,res)) + return -EBUSY; + if (videobuf_queue_is_busy(q)) + return -EBUSY; + fh->type = type; + return 0; +} + +static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f) +{ + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format)); + f->fmt.pix.width = fh->buf.vb.width; + f->fmt.pix.height = fh->buf.vb.height; + f->fmt.pix.pixelformat = fh->buf.fmt->fourcc; + f->fmt.pix.sizeimage = + (fh->buf.vb.width*fh->buf.vb.height*fh->buf.fmt->depth)/8; + return 0; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + memset(&f->fmt.win,0,sizeof(struct v4l2_window)); + f->fmt.win.w = fh->ov.w; + return 0; + case V4L2_BUF_TYPE_VBI_CAPTURE: + bttv_vbi_fmt(fh,f); + return 0; + default: + return -EINVAL; + } +} + +static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv, + struct v4l2_format *f) +{ + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + { + const struct bttv_format *fmt; + enum v4l2_field field; + int maxw,maxh; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; + if (0 != f->fmt.pix.bytesperline) + /* FIXME -- not implemented yet */ + return -EINVAL; + + /* fixup format */ + maxw = bttv_tvnorms[btv->tvnorm].swidth; + maxh = bttv_tvnorms[btv->tvnorm].sheight; + field = f->fmt.pix.field; + if (V4L2_FIELD_ANY == field) + field = (f->fmt.pix.height > maxh/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + if (V4L2_FIELD_SEQ_BT == field) + field = V4L2_FIELD_SEQ_TB; + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + maxh = maxh/2; + break; + case V4L2_FIELD_INTERLACED: + break; + case V4L2_FIELD_SEQ_TB: + if (fmt->flags & FORMAT_FLAGS_PLANAR) + return -EINVAL; + default: + return -EINVAL; + } + + /* update data for the application */ + f->fmt.pix.field = field; + if (f->fmt.pix.width < 48) + f->fmt.pix.width = 48; + if (f->fmt.pix.height < 32) + f->fmt.pix.height = 32; + if (f->fmt.pix.width > maxw) + f->fmt.pix.width = maxw; + if (f->fmt.pix.height > maxh) + f->fmt.pix.height = maxh; + f->fmt.pix.sizeimage = + (fh->buf.vb.width * fh->buf.vb.height * fmt->depth)/8; + + return 0; + } + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + return verify_window(&bttv_tvnorms[btv->tvnorm], + &f->fmt.win, 1); +#if 0 + case V4L2_BUF_TYPE_VBI_CAPTURE: + retval = bttv_switch_type(fh,f->type); + if (0 != retval) + return retval; + if (fh->vbi.reading || fh->vbi.streaming) + return -EBUSY; + bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]); + bttv_vbi_fmt(fh,f); + return 0; +#endif + default: + return -EINVAL; + } +} + +static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv, + struct v4l2_format *f) +{ + int retval; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + { + const struct bttv_format *fmt; + + retval = bttv_switch_type(fh,f->type); + if (0 != retval) + return retval; + retval = bttv_try_fmt(fh,btv,f); + if (0 != retval) + return retval; + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + + /* update our state informations */ + down(&fh->cap.lock); + fh->buf.fmt = fmt; + fh->buf.vb.field = f->fmt.pix.field; + fh->buf.vb.width = f->fmt.pix.width; + fh->buf.vb.height = f->fmt.pix.height; + btv->init.buf.fmt = fmt; + btv->init.buf.vb.field = f->fmt.pix.field; + btv->init.buf.vb.width = f->fmt.pix.width; + btv->init.buf.vb.height = f->fmt.pix.height; + up(&fh->cap.lock); + + return 0; + } + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + return setup_window(fh, btv, &f->fmt.win, 1); + case V4L2_BUF_TYPE_VBI_CAPTURE: + retval = bttv_switch_type(fh,f->type); + if (0 != retval) + return retval; + if (fh->vbi.reading || fh->vbi.streaming) + return -EBUSY; + bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]); + bttv_vbi_fmt(fh,f); + return 0; + default: + return -EINVAL; + } +} + static int bttv_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) { @@ -1676,8 +1954,7 @@ break; case 'V': printk("bttv%d: ioctl 0x%x (v4l2, VIDIOC_%s)\n", - btv->nr, cmd, (_IOC_NR(cmd) < V4L2_IOCTLS) ? - v4l2_ioctls[_IOC_NR(cmd)] : "???"); + btv->nr, cmd, v4l2_ioctl_names[_IOC_NR(cmd)]); break; default: printk("bttv%d: ioctl 0x%x (???)\n", @@ -1696,17 +1973,23 @@ memset(cap,0,sizeof(*cap)); strcpy(cap->name,btv->video_dev.name); - cap->type = VID_TYPE_CAPTURE| - VID_TYPE_TUNER| - VID_TYPE_OVERLAY| - VID_TYPE_CLIPPING| - VID_TYPE_SCALES; - cap->channels = bttv_tvcards[btv->type].video_inputs; - cap->audios = bttv_tvcards[btv->type].audio_inputs; - cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth; - cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight; - cap->minwidth = 48; - cap->minheight = 32; + if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { + /* vbi */ + cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT; + } else { + /* others */ + cap->type = VID_TYPE_CAPTURE| + VID_TYPE_TUNER| + VID_TYPE_OVERLAY| + VID_TYPE_CLIPPING| + VID_TYPE_SCALES; + cap->channels = bttv_tvcards[btv->type].video_inputs; + cap->audios = bttv_tvcards[btv->type].audio_inputs; + cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth; + cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight; + cap->minwidth = 48; + cap->minheight = 32; + } return 0; } @@ -1733,7 +2016,7 @@ fmt = format_by_palette(pic->palette); if (NULL == fmt) return -EINVAL; - down(&fh->q.lock); + down(&fh->cap.lock); retval = -EINVAL; if (fmt->depth != pic->depth && !sloppy) goto fh_unlock_and_return; @@ -1754,7 +2037,7 @@ bt848_contrast(btv,pic->contrast); bt848_hue(btv,pic->hue); bt848_sat(btv,pic->colour); - up(&fh->q.lock); + up(&fh->cap.lock); return 0; } @@ -1763,26 +2046,31 @@ struct video_window *win = arg; memset(win,0,sizeof(*win)); - win->x = fh->ov.x; - win->y = fh->ov.y; - win->width = fh->ov.width; - win->height = fh->ov.height; + win->x = fh->ov.w.left; + win->y = fh->ov.w.top; + win->width = fh->ov.w.width; + win->height = fh->ov.w.height; return 0; } case VIDIOCSWIN: { struct video_window *win = arg; + struct v4l2_window w2; - retval = setup_window(fh,btv,win->x,win->y, - win->width,win->height, - win->clips, - win->clipcount); + w2.field = V4L2_FIELD_ANY; + w2.w.left = win->x; + w2.w.top = win->y; + w2.w.width = win->width; + w2.w.height = win->height; + w2.clipcount = win->clipcount; + w2.clips = (struct v4l2_clip*)win->clips; + retval = setup_window(fh, btv, &w2, 0); if (0 == retval) { /* on v4l1 this ioctl affects the read() size too */ - fh->buf.vb.width = fh->ov.width; - fh->buf.vb.height = fh->ov.height; - btv->init.buf.vb.width = fh->ov.width; - btv->init.buf.vb.height = fh->ov.height; + fh->buf.vb.width = fh->ov.w.width; + fh->buf.vb.height = fh->ov.w.height; + btv->init.buf.vb.width = fh->ov.w.width; + btv->init.buf.vb.height = fh->ov.w.height; } return retval; } @@ -1804,9 +2092,7 @@ return -EPERM; end = (unsigned long)fbuf->base + fbuf->height * fbuf->bytesperline; - if (0 == find_videomem((unsigned long)fbuf->base,end)) - return -EINVAL; - down(&fh->q.lock); + down(&fh->cap.lock); retval = -EINVAL; if (sloppy) { /* also set the default palette -- for backward @@ -1846,14 +2132,12 @@ goto fh_unlock_and_return; } btv->fbuf = *fbuf; - up(&fh->q.lock); + up(&fh->cap.lock); return 0; } case VIDIOCCAPTURE: -#ifdef HAVE_V4L2 - case VIDIOC_PREVIEW: -#endif + case VIDIOC_OVERLAY: { struct bttv_buffer *new; int *on = arg; @@ -1862,10 +2146,10 @@ /* verify args */ if (NULL == btv->fbuf.base) return -EINVAL; - if (fh->ov.width <48 || - fh->ov.height<32 || - fh->ov.width >bttv_tvnorms[btv->tvnorm].swidth || - fh->ov.height>bttv_tvnorms[btv->tvnorm].sheight || + if (fh->ov.w.width <48 || + fh->ov.w.height<32 || + fh->ov.w.width >bttv_tvnorms[btv->tvnorm].swidth || + fh->ov.w.height>bttv_tvnorms[btv->tvnorm].sheight|| NULL == fh->ovfmt) return -EINVAL; } @@ -1873,7 +2157,7 @@ if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY)) return -EBUSY; - down(&fh->q.lock); + down(&fh->cap.lock); if (*on) { fh->ov.tvnorm = btv->tvnorm; new = videobuf_alloc(sizeof(*new)); @@ -1884,7 +2168,7 @@ /* switch over */ retval = bttv_switch_overlay(btv,fh,new); - up(&fh->q.lock); + up(&fh->cap.lock); return retval; } @@ -1893,10 +2177,8 @@ struct video_mbuf *mbuf = arg; int i; - if (!mmap) - return -EINVAL; - down(&fh->q.lock); - retval = videobuf_mmap_setup(file,&fh->q,gbuffers,gbufsize); + down(&fh->cap.lock); + retval = videobuf_mmap_setup(file,&fh->cap,gbuffers,gbufsize); if (retval < 0) goto fh_unlock_and_return; memset(mbuf,0,sizeof(*mbuf)); @@ -1904,20 +2186,21 @@ mbuf->size = gbuffers * gbufsize; for (i = 0; i < gbuffers; i++) mbuf->offsets[i] = i * gbufsize; - up(&fh->q.lock); + up(&fh->cap.lock); return 0; } case VIDIOCMCAPTURE: { struct video_mmap *vm = arg; struct bttv_buffer *buf; + enum v4l2_field field; if (vm->frame >= VIDEO_MAX_FRAME) return -EINVAL; - down(&fh->q.lock); + down(&fh->cap.lock); retval = -EINVAL; - buf = (struct bttv_buffer *)fh->q.bufs[vm->frame]; + buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame]; if (NULL == buf) goto fh_unlock_and_return; if (0 == buf->vb.baddr) @@ -1926,15 +2209,18 @@ buf->vb.state == STATE_ACTIVE) goto fh_unlock_and_return; + field = (vm->height > bttv_tvnorms[btv->tvnorm].sheight/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; retval = bttv_prepare_buffer(btv,buf, format_by_palette(vm->format), - vm->width,vm->height,0); + vm->width,vm->height,field); if (0 != retval) goto fh_unlock_and_return; spin_lock_irqsave(&btv->s_lock,flags); buffer_queue(file,&buf->vb); spin_unlock_irqrestore(&btv->s_lock,flags); - up(&fh->q.lock); + up(&fh->cap.lock); return 0; } case VIDIOCSYNC: @@ -1945,9 +2231,9 @@ if (*frame >= VIDEO_MAX_FRAME) return -EINVAL; - down(&fh->q.lock); + down(&fh->cap.lock); retval = -EINVAL; - buf = (struct bttv_buffer *)fh->q.bufs[*frame]; + buf = (struct bttv_buffer *)fh->cap.bufs[*frame]; if (NULL == buf) goto fh_unlock_and_return; retval = videobuf_waiton(&buf->vb,0,1); @@ -1965,7 +2251,7 @@ retval = -EINVAL; break; } - up(&fh->q.lock); + up(&fh->cap.lock); return retval; } @@ -1980,8 +2266,11 @@ case VIDIOCSAUDIO: return bttv_common_ioctls(btv,cmd,arg); + /* vbi/teletext ioctls */ + case BTTV_VBISIZE: + bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE); + return fh->lines * 2 * 2048; -#ifdef HAVE_V4L2 /* *** v4l2 *** ************************************************ */ case VIDIOC_QUERYCAP: { @@ -1989,25 +2278,21 @@ if (0 == v4l2) return -EINVAL; - strcpy(cap->name,btv->video_dev.name); - cap->type = V4L2_TYPE_CAPTURE; - cap->flags = V4L2_FLAG_TUNER | V4L2_FLAG_PREVIEW - | V4L2_FLAG_READ | V4L2_FLAG_SELECT; - if (mmap) - cap->flags |= V4L2_FLAG_STREAMING; - cap->inputs = bttv_tvcards[btv->type].video_inputs; - cap->outputs = 0; - cap->audios = bttv_tvcards[btv->type].audio_inputs; - cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth; - cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight; - cap->minwidth = 48; - cap->minheight = 32; - cap->maxframerate = 30; + strcpy(cap->driver,"bttv"); + strncpy(cap->card,btv->video_dev.name,sizeof(cap->card)); + sprintf(cap->bus_info,"PCI:%s",btv->dev->slot_name); + cap->version = BTTV_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_TUNER | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; return 0; } - case VIDIOC_ENUM_PIXFMT: - case VIDIOC_ENUM_FBUFFMT: + case VIDIOC_ENUM_FMT: { struct v4l2_fmtdesc *f = arg; int i, index; @@ -2021,81 +2306,38 @@ } if (BTTV_FORMATS == i) return -EINVAL; - if (cmd == VIDIOC_ENUM_FBUFFMT && - 0 == (bttv_formats[i].flags & FORMAT_FLAGS_PACKED)) + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED)) + return -EINVAL; + break; + default: return -EINVAL; + } memset(f,0,sizeof(*f)); f->index = index; strncpy(f->description,bttv_formats[i].name,31); f->pixelformat = bttv_formats[i].fourcc; - f->depth = bttv_formats[i].depth; return 0; } + case VIDIOC_TRY_FMT: + { + struct v4l2_format *f = arg; + return bttv_try_fmt(fh,btv,f); + } case VIDIOC_G_FMT: { struct v4l2_format *f = arg; - - memset(f,0,sizeof(*f)); - f->type = V4L2_BUF_TYPE_CAPTURE; - f->fmt.pix.width = fh->buf.vb.width; - f->fmt.pix.height = fh->buf.vb.height; - f->fmt.pix.depth = fh->buf.fmt->depth; - f->fmt.pix.pixelformat = fh->buf.fmt->fourcc; - f->fmt.pix.sizeimage = - (fh->buf.vb.width*fh->buf.vb.height*fh->buf.fmt->depth)/8; - return 0; + return bttv_g_fmt(fh,f); } case VIDIOC_S_FMT: { struct v4l2_format *f = arg; - const struct bttv_format *fmt; - - if ((f->type & V4L2_BUF_TYPE_field) != V4L2_BUF_TYPE_CAPTURE) - return -EINVAL; - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) - return -EINVAL; - if (f->fmt.pix.width < 48 || - f->fmt.pix.height < 32) - return -EINVAL; - if (f->fmt.pix.flags & V4L2_FMT_FLAG_BYTESPERLINE) - /* FIXME -- not implemented yet */ - return -EINVAL; - - down(&fh->q.lock); - /* fixup format */ - if (f->fmt.pix.width > bttv_tvnorms[btv->tvnorm].swidth) - f->fmt.pix.width = bttv_tvnorms[btv->tvnorm].swidth; - if (f->fmt.pix.height > bttv_tvnorms[btv->tvnorm].sheight) - f->fmt.pix.height = bttv_tvnorms[btv->tvnorm].sheight; - if (!(f->fmt.pix.flags & V4L2_FMT_FLAG_INTERLACED) && - f->fmt.pix.height>bttv_tvnorms[btv->tvnorm].sheight/2) - f->fmt.pix.height=bttv_tvnorms[btv->tvnorm].sheight/2; - - if (f->fmt.pix.height > bttv_tvnorms[btv->tvnorm].sheight/2) { - /* must interlace -- no field splitting available */ - f->fmt.pix.flags &= ~(V4L2_FMT_FLAG_TOPFIELD| - V4L2_FMT_FLAG_BOTFIELD); - } else { - /* one field is enouth -- no interlace needed */ - f->fmt.pix.flags &= ~V4L2_FMT_FLAG_INTERLACED; - } - - /* update our state informations */ - fh->buf.fmt = fmt; - fh->buf.vb.width = f->fmt.pix.width; - fh->buf.vb.height = f->fmt.pix.height; - btv->init.buf.fmt = fmt; - btv->init.buf.vb.width = f->fmt.pix.width; - btv->init.buf.vb.height = f->fmt.pix.height; - - /* update data for the application */ - f->fmt.pix.depth = fmt->depth; - f->fmt.pix.sizeimage = - (fh->buf.vb.width * fh->buf.vb.height * fmt->depth)/8; - up(&fh->q.lock); - return 0; + return bttv_s_fmt(fh,btv,f); } case VIDIOC_G_FBUF: @@ -2103,16 +2345,13 @@ struct v4l2_framebuffer *fb = arg; memset(fb,0,sizeof(*fb)); - fb->base[0] = btv->fbuf.base; + fb->base = btv->fbuf.base; fb->fmt.width = btv->fbuf.width; fb->fmt.height = btv->fbuf.height; fb->fmt.bytesperline = btv->fbuf.bytesperline; - fb->fmt.flags = V4L2_FMT_FLAG_BYTESPERLINE; - fb->capability = V4L2_FBUF_CAP_CLIPPING; - if (fh->ovfmt) { - fb->fmt.depth = fh->ovfmt->depth; + fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; + if (fh->ovfmt) fb->fmt.pixelformat = fh->ovfmt->fourcc; - } return 0; } case VIDIOC_S_FBUF: @@ -2126,18 +2365,16 @@ return -EPERM; /* check args */ - end = (unsigned long)fb->base[0] + + end = (unsigned long)fb->base + fb->fmt.height * fb->fmt.bytesperline; - if (0 == find_videomem((unsigned long)fb->base[0],end)) - return -EINVAL; - + fmt = format_by_fourcc(fb->fmt.pixelformat); if (NULL == fmt) return -EINVAL; if (0 == (fmt->flags & FORMAT_FLAGS_PACKED)) return -EINVAL; - down(&fh->q.lock); + down(&fh->cap.lock); retval = -EINVAL; if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth) @@ -2147,11 +2384,11 @@ } /* ok, accept it */ - btv->fbuf.base = fb->base[0]; + btv->fbuf.base = fb->base; btv->fbuf.width = fb->fmt.width; btv->fbuf.height = fb->fmt.height; btv->fbuf.depth = fmt->depth; - if (fb->fmt.flags & V4L2_FMT_FLAG_BYTESPERLINE) + if (0 != fb->fmt.bytesperline) btv->fbuf.bytesperline = fb->fmt.bytesperline; else btv->fbuf.bytesperline = btv->fbuf.width*fmt->depth/8; @@ -2160,12 +2397,12 @@ fh->ovfmt = fmt; btv->init.ovfmt = fmt; if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { - fh->ov.x = 0; - fh->ov.y = 0; - fh->ov.width = fb->fmt.width; - fh->ov.height = fb->fmt.height; - btv->init.ov.width = fb->fmt.width; - btv->init.ov.height = fb->fmt.height; + fh->ov.w.left = 0; + fh->ov.w.top = 0; + fh->ov.w.width = fb->fmt.width; + fh->ov.w.height = fb->fmt.height; + btv->init.ov.w.width = fb->fmt.width; + btv->init.ov.w.height = fb->fmt.height; if (fh->ov.clips) kfree(fh->ov.clips); fh->ov.clips = NULL; @@ -2179,64 +2416,48 @@ retval = bttv_switch_overlay(btv,fh,new); } } - up(&fh->q.lock); + up(&fh->cap.lock); return retval; } - case VIDIOC_G_WIN: - { - struct v4l2_window *win = arg; - - memset(win,0,sizeof(*win)); - win->x = fh->ov.x; - win->y = fh->ov.y; - win->width = fh->ov.width; - win->height = fh->ov.height; - return 0; - } - case VIDIOC_S_WIN: - { - struct v4l2_window *win = arg; - - return setup_window(fh,btv,win->x,win->y, - win->width,win->height, - (struct video_clip*)win->clips, - win->clipcount); - } case VIDIOC_REQBUFS: - if (!mmap) - return -EINVAL; - return videobuf_reqbufs(file,&fh->q,arg); + return videobuf_reqbufs(file,bttv_queue(fh),arg); case VIDIOC_QUERYBUF: - return videobuf_querybuf(&fh->q,arg); + return videobuf_querybuf(bttv_queue(fh),arg); case VIDIOC_QBUF: - return videobuf_qbuf(file,&fh->q,arg); + return videobuf_qbuf(file,bttv_queue(fh),arg); case VIDIOC_DQBUF: - return videobuf_dqbuf(file,&fh->q,arg); + return videobuf_dqbuf(file,bttv_queue(fh),arg); case VIDIOC_STREAMON: - if (!check_alloc_btres(btv,fh,RESOURCE_STREAMING)) + { + int res = bttv_resource(fh); + + if (!check_alloc_btres(btv,fh,res)) return -EBUSY; bttv_field_count(btv); - return videobuf_streamon(file,&fh->q); - + return videobuf_streamon(file,bttv_queue(fh)); + } case VIDIOC_STREAMOFF: - retval = videobuf_streamoff(file,&fh->q); + { + int res = bttv_resource(fh); + + retval = videobuf_streamoff(file,bttv_queue(fh)); if (retval < 0) return retval; - free_btres(btv,fh,RESOURCE_STREAMING); + free_btres(btv,fh,res); bttv_field_count(btv); return 0; + } case VIDIOC_QUERYCTRL: { struct v4l2_queryctrl *c = arg; int i; - v4l2_fill_ctrl_category(c); if ((c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) && (c->id < V4L2_CID_PRIVATE_BASE || @@ -2250,7 +2471,7 @@ return 0; } *c = bttv_ctls[i]; - if (bttv_ctls[i].category == V4L2_CTRL_CAT_AUDIO) { + if (i >= 4 && i <= 8) { struct video_audio va; memset(&va,0,sizeof(va)); bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va); @@ -2285,11 +2506,12 @@ { struct v4l2_streamparm *parm = arg; struct v4l2_standard s; - if (parm->type != V4L2_BUF_TYPE_CAPTURE) + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; memset(parm,0,sizeof(*parm)); - v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id, 0); - parm->parm.capture.timeperframe = v4l2_video_std_tpf(&s); + v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id, + bttv_tvnorms[btv->tvnorm].name); + parm->parm.capture.timeperframe = s.frameperiod; return 0; } @@ -2301,10 +2523,9 @@ case VIDIOC_S_INPUT: case VIDIOC_G_TUNER: case VIDIOC_S_TUNER: - case VIDIOC_G_FREQ: - case VIDIOC_S_FREQ: + case VIDIOC_G_FREQUENCY: + case VIDIOC_S_FREQUENCY: return bttv_common_ioctls(btv,cmd,arg); -#endif /* HAVE_V4L2 */ default: return -ENOIOCTLCMD; @@ -2312,7 +2533,7 @@ return 0; fh_unlock_and_return: - up(&fh->q.lock); + up(&fh->cap.lock); return retval; } @@ -2322,55 +2543,30 @@ return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl); } -#if 0 -/* - * blocking read for a complete video frame - * => no kernel bounce buffer needed. - */ -static ssize_t -bttv_read_zerocopy(struct bttv_fh *fh, struct bttv *btv, - char *data,size_t count, loff_t *ppos) -{ - int rc; - - /* setup stuff */ - dprintk("bttv%d: read zerocopy\n",btv->nr); - fh->q.read_buf->baddr = (unsigned long)data; - fh->q.read_buf->bsize = count; - rc = bttv_prepare_buffer(btv,fh->q.read_buf,fh->buf.fmt, - fh->buf.vb.width,fh->buf.vb.height,0); - if (0 != rc) - goto done; - - /* start capture & wait */ - bttv_queue_buffer(btv,fh->q.read_buf); - rc = videobuf_waiton(fh->q.read_buf,0,1); - if (0 == rc) { - videobuf_dma_pci_sync(btv->dev,&fh->q.read_buf->dma); - rc = fh->q.read_buf->size; - } - - done: - /* cleanup */ - bttv_dma_free(btv,fh->q.read_buf); - fh->q.read_buf->baddr = 0; - fh->q.read_buf->size = 0; - return rc; -} -#endif - - static ssize_t bttv_read(struct file *file, char *data, size_t count, loff_t *ppos) { struct bttv_fh *fh = file->private_data; + int retval = 0; if (fh->btv->errors) bttv_reinit_bt848(fh->btv); - if (locked_btres(fh->btv,RESOURCE_STREAMING)) - return -EBUSY; + dprintk("read count=%d type=%s\n", + (int)count,v4l2_type_names[fh->type]); - return videobuf_read_one(file, &fh->q, data, count, ppos); + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (locked_btres(fh->btv,RESOURCE_VIDEO)) + return -EBUSY; + retval = videobuf_read_one(file, &fh->cap, data, count, ppos); + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + retval = videobuf_read_stream(file, &fh->vbi, data, count, ppos, 1); + break; + default: + BUG(); + } + return retval; } static unsigned int bttv_poll(struct file *file, poll_table *wait) @@ -2378,34 +2574,37 @@ struct bttv_fh *fh = file->private_data; struct bttv_buffer *buf; - if (check_btres(fh,RESOURCE_STREAMING)) { + if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) + return videobuf_poll_stream(file, &fh->vbi, wait); + + if (check_btres(fh,RESOURCE_VIDEO)) { /* streaming capture */ - if (list_empty(&fh->q.stream)) + if (list_empty(&fh->cap.stream)) return POLLERR; - buf = list_entry(fh->q.stream.next,struct bttv_buffer,vb.stream); + buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream); } else { /* read() capture */ - down(&fh->q.lock); - if (NULL == fh->q.read_buf) { + down(&fh->cap.lock); + if (NULL == fh->cap.read_buf) { /* need to capture a new frame */ - if (locked_btres(fh->btv,RESOURCE_STREAMING)) { - up(&fh->q.lock); + if (locked_btres(fh->btv,RESOURCE_VIDEO)) { + up(&fh->cap.lock); return POLLERR; } - fh->q.read_buf = videobuf_alloc(fh->q.msize); - if (NULL == fh->q.read_buf) { - up(&fh->q.lock); + fh->cap.read_buf = videobuf_alloc(fh->cap.msize); + if (NULL == fh->cap.read_buf) { + up(&fh->cap.lock); return POLLERR; } - if (0 != fh->q.ops->buf_prepare(file,fh->q.read_buf,0)) { - up(&fh->q.lock); + if (0 != fh->cap.ops->buf_prepare(file,fh->cap.read_buf)) { + up(&fh->cap.lock); return POLLERR; } - fh->q.ops->buf_queue(file,fh->q.read_buf); - fh->q.read_off = 0; + fh->cap.ops->buf_queue(file,fh->cap.read_buf); + fh->cap.read_off = 0; } - up(&fh->q.lock); - buf = (struct bttv_buffer*)fh->q.read_buf; + up(&fh->cap.lock); + buf = (struct bttv_buffer*)fh->cap.read_buf; } poll_wait(file, &buf->vb.done, wait); @@ -2420,6 +2619,7 @@ unsigned int minor = minor(inode->i_rdev); struct bttv *btv = NULL; struct bttv_fh *fh; + enum v4l2_buf_type type = 0; int i; dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor); @@ -2427,13 +2627,20 @@ for (i = 0; i < bttv_num; i++) { if (bttvs[i].video_dev.minor == minor) { btv = &bttvs[i]; + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + break; + } + if (bttvs[i].vbi_dev.minor == minor) { + btv = &bttvs[i]; + type = V4L2_BUF_TYPE_VBI_CAPTURE; break; } } if (NULL == btv) return -ENODEV; - dprintk(KERN_DEBUG "bttv%d: open called (video)\n",btv->nr); + dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n", + btv->nr,v4l2_type_names[type]); /* allocate per filehandle data */ fh = kmalloc(sizeof(*fh),GFP_KERNEL); @@ -2441,8 +2648,15 @@ return -ENOMEM; file->private_data = fh; *fh = btv->init; - videobuf_queue_init(&fh->q, &bttv_qops, btv->dev, &btv->s_lock, - V4L2_BUF_TYPE_CAPTURE,sizeof(struct bttv_buffer)); + fh->type = type; + videobuf_queue_init(&fh->cap, &bttv_video_qops, + btv->dev, &btv->s_lock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + sizeof(struct bttv_buffer)); + videobuf_queue_init(&fh->vbi, &bttv_vbi_qops, + btv->dev, &btv->s_lock, + V4L2_BUF_TYPE_VBI_CAPTURE, + sizeof(struct bttv_buffer)); i2c_vidiocschan(btv); return 0; @@ -2456,16 +2670,24 @@ /* turn off overlay, stop outstanding captures */ if (check_btres(fh, RESOURCE_OVERLAY)) bttv_switch_overlay(btv,fh,NULL); - if (check_btres(fh, RESOURCE_STREAMING)) { - videobuf_streamoff(file,&fh->q); - free_btres(btv,fh,RESOURCE_STREAMING); + + /* stop video capture */ + if (check_btres(fh, RESOURCE_VIDEO)) { + videobuf_streamoff(file,&fh->cap); + free_btres(btv,fh,RESOURCE_VIDEO); bttv_field_count(btv); } - if (fh->q.read_buf) { - buffer_release(file,fh->q.read_buf); - kfree(fh->q.read_buf); + if (fh->cap.read_buf) { + buffer_release(file,fh->cap.read_buf); + kfree(fh->cap.read_buf); } + /* stop vbi capture */ + if (fh->vbi.streaming) + videobuf_streamoff(file,&fh->vbi); + if (fh->vbi.reading) + videobuf_read_stop(file,&fh->vbi); + file->private_data = NULL; kfree(fh); return 0; @@ -2476,11 +2698,10 @@ { struct bttv_fh *fh = file->private_data; - if (!mmap) - return -EINVAL; - dprintk("mmap 0x%lx+%ld\n",vma->vm_start, - vma->vm_end - vma->vm_start); - return videobuf_mmap_mapper(vma,&fh->q); + dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n", + fh->btv->nr, v4l2_type_names[fh->type], + vma->vm_start, vma->vm_end - vma->vm_start); + return videobuf_mmap_mapper(vma,bttv_queue(fh)); } static struct file_operations bttv_fops = @@ -2495,7 +2716,7 @@ poll: bttv_poll, }; -static struct video_device bttv_template = +static struct video_device bttv_video_template = { name: "UNSET", type: VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY| @@ -2505,6 +2726,15 @@ minor: -1, }; +struct video_device bttv_vbi_template = +{ + name: "bt848/878 vbi", + type: VID_TYPE_TUNER|VID_TYPE_TELETEXT, + hardware: VID_HARDWARE_BT848, + fops: &bttv_fops, + minor: -1, +}; + /* ----------------------------------------------------------------------- */ /* radio interface */ @@ -2653,20 +2883,20 @@ printk(" main: %08Lx\n", (u64)btv->main.dma); printk(" vbi : o=%08Lx e=%08Lx\n", - btv->vcurr ? (u64)btv->vcurr->odd.dma : 0, - btv->vcurr ? (u64)btv->vcurr->even.dma : 0); + btv->vcurr ? (u64)btv->vcurr->top.dma : 0, + btv->vcurr ? (u64)btv->vcurr->bottom.dma : 0); printk(" cap : o=%08Lx e=%08Lx\n", - btv->odd ? (u64)btv->odd->odd.dma : 0, - btv->even ? (u64)btv->even->even.dma : 0); + btv->top ? (u64)btv->top->top.dma : 0, + btv->bottom ? (u64)btv->bottom->bottom.dma : 0); printk(" scr : o=%08Lx e=%08Lx\n", - btv->screen ? (u64)btv->screen->odd.dma : 0, - btv->screen ? (u64)btv->screen->even.dma : 0); + btv->screen ? (u64)btv->screen->top.dma : 0, + btv->screen ? (u64)btv->screen->bottom.dma : 0); } static void bttv_irq_timeout(unsigned long data) { struct bttv *btv = (struct bttv *)data; - struct bttv_buffer *o_even,*o_odd,*o_vcurr; + struct bttv_buffer *o_bottom,*o_top,*o_vcurr; struct bttv_buffer *capture; if (bttv_verbose) { @@ -2677,12 +2907,12 @@ } spin_lock(&btv->s_lock); - o_odd = btv->odd; - o_even = btv->even; - o_vcurr = btv->vcurr; - btv->odd = NULL; - btv->even = NULL; - btv->vcurr = NULL; + o_top = btv->top; + o_bottom = btv->bottom; + o_vcurr = btv->vcurr; + btv->top = NULL; + btv->bottom = NULL; + btv->vcurr = NULL; /* deactivate stuff */ bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); @@ -2692,19 +2922,19 @@ bttv_set_dma(btv, 0, 0); /* wake up + free */ - if (o_odd == o_even) { - if (NULL != o_odd) { - o_odd->vb.state = STATE_ERROR; - wake_up(&o_odd->vb.done); + if (o_top == o_bottom) { + if (NULL != o_top) { + o_top->vb.state = STATE_ERROR; + wake_up(&o_top->vb.done); } } else { - if (NULL != o_odd) { - o_odd->vb.state = STATE_ERROR; - wake_up(&o_odd->vb.done); - } - if (NULL != o_even) { - o_even->vb.state = STATE_ERROR; - wake_up(&o_even->vb.done); + if (NULL != o_top) { + o_top->vb.state = STATE_ERROR; + wake_up(&o_top->vb.done); + } + if (NULL != o_bottom) { + o_bottom->vb.state = STATE_ERROR; + wake_up(&o_bottom->vb.done); } } if (NULL != o_vcurr) { @@ -2733,20 +2963,18 @@ static void bttv_irq_switch_fields(struct bttv *btv) { - struct bttv_buffer *o_even,*o_odd,*o_vcurr; + struct bttv_buffer *o_bottom,*o_top,*o_vcurr; struct bttv_buffer *capture; int irqflags = 0; -#ifdef HAVE_V4L2 - stamp_t ts; -#endif + struct timeval ts; spin_lock(&btv->s_lock); - o_odd = btv->odd; - o_even = btv->even; - o_vcurr = btv->vcurr; - btv->odd = NULL; - btv->even = NULL; - btv->vcurr = NULL; + o_top = btv->top; + o_bottom = btv->bottom; + o_vcurr = btv->vcurr; + btv->top = NULL; + btv->bottom = NULL; + btv->vcurr = NULL; /* vbi request ? */ if (!list_empty(&btv->vcapture)) { @@ -2760,24 +2988,24 @@ irqflags = 1; capture = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); list_del(&capture->vb.queue); - if (capture->vb.field & VBUF_FIELD_ODD) - btv->odd = capture; - if (capture->vb.field & VBUF_FIELD_EVEN) - btv->even = capture; + if (V4L2_FIELD_HAS_TOP(capture->vb.field)) + btv->top = capture; + if (V4L2_FIELD_HAS_BOTTOM(capture->vb.field)) + btv->bottom = capture; /* capture request for other field ? */ - if (!(capture->vb.field & VBUF_FIELD_INTER) && + if (!V4L2_FIELD_HAS_BOTH(capture->vb.field) && !list_empty(&btv->capture)) { capture = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); - if (!(capture->vb.field & VBUF_FIELD_INTER)) { - if (NULL == btv->odd && - capture->vb.field & VBUF_FIELD_ODD) { - btv->odd = capture; + if (!V4L2_FIELD_HAS_BOTH(capture->vb.field)) { + if (NULL == btv->top && + V4L2_FIELD_TOP == capture->vb.field) { + btv->top = capture; list_del(&capture->vb.queue); } - if (NULL == btv->even && - capture->vb.field & VBUF_FIELD_EVEN) { - btv->even = capture; + if (NULL == btv->bottom && + V4L2_FIELD_BOTTOM == capture->vb.field) { + btv->bottom = capture; list_del(&capture->vb.queue); } } @@ -2786,34 +3014,34 @@ /* screen overlay ? */ if (NULL != btv->screen) { - if (btv->screen->vb.field & VBUF_FIELD_INTER) { - if (NULL == btv->odd && NULL == btv->even) { - btv->odd = btv->screen; - btv->even = btv->screen; + if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) { + if (NULL == btv->top && NULL == btv->bottom) { + btv->top = btv->screen; + btv->bottom = btv->screen; } } else { - if ((btv->screen->vb.field & VBUF_FIELD_ODD) && - NULL == btv->odd) { - btv->odd = btv->screen; + if (V4L2_FIELD_TOP == btv->screen->vb.field && + NULL == btv->top) { + btv->top = btv->screen; } - if ((btv->screen->vb.field & VBUF_FIELD_EVEN) && - NULL == btv->even) { - btv->even = btv->screen; + if (V4L2_FIELD_BOTTOM == btv->screen->vb.field && + NULL == btv->bottom) { + btv->bottom = btv->screen; } } } if (irq_debug) printk(KERN_DEBUG - "bttv: irq odd=%p even=%p screen=%p vbi=%p\n", - btv->odd,btv->even,btv->screen,btv->vcurr); + "bttv: irq top=%p bottom=%p screen=%p vbi=%p\n", + btv->top,btv->bottom,btv->screen,btv->vcurr); /* activate new fields */ - bttv_buffer_activate(btv,btv->odd,btv->even); + bttv_buffer_activate(btv,btv->top,btv->bottom); if (btv->vcurr) { btv->vcurr->vb.state = STATE_ACTIVE; - bttv_risc_hook(btv, RISC_SLOT_O_VBI, &btv->vcurr->odd, 0); - bttv_risc_hook(btv, RISC_SLOT_E_VBI, &btv->vcurr->even, 0); + bttv_risc_hook(btv, RISC_SLOT_O_VBI, &btv->vcurr->top, 0); + bttv_risc_hook(btv, RISC_SLOT_E_VBI, &btv->vcurr->bottom, 0); } else { bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0); bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0); @@ -2821,40 +3049,30 @@ bttv_set_dma(btv, 0, irqflags); /* wake up + free */ -#ifdef HAVE_V4L2 - v4l2_masterclock_gettime(&ts); -#endif - if (o_odd == o_even) { - if (NULL != o_odd && btv->odd != o_odd) { -#ifdef HAVE_V4L2 - o_odd->vb.ts = ts; -#endif - o_odd->vb.field_count = btv->field_count; - o_odd->vb.state = STATE_DONE; - wake_up(&o_odd->vb.done); + do_gettimeofday(&ts); + if (o_top == o_bottom) { + if (NULL != o_top && btv->top != o_top) { + o_top->vb.ts = ts; + o_top->vb.field_count = btv->field_count; + o_top->vb.state = STATE_DONE; + wake_up(&o_top->vb.done); } } else { - if (NULL != o_odd && btv->odd != o_odd) { -#ifdef HAVE_V4L2 - o_odd->vb.ts = ts; -#endif - o_odd->vb.field_count = btv->field_count; - o_odd->vb.state = STATE_DONE; - wake_up(&o_odd->vb.done); - } - if (NULL != o_even && btv->even != o_even) { -#ifdef HAVE_V4L2 - o_even->vb.ts = ts; -#endif - o_even->vb.field_count = btv->field_count; - o_even->vb.state = STATE_DONE; - wake_up(&o_even->vb.done); + if (NULL != o_top && btv->top != o_top) { + o_top->vb.ts = ts; + o_top->vb.field_count = btv->field_count; + o_top->vb.state = STATE_DONE; + wake_up(&o_top->vb.done); + } + if (NULL != o_bottom && btv->bottom != o_bottom) { + o_bottom->vb.ts = ts; + o_bottom->vb.field_count = btv->field_count; + o_bottom->vb.state = STATE_DONE; + wake_up(&o_bottom->vb.done); } } if (NULL != o_vcurr) { -#ifdef HAVE_V4L2 o_vcurr->vb.ts = ts; -#endif o_vcurr->vb.field_count = btv->field_count; o_vcurr->vb.state = STATE_DONE; wake_up(&o_vcurr->vb.done); @@ -2896,7 +3114,7 @@ printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES) ? "yes" : "no"); if (stat & BT848_INT_FMTCHG) - printk(" NUML => %s", (dstat & BT848_DSTATUS_PRES) + printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML) ? "625" : "525"); printk("\n"); } @@ -3006,8 +3224,6 @@ init_waitqueue_head(&btv->gpioq); INIT_LIST_HEAD(&btv->capture); INIT_LIST_HEAD(&btv->vcapture); - videobuf_queue_init(&btv->vbi.q, &vbi_qops, btv->dev, &btv->s_lock, - V4L2_BUF_TYPE_VBI,sizeof(struct bttv_buffer)); btv->timeout.function = bttv_irq_timeout; btv->timeout.data = (unsigned long)btv; @@ -3015,9 +3231,9 @@ btv->i2c_rc = -1; btv->tuner_type = -1; - memcpy(&btv->video_dev, &bttv_template, sizeof(bttv_template)); - memcpy(&btv->radio_dev, &radio_template, sizeof(radio_template)); - memcpy(&btv->vbi_dev, &bttv_vbi_template, sizeof(bttv_vbi_template)); + memcpy(&btv->video_dev, &bttv_video_template, sizeof(bttv_video_template)); + memcpy(&btv->radio_dev, &radio_template, sizeof(radio_template)); + memcpy(&btv->vbi_dev, &bttv_vbi_template, sizeof(bttv_vbi_template)); btv->video_dev.minor = -1; btv->video_dev.priv = btv; btv->radio_dev.minor = -1; @@ -3060,9 +3276,8 @@ } pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision); pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); - printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %02x:%02x.%x, ", - bttv_num,btv->id, btv->revision, dev->bus->number, - PCI_SLOT(dev->devfn),PCI_FUNC(dev->devfn)); + printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ", + bttv_num,btv->id, btv->revision, dev->slot_name); printk("irq: %d, latency: %d, mmio: 0x%lx\n", btv->dev->irq, lat, pci_resource_start(dev,0)); @@ -3100,11 +3315,13 @@ /* fill struct bttv with some useful defaults */ btv->init.btv = btv; - btv->init.ov.width = 320; - btv->init.ov.height = 240; + btv->init.ov.w.width = 320; + btv->init.ov.w.height = 240; btv->init.buf.fmt = format_by_palette(VIDEO_PALETTE_RGB24); btv->init.buf.vb.width = 320; btv->init.buf.vb.height = 240; + btv->init.buf.vb.field = V4L2_FIELD_BOTTOM; + btv->init.lines = 16; btv->input = 0; /* initialize hardware */ @@ -3173,7 +3390,7 @@ /* shutdown everything (DMA+IRQs) */ btand(~15, BT848_GPIO_DMA_CTL); btwrite(0, BT848_INT_MASK); - btwrite(~0x0UL,BT848_INT_STAT); + btwrite(~0x0, BT848_INT_STAT); btwrite(0x0, BT848_GPIO_OUT_EN); if (bttv_gpio) bttv_gpio_tracking(btv,"cleanup"); @@ -3231,8 +3448,7 @@ { bttv_num = 0; - printk(KERN_INFO "bttv: driver version %d.%d.%d loaded " - BTTV_APIS "\n", + printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n", (BTTV_VERSION_CODE >> 16) & 0xff, (BTTV_VERSION_CODE >> 8) & 0xff, BTTV_VERSION_CODE & 0xff); diff -Nru a/drivers/media/video/bttv-if.c b/drivers/media/video/bttv-if.c --- a/drivers/media/video/bttv-if.c Mon Nov 4 14:31:00 2002 +++ b/drivers/media/video/bttv-if.c Mon Nov 4 14:31:00 2002 @@ -41,11 +41,13 @@ static struct i2c_client bttv_i2c_client_template; EXPORT_SYMBOL(bttv_get_cardinfo); +EXPORT_SYMBOL(bttv_get_pcidev); EXPORT_SYMBOL(bttv_get_id); EXPORT_SYMBOL(bttv_gpio_enable); EXPORT_SYMBOL(bttv_read_gpio); EXPORT_SYMBOL(bttv_write_gpio); EXPORT_SYMBOL(bttv_get_gpio_queue); +EXPORT_SYMBOL(bttv_i2c_call); /* ----------------------------------------------------------------------- */ /* Exported functions - for other modules which want to access the */ @@ -62,6 +64,13 @@ return 0; } +struct pci_dev* bttv_get_pcidev(unsigned int card) +{ + if (card >= bttv_num) + return NULL; + return bttvs[card].dev; +} + int bttv_get_id(unsigned int card) { printk("bttv_get_id is obsolete, use bttv_get_cardinfo instead\n"); @@ -243,6 +252,13 @@ btv->i2c_clients[i]->driver->command( btv->i2c_clients[i],cmd,arg); } +} + +void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg) +{ + if (card >= bttv_num) + return; + bttv_call_i2c_clients(&bttvs[card], cmd, arg); } static struct i2c_algo_bit_data bttv_i2c_algo_template = { diff -Nru a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c --- a/drivers/media/video/bttv-risc.c Mon Nov 4 14:31:01 2002 +++ b/drivers/media/video/bttv-risc.c Mon Nov 4 14:31:01 2002 @@ -5,7 +5,7 @@ - memory management - generation - (c) 2000 Gerd Knorr + (c) 2000 Gerd Knorr 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 @@ -43,8 +43,8 @@ struct bttv_riscmem *risc, unsigned int size) { - unsigned long *cpu; - dma_addr_t dma; + u32 *cpu; + dma_addr_t dma; cpu = pci_alloc_consistent(pci, size, &dma); if (NULL == cpu) @@ -82,7 +82,7 @@ { int instructions,rc,line,todo; struct scatterlist *sg; - unsigned long *rp; + u32 *rp; /* estimate risc mem: worst case is one write per page border + one write per scan line + sync + jump (all 2 dwords) */ @@ -146,7 +146,7 @@ int cpadding) { int instructions,rc,line,todo,ylen,chroma; - unsigned long *rp,ri; + u32 *rp,ri; struct scatterlist *ysg; struct scatterlist *usg; struct scatterlist *vsg; @@ -241,54 +241,53 @@ }; int -bttv_screen_clips(struct video_buffer *fbuf, - int x, int y, int width, int height, - struct video_clip *clips, int n) +bttv_screen_clips(int swidth, int sheight, struct v4l2_rect *win, + struct v4l2_clip *clips, int n) { - if (x < 0) { + if (win->left < 0) { /* left */ - clips[n].x = 0; - clips[n].y = 0; - clips[n].width = -x; - clips[n].height = height; + clips[n].c.left = 0; + clips[n].c.top = 0; + clips[n].c.width = -win->left; + clips[n].c.height = win->height; n++; } - if (x+width > fbuf->width) { + if (win->left + win->width > swidth) { /* right */ - clips[n].x = fbuf->width - x; - clips[n].y = 0; - clips[n].width = width - clips[n].x; - clips[n].height = height; + clips[n].c.left = swidth - win->left; + clips[n].c.top = 0; + clips[n].c.width = win->width - clips[n].c.left; + clips[n].c.height = win->height; n++; } - if (y < 0) { + if (win->top < 0) { /* top */ - clips[n].x = 0; - clips[n].y = 0; - clips[n].width = width; - clips[n].height = -y; + clips[n].c.left = 0; + clips[n].c.top = 0; + clips[n].c.width = win->width; + clips[n].c.height = -win->top; n++; } - if (y+height > fbuf->height) { + if (win->top + win->height > sheight) { /* bottom */ - clips[n].x = 0; - clips[n].y = fbuf->height - y; - clips[n].width = width; - clips[n].height = height - clips[n].y; + clips[n].c.left = 0; + clips[n].c.top = sheight - win->top; + clips[n].c.width = win->width; + clips[n].c.height = win->height - clips[n].c.top; n++; } return n; } void -bttv_sort_clips(struct video_clip *clips, int nclips) +bttv_sort_clips(struct v4l2_clip *clips, int nclips) { - struct video_clip swap; + struct v4l2_clip swap; int i,j,n; for (i = nclips-2; i >= 0; i--) { for (n = 0, j = 0; j <= i; j++) { - if (clips[j].x > clips[j+1].x) { + if (clips[j].c.left > clips[j+1].c.left) { swap = clips[j]; clips[j] = clips[j+1]; clips[j+1] = swap; @@ -303,7 +302,7 @@ static void calc_skips(int line, int width, int *maxy, struct SKIPLIST *skips, int *nskips, - const struct video_clip *clips, int nclips) + const struct v4l2_clip *clips, int nclips) { int clip,skip,maxline,end; @@ -312,35 +311,35 @@ for (clip = 0; clip < nclips; clip++) { /* sanity checks */ - if (clips[clip].x + clips[clip].width <= 0) + if (clips[clip].c.left + clips[clip].c.width <= 0) continue; - if (clips[clip].x > width) + if (clips[clip].c.left > width) break; /* vertical range */ - if (line > clips[clip].y+clips[clip].height-1) + if (line > clips[clip].c.top+clips[clip].c.height-1) continue; - if (line < clips[clip].y) { - if (maxline > clips[clip].y-1) - maxline = clips[clip].y-1; + if (line < clips[clip].c.top) { + if (maxline > clips[clip].c.top-1) + maxline = clips[clip].c.top-1; continue; } - if (maxline > clips[clip].y+clips[clip].height-1) - maxline = clips[clip].y+clips[clip].height-1; + if (maxline > clips[clip].c.top+clips[clip].c.height-1) + maxline = clips[clip].c.top+clips[clip].c.height-1; /* horizontal range */ - if (0 == skip || clips[clip].x > skips[skip-1].end) { + if (0 == skip || clips[clip].c.left > skips[skip-1].end) { /* new one */ - skips[skip].start = clips[clip].x; + skips[skip].start = clips[clip].c.left; if (skips[skip].start < 0) skips[skip].start = 0; - skips[skip].end = clips[clip].x + clips[clip].width; + skips[skip].end = clips[clip].c.left + clips[clip].c.width; if (skips[skip].end > width) skips[skip].end = width; skip++; } else { /* overlaps -- expand last one */ - end = clips[clip].x + clips[clip].width; + end = clips[clip].c.left + clips[clip].c.width; if (skips[skip-1].end < end) skips[skip-1].end = end; if (skips[skip-1].end > width) @@ -362,12 +361,12 @@ int bttv_risc_overlay(struct bttv *btv, struct bttv_riscmem *risc, const struct bttv_format *fmt, struct bttv_overlay *ov, - int fields) + int skip_even, int skip_odd) { int instructions,rc,line,maxy,start,end,skip,nskips; struct SKIPLIST *skips; - unsigned long *rp,ri,ra; - unsigned long addr; + u32 *rp,ri,ra; + u32 addr; /* skip list for window clipping */ if (NULL == (skips = kmalloc(sizeof(*skips) * ov->nclips,GFP_KERNEL))) @@ -376,7 +375,7 @@ /* estimate risc mem: worst case is (clip+1) * lines instructions + sync + jump (all 2 dwords) */ instructions = (ov->nclips + 1) * - ((fields & VBUF_FIELD_INTER) ? ov->height>>1 : ov->height); + ((skip_even || skip_odd) ? ov->w.height>>1 : ov->w.height); instructions += 2; if ((rc = bttv_riscmem_alloc(btv->dev,risc,instructions*8)) < 0) return rc; @@ -387,29 +386,27 @@ *(rp++) = cpu_to_le32(0); addr = (unsigned long)btv->fbuf.base; - addr += btv->fbuf.bytesperline * ov->y; - addr += ((btv->fbuf.depth+7) >> 3) * ov->x; + addr += btv->fbuf.bytesperline * ov->w.top; + addr += ((btv->fbuf.depth+7) >> 3) * ov->w.left; /* scan lines */ - for (maxy = -1, line = 0; line < ov->height; + for (maxy = -1, line = 0; line < ov->w.height; line++, addr += btv->fbuf.bytesperline) { - if (fields & VBUF_FIELD_INTER) { - if ((line%2) != 0 && (fields & VBUF_FIELD_ODD)) - continue; - if ((line%2) != 1 && (fields & VBUF_FIELD_EVEN)) - continue; - } + if ((line%2) == 0 && skip_even) + continue; + if ((line%2) == 1 && skip_odd) + continue; /* calculate clipping */ if (line > maxy) - calc_skips(line, ov->width, &maxy, + calc_skips(line, ov->w.width, &maxy, skips, &nskips, ov->clips, ov->nclips); /* write out risc code */ - for (start = 0, skip = 0; start < ov->width; start = end) { + for (start = 0, skip = 0; start < ov->w.width; start = end) { if (skip >= nskips) { ri = BT848_RISC_WRITE; - end = ov->width; + end = ov->w.width; } else if (start < skips[skip].start) { ri = BT848_RISC_WRITE; end = skips[skip].start; @@ -425,7 +422,7 @@ if (0 == start) ri |= BT848_RISC_SOL; - if (ov->width == end) + if (ov->w.width == end) ri |= BT848_RISC_EOL; ri |= (fmt->depth>>3) * (end-start); @@ -448,19 +445,30 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo, int width, int height, int interleaved, int norm) { - const struct bttv_tvnorm *tvnorm; + const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm]; u32 xsf, sr; int vdelay; - tvnorm = &bttv_tvnorms[norm]; + int swidth = tvnorm->swidth; + int totalwidth = tvnorm->totalwidth; + int scaledtwidth = tvnorm->scaledtwidth; + + if (btv->digital_video) { + swidth = 720; + totalwidth = 858; + scaledtwidth = 858; + } + vdelay = tvnorm->vdelay; +#if 0 /* FIXME */ if (vdelay < btv->vbi.lines*2) vdelay = btv->vbi.lines*2; +#endif - xsf = (width*tvnorm->scaledtwidth)/tvnorm->swidth; - geo->hscale = ((tvnorm->totalwidth*4096UL)/xsf-4096); + xsf = (width*scaledtwidth)/swidth; + geo->hscale = ((totalwidth*4096UL)/xsf-4096); geo->hdelay = tvnorm->hdelayx1; - geo->hdelay = (geo->hdelay*width)/tvnorm->swidth; + geo->hdelay = (geo->hdelay*width)/swidth; geo->hdelay &= 0x3fe; sr = ((tvnorm->sheight >> (interleaved?0:1))*512)/height - 512; geo->vscale = (0x10000UL-sr) & 0x1fff; @@ -512,8 +520,8 @@ int capctl; btv->cap_ctl = 0; - if (NULL != btv->odd) btv->cap_ctl |= 0x02; - if (NULL != btv->even) btv->cap_ctl |= 0x01; + if (NULL != btv->top) btv->cap_ctl |= 0x02; + if (NULL != btv->bottom) btv->cap_ctl |= 0x01; if (NULL != btv->vcurr) btv->cap_ctl |= 0x0c; capctl = 0; @@ -522,12 +530,12 @@ capctl |= override; d2printk(KERN_DEBUG - "bttv%d: capctl=%x irq=%d odd=%08Lx/%08Lx even=%08Lx/%08Lx\n", + "bttv%d: capctl=%x irq=%d top=%08Lx/%08Lx even=%08Lx/%08Lx\n", btv->nr,capctl,irqflags, - btv->vcurr ? (u64)btv->vcurr->odd.dma : 0, - btv->odd ? (u64)btv->odd->odd.dma : 0, - btv->vcurr ? (u64)btv->vcurr->even.dma : 0, - btv->even ? (u64)btv->even->even.dma : 0); + btv->vcurr ? (u64)btv->vcurr->top.dma : 0, + btv->top ? (u64)btv->top->top.dma : 0, + btv->vcurr ? (u64)btv->vcurr->bottom.dma : 0, + btv->bottom ? (u64)btv->bottom->bottom.dma : 0); cmd = BT848_RISC_JUMP; if (irqflags) { @@ -570,7 +578,7 @@ btv->main.cpu[2] = cpu_to_le32(BT848_RISC_JUMP); btv->main.cpu[3] = cpu_to_le32(btv->main.dma + (4<<2)); - /* odd field */ + /* top field */ btv->main.cpu[4] = cpu_to_le32(BT848_RISC_JUMP); btv->main.cpu[5] = cpu_to_le32(btv->main.dma + (6<<2)); btv->main.cpu[6] = cpu_to_le32(BT848_RISC_JUMP); @@ -580,13 +588,13 @@ BT848_FIFO_STATUS_VRO); btv->main.cpu[9] = cpu_to_le32(0); - /* even field */ + /* bottom field */ btv->main.cpu[10] = cpu_to_le32(BT848_RISC_JUMP); btv->main.cpu[11] = cpu_to_le32(btv->main.dma + (12<<2)); btv->main.cpu[12] = cpu_to_le32(BT848_RISC_JUMP); btv->main.cpu[13] = cpu_to_le32(btv->main.dma + (14<<2)); - /* jump back to odd field */ + /* jump back to top field */ btv->main.cpu[14] = cpu_to_le32(BT848_RISC_JUMP); btv->main.cpu[15] = cpu_to_le32(btv->main.dma + (0<<2)); @@ -625,43 +633,43 @@ videobuf_waiton(&buf->vb,0,0); videobuf_dma_pci_unmap(btv->dev, &buf->vb.dma); videobuf_dma_free(&buf->vb.dma); - bttv_riscmem_free(btv->dev,&buf->even); - bttv_riscmem_free(btv->dev,&buf->odd); + bttv_riscmem_free(btv->dev,&buf->bottom); + bttv_riscmem_free(btv->dev,&buf->top); buf->vb.state = STATE_NEEDS_INIT; } int bttv_buffer_activate(struct bttv *btv, - struct bttv_buffer *odd, - struct bttv_buffer *even) + struct bttv_buffer *top, + struct bttv_buffer *bottom) { - if (NULL != odd && NULL != even) { - odd->vb.state = STATE_ACTIVE; - even->vb.state = STATE_ACTIVE; - bttv_apply_geo(btv, &odd->geo, 1); - bttv_apply_geo(btv, &even->geo,0); - bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &odd->odd, 0); - bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &even->even, 0); - btaor((odd->btformat & 0xf0) | (even->btformat & 0x0f), + if (NULL != top && NULL != bottom) { + top->vb.state = STATE_ACTIVE; + bottom->vb.state = STATE_ACTIVE; + bttv_apply_geo(btv, &top->geo, 1); + bttv_apply_geo(btv, &bottom->geo,0); + bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &top->top, 0); + bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &bottom->bottom, 0); + btaor((top->btformat & 0xf0) | (bottom->btformat & 0x0f), ~0xff, BT848_COLOR_FMT); - btaor((odd->btswap & 0x0a) | (even->btswap & 0x05), + btaor((top->btswap & 0x0a) | (bottom->btswap & 0x05), ~0x0f, BT848_COLOR_CTL); - } else if (NULL != odd) { - odd->vb.state = STATE_ACTIVE; - bttv_apply_geo(btv, &odd->geo,1); - bttv_apply_geo(btv, &odd->geo,0); - bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &odd->odd, 0); + } else if (NULL != top) { + top->vb.state = STATE_ACTIVE; + bttv_apply_geo(btv, &top->geo,1); + bttv_apply_geo(btv, &top->geo,0); + bttv_risc_hook(btv, RISC_SLOT_O_FIELD, &top->top, 0); bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0); - btaor(odd->btformat & 0xff, ~0xff, BT848_COLOR_FMT); - btaor(odd->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); - } else if (NULL != even) { - even->vb.state = STATE_ACTIVE; - bttv_apply_geo(btv, &even->geo,1); - bttv_apply_geo(btv, &even->geo,0); - bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); - bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &even->even, 0); - btaor(even->btformat & 0xff, ~0xff, BT848_COLOR_FMT); - btaor(even->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); + btaor(top->btformat & 0xff, ~0xff, BT848_COLOR_FMT); + btaor(top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); + } else if (NULL != bottom) { + bottom->vb.state = STATE_ACTIVE; + bttv_apply_geo(btv, &bottom->geo,1); + bttv_apply_geo(btv, &bottom->geo,0); + bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); + bttv_risc_hook(btv, RISC_SLOT_E_FIELD, &bottom->bottom, 0); + btaor(bottom->btformat & 0xff, ~0xff, BT848_COLOR_FMT); + btaor(bottom->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); } else { bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); bttv_risc_hook(btv, RISC_SLOT_E_FIELD, NULL, 0); @@ -671,72 +679,53 @@ /* ---------------------------------------------------------- */ -int -bttv_buffer_field(struct bttv *btv, int field, int def_field, - int norm, int height) -{ - const struct bttv_tvnorm *tvnorm = bttv_tvnorms + norm; - - /* check interleave, even+odd fields */ - if (height > (tvnorm->sheight >> 1)) { - field = VBUF_FIELD_ODD | VBUF_FIELD_EVEN | VBUF_FIELD_INTER; - } else { - if (field & def_field) { - field = def_field; - } else { - field = (def_field & VBUF_FIELD_EVEN) - ? VBUF_FIELD_ODD : VBUF_FIELD_EVEN; - } - } - return field; -} - /* calculate geometry, build risc code */ int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) { const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm; - buf->vb.field = bttv_buffer_field(btv,buf->vb.field, VBUF_FIELD_EVEN, - buf->tvnorm,buf->vb.height); dprintk(KERN_DEBUG - "bttv%d: buffer flags:%s%s%s format: %s size: %dx%d\n", - btv->nr, - (buf->vb.field & VBUF_FIELD_INTER) ? " interleave" : "", - (buf->vb.field & VBUF_FIELD_ODD) ? " odd" : "", - (buf->vb.field & VBUF_FIELD_EVEN) ? " even" : "", - buf->fmt->name,buf->vb.width,buf->vb.height); + "bttv%d: buffer field: %s format: %s size: %dx%d\n", + btv->nr, v4l2_field_names[buf->vb.field], + buf->fmt->name, buf->vb.width, buf->vb.height); /* packed pixel modes */ if (buf->fmt->flags & FORMAT_FLAGS_PACKED) { - int bpl, padding, lines; - bpl = (buf->fmt->depth >> 3) * buf->vb.width; + int bpl = (buf->fmt->depth >> 3) * buf->vb.width; + int bpf = bpl * (buf->vb.height >> 1); - /* calculate geometry */ - if (buf->vb.field & VBUF_FIELD_INTER) { - bttv_calc_geo(btv,&buf->geo,buf->vb.width, - buf->vb.height,1,buf->tvnorm); - lines = buf->vb.height >> 1; - padding = bpl; - } else { - bttv_calc_geo(btv,&buf->geo,buf->vb.width, - buf->vb.height,0,buf->tvnorm); - lines = buf->vb.height; - padding = 0; - } + bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height, + V4L2_FIELD_HAS_BOTH(buf->vb.field),buf->tvnorm); - /* build risc code */ - if (buf->vb.field & VBUF_FIELD_ODD) - bttv_risc_packed(btv,&buf->odd,buf->vb.dma.sglist, - 0,bpl,padding,lines); - if (buf->vb.field & VBUF_FIELD_EVEN) - bttv_risc_packed(btv,&buf->even,buf->vb.dma.sglist, - padding,bpl,padding,lines); + switch (buf->vb.field) { + case V4L2_FIELD_TOP: + bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, + 0,bpl,0,buf->vb.height); + break; + case V4L2_FIELD_BOTTOM: + bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, + 0,bpl,0,buf->vb.height); + break; + case V4L2_FIELD_INTERLACED: + bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, + 0,bpl,bpl,buf->vb.height >> 1); + bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, + bpl,bpl,bpl,buf->vb.height >> 1); + break; + case V4L2_FIELD_SEQ_TB: + bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist, + 0,bpl,0,buf->vb.height >> 1); + bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist, + bpf,bpl,0,buf->vb.height >> 1); + break; + default: + BUG(); + } } /* planar modes */ if (buf->fmt->flags & FORMAT_FLAGS_PLANAR) { - struct bttv_riscmem *risc; int uoffset, voffset; int ypadding, cpadding, lines; @@ -755,54 +744,59 @@ voffset += uoffset; } - if (buf->vb.field & VBUF_FIELD_INTER) { + switch (buf->vb.field) { + case V4L2_FIELD_TOP: + bttv_calc_geo(btv,&buf->geo,buf->vb.width, + buf->vb.height,0,buf->tvnorm); + bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist, + 0,buf->vb.width,0,buf->vb.height, + uoffset,voffset,buf->fmt->hshift, + buf->fmt->vshift,0); + break; + case V4L2_FIELD_BOTTOM: + bttv_calc_geo(btv,&buf->geo,buf->vb.width, + buf->vb.height,0,buf->tvnorm); + bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist, + 0,buf->vb.width,0,buf->vb.height, + uoffset,voffset,buf->fmt->hshift, + buf->fmt->vshift,0); + break; + case V4L2_FIELD_INTERLACED: bttv_calc_geo(btv,&buf->geo,buf->vb.width, buf->vb.height,1,buf->tvnorm); lines = buf->vb.height >> 1; ypadding = buf->vb.width; - if (!buf->fmt->vshift) { - /* chroma planes are interleaved too */ - cpadding = buf->vb.width >> buf->fmt->hshift; - } else { - cpadding = 0; - } - bttv_risc_planar(btv,&buf->odd, + cpadding = buf->vb.width >> buf->fmt->hshift; + bttv_risc_planar(btv,&buf->top, buf->vb.dma.sglist, 0,buf->vb.width,ypadding,lines, - uoffset,voffset,buf->fmt->hshift, + uoffset,voffset, + buf->fmt->hshift, buf->fmt->vshift >> 1, cpadding); - bttv_risc_planar(btv,&buf->even, + bttv_risc_planar(btv,&buf->bottom, buf->vb.dma.sglist, ypadding,buf->vb.width,ypadding,lines, uoffset+cpadding, voffset+cpadding, buf->fmt->hshift, - cpadding ? (buf->fmt->vshift>>1) : -1, + buf->fmt->vshift >> 1, cpadding); - } else { - if (buf->vb.field & VBUF_FIELD_ODD) - risc = &buf->odd; - else - risc = &buf->even; - bttv_calc_geo(btv,&buf->geo,buf->vb.width, - buf->vb.height,0,buf->tvnorm); - bttv_risc_planar(btv, risc, buf->vb.dma.sglist, - 0,buf->vb.width,0,buf->vb.height, - uoffset,voffset,buf->fmt->hshift, - buf->fmt->vshift,0); + break; + default: + BUG(); } } /* raw data */ if (buf->fmt->flags & FORMAT_FLAGS_RAW) { /* build risc code */ - buf->vb.field = VBUF_FIELD_INTER | VBUF_FIELD_ODD | VBUF_FIELD_EVEN; + buf->vb.field = V4L2_FIELD_SEQ_TB; bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight, 1,buf->tvnorm); - bttv_risc_packed(btv, &buf->odd, buf->vb.dma.sglist, + bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist, 0, RAW_BPL, 0, RAW_LINES); - bttv_risc_packed(btv, &buf->even, buf->vb.dma.sglist, + bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist, buf->vb.size/2 , RAW_BPL, 0, RAW_LINES); } @@ -821,35 +815,41 @@ const struct bttv_format *fmt, struct bttv_buffer *buf) { - int interleave; - - /* check interleave, even+odd fields */ - buf->vb.field = bttv_buffer_field(btv, 0, VBUF_FIELD_ODD, - ov->tvnorm,ov->height); + /* check interleave, bottom+top fields */ dprintk(KERN_DEBUG - "bttv%d: overlay flags:%s%s%s format: %s size: %dx%d\n", - btv->nr, - (buf->vb.field & VBUF_FIELD_INTER) ? " interleave" : "", - (buf->vb.field & VBUF_FIELD_ODD) ? " odd" : "", - (buf->vb.field & VBUF_FIELD_EVEN) ? " even" : "", - fmt->name,ov->width,ov->height); + "bttv%d: overlay fields: %s format: %s size: %dx%d\n", + btv->nr, v4l2_field_names[buf->vb.field], + fmt->name,ov->w.width,ov->w.height); /* calculate geometry */ - interleave = buf->vb.field & VBUF_FIELD_INTER; - bttv_calc_geo(btv,&buf->geo,ov->width,ov->height, - interleave, ov->tvnorm); + bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height, + V4L2_FIELD_HAS_BOTH(ov->field), ov->tvnorm); /* build risc code */ - if (buf->vb.field & VBUF_FIELD_ODD) - bttv_risc_overlay(btv, &buf->odd, fmt, ov, - interleave | VBUF_FIELD_ODD); - if (buf->vb.field & VBUF_FIELD_EVEN) - bttv_risc_overlay(btv, &buf->even,fmt, ov, - interleave | VBUF_FIELD_EVEN); + switch (ov->field) { + case V4L2_FIELD_TOP: + bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 0); + break; + case V4L2_FIELD_BOTTOM: + bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0); + break; + case V4L2_FIELD_INTERLACED: +#if 0 + bttv_risc_overlay(btv, &buf->top, fmt, ov, 1, 0); + bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 1); +#else + bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1); + bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0); +#endif + break; + default: + BUG(); + } /* copy format info */ buf->btformat = fmt->btformat; buf->btswap = fmt->btswap; + buf->vb.field = ov->field; return 0; } diff -Nru a/drivers/media/video/bttv-vbi.c b/drivers/media/video/bttv-vbi.c --- a/drivers/media/video/bttv-vbi.c Mon Nov 4 14:31:02 2002 +++ b/drivers/media/video/bttv-vbi.c Mon Nov 4 14:31:02 2002 @@ -47,58 +47,51 @@ #define dprintk(fmt, arg...) if (vbi_debug) \ printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->nr, ## arg) -#ifndef HAVE_V4L2 -/* some dummy defines to avoid cluttering up the source code with - a huge number of ifdef's for V4L2 */ -# define V4L2_BUF_TYPE_CAPTURE -1 -# define V4L2_BUF_TYPE_VBI -1 -#endif - /* ----------------------------------------------------------------------- */ /* vbi risc code + mm */ static int -vbi_buffer_risc(struct bttv *btv, struct bttv_buffer *buf) +vbi_buffer_risc(struct bttv *btv, struct bttv_buffer *buf, int lines) { int bpl = 2048; - bttv_risc_packed(btv, &buf->odd, buf->vb.dma.sglist, - 0, bpl-4, 4, btv->vbi.lines); - bttv_risc_packed(btv, &buf->even, buf->vb.dma.sglist, - btv->vbi.lines * bpl, bpl-4, 4, btv->vbi.lines); + bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist, + 0, bpl-4, 4, lines); + bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist, + lines * bpl, bpl-4, 4, lines); return 0; } static int vbi_buffer_setup(struct file *file, int *count, int *size) { - struct bttv *btv = file->private_data; + struct bttv_fh *fh = file->private_data; if (0 == *count) *count = vbibufs; - *size = btv->vbi.lines * 2 * 2048; + *size = fh->lines * 2 * 2048; return 0; } -static int vbi_buffer_prepare(struct file *file, struct videobuf_buffer *vb, - int fields) +static int vbi_buffer_prepare(struct file *file, struct videobuf_buffer *vb) { - struct bttv *btv = file->private_data; + struct bttv_fh *fh = file->private_data; + struct bttv *btv = fh->btv; struct bttv_buffer *buf = (struct bttv_buffer*)vb; int rc; - buf->vb.size = btv->vbi.lines * 2 * 2048; + buf->vb.size = fh->lines * 2 * 2048; if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) return -EINVAL; if (STATE_NEEDS_INIT == buf->vb.state) { if (0 != (rc = videobuf_iolock(btv->dev,&buf->vb))) goto fail; - if (0 != (rc = vbi_buffer_risc(btv,buf))) + if (0 != (rc = vbi_buffer_risc(btv,buf,fh->lines))) goto fail; } buf->vb.state = STATE_PREPARED; - dprintk("buf prepare %p: odd=%p even=%p\n", - vb,&buf->odd,&buf->even); + dprintk("buf prepare %p: top=%p bottom=%p\n", + vb,&buf->top,&buf->bottom); return 0; fail: @@ -109,7 +102,8 @@ static void vbi_buffer_queue(struct file *file, struct videobuf_buffer *vb) { - struct bttv *btv = file->private_data; + struct bttv_fh *fh = file->private_data; + struct bttv *btv = fh->btv; struct bttv_buffer *buf = (struct bttv_buffer*)vb; dprintk("queue %p\n",vb); @@ -120,14 +114,15 @@ static void vbi_buffer_release(struct file *file, struct videobuf_buffer *vb) { - struct bttv *btv = file->private_data; + struct bttv_fh *fh = file->private_data; + struct bttv *btv = fh->btv; struct bttv_buffer *buf = (struct bttv_buffer*)vb; dprintk("free %p\n",vb); - bttv_dma_free(btv,buf); + bttv_dma_free(fh->btv,buf); } -struct videobuf_queue_ops vbi_qops = { +struct videobuf_queue_ops bttv_vbi_qops = { buf_setup: vbi_buffer_setup, buf_prepare: vbi_buffer_prepare, buf_queue: vbi_buffer_queue, @@ -136,7 +131,7 @@ /* ----------------------------------------------------------------------- */ -static void vbi_setlines(struct bttv *btv, int lines) +void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines) { int vdelay; @@ -144,7 +139,7 @@ lines = 1; if (lines > VBI_MAXLINES) lines = VBI_MAXLINES; - btv->vbi.lines = lines; + fh->lines = lines; vdelay = btread(BT848_E_VDELAY_LO); if (vdelay < lines*2) { @@ -154,19 +149,18 @@ } } -#ifdef HAVE_V4L2 -static void vbi_fmt(struct bttv *btv, struct v4l2_format *f) +void bttv_vbi_fmt(struct bttv_fh *fh, struct v4l2_format *f) { memset(f,0,sizeof(*f)); - f->type = V4L2_BUF_TYPE_VBI; + f->type = V4L2_BUF_TYPE_VBI_CAPTURE; f->fmt.vbi.sampling_rate = 35468950; f->fmt.vbi.samples_per_line = 2048; - f->fmt.vbi.sample_format = V4L2_VBI_SF_UBYTE; + f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; f->fmt.vbi.offset = 244; - f->fmt.vbi.count[0] = btv->vbi.lines; - f->fmt.vbi.count[1] = btv->vbi.lines; + f->fmt.vbi.count[0] = fh->lines; + f->fmt.vbi.count[1] = fh->lines; f->fmt.vbi.flags = 0; - switch (btv->tvnorm) { + switch (fh->btv->tvnorm) { case 1: /* NTSC */ f->fmt.vbi.start[0] = 10; f->fmt.vbi.start[1] = 273; @@ -178,212 +172,8 @@ f->fmt.vbi.start[1] = 319; } } -#endif /* ----------------------------------------------------------------------- */ -/* vbi interface */ - -static int vbi_open(struct inode *inode, struct file *file) -{ - unsigned int minor = minor(inode->i_rdev); - struct bttv *btv = NULL; - int i; - - for (i = 0; i < bttv_num; i++) { - if (bttvs[i].vbi_dev.minor == minor) { - btv = &bttvs[i]; - break; - } - } - if (NULL == btv) - return -ENODEV; - - down(&btv->vbi.q.lock); - if (btv->vbi.users) { - up(&btv->vbi.q.lock); - return -EBUSY; - } - dprintk("open minor=%d\n",minor); - file->private_data = btv; - btv->vbi.users++; - vbi_setlines(btv,VBI_DEFLINES); - bttv_field_count(btv); - - up(&btv->vbi.q.lock); - - return 0; -} - -static int vbi_release(struct inode *inode, struct file *file) -{ - struct bttv *btv = file->private_data; - - if (btv->vbi.q.streaming) - videobuf_streamoff(file,&btv->vbi.q); - down(&btv->vbi.q.lock); - if (btv->vbi.q.reading) - videobuf_read_stop(file,&btv->vbi.q); - btv->vbi.users--; - bttv_field_count(btv); - vbi_setlines(btv,0); - up(&btv->vbi.q.lock); - return 0; -} - -static int vbi_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - struct bttv *btv = file->private_data; - - if (btv->errors) - bttv_reinit_bt848(btv); - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability *cap = arg; - - memset(cap,0,sizeof(*cap)); - strcpy(cap->name,btv->vbi_dev.name); - cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT; - return 0; - } - - /* vbi/teletext ioctls */ - case BTTV_VBISIZE: - return btv->vbi.lines * 2 * 2048; - - case BTTV_VERSION: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGTUNER: - case VIDIOCSTUNER: - case VIDIOCGCHAN: - case VIDIOCSCHAN: - return bttv_common_ioctls(btv,cmd,arg); - -#ifdef HAVE_V4L2 - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - - memset(cap,0,sizeof(*cap)); - strcpy(cap->name, btv->name); - cap->type = V4L2_TYPE_VBI; - cap->flags = V4L2_FLAG_TUNER | V4L2_FLAG_READ | - V4L2_FLAG_STREAMING | V4L2_FLAG_SELECT; - return 0; - } - case VIDIOC_G_FMT: - { - struct v4l2_format *f = arg; - - vbi_fmt(btv,f); - return 0; - } - case VIDIOC_S_FMT: - { - struct v4l2_format *f = arg; - - if (btv->vbi.q.reading || btv->vbi.q.streaming) - return -EBUSY; - vbi_setlines(btv,f->fmt.vbi.count[0]); - vbi_fmt(btv,f); - return 0; - } - - case VIDIOC_REQBUFS: - return videobuf_reqbufs(file,&btv->vbi.q,arg); - - case VIDIOC_QUERYBUF: - return videobuf_querybuf(&btv->vbi.q, arg); - - case VIDIOC_QBUF: - return videobuf_qbuf(file, &btv->vbi.q, arg); - - case VIDIOC_DQBUF: - return videobuf_dqbuf(file, &btv->vbi.q, arg); - - case VIDIOC_STREAMON: - return videobuf_streamon(file, &btv->vbi.q); - - case VIDIOC_STREAMOFF: - return videobuf_streamoff(file, &btv->vbi.q); - - case VIDIOC_ENUMSTD: - case VIDIOC_G_STD: - case VIDIOC_S_STD: - case VIDIOC_ENUMINPUT: - case VIDIOC_G_INPUT: - case VIDIOC_S_INPUT: - case VIDIOC_G_TUNER: - case VIDIOC_S_TUNER: - case VIDIOC_G_FREQ: - case VIDIOC_S_FREQ: - return bttv_common_ioctls(btv,cmd,arg); -#endif /* HAVE_V4L2 */ - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static int vbi_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(inode, file, cmd, arg, vbi_do_ioctl); -} - -static ssize_t vbi_read(struct file *file, char *data, - size_t count, loff_t *ppos) -{ - struct bttv *btv = file->private_data; - - if (btv->errors) - bttv_reinit_bt848(btv); - dprintk("read %d\n",count); - return videobuf_read_stream(file, &btv->vbi.q, data, count, ppos, 1); -} - -static unsigned int vbi_poll(struct file *file, poll_table *wait) -{ - struct bttv *btv = file->private_data; - - dprintk("poll%s\n",""); - return videobuf_poll_stream(file, &btv->vbi.q, wait); -} - -static int -vbi_mmap(struct file *file, struct vm_area_struct * vma) -{ - struct bttv *btv = file->private_data; - - dprintk("mmap 0x%lx+%ld\n",vma->vm_start, - vma->vm_end - vma->vm_start); - return videobuf_mmap_mapper(vma, &btv->vbi.q); -} - -static struct file_operations vbi_fops = -{ - owner: THIS_MODULE, - open: vbi_open, - release: vbi_release, - ioctl: vbi_ioctl, - llseek: no_llseek, - read: vbi_read, - poll: vbi_poll, - mmap: vbi_mmap, -}; - -struct video_device bttv_vbi_template = -{ - name: "bt848/878 vbi", - type: VID_TYPE_TUNER|VID_TYPE_TELETEXT, - hardware: VID_HARDWARE_BT848, - fops: &vbi_fops, - minor: -1, -}; - /* * Local variables: * c-basic-offset: 8 diff -Nru a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h --- a/drivers/media/video/bttv.h Mon Nov 4 14:31:00 2002 +++ b/drivers/media/video/bttv.h Mon Nov 4 14:31:00 2002 @@ -90,10 +90,26 @@ #define BTTV_SENSORAY311 0x49 #define BTTV_RV605 0x4a #define BTTV_WINDVR 0x4c +#define BTTV_HAUPPAUGEPVR 0x50 +#define BTTV_GVBCTV5PCI 0x51 +#define BTTV_OSPREY1x0 0x52 +#define BTTV_OSPREY1x0_848 0x53 +#define BTTV_OSPREY101_848 0x54 +#define BTTV_OSPREY1x1 0x55 +#define BTTV_OSPREY1x1_SVID 0x56 +#define BTTV_OSPREY2xx 0x57 +#define BTTV_OSPREY2x0_SVID 0x58 +#define BTTV_OSPREY2x0 0x59 +#define BTTV_OSPREY500 0x5a +#define BTTV_OSPREY540 0x5b +#define BTTV_OSPREY2000 0x5c +#define BTTV_IDS_EAGLE 0x5d /* i2c address list */ #define I2C_TSA5522 0xc2 #define I2C_TDA7432 0x8a +#define I2C_BT832_ALT1 0x88 +#define I2C_BT832_ALT2 0x8a // alternate setting #define I2C_TDA8425 0x82 #define I2C_TDA9840 0x84 #define I2C_TDA9850 0xb6 /* also used by 9855,9873 */ @@ -105,6 +121,7 @@ #define I2C_MSP3400 0x80 #define I2C_TEA6300 0x80 #define I2C_DPL3518 0x84 +#define I2C_TDA9887 0x86 /* more card-specific defines */ #define PT2254_L_CHANNEL 0x10 @@ -132,6 +149,7 @@ /* i2c audio flags */ int no_msp34xx:1; int no_tda9875:1; + int no_tda7432:1; int needs_tvaudio:1; /* other settings */ @@ -174,6 +192,7 @@ returns negative value if error occurred */ extern int bttv_get_cardinfo(unsigned int card, int *type, int *cardid); +extern struct pci_dev* bttv_get_pcidev(unsigned int card); /* obsolete, use bttv_get_cardinfo instead */ extern int bttv_get_id(unsigned int card); @@ -207,6 +226,11 @@ process data ASAP */ extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card); + +/* call i2c clients +*/ +extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg); + /* i2c */ #define I2C_CLIENTS_MAX 16 diff -Nru a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h --- a/drivers/media/video/bttvp.h Mon Nov 4 14:31:01 2002 +++ b/drivers/media/video/bttvp.h Mon Nov 4 14:31:01 2002 @@ -24,7 +24,7 @@ #ifndef _BTTVP_H_ #define _BTTVP_H_ -#define BTTV_VERSION_CODE KERNEL_VERSION(0,8,42) +#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,1) #include #include @@ -54,7 +54,8 @@ #define RISC_SLOT_LOOP 14 #define RESOURCE_OVERLAY 1 -#define RESOURCE_STREAMING 2 +#define RESOURCE_VIDEO 2 +#define RESOURCE_VBI 3 #define RAW_LINES 640 #define RAW_BPL 1024 @@ -63,15 +64,17 @@ struct bttv_tvnorm { - int v4l2_id; - u32 Fsc; - u16 swidth, sheight; /* scaled standard width, height */ - u16 totalwidth; - u8 adelay, bdelay, iform; - u32 scaledtwidth; - u16 hdelayx1, hactivex1; - u16 vdelay; - u8 vbipack; + int v4l2_id; + char *name; + u32 Fsc; + u16 swidth, sheight; /* scaled standard width, height */ + u16 totalwidth; + u8 adelay, bdelay, iform; + u32 scaledtwidth; + u16 hdelayx1, hactivex1; + u16 vdelay; + u8 vbipack; + int sram; }; extern const struct bttv_tvnorm bttv_tvnorms[]; extern const int BTTV_TVNORMS; @@ -99,8 +102,8 @@ struct bttv_riscmem { unsigned int size; - unsigned long *cpu; - unsigned long *jmp; + u32 *cpu; + u32 *jmp; dma_addr_t dma; }; @@ -114,32 +117,34 @@ int btformat; int btswap; struct bttv_geometry geo; - struct bttv_riscmem even; - struct bttv_riscmem odd; + struct bttv_riscmem top; + struct bttv_riscmem bottom; }; struct bttv_overlay { int tvnorm; - int x,y,width,height; - struct video_clip *clips; + struct v4l2_rect w; + enum v4l2_field field; + struct v4l2_clip *clips; int nclips; }; -struct bttv_vbi { - int users; - int lines; - struct videobuf_queue q; -}; - struct bttv_fh { struct bttv *btv; - struct videobuf_queue q; int resources; - + enum v4l2_buf_type type; + + /* video capture */ + struct videobuf_queue cap; + struct bttv_buffer buf; + /* current settings */ const struct bttv_format *ovfmt; struct bttv_overlay ov; - struct bttv_buffer buf; + + /* video overlay */ + struct videobuf_queue vbi; + int lines; }; /* ---------------------------------------------------------- */ @@ -163,18 +168,18 @@ int cpadding); /* risc code generator + helpers - screen overlay */ -int bttv_screen_clips(struct video_buffer *fbuf, - int x, int y, int width, int height, - struct video_clip *clips, int n); -void bttv_sort_clips(struct video_clip *clips, int nclips); +int bttv_screen_clips(int swidth, int sheight, struct v4l2_rect *win, + struct v4l2_clip *clips, int n); +void bttv_sort_clips(struct v4l2_clip *clips, int nclips); int bttv_risc_overlay(struct bttv *btv, struct bttv_riscmem *risc, const struct bttv_format *fmt, - struct bttv_overlay *ov, int flags); + struct bttv_overlay *ov, + int skip_top, int skip_bottom); /* calculate / apply geometry settings */ void bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo, int width, int height, int interleaved, int norm); -void bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd); +void bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int top); /* control dma register + risc main loop */ void bttv_set_dma(struct bttv *btv, int override, int irqflags); @@ -183,11 +188,9 @@ int irqflags); /* capture buffer handling */ -int bttv_buffer_field(struct bttv *btv, int field, int def_field, - int tvnorm, int height); int bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf); -int bttv_buffer_activate(struct bttv *btv, struct bttv_buffer *odd, - struct bttv_buffer *even); +int bttv_buffer_activate(struct bttv *btv, struct bttv_buffer *top, + struct bttv_buffer *bottom); void bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf); /* overlay handling */ @@ -199,8 +202,10 @@ /* ---------------------------------------------------------- */ /* bttv-vbi.c */ -extern struct video_device bttv_vbi_template; -extern struct videobuf_queue_ops vbi_qops; +void bttv_vbi_fmt(struct bttv_fh *fh, struct v4l2_format *f); +void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines); + +extern struct videobuf_queue_ops bttv_vbi_qops; /* ---------------------------------------------------------- */ @@ -212,6 +217,7 @@ extern unsigned int bttv_gpio; extern void bttv_gpio_tracking(struct bttv *btv, char *comment); extern int init_bttv_i2c(struct bttv *btv); +extern int pvr_boot(struct bttv *btv); extern int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg); extern void bttv_reinit_bt848(struct bttv *btv); @@ -285,6 +291,7 @@ int tvnorm,hue,contrast,bright,saturation; struct video_buffer fbuf; int field_count; + int digital_video; /* various options */ int opt_combfilter; @@ -293,27 +300,32 @@ int opt_chroma_agc; int opt_adc_crush; - /* vbi data/state */ - struct bttv_vbi vbi; - /* radio data/state */ int has_radio; + int radio_user; + + /* miro/pinnacle + Aimslab VHX + philips matchbox (tea5757 radio tuner) support */ int has_matchbox; - int mbox_we; + int mbox_we; int mbox_data; int mbox_clk; int mbox_most; int mbox_mask; - int radio_user; - + + /* ISA stuff (Terratec Active Radio Upgrade) */ + int mbox_ior; + int mbox_iow; + int mbox_csel; + /* risc memory management data - must aquire s_lock before changing these - only the irq handler is supported to touch odd + even */ struct bttv_riscmem main; - struct bttv_buffer *odd; /* current active odd field */ - struct bttv_buffer *even; /* current active even field */ - struct bttv_buffer *screen; /* overlay */ - struct list_head capture; /* capture buffer queue */ + struct bttv_buffer *top; /* current active top field */ + struct bttv_buffer *bottom; /* current active bottom field */ + struct bttv_buffer *screen; /* overlay */ + struct list_head capture; /* capture buffer queue */ struct bttv_buffer *vcurr; struct list_head vcapture; diff -Nru a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/saa7134/Makefile Mon Nov 4 14:31:04 2002 @@ -0,0 +1,11 @@ + +saa7134-objs := saa7134-cards.o saa7134-core.o saa7134-i2c.o \ + saa7134-oss.o saa7134-ts.o saa7134-tvaudio.o \ + saa7134-vbi.o saa7134-video.o + +obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o + +EXTRA_CFLAGS = -I$(src)/.. + +include $(TOPDIR)/Rules.make + diff -Nru a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/saa7134/saa7134-cards.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,361 @@ +/* + * device driver for philips saa7134 based TV cards + * card-specific stuff. + * + * (c) 2001,02 Gerd Knorr [SuSE Labs] + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +#include "saa7134-reg.h" +#include "saa7134.h" +#include "tuner.h" + +/* commly used strings */ +static char name_mute[] = "mute"; +static char name_radio[] = "Radio"; +static char name_tv[] = "Television"; +static char name_comp1[] = "Composite1"; +static char name_comp2[] = "Composite2"; +static char name_svideo[] = "S-Video"; + +/* ------------------------------------------------------------------ */ +/* board config info */ + +struct saa7134_board saa7134_boards[] = { + [SAA7134_BOARD_UNKNOWN] = { + name: "UNKNOWN/GENERIC", + audio_clock: 0x00187de7, + tuner_type: TUNER_ABSENT, + inputs: {{ + name: "default", + vmux: 0, + amux: LINE1, + }}, + }, + [SAA7134_BOARD_PROTEUS_PRO] = { + /* /me */ + name: "Proteus Pro [philips reference design]", + audio_clock: 0x00187de7, + tuner_type: TUNER_PHILIPS_PAL, + inputs: {{ + name: name_comp1, + vmux: 0, + amux: LINE1, + },{ + name: name_tv, + vmux: 1, + amux: TV, + tv: 1, + }}, + }, + [SAA7134_BOARD_FLYVIDEO3000] = { + /* "Marco d'Itri" */ + name: "LifeView FlyVIDEO3000", + audio_clock: 0x00200000, + tuner_type: TUNER_PHILIPS_PAL, + inputs: {{ + name: name_tv, + vmux: 1, + amux: TV, + tv: 1, + },{ + name: name_comp1, + vmux: 0, + amux: LINE1, + },{ + name: name_comp2, + vmux: 3, + amux: LINE1, + },{ + name: name_svideo, + vmux: 8, + amux: LINE1, + }}, + radio: { + name: name_radio, + amux: LINE2, + }, + }, + [SAA7134_BOARD_FLYVIDEO2000] = { + /* "TC Wan" */ + name: "LifeView FlyVIDEO2000", + audio_clock: 0x00200000, + tuner_type: TUNER_LG_PAL_NEW_TAPC, + gpiomask: 0x6000, + inputs: {{ + name: name_tv, + vmux: 1, + amux: LINE2, + gpio: 0x0000, + tv: 1, + },{ + name: name_comp1, + vmux: 0, + amux: LINE2, + gpio: 0x4000, + },{ + name: name_comp2, + vmux: 3, + amux: LINE2, + gpio: 0x4000, + },{ + name: name_svideo, + vmux: 8, + amux: LINE2, + gpio: 0x4000, + }}, + radio: { + name: name_radio, + amux: LINE2, + }, + mute: { + name: name_mute, + amux: LINE1, + }, + }, + [SAA7134_BOARD_EMPRESS] = { + /* "Gert Vervoort" */ + name: "EMPRESS", + audio_clock: 0x00187de7, + tuner_type: TUNER_PHILIPS_PAL, + inputs: {{ + name: name_comp1, + vmux: 0, + amux: LINE1, + },{ + name: name_svideo, + vmux: 8, + amux: LINE1, + },{ + name: name_tv, + vmux: 1, + amux: LINE2, + tv: 1, + }}, + radio: { + name: name_radio, + amux: LINE2, + }, + i2s_rate: 48000, + has_ts: 1, + video_out: CCIR656, + }, + [SAA7134_BOARD_MONSTERTV] = { + /* "K.Ohta" */ + name: "SKNet Monster TV", + audio_clock: 0x00187de7, + tuner_type: TUNER_PHILIPS_NTSC_M, + inputs: {{ + name: name_tv, + vmux: 1, + amux: TV, + tv: 1, + },{ + name: name_comp1, + vmux: 0, + amux: LINE1, + },{ + name: name_svideo, + vmux: 8, + amux: LINE1, + }}, + radio: { + name: name_radio, + amux: LINE2, + }, + }, + [SAA7134_BOARD_MD9717] = { + name: "Tevion MD 9717", + audio_clock: 0x00200000, + tuner_type: TUNER_PHILIPS_PAL, + inputs: {{ + name: name_tv, + vmux: 1, + amux: TV, + tv: 1, + },{ + /* workaround for problems with normal TV sound */ + name: "TV (mono only)", + vmux: 1, + amux: LINE2, + tv: 1, + },{ + name: name_comp1, + vmux: 2, + amux: LINE1, + },{ + name: name_comp2, + vmux: 3, + amux: LINE1, + },{ + name: name_svideo, + vmux: 8, + amux: LINE1, + }}, + radio: { + name: name_radio, + amux: LINE2, + }, + }, + [SAA7134_BOARD_TVSTATION_RDS] = { + name: "KNC One TV-Station RDS", + audio_clock: 0x00200000, + tuner_type: TUNER_PHILIPS_FM1216ME_MK3, + need_tda9887: 1, + inputs: {{ + name: name_tv, + vmux: 1, + amux: TV, + tv: 1, + },{ + name: name_comp1, + vmux: 2, + amux: LINE1, + },{ + name: name_comp2, + vmux: 3, + amux: LINE1, + }}, + radio: { + name: name_radio, + amux: LINE2, + }, + }, + [SAA7134_BOARD_CINERGY400] = { + name: "Terratec Cinergy 400 TV", + audio_clock: 0x00200000, + tuner_type: TUNER_PHILIPS_PAL, + inputs: {{ + name: name_tv, + vmux: 1, + amux: TV, + tv: 1, + },{ + name: name_comp1, + vmux: 4, + amux: LINE1, + },{ + name: name_svideo, + vmux: 8, + amux: LINE1, + },{ + name: name_comp2, // CVideo over SVideo Connector + vmux: 0, + amux: LINE1, + }} + }, + [SAA7134_BOARD_MD5044] = { + name: "Medion 5044", + audio_clock: 0x00200000, + tuner_type: TUNER_PHILIPS_FM1216ME_MK3, + need_tda9887: 1, + inputs: {{ + name: name_tv, + vmux: 1, + amux: TV, + tv: 1, + },{ + name: name_comp1, + vmux: 0, + amux: LINE2, + },{ + name: name_comp2, + vmux: 3, + amux: LINE2, + },{ + name: name_svideo, + vmux: 8, + amux: LINE2, + }}, + radio: { + name: name_radio, + amux: LINE2, + }, + }, +}; +const int saa7134_bcount = (sizeof(saa7134_boards)/sizeof(struct saa7134_board)); + +/* ------------------------------------------------------------------ */ +/* PCI ids + subsystem IDs */ + +struct pci_device_id __devinitdata saa7134_pci_tbl[] = { + { + vendor: PCI_VENDOR_ID_PHILIPS, + device: PCI_DEVICE_ID_PHILIPS_SAA7134, + subvendor: PCI_VENDOR_ID_PHILIPS, + subdevice: 0x2001, + driver_data: SAA7134_BOARD_PROTEUS_PRO, + },{ + vendor: PCI_VENDOR_ID_PHILIPS, + device: PCI_DEVICE_ID_PHILIPS_SAA7134, + subvendor: PCI_VENDOR_ID_PHILIPS, + subdevice: 0x6752, + driver_data: SAA7134_BOARD_EMPRESS, + },{ + vendor: PCI_VENDOR_ID_PHILIPS, + device: PCI_DEVICE_ID_PHILIPS_SAA7134, + subvendor: 0x1131, + subdevice: 0x4e85, + driver_data: SAA7134_BOARD_MONSTERTV, + },{ + vendor: PCI_VENDOR_ID_PHILIPS, + device: PCI_DEVICE_ID_PHILIPS_SAA7134, + subvendor: 0x153B, + subdevice: 0x1142, + driver_data: SAA7134_BOARD_CINERGY400, + },{ + + /* --- boards without eeprom + subsystem ID --- */ + vendor: PCI_VENDOR_ID_PHILIPS, + device: PCI_DEVICE_ID_PHILIPS_SAA7134, + subvendor: PCI_VENDOR_ID_PHILIPS, + subdevice: 0, + driver_data: SAA7134_BOARD_NOAUTO, + },{ + vendor: PCI_VENDOR_ID_PHILIPS, + device: PCI_DEVICE_ID_PHILIPS_SAA7130, + subvendor: PCI_VENDOR_ID_PHILIPS, + subdevice: 0, + driver_data: SAA7134_BOARD_NOAUTO, + },{ + + /* --- default catch --- */ + vendor: PCI_VENDOR_ID_PHILIPS, + device: PCI_DEVICE_ID_PHILIPS_SAA7130, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + driver_data: SAA7134_BOARD_UNKNOWN, + },{ + vendor: PCI_VENDOR_ID_PHILIPS, + device: PCI_DEVICE_ID_PHILIPS_SAA7134, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + driver_data: SAA7134_BOARD_UNKNOWN, + },{ + /* --- end of list --- */ + } +}; +MODULE_DEVICE_TABLE(pci, saa7134_pci_tbl); + +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/saa7134/saa7134-core.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,928 @@ +/* + * device driver for philips saa7134 based TV cards + * driver core + * + * (c) 2001,02 Gerd Knorr [SuSE Labs] + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "saa7134-reg.h" +#include "saa7134.h" +#include "tuner.h" + +MODULE_DESCRIPTION("v4l2 driver module for saa7130/34 based TV cards"); +MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); +MODULE_LICENSE("GPL"); + +#define SAA7134_MAXBOARDS 4 + +/* ------------------------------------------------------------------ */ + +static unsigned int irq_debug = 0; +MODULE_PARM(irq_debug,"i"); +MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]"); + +static unsigned int core_debug = 0; +MODULE_PARM(core_debug,"i"); +MODULE_PARM_DESC(core_debug,"enable debug messages [core]"); + +static unsigned int gpio_tracking = 0; +MODULE_PARM(gpio_tracking,"i"); +MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]"); + +static unsigned int video_nr = -1; +MODULE_PARM(video_nr,"i"); +MODULE_PARM_DESC(video_nr,"video device number"); + +static unsigned int ts_nr = -1; +MODULE_PARM(ts_nr,"i"); +MODULE_PARM_DESC(ts_nr,"ts device number"); + +static unsigned int vbi_nr = -1; +MODULE_PARM(vbi_nr,"i"); +MODULE_PARM_DESC(vbi_nr,"vbi device number"); + +static unsigned int radio_nr = -1; +MODULE_PARM(radio_nr,"i"); +MODULE_PARM_DESC(radio_nr,"radio device number"); + +static unsigned int dsp_nr = -1; +MODULE_PARM(dsp_nr,"i"); +MODULE_PARM_DESC(dsp_nr,"oss dsp device number"); + +static unsigned int mixer_nr = -1; +MODULE_PARM(mixer_nr,"i"); +MODULE_PARM_DESC(mixer_nr,"oss mixer device number"); + +static int tuner[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = -1}; +MODULE_PARM(tuner,"1-" __stringify(SAA7134_MAXBOARDS) "i"); +MODULE_PARM_DESC(tuner,"tuner type"); + +static int card[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = -1}; +MODULE_PARM(card,"1-" __stringify(SAA7134_MAXBOARDS) "i"); +MODULE_PARM_DESC(card,"card type"); + +static int latency = -1; +MODULE_PARM(latency,"i"); +MODULE_PARM_DESC(latency,"pci latency timer"); + +struct list_head saa7134_devlist; +int saa7134_devcount; + +#define dprintk(fmt, arg...) if (core_debug) \ + printk(KERN_DEBUG "%s/core: " fmt, dev->name, ## arg) + +/* ------------------------------------------------------------------ */ +/* debug help functions */ + +static const char *v4l1_ioctls[] = { + "0", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT", + "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ", + "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT", + "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", + "SMICROCODE", "GVBIFMT", "SVBIFMT" }; +#define V4L1_IOCTLS (sizeof(v4l1_ioctls)/sizeof(char*)) + +static const char *v4l2_ioctls[] = { + "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT", + "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF", + "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON", + "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD", + "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER", + "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL", + "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43", + "44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT", + "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR", + "S_MODULATOR" +}; +#define V4L2_IOCTLS (sizeof(v4l2_ioctls)/sizeof(char*)) + +static const char *osspcm_ioctls[] = { + "RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT", + "CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS", + "GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER", + "GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO", + "SETDUPLEX", "GETODELAY" +}; +#define OSSPCM_IOCTLS (sizeof(v4l2_ioctls)/sizeof(char*)) + +void saa7134_print_ioctl(char *name, unsigned int cmd) +{ + char *dir; + + switch (_IOC_DIR(cmd)) { + case _IOC_NONE: dir = "--"; break; + case _IOC_READ: dir = "r-"; break; + case _IOC_WRITE: dir = "-w"; break; + case _IOC_READ | _IOC_WRITE: dir = "rw"; break; + default: dir = "??"; break; + } + switch (_IOC_TYPE(cmd)) { + case 'v': + printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n", + name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ? + v4l1_ioctls[_IOC_NR(cmd)] : "???"); + break; + case 'V': + printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n", + name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ? + v4l2_ioctls[_IOC_NR(cmd)] : "???"); + break; + case 'P': + printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n", + name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ? + osspcm_ioctls[_IOC_NR(cmd)] : "???"); + break; + case 'M': + printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n", + name, cmd, dir, _IOC_NR(cmd)); + break; + default: + printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n", + name, cmd, dir, _IOC_NR(cmd)); + } +} + +void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) +{ + unsigned long mode,status; + + if (!gpio_tracking) + return; + /* rising SAA7134_GPIO_GPRESCAN reads the status */ + saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,0); + saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,SAA7134_GPIO_GPRESCAN); + mode = saa_readl(SAA7134_GPIO_GPMODE0 >> 2) & 0xfffffff; + status = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & 0xfffffff; + printk(KERN_DEBUG + "%s: gpio: mode=0x%07lx in=0x%07lx out=0x%07lx [%s]\n", + dev->name, mode, (~mode) & status, mode & status, msg); +} + +/* ------------------------------------------------------------------ */ + +#if 0 +static char *dec1_bits[8] = { + "DCSTD0", "DCSCT1", "WIPA", "GLIMB", + "GLIMT", "SLTCA", "HLCK" +}; +static char *dec2_bits[8] = { + "RDCAP", "COPRO", "COLSTR", "TYPE3", + NULL, "FIDT", "HLVLN", "INTL" +}; +static char *scale1_bits[8] = { + "VID_A", "VBI_A", NULL, NULL, "VID_B", "VBI_B" +}; +static char *scale2_bits[8] = { + "TRERR", "CFERR", "LDERR", "WASRST", + "FIDSCI", "FIDSCO", "D6^D5", "TASK" +}; + +static void dump_statusreg(struct saa7134_dev *dev, int reg, + char *regname, char **bits) +{ + int value,i; + + value = saa_readb(reg); + printk(KERN_DEBUG "%s: %s:", dev->name, regname); + for (i = 7; i >= 0; i--) { + if (NULL == bits[i]) + continue; + printk(" %s=%d", bits[i], (value & (1 << i)) ? 1 : 0); + } + printk("\n"); +} + +static void dump_statusregs(struct saa7134_dev *dev) +{ + dump_statusreg(dev,SAA7134_STATUS_VIDEO1,"dec1",dec1_bits); + dump_statusreg(dev,SAA7134_STATUS_VIDEO2,"dec2",dec2_bits); + dump_statusreg(dev,SAA7134_SCALER_STATUS0,"scale0",scale1_bits); + dump_statusreg(dev,SAA7134_SCALER_STATUS1,"scale1",scale2_bits); +} +#endif + +/* ------------------------------------------------------------------ */ + +/* nr of (saa7134-)pages for the given buffer size */ +int saa7134_buffer_pages(int size) +{ + size = PAGE_ALIGN(size); + size += PAGE_SIZE; /* for non-page-aligned buffers */ + size /= 4096; + return size; +} + +/* calc max # of buffers from size (must not exceed the 4MB virtual + * address space per DMA channel) */ +int saa7134_buffer_count(int size, int count) +{ + int maxcount; + + maxcount = 1024 / saa7134_buffer_pages(size); + if (count > maxcount) + count = maxcount; + return count; +} + +int saa7134_buffer_startpage(struct saa7134_buf *buf) +{ + return saa7134_buffer_pages(buf->vb.bsize) * buf->vb.i; +} + +unsigned long saa7134_buffer_base(struct saa7134_buf *buf) +{ + unsigned long base; + + base = saa7134_buffer_startpage(buf) * 4096; + base += buf->vb.dma.sglist[0].offset; + return base; +} + +/* ------------------------------------------------------------------ */ + +int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt) +{ + u32 *cpu; + dma_addr_t dma_addr; + + cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr); + if (NULL == cpu) + return -ENOMEM; + pt->size = SAA7134_PGTABLE_SIZE; + pt->cpu = cpu; + pt->dma = dma_addr; + return 0; +} + +int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt, + struct scatterlist *list, int length, + int startpage) +{ + u32 *ptr; + int i,p; + + BUG_ON(NULL == pt || NULL == pt->cpu); + + ptr = pt->cpu + startpage; + for (i = 0; i < length; i++, list++) + for (p = 0; p * 4096 < list->length; p++, ptr++) + *ptr = sg_dma_address(list) - list->offset; + return 0; +} + +void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt) +{ + if (NULL == pt->cpu) + return; + pci_free_consistent(pci, pt->size, pt->cpu, pt->dma); + pt->cpu = NULL; +} + +/* ------------------------------------------------------------------ */ + +void saa7134_dma_free(struct saa7134_dev *dev,struct saa7134_buf *buf) +{ + if (in_interrupt()) + BUG(); + + videobuf_waiton(&buf->vb,0,0); + videobuf_dma_pci_unmap(dev->pci, &buf->vb.dma); + videobuf_dma_free(&buf->vb.dma); + buf->vb.state = STATE_NEEDS_INIT; +} + +/* ------------------------------------------------------------------ */ + +int saa7134_buffer_queue(struct saa7134_dev *dev, + struct saa7134_dmaqueue *q, + struct saa7134_buf *buf) +{ +#if DEBUG_SPINLOCKS + BUG_ON(!spin_is_locked(&dev->slock)); +#endif + + dprintk("buffer_queue %p\n",buf); + if (NULL == q->curr) { + q->curr = buf; + buf->activate(dev,buf,NULL); + } else { + list_add_tail(&buf->vb.queue,&q->queue); + buf->vb.state = STATE_QUEUED; + } + return 0; +} + +void saa7134_buffer_finish(struct saa7134_dev *dev, + struct saa7134_dmaqueue *q, + int state) +{ +#if DEBUG_SPINLOCKS + BUG_ON(!spin_is_locked(&dev->slock)); +#endif + dprintk("buffer_finish %p\n",q->curr); + + /* finish current buffer */ + q->curr->vb.state = state; + do_gettimeofday(&q->curr->vb.ts); + wake_up(&q->curr->vb.done); + q->curr = NULL; +} + +void saa7134_buffer_next(struct saa7134_dev *dev, + struct saa7134_dmaqueue *q) +{ + struct saa7134_buf *buf,*next = NULL; + +#if DEBUG_SPINLOCKS + BUG_ON(!spin_is_locked(&dev->slock)); +#endif + BUG_ON(NULL != q->curr); + + if (!list_empty(&q->queue)) { + /* activate next one from queue */ + buf = list_entry(q->queue.next,struct saa7134_buf,vb.queue); + dprintk("buffer_next %p [prev=%p/next=%p]\n", + buf,q->queue.prev,q->queue.next); + list_del(&buf->vb.queue); + if (!list_empty(&q->queue)) + next = list_entry(q->queue.next,struct saa7134_buf, + vb.queue); + q->curr = buf; + buf->activate(dev,buf,next); + dprintk("buffer_next #2 prev=%p/next=%p\n", + q->queue.prev,q->queue.next); + } else { + /* nothing to do -- just stop DMA */ + dprintk("buffer_next %p\n",NULL); + saa7134_set_dmabits(dev); + del_timer(&q->timeout); + } +} + +void saa7134_buffer_timeout(unsigned long data) +{ + struct saa7134_dmaqueue *q = (struct saa7134_dmaqueue*)data; + struct saa7134_dev *dev = q->dev; + unsigned long flags; + + spin_lock_irqsave(&dev->slock,flags); + if (q->curr) { + dprintk("timeout on %p\n",q->curr); + saa7134_buffer_finish(dev,q,STATE_ERROR); + } + saa7134_buffer_next(dev,q); + spin_unlock_irqrestore(&dev->slock,flags); +} + +/* ------------------------------------------------------------------ */ + +int saa7134_set_dmabits(struct saa7134_dev *dev) +{ + unsigned long task=0, ctrl=0, irq=0, split = 0; + enum v4l2_field cap = V4L2_FIELD_ANY; + enum v4l2_field ov = V4L2_FIELD_ANY; + +#if DEBUG_SPINLOCKS + BUG_ON(!spin_is_locked(&dev->slock)); +#endif + + /* video capture -- dma 0 + video task A */ + if (dev->video_q.curr) { + task |= 0x01; + ctrl |= SAA7134_MAIN_CTRL_TE0; + irq |= SAA7134_IRQ1_INTE_RA0_1 | + SAA7134_IRQ1_INTE_RA0_0; + cap = dev->video_q.curr->vb.field; + } + + /* video capture -- dma 1+2 (planar modes) */ + if (dev->video_q.curr && + dev->video_q.curr->fmt->planar) { + ctrl |= SAA7134_MAIN_CTRL_TE4 | + SAA7134_MAIN_CTRL_TE5; + } + + /* screen overlay -- dma 0 + video task B */ + if (dev->ovenable) { + task |= 0x10; + ctrl |= SAA7134_MAIN_CTRL_TE1; + ov = dev->ovfield; + } + + /* vbi capture -- dma 0 + vbi task A+B */ + if (dev->vbi_q.curr) { + task |= 0x22; + ctrl |= SAA7134_MAIN_CTRL_TE2 | + SAA7134_MAIN_CTRL_TE3; + irq |= SAA7134_IRQ1_INTE_RA0_7 | + SAA7134_IRQ1_INTE_RA0_6 | + SAA7134_IRQ1_INTE_RA0_5 | + SAA7134_IRQ1_INTE_RA0_4; + } + + /* audio capture -- dma 3 */ + if (dev->oss.recording) { + ctrl |= SAA7134_MAIN_CTRL_TE6; + irq |= SAA7134_IRQ1_INTE_RA3_1 | + SAA7134_IRQ1_INTE_RA3_0; + } + + /* TS capture -- dma 5 */ + if (dev->ts_q.curr) { + ctrl |= SAA7134_MAIN_CTRL_TE5; + irq |= SAA7134_IRQ1_INTE_RA2_3 | + SAA7134_IRQ1_INTE_RA2_2 | + SAA7134_IRQ1_INTE_RA2_1 | + SAA7134_IRQ1_INTE_RA2_0; + } + + /* set task conditions + field handling */ + if (V4L2_FIELD_HAS_BOTH(cap) || V4L2_FIELD_HAS_BOTH(ov) || cap == ov) { + /* default config -- use full frames: + odd A, even A, odd B, even B, repeat */ + saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0d); + saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0d); + saa_writeb(SAA7134_FIELD_HANDLING(TASK_A), 0x02); + saa_writeb(SAA7134_FIELD_HANDLING(TASK_B), 0x02); + } else { + /* split fields between tasks */ + if (V4L2_FIELD_TOP == cap) { + /* odd A, even B, repeat */ + saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0d); + saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0e); + } else { + /* odd B, even A, repeat */ + saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0e); + saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0d); + } + saa_writeb(SAA7134_FIELD_HANDLING(TASK_A), 0x01); + saa_writeb(SAA7134_FIELD_HANDLING(TASK_B), 0x01); + split = 1; + } + + /* irqs */ + saa_writeb(SAA7134_REGION_ENABLE, task); + saa_writel(SAA7134_IRQ1, irq); + saa_andorl(SAA7134_MAIN_CTRL, + SAA7134_MAIN_CTRL_TE0 | + SAA7134_MAIN_CTRL_TE1 | + SAA7134_MAIN_CTRL_TE2 | + SAA7134_MAIN_CTRL_TE3 | + SAA7134_MAIN_CTRL_TE4 | + SAA7134_MAIN_CTRL_TE5 | + SAA7134_MAIN_CTRL_TE6, + ctrl); + dprintk("dmabits: task=0x%02lx ctrl=0x%02lx irq=0x%lx split=%s\n", + task, ctrl, irq, split ? "no" : "yes"); + + return 0; +} + +/* ------------------------------------------------------------------ */ +/* IRQ handler + helpers */ + +static char *irqbits[] = { + "DONE_RA0", "DONE_RA1", "DONE_RA2", "DONE_RA3", + "AR", "PE", "PWR_ON", "RDCAP", "INTL", "FIDT", "MMC", + "TRIG_ERR", "CONF_ERR", "LOAD_ERR" +}; +#define IRQBITS (sizeof(irqbits)/sizeof(char*)) + +static void print_irqstatus(struct saa7134_dev *dev, int loop, + unsigned long report, unsigned long status) +{ + int i; + + printk(KERN_DEBUG "%s/irq[%d,%ld]: r=0x%lx s=0x%02lx", + dev->name,loop,jiffies,report,status); + for (i = 0; i < IRQBITS; i++) { + if (!(report & (1 << i))) + continue; + printk(" %s",irqbits[i]); + } + if (report & SAA7134_IRQ_REPORT_DONE_RA0) { + printk(" | RA0=%s,%s,%s,%ld", + (status & 0x40) ? "vbi" : "video", + (status & 0x20) ? "b" : "a", + (status & 0x10) ? "odd" : "even", + (status & 0x0f)); + } + printk("\n"); +} + +static void saa7134_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct saa7134_dev *dev = (struct saa7134_dev*) dev_id; + unsigned long report,status; + int loop; + + for (loop = 0; loop < 10; loop++) { + report = saa_readl(SAA7134_IRQ_REPORT); + status = saa_readl(SAA7134_IRQ_STATUS); + saa_writel(SAA7134_IRQ_REPORT,report); + if (0 == report) { + if (irq_debug > 1) + printk(KERN_DEBUG "%s/irq: no (more) work\n", + dev->name); + return; + } + if (irq_debug) + print_irqstatus(dev,loop,report,status); + +#if 0 + if (report & SAA7134_IRQ_REPORT_CONF_ERR) + dump_statusregs(dev); +#endif + + if (report & SAA7134_IRQ_REPORT_INTL) + saa7134_irq_video_intl(dev); + + if ((report & SAA7134_IRQ_REPORT_DONE_RA0) && + (status & 0x60) == 0) + saa7134_irq_video_done(dev,status); + + if ((report & SAA7134_IRQ_REPORT_DONE_RA0) && + (status & 0x40) == 0x40) + saa7134_irq_vbi_done(dev,status); + + if ((report & SAA7134_IRQ_REPORT_DONE_RA2) && + card_has_ts(dev)) + saa7134_irq_ts_done(dev,status); + + if ((report & SAA7134_IRQ_REPORT_DONE_RA3)) + saa7134_irq_oss_done(dev,status); + + }; + if (10 == loop) { + print_irqstatus(dev,loop,report,status); + printk(KERN_WARNING "%s/irq: looping -- clearing enable bits\n",dev->name); + /* disable all irqs */ + saa_writel(SAA7134_IRQ1,0); + saa_writel(SAA7134_IRQ2,0); + } +} + +/* ------------------------------------------------------------------ */ + +static int saa7134_hwinit(struct saa7134_dev *dev) +{ + init_MUTEX(&dev->lock); + dev->slock = SPIN_LOCK_UNLOCKED; + + saa7134_track_gpio(dev,"pre-init"); + saa7134_tvaudio_init(dev); + saa7134_video_init(dev); + saa7134_vbi_init(dev); + if (card_has_ts(dev)) + saa7134_ts_init(dev); + if (card_has_audio(dev)) + saa7134_oss_init(dev); + + /* RAM FIFO config */ + saa_writel(SAA7134_FIFO_SIZE, 0x08070503); + saa_writel(SAA7134_THRESHOULD,0x02020202); + + /* enable audio + video processing */ + saa_writel(SAA7134_MAIN_CTRL, + SAA7134_MAIN_CTRL_VPLLE | + SAA7134_MAIN_CTRL_APLLE | + SAA7134_MAIN_CTRL_EXOSC | + SAA7134_MAIN_CTRL_EVFE1 | + SAA7134_MAIN_CTRL_EVFE2 | + SAA7134_MAIN_CTRL_ESFE | + SAA7134_MAIN_CTRL_EBADC | + SAA7134_MAIN_CTRL_EBDAC); + + /* IRQ's */ + saa_writel(SAA7134_IRQ1, 0); + saa_writel(SAA7134_IRQ2, + SAA7134_IRQ2_INTE_SC2 | + SAA7134_IRQ2_INTE_SC1 | + SAA7134_IRQ2_INTE_SC0 | + /* SAA7134_IRQ2_INTE_DEC5 | FIXME: TRIG_ERR ??? */ + SAA7134_IRQ2_INTE_DEC3 | + SAA7134_IRQ2_INTE_DEC2 | + /* SAA7134_IRQ2_INTE_DEC1 | */ + SAA7134_IRQ2_INTE_DEC0 | + SAA7134_IRQ2_INTE_PE | + SAA7134_IRQ2_INTE_AR); + + /* enable peripheral devices */ + saa_writeb(SAA7134_SPECIAL_MODE, 0x01); + + return 0; +} + +static void __devinit must_configure_manually(void) +{ + int i,p; + + printk(KERN_WARNING + "saa7134: \n" + "saa7134: Congratulations! Your TV card vendor saved a few\n" + "saa7134: cents for a eeprom, thus your pci board has no\n" + "saa7134: subsystem ID and I can't identify it automatically\n" + "saa7134: \n" + "saa7134: I feel better now. Ok, here are the good news:\n" + "saa7134: You can use the card= insmod option to specify\n" + "saa7134: which board do you have. The list:\n"); + for (i = 0; i < saa7134_bcount; i++) { + printk(KERN_WARNING "saa7134: card=%d -> %-40.40s", + i,saa7134_boards[i].name); + for (p = 0; saa7134_pci_tbl[p].driver_data; p++) { + if (saa7134_pci_tbl[p].driver_data != i) + continue; + printk(" %04x:%04x", + saa7134_pci_tbl[p].subvendor, + saa7134_pci_tbl[p].subdevice); + } + printk("\n"); + } +} + +static int __devinit saa7134_initdev(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + struct saa7134_dev *dev; + int err; + + dev = kmalloc(sizeof(*dev),GFP_KERNEL); + if (NULL == dev) + return -ENOMEM; + memset(dev,0,sizeof(*dev)); + + /* pci stuff */ + dev->pci = pci_dev; + if (pci_enable_device(pci_dev)) { + err = -EIO; + goto fail1; + } + sprintf(dev->name,"saa%x[%d]",pci_dev->device,saa7134_devcount); + if (-1 != latency) { + printk(KERN_INFO "%s: setting pci latency timer to %d\n", + dev->name,latency); + pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency); + } + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); + pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); + printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, " + "latency: %d, mmio: 0x%lx\n", dev->name, + pci_dev->slot_name, dev->pci_rev, pci_dev->irq, + dev->pci_lat,pci_resource_start(pci_dev,0)); + pci_set_master(pci_dev); + if (!pci_dma_supported(pci_dev,0xffffffff)) { + printk("%s: Oops: no 32bit PCI DMA ???\n",dev->name); + err = -EIO; + goto fail1; + } + + /* board config */ + dev->board = pci_id->driver_data; + if (card[saa7134_devcount] >= 0 && + card[saa7134_devcount] < saa7134_bcount) + dev->board = card[saa7134_devcount]; + if (SAA7134_BOARD_NOAUTO == dev->board) { + must_configure_manually(); + dev->board = SAA7134_BOARD_UNKNOWN; + } + dev->tuner_type = saa7134_boards[dev->board].tuner_type; + if (-1 != tuner[saa7134_devcount]) + dev->tuner_type = tuner[saa7134_devcount]; + printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + dev->name,pci_dev->subsystem_vendor, + pci_dev->subsystem_device,saa7134_boards[dev->board].name, + dev->board, card[saa7134_devcount] == dev->board ? + "insmod option" : "autodetected"); + + /* get mmio */ + if (!request_mem_region(pci_resource_start(pci_dev,0), + pci_resource_len(pci_dev,0), + dev->name)) { + err = -EBUSY; + printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n", + dev->name,pci_resource_start(pci_dev,0)); + goto fail1; + } + dev->lmmio = ioremap(pci_resource_start(pci_dev,0), 0x1000); + dev->bmmio = (__u8*)dev->lmmio; + + /* get irq */ + err = request_irq(pci_dev->irq, saa7134_irq, + SA_SHIRQ | SA_INTERRUPT, dev->name, dev); + if (err < 0) { + printk(KERN_ERR "%s: can't get IRQ %d\n", + dev->name,pci_dev->irq); + goto fail2; + } + + /* initialize hardware */ + saa7134_hwinit(dev); + + /* register i2c bus + load i2c helpers */ + saa7134_i2c_register(dev); + if (TUNER_ABSENT != card(dev).tuner_type) + request_module("tuner"); + if (saa7134_boards[dev->board].need_tda9887) + request_module("tda9887"); + + /* register v4l devices */ + dev->video_dev = saa7134_video_template; + dev->video_dev.priv = dev; + err = video_register_device(&dev->video_dev,VFL_TYPE_GRABBER,video_nr); + if (err < 0) { + printk(KERN_INFO "%s: can't register video device\n", + dev->name); + goto fail3; + } + printk(KERN_INFO "%s: registered device video%d [v4l2]\n", + dev->name,dev->video_dev.minor & 0x1f); + + dev->ts_dev = saa7134_ts_template; + dev->ts_dev.priv = dev; + if (card_has_ts(dev)) { + err = video_register_device(&dev->ts_dev,VFL_TYPE_GRABBER,ts_nr); + if (err < 0) { + printk(KERN_INFO "%s: can't register video device\n", + dev->name); + goto fail4; + } + printk(KERN_INFO "%s: registered device video%d [ts]\n", + dev->name,dev->ts_dev.minor & 0x1f); + } + + dev->vbi_dev = saa7134_vbi_template; + dev->vbi_dev.priv = dev; + err = video_register_device(&dev->vbi_dev,VFL_TYPE_VBI,vbi_nr); + if (err < 0) + goto fail5; + printk(KERN_INFO "%s: registered device vbi%d\n", + dev->name,dev->vbi_dev.minor & 0x1f); + + dev->radio_dev = saa7134_radio_template; + dev->radio_dev.priv = dev; + if (card_has_radio(dev)) { + err = video_register_device(&dev->radio_dev,VFL_TYPE_RADIO,radio_nr); + if (err < 0) + goto fail6; + printk(KERN_INFO "%s: registered device radio%d\n", + dev->name,dev->radio_dev.minor & 0x1f); + } + + /* register oss devices */ + if (card_has_audio(dev)) { + dev->oss.minor_dsp = register_sound_dsp(&saa7134_dsp_fops,dsp_nr); + if (dev->oss.minor_dsp < 0) + goto fail7; + printk(KERN_INFO "%s: registered device dsp%d\n", + dev->name,dev->oss.minor_dsp >> 4); + + dev->oss.minor_mixer = + register_sound_mixer(&saa7134_mixer_fops,mixer_nr); + if (dev->oss.minor_mixer < 0) + goto fail8; + printk(KERN_INFO "%s: registered device mixer%d\n", + dev->name,dev->oss.minor_mixer >> 4); + } + + /* everything worked */ + list_add_tail(&dev->devlist,&saa7134_devlist); + pci_set_drvdata(pci_dev,dev); + saa7134_devcount++; + return 0; + + fail8: + if (card_has_audio(dev)) + unregister_sound_dsp(dev->oss.minor_dsp); + fail7: + if (card_has_radio(dev)) + video_unregister_device(&dev->radio_dev); + fail6: + video_unregister_device(&dev->vbi_dev); + fail5: + if (card_has_ts(dev)) + video_unregister_device(&dev->ts_dev); + fail4: + video_unregister_device(&dev->video_dev); + fail3: + if (card_has_audio(dev)) + saa7134_oss_fini(dev); + if (card_has_ts(dev)) + saa7134_ts_fini(dev); + saa7134_vbi_fini(dev); + saa7134_video_fini(dev); + saa7134_tvaudio_fini(dev); + saa7134_i2c_unregister(dev); + free_irq(pci_dev->irq, dev); + fail2: + release_mem_region(pci_resource_start(pci_dev,0), + pci_resource_len(pci_dev,0)); + fail1: + kfree(dev); + return err; +} + +static void __devexit saa7134_finidev(struct pci_dev *pci_dev) +{ + struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + + /* disable peripheral devices */ + saa_writeb(SAA7134_SPECIAL_MODE,0); + + /* shutdown hardware */ + saa_writel(SAA7134_IRQ1,0); + saa_writel(SAA7134_IRQ2,0); + saa_writel(SAA7134_MAIN_CTRL,0); + + /* shutdown subsystems */ + if (card_has_audio(dev)) + saa7134_oss_fini(dev); + if (card_has_ts(dev)) + saa7134_ts_fini(dev); + saa7134_vbi_fini(dev); + saa7134_video_fini(dev); + saa7134_tvaudio_fini(dev); + saa7134_i2c_unregister(dev); + + /* release ressources */ + free_irq(pci_dev->irq, dev); + release_mem_region(pci_resource_start(pci_dev,0), + pci_resource_len(pci_dev,0)); + + /* unregister */ + saa7134_i2c_unregister(dev); + if (card_has_audio(dev)) { + unregister_sound_mixer(dev->oss.minor_mixer); + unregister_sound_dsp(dev->oss.minor_dsp); + } + if (card_has_radio(dev)) + video_unregister_device(&dev->radio_dev); + video_unregister_device(&dev->vbi_dev); + if (card_has_ts(dev)) + video_unregister_device(&dev->ts_dev); + video_unregister_device(&dev->video_dev); + pci_set_drvdata(pci_dev, NULL); +#if 0 + /* causes some trouble when reinserting the driver ... */ + pci_disable_device(pci_dev); +#endif + + /* free memory */ + list_del(&dev->devlist); + saa7134_devcount--; + kfree(dev); +} + +static struct pci_driver saa7134_pci_driver = { + name: "saa7134", + id_table: saa7134_pci_tbl, + probe: saa7134_initdev, + remove: saa7134_finidev, +}; + +static int saa7134_init(void) +{ + INIT_LIST_HEAD(&saa7134_devlist); + printk(KERN_INFO "saa7130/34: v4l2 driver version %d.%d.%d loaded\n", + (SAA7134_VERSION_CODE >> 16) & 0xff, + (SAA7134_VERSION_CODE >> 8) & 0xff, + SAA7134_VERSION_CODE & 0xff); + return pci_module_init(&saa7134_pci_driver); +} + +static void saa7134_fini(void) +{ + pci_unregister_driver(&saa7134_pci_driver); +} + +module_init(saa7134_init); +module_exit(saa7134_fini); + +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/saa7134/saa7134-i2c.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,451 @@ +/* + * device driver for philips saa7134 based TV cards + * i2c interface support + * + * (c) 2001,02 Gerd Knorr [SuSE Labs] + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define __NO_VERSION__ 1 + +#include +#include +#include +#include +#include +#include + +#include "saa7134-reg.h" +#include "saa7134.h" +#include "tuner.h" +#include "id.h" + +/* ----------------------------------------------------------- */ + +static unsigned int i2c_debug = 0; +MODULE_PARM(i2c_debug,"i"); +MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]"); + +static unsigned int i2c_scan = 0; +MODULE_PARM(i2c_scan,"i"); +MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); + +#define d1printk if (1 == i2c_debug) printk +#define d2printk if (2 == i2c_debug) printk + +#define I2C_WAIT_DELAY 32 +#define I2C_WAIT_RETRY 16 + +/* ----------------------------------------------------------- */ + +static char *str_i2c_status[] = { + "IDLE", "DONE_STOP", "BUSY", "TO_SCL", "TO_ARB", "DONE_WRITE", + "DONE_READ", "DONE_WRITE_TO", "DONE_READ_TO", "NO_DEVICE", + "NO_ACKN", "BUS_ERR", "ARB_LOST", "SEQ_ERR", "ST_ERR", "SW_ERR" +}; + +enum i2c_status { + IDLE = 0, // no I2C command pending + DONE_STOP = 1, // I2C command done and STOP executed + BUSY = 2, // executing I2C command + TO_SCL = 3, // executing I2C command, time out on clock stretching + TO_ARB = 4, // time out on arbitration trial, still trying + DONE_WRITE = 5, // I2C command done and awaiting next write command + DONE_READ = 6, // I2C command done and awaiting next read command + DONE_WRITE_TO = 7, // see 5, and time out on status echo + DONE_READ_TO = 8, // see 6, and time out on status echo + NO_DEVICE = 9, // no acknowledge on device slave address + NO_ACKN = 10, // no acknowledge after data byte transfer + BUS_ERR = 11, // bus error + ARB_LOST = 12, // arbitration lost during transfer + SEQ_ERR = 13, // erroneous programming sequence + ST_ERR = 14, // wrong status echoing + SW_ERR = 15 // software error +}; + +static char *str_i2c_attr[] = { + "NOP", "STOP", "CONTINUE", "START" +}; + +enum i2c_attr { + NOP = 0, // no operation on I2C bus + STOP = 1, // stop condition, no associated byte transfer + CONTINUE = 2, // continue with byte transfer + START = 3 // start condition with byte transfer +}; + +static inline enum i2c_status i2c_get_status(struct saa7134_dev *dev) +{ + enum i2c_status status; + + status = saa_readb(SAA7134_I2C_ATTR_STATUS) & 0x0f; + d2printk(KERN_DEBUG "%s: i2c stat <= %s\n",dev->name, + str_i2c_status[status]); + return status; +} + +static inline void i2c_set_status(struct saa7134_dev *dev, + enum i2c_status status) +{ + d2printk(KERN_DEBUG "%s: i2c stat => %s\n",dev->name, + str_i2c_status[status]); + saa_andorb(SAA7134_I2C_ATTR_STATUS,0x0f,status); +} + +static inline void i2c_set_attr(struct saa7134_dev *dev, enum i2c_attr attr) +{ + d2printk(KERN_DEBUG "%s: i2c attr => %s\n",dev->name, + str_i2c_attr[attr]); + saa_andorb(SAA7134_I2C_ATTR_STATUS,0xc0,attr << 6); +} + +static inline int i2c_is_error(enum i2c_status status) +{ + switch (status) { + case NO_DEVICE: + case NO_ACKN: + case BUS_ERR: + case ARB_LOST: + case SEQ_ERR: + case ST_ERR: + return TRUE; + default: + return FALSE; + } +} + +static inline int i2c_is_idle(enum i2c_status status) +{ + switch (status) { + case IDLE: + case DONE_STOP: + return TRUE; + default: + return FALSE; + } +} + +static inline int i2c_is_busy(enum i2c_status status) +{ + switch (status) { + case BUSY: + return TRUE; + default: + return FALSE; + } +} + +static int i2c_is_busy_wait(struct saa7134_dev *dev) +{ + enum i2c_status status; + int count; + + for (count = 0; count < I2C_WAIT_RETRY; count++) { + status = i2c_get_status(dev); + if (!i2c_is_busy(status)) + break; + if (need_resched()) + schedule(); + else + udelay(I2C_WAIT_DELAY); + } + if (I2C_WAIT_RETRY == count) + return FALSE; + return TRUE; +} + +static int i2c_reset(struct saa7134_dev *dev) +{ + enum i2c_status status; + int count; + + d2printk(KERN_DEBUG "%s: i2c reset\n",dev->name); + status = i2c_get_status(dev); + if (!i2c_is_error(status)) + return TRUE; + i2c_set_status(dev,status); + + for (count = 0; count < I2C_WAIT_RETRY; count++) { + status = i2c_get_status(dev); + if (!i2c_is_error(status)) + break; + udelay(I2C_WAIT_DELAY); + } + if (I2C_WAIT_RETRY == count) + return FALSE; + + if (!i2c_is_idle(status)) + return FALSE; + + i2c_set_attr(dev,NOP); + return TRUE; +} + +static inline int i2c_send_byte(struct saa7134_dev *dev, + enum i2c_attr attr, + unsigned char data) +{ + enum i2c_status status; + __u32 dword; + +#if 0 + i2c_set_attr(dev,attr); + saa_writeb(SAA7134_I2C_DATA, data); +#else + /* have to write both attr + data in one 32bit word */ + dword = saa_readl(SAA7134_I2C_ATTR_STATUS >> 2); + dword &= 0x0f; + dword |= (attr << 6); + dword |= ((__u32)data << 8); + dword |= 0x00 << 16; + dword |= 0xf0 << 24; + saa_writel(SAA7134_I2C_ATTR_STATUS >> 2, dword); +#endif + d2printk(KERN_DEBUG "%s: i2c data => 0x%x\n",dev->name,data); + + if (!i2c_is_busy_wait(dev)) + return -EIO; + status = i2c_get_status(dev); + if (i2c_is_error(status)) + return -EIO; + return 0; +} + +static inline int i2c_recv_byte(struct saa7134_dev *dev) +{ + enum i2c_status status; + unsigned char data; + + i2c_set_attr(dev,CONTINUE); + if (!i2c_is_busy_wait(dev)) + return -EIO; + status = i2c_get_status(dev); + if (i2c_is_error(status)) + return -EIO; + data = saa_readb(SAA7134_I2C_DATA); + d2printk(KERN_DEBUG "%s: i2c data <= 0x%x\n",dev->name,data); + return data; +} + +static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], int num) +{ + struct saa7134_dev *dev = i2c_adap->algo_data; + enum i2c_status status; + unsigned char data; + int addr,rc,i,byte; + + status = i2c_get_status(dev); + if (!i2c_is_idle(status)) + if (!i2c_reset(dev)) + return -EIO; + + d1printk(KERN_DEBUG "%s: i2c xfer:",dev->name); + for (i = 0; i < num; i++) { + if (!(msgs[i].flags & I2C_M_NOSTART) || 0 == i) { + /* send address */ + addr = msgs[i].addr << 1; + if (msgs[i].flags & I2C_M_RD) + addr |= 1; + d1printk(" < %02x", addr); + rc = i2c_send_byte(dev,START,addr); + if (rc < 0) + goto err; + } + if (msgs[i].flags & I2C_M_RD) { + /* read bytes */ + for (byte = 0; byte < msgs[i].len; byte++) { + d1printk(" ="); + rc = i2c_recv_byte(dev); + if (rc < 0) + goto err; + d1printk("%02x", rc); + msgs[i].buf[byte] = rc; + } + } else { + /* write bytes */ + for (byte = 0; byte < msgs[i].len; byte++) { + data = msgs[i].buf[byte]; + d1printk(" %02x", data); + rc = i2c_send_byte(dev,CONTINUE,data); + if (rc < 0) + goto err; + } + } + } + d1printk(" >"); + i2c_set_attr(dev,STOP); + rc = -EIO; + if (!i2c_is_busy_wait(dev)) + goto err; + status = i2c_get_status(dev); + if (i2c_is_error(status)) + goto err; + + d1printk("\n"); + return num; + err: + if (1 == i2c_debug) { + status = i2c_get_status(dev); + printk(" ERROR: %s\n",str_i2c_status[status]); + } + return rc; +} + +/* ----------------------------------------------------------- */ + +static int algo_control(struct i2c_adapter *adapter, + unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static u32 functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static void inc_use(struct i2c_adapter *adap) +{ + MOD_INC_USE_COUNT; +} + +static void dec_use(struct i2c_adapter *adap) +{ + MOD_DEC_USE_COUNT; +} + +static int attach_inform(struct i2c_client *client) +{ + struct saa7134_dev *dev = client->adapter->algo_data; + int tuner = card(dev).tuner_type; + + saa7134_i2c_call_clients(dev,TUNER_SET_TYPE,&tuner); + return 0; +} + +static struct i2c_algorithm saa7134_algo = { + name: "saa7134", + id: I2C_ALGO_SAA7134, + master_xfer: saa7134_i2c_xfer, + algo_control: algo_control, + functionality: functionality, +}; + +static struct i2c_adapter saa7134_adap_template = { + name: "saa7134", + id: I2C_ALGO_SAA7134, + algo: &saa7134_algo, + inc_use: inc_use, + dec_use: dec_use, + client_register: attach_inform, +}; + +static struct i2c_client saa7134_client_template = { + name: "saa7134 internal", + id: -1, +}; + +/* ----------------------------------------------------------- */ + +static int +saa7134_i2c_eeprom(struct saa7134_dev *dev, unsigned char *eedata, int len) +{ + unsigned char buf; + int i,err; + + dev->i2c_client.addr = 0xa0 >> 1; + buf = 0; + if (1 != (err = i2c_master_send(&dev->i2c_client,&buf,1))) { + printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", + dev->name,err); + return -1; + } + if (len != (err = i2c_master_recv(&dev->i2c_client,eedata,len))) { + printk(KERN_WARNING "%s: i2c eeprom read error (err=%d)\n", + dev->name,err); + return -1; + } + for (i = 0; i < len; i++) { + if (0 == (i % 16)) + printk(KERN_INFO "%s: i2c eeprom %02x:",dev->name,i); + printk(" %02x",eedata[i]); + if (15 == (i % 16)) + printk("\n"); + } + return 0; +} + +static int +saa7134_i2c_scan(struct saa7134_dev *dev) +{ + unsigned char buf; + int i,rc; + + for (i = 0; i < 256; i+= 2) { + dev->i2c_client.addr = i >> 1; + rc = i2c_master_recv(&dev->i2c_client,&buf,0); + if (rc < 0) + continue; + printk("%s: i2c scan: found device @ %x%s\n", + dev->name, i, (i == 0xa0) ? " [eeprom]" : ""); + } + return 0; +} + +void saa7134_i2c_call_clients(struct saa7134_dev *dev, + unsigned int cmd, void *arg) +{ + int i; + + for (i = 0; i < I2C_CLIENT_MAX; i++) { + if (NULL == dev->i2c_adap.clients[i]) + continue; + if (NULL == dev->i2c_adap.clients[i]->driver->command) + continue; + dev->i2c_adap.clients[i]->driver->command + (dev->i2c_adap.clients[i],cmd,arg); + } +} + +int saa7134_i2c_register(struct saa7134_dev *dev) +{ + dev->i2c_adap = saa7134_adap_template; + strcpy(dev->i2c_adap.name,dev->name); + dev->i2c_adap.algo_data = dev; + i2c_add_adapter(&dev->i2c_adap); + + dev->i2c_client = saa7134_client_template; + dev->i2c_client.adapter = &dev->i2c_adap; + + saa7134_i2c_eeprom(dev,dev->eedata,sizeof(dev->eedata)); + if (i2c_scan) + saa7134_i2c_scan(dev); + return 0; +} + +int saa7134_i2c_unregister(struct saa7134_dev *dev) +{ + i2c_del_adapter(&dev->i2c_adap); + return 0; +} + +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/saa7134/saa7134-oss.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,762 @@ +/* + * device driver for philips saa7134 based TV cards + * oss dsp interface + * + * (c) 2001,02 Gerd Knorr [SuSE Labs] + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define __NO_VERSION__ 1 + +#include +#include +#include +#include +#include +#include + +#include "saa7134-reg.h" +#include "saa7134.h" + +/* ------------------------------------------------------------------ */ + +static unsigned int oss_debug = 0; +MODULE_PARM(oss_debug,"i"); +MODULE_PARM_DESC(oss_debug,"enable debug messages [oss]"); + +static unsigned int oss_rate = 0; +MODULE_PARM(oss_rate,"i"); +MODULE_PARM_DESC(oss_rate,"sample rate (valid are: 32000,48000)"); + +#define dprintk(fmt, arg...) if (oss_debug) \ + printk(KERN_DEBUG "%s/oss: " fmt, dev->name, ## arg) + +/* ------------------------------------------------------------------ */ + +static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks) +{ + blksize &= ~0xff; + if (blksize < 0x100) + blksize = 0x100; + if (blksize > 0x10000) + blksize = 0x100; + + if (blocks < 2) + blocks = 2; + while ((blksize * blocks) & ~PAGE_MASK) + blocks++; + if ((blksize * blocks) > 1024*1024) + blocks = 1024*1024 / blksize; + + dev->oss.blocks = blocks; + dev->oss.blksize = blksize; + dev->oss.bufsize = blksize * blocks; + + dprintk("buffer config: %d blocks / %d bytes, %d kB total\n", + blocks,blksize,blksize * blocks / 1024); + return 0; +} + +static int dsp_buffer_init(struct saa7134_dev *dev) +{ + int err; + + if (!dev->oss.bufsize) + BUG(); + err = videobuf_dma_init_kernel(&dev->oss.dma, PCI_DMA_FROMDEVICE, + dev->oss.bufsize >> PAGE_SHIFT); + if (0 != err) + return err; + return 0; +} + +static int dsp_buffer_free(struct saa7134_dev *dev) +{ + if (!dev->oss.blksize) + BUG(); + videobuf_dma_free(&dev->oss.dma); + dev->oss.blocks = 0; + dev->oss.blksize = 0; + dev->oss.bufsize = 0; + return 0; +} + +static int dsp_rec_start(struct saa7134_dev *dev) +{ + int err, fmt, bswap, wswap; + unsigned long control,flags; + + /* prepare buffer */ + if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->oss.dma))) + return err; + if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->oss.pt, + dev->oss.dma.sglist, + dev->oss.dma.sglen, + 0))) + goto fail1; + + /* sample format */ + switch (dev->oss.afmt) { + case AFMT_U8: fmt = 0x00; break; + case AFMT_S8: fmt = 0x00 | 0x04; break; + case AFMT_U16_LE: + case AFMT_U16_BE: fmt = 0x01; break; + case AFMT_S16_LE: + case AFMT_S16_BE: fmt = 0x01 | 0x04; break; +/* 4front API specs mention these ones, + the (2.4.15) kernel header hasn't them ... */ +#ifdef AFMT_S32_LE + case AFMT_S32_LE: + case AFMT_S32_BE: fmt = 0x02 | 0x04; break; +#endif + default: + err = -EINVAL; + goto fail2; + } + + switch (dev->oss.afmt) { + case AFMT_U16_BE: + case AFMT_S16_BE: bswap = 1; wswap = 0; break; +#ifdef AFMT_S32_LE + case AFMT_S32_BE: bswap = 1; wswap = 1; break; +#endif + default: bswap = 0; wswap = 0; break; + } + + if (1 == dev->oss.channels) + fmt |= (1 << 3); + if (2 == dev->oss.channels) + fmt |= (3 << 3); + fmt |= (TV == dev->oss.input) ? 0xc0 : 0x80; + + saa_writeb(SAA7134_NUM_SAMPLES0, (dev->oss.blksize & 0x0000ff)); + saa_writeb(SAA7134_NUM_SAMPLES1, (dev->oss.blksize & 0x00ff00) >> 8); + saa_writeb(SAA7134_NUM_SAMPLES2, (dev->oss.blksize & 0xff0000) >> 16); + saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt); + dprintk("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c%c\n", + dev->oss.afmt, dev->oss.channels, fmt, + bswap ? 'b' : '-', wswap ? 'w' : '-'); + + /* dma: setup channel 6 (= AUDIO) */ + control = SAA7134_RS_CONTROL_BURST_16 | + SAA7134_RS_CONTROL_ME | + (dev->oss.pt.dma >> 12); + if (bswap) + control |= SAA7134_RS_CONTROL_BSWAP; + if (wswap) + control |= SAA7134_RS_CONTROL_WSWAP; + saa_writel(SAA7134_RS_BA1(6),0); + saa_writel(SAA7134_RS_BA2(6),dev->oss.blksize); + saa_writel(SAA7134_RS_PITCH(6),0); + saa_writel(SAA7134_RS_CONTROL(6),control); + + /* start dma */ + spin_lock_irqsave(&dev->slock,flags); + dev->oss.recording = 1; + dev->oss.dma_blk = 0; + saa7134_set_dmabits(dev); + spin_unlock_irqrestore(&dev->slock,flags); + return 0; + + fail2: + saa7134_pgtable_free(dev->pci,&dev->oss.pt); + fail1: + videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma); + return err; +} + +static int dsp_rec_stop(struct saa7134_dev *dev) +{ + unsigned long flags; + + dprintk("rec_stop dma_blk=%d\n",dev->oss.dma_blk); + + /* stop dma */ + spin_lock_irqsave(&dev->slock,flags); + dev->oss.dma_blk = -1; + dev->oss.recording = 0; + saa7134_set_dmabits(dev); + spin_unlock_irqrestore(&dev->slock,flags); + + /* unlock buffer */ + saa7134_pgtable_free(dev->pci,&dev->oss.pt); + videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma); + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int dsp_open(struct inode *inode, struct file *file) +{ + unsigned int minor = minor(inode->i_rdev); + struct saa7134_dev *h,*dev = NULL; + struct list_head *list; + int err; + + list_for_each(list,&saa7134_devlist) { + h = list_entry(list, struct saa7134_dev, devlist); + if (h->oss.minor_dsp == minor) + dev = h; + } + if (NULL == dev) + return -ENODEV; + + down(&dev->oss.lock); + err = -EBUSY; + if (dev->oss.users_dsp) + goto fail1; + dev->oss.users_dsp++; + file->private_data = dev; + + dev->oss.afmt = AFMT_U8; + dev->oss.channels = 1; + dev->oss.read_count = 0; + dev->oss.read_offset = 0; + dsp_buffer_conf(dev,PAGE_SIZE,64); + err = dsp_buffer_init(dev); + if (0 != err) + goto fail2; + + up(&dev->oss.lock); + return 0; + + fail2: + dev->oss.users_dsp--; + fail1: + up(&dev->oss.lock); + return err; +} + +static int dsp_release(struct inode *inode, struct file *file) +{ + struct saa7134_dev *dev = file->private_data; + + down(&dev->oss.lock); + if (dev->oss.recording) + dsp_rec_stop(dev); + dsp_buffer_free(dev); + dev->oss.users_dsp--; + file->private_data = NULL; + up(&dev->oss.lock); + return 0; +} + +static ssize_t dsp_read(struct file *file, char *buffer, + size_t count, loff_t *ppos) +{ + struct saa7134_dev *dev = file->private_data; + DECLARE_WAITQUEUE(wait, current); + int bytes,err,ret = 0; + + add_wait_queue(&dev->oss.wq, &wait); + down(&dev->oss.lock); + while (count > 0) { + /* wait for data if needed */ + if (0 == dev->oss.read_count) { + if (!dev->oss.recording) { + err = dsp_rec_start(dev); + if (err < 0) { + if (0 == ret) + ret = err; + break; + } + } + if (file->f_flags & O_NONBLOCK) { + if (0 == ret) + ret = -EAGAIN; + break; + } + up(&dev->oss.lock); + current->state = TASK_INTERRUPTIBLE; + schedule(); + down(&dev->oss.lock); + if (signal_pending(current)) { + if (0 == ret) + ret = -EINTR; + break; + } + } + + /* copy data to userspace */ + bytes = count; + if (bytes > dev->oss.read_count) + bytes = dev->oss.read_count; + if (bytes > dev->oss.bufsize - dev->oss.read_offset) + bytes = dev->oss.bufsize - dev->oss.read_offset; + if (copy_to_user(buffer + ret, + dev->oss.dma.vmalloc + dev->oss.read_offset, + bytes)) { + if (0 == ret) + ret = -EFAULT; + break; + } + + ret += bytes; + count -= bytes; + dev->oss.read_count -= bytes; + dev->oss.read_offset += bytes; + if (dev->oss.read_offset == dev->oss.bufsize) + dev->oss.read_offset = 0; + } + up(&dev->oss.lock); + remove_wait_queue(&dev->oss.wq, &wait); + current->state = TASK_RUNNING; + return ret; +} + +static ssize_t dsp_write(struct file *file, const char *buffer, + size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static int dsp_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct saa7134_dev *dev = file->private_data; + int val = 0; + + if (oss_debug > 1) + saa7134_print_ioctl(dev->name,cmd); + switch (cmd) { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, (int *)arg); + case SNDCTL_DSP_GETCAPS: + return 0; + + case SNDCTL_DSP_SPEED: + if (get_user(val, (int*)arg)) + return -EFAULT; + /* fall through */ + case SOUND_PCM_READ_RATE: + return put_user(dev->oss.rate, (int*)arg); + + case SNDCTL_DSP_STEREO: + if (get_user(val, (int*)arg)) + return -EFAULT; + down(&dev->oss.lock); + dev->oss.channels = val ? 2 : 1; + if (dev->oss.recording) { + dsp_rec_stop(dev); + dsp_rec_start(dev); + } + up(&dev->oss.lock); + return put_user(dev->oss.channels-1, (int *)arg); + + case SNDCTL_DSP_CHANNELS: + if (get_user(val, (int*)arg)) + return -EFAULT; + if (val != 1 && val != 2) + return -EINVAL; + down(&dev->oss.lock); + dev->oss.channels = val; + if (dev->oss.recording) { + dsp_rec_stop(dev); + dsp_rec_start(dev); + } + up(&dev->oss.lock); + /* fall through */ + case SOUND_PCM_READ_CHANNELS: + return put_user(dev->oss.channels, (int *)arg); + + case SNDCTL_DSP_GETFMTS: /* Returns a mask */ + return put_user(AFMT_U8 | AFMT_S8 | + AFMT_U16_LE | AFMT_U16_BE | + AFMT_S16_LE | AFMT_S16_BE, (int*)arg); + + case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */ + if (get_user(val, (int*)arg)) + return -EFAULT; + switch (val) { + case AFMT_QUERY: + /* nothing to do */ + break; + case AFMT_U8: + case AFMT_S8: + case AFMT_U16_LE: + case AFMT_U16_BE: + case AFMT_S16_LE: + case AFMT_S16_BE: +#ifdef AFMT_S32_LE + case AFMT_S32_LE: + case AFMT_S32_BE: +#endif + down(&dev->oss.lock); + dev->oss.afmt = val; + if (dev->oss.recording) { + dsp_rec_stop(dev); + dsp_rec_start(dev); + } + up(&dev->oss.lock); + return put_user(dev->oss.afmt,(int*)arg); + default: + return -EINVAL; + } + + case SOUND_PCM_READ_BITS: + switch (dev->oss.afmt) { + case AFMT_U8: + case AFMT_S8: + return put_user(8, (int*)arg); + case AFMT_U16_LE: + case AFMT_U16_BE: + case AFMT_S16_LE: + case AFMT_S16_BE: + return put_user(16, (int*)arg); +#ifdef AFMT_S32_LE + case AFMT_S32_LE: + case AFMT_S32_BE: + return put_user(20, (int*)arg); +#endif + default: + return -EINVAL; + } + + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_RESET: + down(&dev->oss.lock); + if (dev->oss.recording) + dsp_rec_stop(dev); + up(&dev->oss.lock); + return 0; + case SNDCTL_DSP_GETBLKSIZE: + return put_user(dev->oss.blksize,(int*)arg); + + case SNDCTL_DSP_SETFRAGMENT: + if (get_user(val, (int*)arg)) + return -EFAULT; + if (dev->oss.recording) + return -EBUSY; + dsp_buffer_free(dev); + dsp_buffer_conf(dev,1 << (val & 0xffff), (arg >> 16) & 0xffff); + dsp_buffer_init(dev); + return 0; + + case SNDCTL_DSP_SYNC: + /* NOP */ + return 0; + + case SNDCTL_DSP_GETISPACE: + { + audio_buf_info info; + info.fragsize = dev->oss.blksize; + info.fragstotal = dev->oss.blocks; + info.bytes = dev->oss.read_count; + info.fragments = info.bytes / info.fragsize; + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + default: + return -EINVAL; + } +} + +static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait) +{ + struct saa7134_dev *dev = file->private_data; + unsigned int mask = 0; + + poll_wait(file, &dev->oss.wq, wait); + + if (0 == dev->oss.read_count) { + down(&dev->oss.lock); + if (!dev->oss.recording) + dsp_rec_start(dev); + up(&dev->oss.lock); + } else + mask |= (POLLIN | POLLRDNORM); + return mask; +} + +struct file_operations saa7134_dsp_fops = { + owner: THIS_MODULE, + open: dsp_open, + release: dsp_release, + read: dsp_read, + write: dsp_write, + ioctl: dsp_ioctl, + poll: dsp_poll, + llseek: no_llseek, +}; + +/* ------------------------------------------------------------------ */ + +static int +mixer_recsrc(struct saa7134_dev *dev, enum saa7134_audio_in src) +{ + static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" }; + int analog_io,rate; + + dev->oss.count++; + dev->oss.input = src; + dprintk("mixer input = %s\n",iname[dev->oss.input]); + switch (dev->oss.input) { + case TV: + saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0); + saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x00); + break; + case LINE1: + case LINE2: + analog_io = (LINE1 == dev->oss.input) ? 0x00 : 0x08; + rate = (32000 == dev->oss.rate) ? 0x01 : 0x03; + saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, analog_io); + saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80); + saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate); + break; + } + return 0; +} + +static int +mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level) +{ + switch (src) { + case TV: + /* nothing */ + break; + case LINE1: + saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x10, + (100 == level) ? 0x00 : 0x10); + break; + case LINE2: + saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x20, + (100 == level) ? 0x00 : 0x20); + break; + } + return 0; +} + +static int mixer_open(struct inode *inode, struct file *file) +{ + unsigned int minor = minor(inode->i_rdev); + struct saa7134_dev *h,*dev = NULL; + struct list_head *list; + + list_for_each(list,&saa7134_devlist) { + h = list_entry(list, struct saa7134_dev, devlist); + if (h->oss.minor_mixer == minor) + dev = h; + } + if (NULL == dev) + return -ENODEV; + + file->private_data = dev; + return 0; +} + +static int mixer_release(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + return 0; +} + +static int mixer_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct saa7134_dev *dev = file->private_data; + enum saa7134_audio_in input; + int val,ret; + + if (oss_debug > 1) + saa7134_print_ioctl(dev->name,cmd); + switch (cmd) { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, (int *)arg); + case SOUND_MIXER_INFO: + { + mixer_info info; + memset(&info,0,sizeof(info)); + strncpy(info.id, "TV audio", sizeof(info.id)-1); + strncpy(info.name, dev->name, sizeof(info.name)-1); + info.modify_counter = dev->oss.count; + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + case SOUND_OLD_MIXER_INFO: + { + _old_mixer_info info; + memset(&info,0,sizeof(info)); + strncpy(info.id, "TV audio", sizeof(info.id)-1); + strncpy(info.name, dev->name, sizeof(info.name)-1); + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + case MIXER_READ(SOUND_MIXER_CAPS): + return put_user(SOUND_CAP_EXCL_INPUT,(int*)arg); + case MIXER_READ(SOUND_MIXER_STEREODEVS): + return put_user(0,(int*)arg); + case MIXER_READ(SOUND_MIXER_RECMASK): + case MIXER_READ(SOUND_MIXER_DEVMASK): + val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2; + if (32000 == dev->oss.rate) + val |= SOUND_MASK_VIDEO; + return put_user(val,(int*)arg); + + case MIXER_WRITE(SOUND_MIXER_RECSRC): + if (get_user(val, (int *)arg)) + return -EFAULT; + input = dev->oss.input; + if (32000 == dev->oss.rate && + val & SOUND_MASK_VIDEO && dev->oss.input != TV) + input = TV; + if (val & SOUND_MASK_LINE1 && dev->oss.input != LINE1) + input = LINE1; + if (val & SOUND_MASK_LINE2 && dev->oss.input != LINE2) + input = LINE2; + if (input != dev->oss.input) + mixer_recsrc(dev,input); + /* fall throuth */ + case MIXER_READ(SOUND_MIXER_RECSRC): + switch (dev->oss.input) { + case TV: ret = SOUND_MASK_VIDEO; break; + case LINE1: ret = SOUND_MASK_LINE1; break; + case LINE2: ret = SOUND_MASK_LINE2; break; + default: ret = 0; + } + return put_user(ret,(int*)arg); + + case MIXER_WRITE(SOUND_MIXER_VIDEO): + case MIXER_READ(SOUND_MIXER_VIDEO): + if (32000 != dev->oss.rate) + return -EINVAL; + return put_user(100 | 100 << 8,(int*)arg); + + case MIXER_WRITE(SOUND_MIXER_LINE1): + if (get_user(val, (int *)arg)) + return -EFAULT; + val &= 0xff; + val = (val <= 50) ? 50 : 100; + dev->oss.line1 = val; + mixer_level(dev,LINE1,dev->oss.line1); + /* fall throuth */ + case MIXER_READ(SOUND_MIXER_LINE1): + return put_user(dev->oss.line1 | dev->oss.line1 << 8, + (int*)arg); + + case MIXER_WRITE(SOUND_MIXER_LINE2): + if (get_user(val, (int *)arg)) + return -EFAULT; + val &= 0xff; + val = (val <= 50) ? 50 : 100; + dev->oss.line2 = val; + mixer_level(dev,LINE2,dev->oss.line2); + /* fall throuth */ + case MIXER_READ(SOUND_MIXER_LINE2): + return put_user(dev->oss.line2 | dev->oss.line2 << 8, + (int*)arg); + + default: + return -EINVAL; + } +} + +struct file_operations saa7134_mixer_fops = { + owner: THIS_MODULE, + open: mixer_open, + release: mixer_release, + ioctl: mixer_ioctl, + llseek: no_llseek, +}; + +/* ------------------------------------------------------------------ */ + +int saa7134_oss_init(struct saa7134_dev *dev) +{ + init_MUTEX(&dev->oss.lock); + init_waitqueue_head(&dev->oss.wq); + dev->oss.line1 = 50; + dev->oss.line2 = 50; + mixer_level(dev,LINE1,dev->oss.line1); + mixer_level(dev,LINE2,dev->oss.line2); + + dev->oss.rate = 32000; + if (oss_rate) + dev->oss.rate = oss_rate; + if (saa7134_boards[dev->board].i2s_rate) + dev->oss.rate = saa7134_boards[dev->board].i2s_rate; + dev->oss.rate = (dev->oss.rate > 40000) ? 48000 : 32000; + + mixer_recsrc(dev, (dev->oss.rate == 32000) ? TV : LINE2); + return 0; +} + +int saa7134_oss_fini(struct saa7134_dev *dev) +{ + /* nothing */ + return 0; +} + +void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status) +{ + int next_blk, reg = 0; + + spin_lock(&dev->slock); + if (-1 == dev->oss.dma_blk) { + dprintk("irq: recording stopped%s\n",""); + goto done; + } + if (0 != (status & 0x0f000000)) + dprintk("irq: lost %ld\n", (status >> 24) & 0x0f); + if (0 == (status & 0x10000000)) { + /* odd */ + if (0 == (dev->oss.dma_blk & 0x01)) + reg = SAA7134_RS_BA1(6); + } else { + /* even */ + if (0 == (dev->oss.dma_blk & 0x00)) + reg = SAA7134_RS_BA2(6); + } + if (0 == reg) { + dprintk("irq: field oops [%s]\n", + (status & 0x10000000) ? "even" : "odd"); + goto done; + } + if (dev->oss.read_count >= dev->oss.blksize * (dev->oss.blocks-2)) { + dprintk("irq: overrun [full=%d/%d]\n",dev->oss.read_count, + dev->oss.bufsize); + dsp_rec_stop(dev); + goto done; + } + + /* next block addr */ + next_blk = (dev->oss.dma_blk + 2) % dev->oss.blocks; + saa_writel(reg,next_blk * dev->oss.blksize); + if (oss_debug > 2) + dprintk("irq: ok, %s, next_blk=%d, addr=%x\n", + (status & 0x10000000) ? "even" : "odd ", next_blk, + next_blk * dev->oss.blksize); + + /* update status & wake waiting readers */ + dev->oss.dma_blk = (dev->oss.dma_blk + 1) % dev->oss.blocks; + dev->oss.read_count += dev->oss.blksize; + wake_up(&dev->oss.wq); + + done: + spin_unlock(&dev->slock); +} + +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru a/drivers/media/video/saa7134/saa7134-reg.h b/drivers/media/video/saa7134/saa7134-reg.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/saa7134/saa7134-reg.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,338 @@ +/* + * philips saa7134 registers + */ + +/* ------------------------------------------------------------------ */ +/* + * PCI ID's + */ +#ifndef PCI_DEVICE_ID_PHILIPS_SAA7130 +# define PCI_DEVICE_ID_PHILIPS_SAA7130 0x7130 +#endif +#ifndef PCI_DEVICE_ID_PHILIPS_SAA7134 +# define PCI_DEVICE_ID_PHILIPS_SAA7134 0x7134 +#endif + +/* ------------------------------------------------------------------ */ +/* + * registers -- 32 bit + */ + +/* DMA channels, n = 0 ... 6 */ +#define SAA7134_RS_BA1(n) ((0x200 >> 2) + 4*n) +#define SAA7134_RS_BA2(n) ((0x204 >> 2) + 4*n) +#define SAA7134_RS_PITCH(n) ((0x208 >> 2) + 4*n) +#define SAA7134_RS_CONTROL(n) ((0x20c >> 2) + 4*n) +#define SAA7134_RS_CONTROL_WSWAP (0x01 << 25) +#define SAA7134_RS_CONTROL_BSWAP (0x01 << 24) +#define SAA7134_RS_CONTROL_BURST_2 (0x01 << 21) +#define SAA7134_RS_CONTROL_BURST_4 (0x02 << 21) +#define SAA7134_RS_CONTROL_BURST_8 (0x03 << 21) +#define SAA7134_RS_CONTROL_BURST_16 (0x04 << 21) +#define SAA7134_RS_CONTROL_BURST_32 (0x05 << 21) +#define SAA7134_RS_CONTROL_BURST_64 (0x06 << 21) +#define SAA7134_RS_CONTROL_BURST_MAX (0x07 << 21) +#define SAA7134_RS_CONTROL_ME (0x01 << 20) +#define SAA7134_FIFO_SIZE (0x2a0 >> 2) +#define SAA7134_THRESHOULD (0x2a4 >> 2) + +/* main control */ +#define SAA7134_MAIN_CTRL (0x2a8 >> 2) +#define SAA7134_MAIN_CTRL_VPLLE (1 << 15) +#define SAA7134_MAIN_CTRL_APLLE (1 << 14) +#define SAA7134_MAIN_CTRL_EXOSC (1 << 13) +#define SAA7134_MAIN_CTRL_EVFE1 (1 << 12) +#define SAA7134_MAIN_CTRL_EVFE2 (1 << 11) +#define SAA7134_MAIN_CTRL_ESFE (1 << 10) +#define SAA7134_MAIN_CTRL_EBADC (1 << 9) +#define SAA7134_MAIN_CTRL_EBDAC (1 << 8) +#define SAA7134_MAIN_CTRL_TE6 (1 << 6) +#define SAA7134_MAIN_CTRL_TE5 (1 << 5) +#define SAA7134_MAIN_CTRL_TE4 (1 << 4) +#define SAA7134_MAIN_CTRL_TE3 (1 << 3) +#define SAA7134_MAIN_CTRL_TE2 (1 << 2) +#define SAA7134_MAIN_CTRL_TE1 (1 << 1) +#define SAA7134_MAIN_CTRL_TE0 (1 << 0) + +/* DMA status */ +#define SAA7134_DMA_STATUS (0x2ac >> 2) + +/* audio / video status */ +#define SAA7134_AV_STATUS (0x2c0 >> 2) +#define SAA7134_AV_STATUS_STEREO (1 << 17) +#define SAA7134_AV_STATUS_DUAL (1 << 16) +#define SAA7134_AV_STATUS_PILOT (1 << 15) +#define SAA7134_AV_STATUS_SMB (1 << 14) +#define SAA7134_AV_STATUS_DMB (1 << 13) +#define SAA7134_AV_STATUS_VDSP (1 << 12) +#define SAA7134_AV_STATUS_IIC_STATUS (3 << 10) +#define SAA7134_AV_STATUS_MVM (7 << 7) +#define SAA7134_AV_STATUS_FIDT (1 << 6) +#define SAA7134_AV_STATUS_INTL (1 << 5) +#define SAA7134_AV_STATUS_RDCAP (1 << 4) +#define SAA7134_AV_STATUS_PWR_ON (1 << 3) +#define SAA7134_AV_STATUS_LOAD_ERR (1 << 2) +#define SAA7134_AV_STATUS_TRIG_ERR (1 << 1) +#define SAA7134_AV_STATUS_CONF_ERR (1 << 0) + +/* interrupt */ +#define SAA7134_IRQ1 (0x2c4 >> 2) +#define SAA7134_IRQ1_INTE_RA3_1 (1 << 25) +#define SAA7134_IRQ1_INTE_RA3_0 (1 << 24) +#define SAA7134_IRQ1_INTE_RA2_3 (1 << 19) +#define SAA7134_IRQ1_INTE_RA2_2 (1 << 18) +#define SAA7134_IRQ1_INTE_RA2_1 (1 << 17) +#define SAA7134_IRQ1_INTE_RA2_0 (1 << 16) +#define SAA7134_IRQ1_INTE_RA1_3 (1 << 11) +#define SAA7134_IRQ1_INTE_RA1_2 (1 << 10) +#define SAA7134_IRQ1_INTE_RA1_1 (1 << 9) +#define SAA7134_IRQ1_INTE_RA1_0 (1 << 8) +#define SAA7134_IRQ1_INTE_RA0_7 (1 << 7) +#define SAA7134_IRQ1_INTE_RA0_6 (1 << 6) +#define SAA7134_IRQ1_INTE_RA0_5 (1 << 5) +#define SAA7134_IRQ1_INTE_RA0_4 (1 << 4) +#define SAA7134_IRQ1_INTE_RA0_3 (1 << 3) +#define SAA7134_IRQ1_INTE_RA0_2 (1 << 2) +#define SAA7134_IRQ1_INTE_RA0_1 (1 << 1) +#define SAA7134_IRQ1_INTE_RA0_0 (1 << 0) +#define SAA7134_IRQ2 (0x2c8 >> 2) +#define SAA7134_IRQ2_INTE_SC2 (1 << 10) +#define SAA7134_IRQ2_INTE_SC1 (1 << 9) +#define SAA7134_IRQ2_INTE_SC0 (1 << 8) +#define SAA7134_IRQ2_INTE_DEC5 (1 << 7) +#define SAA7134_IRQ2_INTE_DEC4 (1 << 6) +#define SAA7134_IRQ2_INTE_DEC3 (1 << 5) +#define SAA7134_IRQ2_INTE_DEC2 (1 << 4) +#define SAA7134_IRQ2_INTE_DEC1 (1 << 3) +#define SAA7134_IRQ2_INTE_DEC0 (1 << 2) +#define SAA7134_IRQ2_INTE_PE (1 << 1) +#define SAA7134_IRQ2_INTE_AR (1 << 0) +#define SAA7134_IRQ_REPORT (0x2cc >> 2) +#define SAA7134_IRQ_REPORT_LOAD_ERR (1 << 13) +#define SAA7134_IRQ_REPORT_CONF_ERR (1 << 12) +#define SAA7134_IRQ_REPORT_TRIG_ERR (1 << 11) +#define SAA7134_IRQ_REPORT_MMC (1 << 10) +#define SAA7134_IRQ_REPORT_FIDT (1 << 9) +#define SAA7134_IRQ_REPORT_INTL (1 << 8) +#define SAA7134_IRQ_REPORT_RDCAP (1 << 7) +#define SAA7134_IRQ_REPORT_PWR_ON (1 << 6) +#define SAA7134_IRQ_REPORT_PE (1 << 5) +#define SAA7134_IRQ_REPORT_AR (1 << 4) +#define SAA7134_IRQ_REPORT_DONE_RA3 (1 << 3) +#define SAA7134_IRQ_REPORT_DONE_RA2 (1 << 2) +#define SAA7134_IRQ_REPORT_DONE_RA1 (1 << 1) +#define SAA7134_IRQ_REPORT_DONE_RA0 (1 << 0) +#define SAA7134_IRQ_STATUS (0x2d0 >> 2) + + +/* ------------------------------------------------------------------ */ +/* + * registers -- 8 bit + */ + +/* video decoder */ +#define SAA7134_INCR_DELAY 0x101 +#define SAA7134_ANALOG_IN_CTRL1 0x102 +#define SAA7134_ANALOG_IN_CTRL2 0x103 +#define SAA7134_ANALOG_IN_CTRL3 0x104 +#define SAA7134_ANALOG_IN_CTRL4 0x105 +#define SAA7134_HSYNC_START 0x106 +#define SAA7134_HSYNC_STOP 0x107 +#define SAA7134_SYNC_CTRL 0x108 +#define SAA7134_LUMA_CTRL 0x109 +#define SAA7134_DEC_LUMA_BRIGHT 0x10a +#define SAA7134_DEC_LUMA_CONTRAST 0x10b +#define SAA7134_DEC_CHROMA_SATURATION 0x10c +#define SAA7134_DEC_CHROMA_HUE 0x10d +#define SAA7134_CHROMA_CTRL1 0x10e +#define SAA7134_CHROMA_GAIN 0x10f +#define SAA7134_CHROMA_CTRL2 0x110 +#define SAA7134_MODE_DELAY_CTRL 0x111 + +#define SAA7134_ANALOG_ADC 0x114 +#define SAA7134_VGATE_START 0x115 +#define SAA7134_VGATE_STOP 0x116 +#define SAA7134_MISC_VGATE_MSB 0x117 +#define SAA7134_RAW_DATA_GAIN 0x118 +#define SAA7134_RAW_DATA_OFFSET 0x119 +#define SAA7134_STATUS_VIDEO1 0x11e +#define SAA7134_STATUS_VIDEO2 0x11f + +/* video scaler */ +#define SAA7134_SOURCE_TIMING1 0x000 +#define SAA7134_SOURCE_TIMING2 0x001 +#define SAA7134_REGION_ENABLE 0x004 +#define SAA7134_SCALER_STATUS0 0x006 +#define SAA7134_SCALER_STATUS1 0x007 +#define SAA7134_START_GREEN 0x00c +#define SAA7134_START_BLUE 0x00d +#define SAA7134_START_RED 0x00e +#define SAA7134_GREEN_PATH(x) (0x010 +x) +#define SAA7134_BLUE_PATH(x) (0x020 +x) +#define SAA7134_RED_PATH(x) (0x030 +x) + +#define TASK_A 0x040 +#define TASK_B 0x080 +#define SAA7134_TASK_CONDITIONS(t) (0x000 +t) +#define SAA7134_FIELD_HANDLING(t) (0x001 +t) +#define SAA7134_DATA_PATH(t) (0x002 +t) +#define SAA7134_VBI_H_START1(t) (0x004 +t) +#define SAA7134_VBI_H_START2(t) (0x005 +t) +#define SAA7134_VBI_H_STOP1(t) (0x006 +t) +#define SAA7134_VBI_H_STOP2(t) (0x007 +t) +#define SAA7134_VBI_V_START1(t) (0x008 +t) +#define SAA7134_VBI_V_START2(t) (0x009 +t) +#define SAA7134_VBI_V_STOP1(t) (0x00a +t) +#define SAA7134_VBI_V_STOP2(t) (0x00b +t) +#define SAA7134_VBI_H_LEN1(t) (0x00c +t) +#define SAA7134_VBI_H_LEN2(t) (0x00d +t) +#define SAA7134_VBI_V_LEN1(t) (0x00e +t) +#define SAA7134_VBI_V_LEN2(t) (0x00f +t) + +#define SAA7134_VIDEO_H_START1(t) (0x014 +t) +#define SAA7134_VIDEO_H_START2(t) (0x015 +t) +#define SAA7134_VIDEO_H_STOP1(t) (0x016 +t) +#define SAA7134_VIDEO_H_STOP2(t) (0x017 +t) +#define SAA7134_VIDEO_V_START1(t) (0x018 +t) +#define SAA7134_VIDEO_V_START2(t) (0x019 +t) +#define SAA7134_VIDEO_V_STOP1(t) (0x01a +t) +#define SAA7134_VIDEO_V_STOP2(t) (0x01b +t) +#define SAA7134_VIDEO_PIXELS1(t) (0x01c +t) +#define SAA7134_VIDEO_PIXELS2(t) (0x01d +t) +#define SAA7134_VIDEO_LINES1(t) (0x01e +t) +#define SAA7134_VIDEO_LINES2(t) (0x01f +t) + +#define SAA7134_H_PRESCALE(t) (0x020 +t) +#define SAA7134_ACC_LENGTH(t) (0x021 +t) +#define SAA7134_LEVEL_CTRL(t) (0x022 +t) +#define SAA7134_FIR_PREFILTER_CTRL(t) (0x023 +t) +#define SAA7134_LUMA_BRIGHT(t) (0x024 +t) +#define SAA7134_LUMA_CONTRAST(t) (0x025 +t) +#define SAA7134_CHROMA_SATURATION(t) (0x026 +t) +#define SAA7134_VBI_H_SCALE_INC1(t) (0x028 +t) +#define SAA7134_VBI_H_SCALE_INC2(t) (0x029 +t) +#define SAA7134_VBI_PHASE_OFFSET_LUMA(t) (0x02a +t) +#define SAA7134_VBI_PHASE_OFFSET_CHROMA(t) (0x02b +t) +#define SAA7134_H_SCALE_INC1(t) (0x02c +t) +#define SAA7134_H_SCALE_INC2(t) (0x02d +t) +#define SAA7134_H_PHASE_OFF_LUMA(t) (0x02e +t) +#define SAA7134_H_PHASE_OFF_CHROMA(t) (0x02f +t) +#define SAA7134_V_SCALE_RATIO1(t) (0x030 +t) +#define SAA7134_V_SCALE_RATIO2(t) (0x031 +t) +#define SAA7134_V_FILTER(t) (0x032 +t) +#define SAA7134_V_PHASE_OFFSET0(t) (0x034 +t) +#define SAA7134_V_PHASE_OFFSET1(t) (0x035 +t) +#define SAA7134_V_PHASE_OFFSET2(t) (0x036 +t) +#define SAA7134_V_PHASE_OFFSET3(t) (0x037 +t) + +/* clipping & dma */ +#define SAA7134_OFMT_VIDEO_A 0x300 +#define SAA7134_OFMT_DATA_A 0x301 +#define SAA7134_OFMT_VIDEO_B 0x302 +#define SAA7134_OFMT_DATA_B 0x303 +#define SAA7134_ALPHA_NOCLIP 0x304 +#define SAA7134_ALPHA_CLIP 0x305 +#define SAA7134_UV_PIXEL 0x308 +#define SAA7134_CLIP_RED 0x309 +#define SAA7134_CLIP_GREEN 0x30a +#define SAA7134_CLIP_BLUE 0x30b + +/* i2c bus */ +#define SAA7134_I2C_ATTR_STATUS 0x180 +#define SAA7134_I2C_DATA 0x181 +#define SAA7134_I2C_CLOCK_SELECT 0x182 +#define SAA7134_I2C_TIMER 0x183 + +/* audio */ +#define SAA7134_NICAM_ADD_DATA1 0x140 +#define SAA7134_NICAM_ADD_DATA2 0x141 +#define SAA7134_NICAM_STATUS 0x142 +#define SAA7134_AUDIO_STATUS 0x143 +#define SAA7134_NICAM_ERROR_COUNT 0x144 +#define SAA7134_IDENT_SIF 0x145 +#define SAA7134_LEVEL_READOUT1 0x146 +#define SAA7134_LEVEL_READOUT2 0x147 +#define SAA7134_NICAM_ERROR_LOW 0x148 +#define SAA7134_NICAM_ERROR_HIGH 0x149 +#define SAA7134_DCXO_IDENT_CTRL 0x14a +#define SAA7134_DEMODULATOR 0x14b +#define SAA7134_AGC_GAIN_SELECT 0x14c +#define SAA7134_CARRIER1_FREQ0 0x150 +#define SAA7134_CARRIER1_FREQ1 0x151 +#define SAA7134_CARRIER1_FREQ2 0x152 +#define SAA7134_CARRIER2_FREQ0 0x154 +#define SAA7134_CARRIER2_FREQ1 0x155 +#define SAA7134_CARRIER2_FREQ2 0x156 +#define SAA7134_NUM_SAMPLES0 0x158 +#define SAA7134_NUM_SAMPLES1 0x159 +#define SAA7134_NUM_SAMPLES2 0x15a +#define SAA7134_AUDIO_FORMAT_CTRL 0x15b +#define SAA7134_MONITOR_SELECT 0x160 +#define SAA7134_FM_DEEMPHASIS 0x161 +#define SAA7134_FM_DEMATRIX 0x162 +#define SAA7134_CHANNEL1_LEVEL 0x163 +#define SAA7134_CHANNEL2_LEVEL 0x164 +#define SAA7134_NICAM_CONFIG 0x165 +#define SAA7134_NICAM_LEVEL_ADJUST 0x166 +#define SAA7134_STEREO_DAC_OUTPUT_SELECT 0x167 +#define SAA7134_I2S_OUTPUT_FORMAT 0x168 +#define SAA7134_I2S_OUTPUT_SELECT 0x169 +#define SAA7134_I2S_OUTPUT_LEVEL 0x16a +#define SAA7134_DSP_OUTPUT_SELECT 0x16b +#define SAA7134_AUDIO_MUTE_CTRL 0x16c +#define SAA7134_SIF_SAMPLE_FREQ 0x16d +#define SAA7134_ANALOG_IO_SELECT 0x16e +#define SAA7134_AUDIO_CLOCK0 0x170 +#define SAA7134_AUDIO_CLOCK1 0x171 +#define SAA7134_AUDIO_CLOCK2 0x172 +#define SAA7134_AUDIO_PLL_CTRL 0x173 +#define SAA7134_AUDIO_CLOCKS_PER_FIELD0 0x174 +#define SAA7134_AUDIO_CLOCKS_PER_FIELD1 0x175 +#define SAA7134_AUDIO_CLOCKS_PER_FIELD2 0x176 + +/* video port output */ +#define SAA7134_VIDEO_PORT_CTRL0 0x190 +#define SAA7134_VIDEO_PORT_CTRL1 0x191 +#define SAA7134_VIDEO_PORT_CTRL2 0x192 +#define SAA7134_VIDEO_PORT_CTRL3 0x193 +#define SAA7134_VIDEO_PORT_CTRL4 0x194 +#define SAA7134_VIDEO_PORT_CTRL5 0x195 +#define SAA7134_VIDEO_PORT_CTRL6 0x196 +#define SAA7134_VIDEO_PORT_CTRL7 0x197 +#define SAA7134_VIDEO_PORT_CTRL8 0x198 + +/* transport stream interface */ +#define SAA7134_TS_PARALLEL 0x1a0 +#define SAA7134_TS_PARALLEL_SERIAL 0x1a1 +#define SAA7134_TS_SERIAL0 0x1a2 +#define SAA7134_TS_SERIAL1 0x1a3 +#define SAA7134_TS_DMA0 0x1a4 +#define SAA7134_TS_DMA1 0x1a5 +#define SAA7134_TS_DMA2 0x1a6 + +/* GPIO Controls */ +#define SAA7134_GPIO_GPRESCAN 0x80 +#define SAA7134_GPIO_27_25 0x0E + +#define SAA7134_GPIO_GPMODE0 0x1B0 +#define SAA7134_GPIO_GPMODE1 0x1B1 +#define SAA7134_GPIO_GPMODE2 0x1B2 +#define SAA7134_GPIO_GPMODE3 0x1B3 +#define SAA7134_GPIO_GPSTATUS0 0x1B4 +#define SAA7134_GPIO_GPSTATUS1 0x1B5 +#define SAA7134_GPIO_GPSTATUS2 0x1B6 +#define SAA7134_GPIO_GPSTATUS3 0x1B7 + +/* I2S output */ +#define SAA7134_I2S_AUDIO_OUTPUT 0x1c0 + +/* test modes */ +#define SAA7134_SPECIAL_MODE 0x1d0 + +/* ------------------------------------------------------------------ */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ + diff -Nru a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/saa7134/saa7134-ts.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,453 @@ +/* + * device driver for philips saa7134 based TV cards + * video4linux video interface + * + * (c) 2001,02 Gerd Knorr [SuSE Labs] + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define __NO_VERSION__ 1 + +#include +#include +#include +#include +#include + +#include "saa7134-reg.h" +#include "saa7134.h" + +/* ------------------------------------------------------------------ */ + +static unsigned int ts_debug = 0; +MODULE_PARM(ts_debug,"i"); +MODULE_PARM_DESC(ts_debug,"enable debug messages [ts]"); + +static unsigned int tsbufs = 4; +MODULE_PARM(tsbufs,"i"); +MODULE_PARM_DESC(tsbufs,"number of ts buffers, range 2-32"); + +#define TS_PACKET_SIZE 188 /* TS packets 188 bytes */ +#define TS_NR_PACKETS 312 + +#define dprintk(fmt, arg...) if (ts_debug) \ + printk(KERN_DEBUG "%s/ts: " fmt, dev->name, ## arg) + +/* ------------------------------------------------------------------ */ + +static int buffer_activate(struct saa7134_dev *dev, + struct saa7134_buf *buf, + struct saa7134_buf *next) +{ + unsigned long control,status; + + dprintk("buffer_activate [%p]\n",buf); + buf->vb.state = STATE_ACTIVE; + + /* dma: setup channel 5 (= TS) */ + control = SAA7134_RS_CONTROL_BURST_16 | + SAA7134_RS_CONTROL_ME | + (buf->pt->dma >> 12); + + status = saa_readl(SAA7134_IRQ_STATUS); + if (0 == (status & 0x100000)) { + saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(buf)); + saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(next)); + } else { + saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next)); + saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf)); + } + saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE); + saa_writel(SAA7134_RS_CONTROL(5),control); + + /* start DMA */ + saa7134_set_dmabits(dev); + + mod_timer(&dev->ts_q.timeout, jiffies+BUFFER_TIMEOUT); + return 0; +} + +static int buffer_prepare(struct file *file, struct videobuf_buffer *vb) +{ + struct saa7134_dev *dev = file->private_data; + struct saa7134_buf *buf = (struct saa7134_buf *)vb; + int lines, llength, size, err; + + llength = TS_PACKET_SIZE; + lines = TS_NR_PACKETS; + + size = lines * llength; + if (0 != buf->vb.baddr && buf->vb.bsize < size) + return -EINVAL; + + if (buf->vb.size != size) { + saa7134_dma_free(dev,buf); + } + + if (STATE_NEEDS_INIT == buf->vb.state) { + buf->vb.width = llength; + buf->vb.height = lines; + buf->vb.size = size; + buf->pt = &dev->ts.pt_ts; + + err = videobuf_iolock(dev->pci,&buf->vb); + if (err) + goto oops; + err = saa7134_pgtable_build(dev->pci,buf->pt, + buf->vb.dma.sglist, + buf->vb.dma.sglen, + saa7134_buffer_startpage(buf)); + if (err) + goto oops; + } + buf->vb.state = STATE_PREPARED; + buf->top_seen = 0; + buf->activate = buffer_activate; + buf->vb.field = V4L2_FIELD_SEQ_TB; + return 0; + + oops: + saa7134_dma_free(dev,buf); + return err; +} + +static int +buffer_setup(struct file *file, int *count, int *size) +{ + *size = TS_PACKET_SIZE * TS_NR_PACKETS; + if (0 == *count) + *count = tsbufs; + *count = saa7134_buffer_count(*size,*count); + return 0; +} + +static void buffer_queue(struct file *file, struct videobuf_buffer *vb) +{ + struct saa7134_dev *dev = file->private_data; + struct saa7134_buf *buf = (struct saa7134_buf *)vb; + + saa7134_buffer_queue(dev,&dev->ts_q,buf); +} + +static void buffer_release(struct file *file, struct videobuf_buffer *vb) +{ + struct saa7134_dev *dev = file->private_data; + struct saa7134_buf *buf = (struct saa7134_buf *)vb; + + saa7134_dma_free(dev,buf); +} + +static struct videobuf_queue_ops ts_qops = { + buf_setup: buffer_setup, + buf_prepare: buffer_prepare, + buf_queue: buffer_queue, + buf_release: buffer_release, +}; + +/* ------------------------------------------------------------------ */ + +static int ts_open(struct inode *inode, struct file *file) +{ + unsigned int minor = minor(inode->i_rdev); + struct saa7134_dev *h,*dev = NULL; + struct list_head *list; + int err; + + list_for_each(list,&saa7134_devlist) { + h = list_entry(list, struct saa7134_dev, devlist); + if (h->ts_dev.minor == minor) + dev = h; + } + if (NULL == dev) + return -ENODEV; + + dprintk("open minor=%d\n",minor); + down(&dev->ts.ts.lock); + err = -EBUSY; + if (dev->ts.users) + goto done; + + dev->ts.users++; + file->private_data = dev; + err = 0; + done: + up(&dev->ts.ts.lock); + return err; +} + +static int ts_release(struct inode *inode, struct file *file) +{ + struct saa7134_dev *dev = file->private_data; + + if (dev->ts.ts.streaming) + videobuf_streamoff(file,&dev->ts.ts); + down(&dev->ts.ts.lock); + if (dev->ts.ts.reading) + videobuf_read_stop(file,&dev->ts.ts); + dev->ts.users--; + up(&dev->ts.ts.lock); + return 0; +} + +static ssize_t +ts_read(struct file *file, char *data, size_t count, loff_t *ppos) +{ + struct saa7134_dev *dev = file->private_data; + + return videobuf_read_stream(file, &dev->ts.ts, data, count, ppos, 0); +} + +static unsigned int +ts_poll(struct file *file, struct poll_table_struct *wait) +{ + struct saa7134_dev *dev = file->private_data; + + return videobuf_poll_stream(file, &dev->ts.ts, wait); +} + + +static int +ts_mmap(struct file *file, struct vm_area_struct * vma) +{ + struct saa7134_dev *dev = file->private_data; + + return videobuf_mmap_mapper(vma, &dev->ts.ts); +} + +/* + * This function is _not_ called directly, but from + * video_generic_ioctl (and maybe others). userspace + * copying is done already, arg is a kernel pointer. + */ +static int ts_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct saa7134_dev *dev = file->private_data; + + if (ts_debug > 1) + saa7134_print_ioctl(dev->name,cmd); + switch (cmd) { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *cap = arg; + + memset(cap,0,sizeof(*cap)); + strcpy(cap->driver, "saa7134"); + strncpy(cap->card, saa7134_boards[dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info,"PCI:%s",dev->pci->slot_name); + cap->version = SAA7134_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + return 0; + } + + /* --- input switching --------------------------------------- */ + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *i = arg; + + if (i->index != 0) + return -EINVAL; + i->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(i->name,"CCIR656"); + return 0; + } + case VIDIOC_G_INPUT: + { + int *i = arg; + *i = 0; + return 0; + } + case VIDIOC_S_INPUT: + { + int *i = arg; + + if (*i != 0) + return -EINVAL; + return 0; + } + /* --- capture ioctls ---------------------------------------- */ + + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc *f = arg; + int index; + + index = f->index; + if (index != 0) + return -EINVAL; + + memset(f,0,sizeof(*f)); + f->index = index; + strncpy(f->description, "MPEG TS", 31); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + f->pixelformat = V4L2_PIX_FMT_MPEG; + return 0; + } + + case VIDIOC_G_FMT: + { + struct v4l2_format *f = arg; + + memset(f,0,sizeof(*f)); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + /* FIXME: translate subsampling type EMPRESS into + * width/height: */ + f->fmt.pix.width = 720; /* D1 */ + f->fmt.pix.height = 576; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.sizeimage = TS_PACKET_SIZE*TS_NR_PACKETS; + return 0; + } + + case VIDIOC_S_FMT: + { + struct v4l2_format *f = arg; + + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + /* + FIXME: translate and round width/height into EMPRESS + subsample type: + + type | PAL | NTSC + --------------------------- + SIF | 352x288 | 352x240 + 1/2 D1 | 352x576 | 352x480 + 2/3 D1 | 480x576 | 480x480 + D1 | 720x576 | 720x480 + */ + + f->fmt.pix.width = 720; /* D1 */ + f->fmt.pix.height = 576; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.sizeimage = TS_PACKET_SIZE*TS_NR_PACKETS; + } + + case VIDIOC_REQBUFS: + return videobuf_reqbufs(file,&dev->ts.ts,arg); + + case VIDIOC_QUERYBUF: + return videobuf_querybuf(&dev->ts.ts,arg); + + case VIDIOC_QBUF: + return videobuf_qbuf(file,&dev->ts.ts,arg); + + case VIDIOC_DQBUF: + return videobuf_dqbuf(file,&dev->ts.ts,arg); + + case VIDIOC_STREAMON: + return videobuf_streamon(file,&dev->ts.ts); + + case VIDIOC_STREAMOFF: + return videobuf_streamoff(file,&dev->ts.ts); + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static int ts_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return video_usercopy(inode, file, cmd, arg, ts_do_ioctl); +} + + +static struct file_operations ts_fops = +{ + owner: THIS_MODULE, + open: ts_open, + release: ts_release, + read: ts_read, + poll: ts_poll, + mmap: ts_mmap, + ioctl: ts_ioctl, + llseek: no_llseek, +}; + + +/* ----------------------------------------------------------- */ +/* exported stuff */ + +struct video_device saa7134_ts_template = +{ + name: "saa7134-ts", + type: 0 /* FIXME */, + type2: 0 /* FIXME */, + hardware: 0, + fops: &ts_fops, + minor: -1, +}; + +int saa7134_ts_init(struct saa7134_dev *dev) +{ + /* sanitycheck insmod options */ + if (tsbufs < 2) + tsbufs = 2; + if (tsbufs > VIDEO_MAX_FRAME) + tsbufs = VIDEO_MAX_FRAME; + + INIT_LIST_HEAD(&dev->ts_q.queue); + dev->ts_q.timeout.function = saa7134_buffer_timeout; + dev->ts_q.timeout.data = (unsigned long)(&dev->ts_q); + dev->ts_q.dev = dev; + videobuf_queue_init(&dev->ts.ts, &ts_qops, dev->pci, &dev->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + sizeof(struct saa7134_buf)); + saa7134_pgtable_alloc(dev->pci,&dev->ts.pt_ts); + + /* init TS hw */ + saa_writeb(SAA7134_TS_SERIAL1, 0x00); /* deactivate TS softreset */ + saa_writeb(SAA7134_TS_PARALLEL, 0xec); /* TSSOP high active, TSVAL high active, TSLOCK ignored */ + saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1)); + saa_writeb(SAA7134_TS_DMA0, ((TS_NR_PACKETS-1)&0xff)); + saa_writeb(SAA7134_TS_DMA1, (((TS_NR_PACKETS-1)>>8)&0xff)); + saa_writeb(SAA7134_TS_DMA2, ((((TS_NR_PACKETS-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */ + + return 0; +} + +int saa7134_ts_fini(struct saa7134_dev *dev) +{ + /* nothing */ + saa7134_pgtable_free(dev->pci,&dev->ts.pt_ts); + return 0; +} + + +void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status) +{ + spin_lock(&dev->slock); + if (dev->ts_q.curr) { + saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE); + } + saa7134_buffer_next(dev,&dev->ts_q); + spin_unlock(&dev->slock); +} + +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,552 @@ +/* + * device driver for philips saa7134 based TV cards + * tv audio decoder (fm stereo, nicam, ...) + * + * (c) 2001,02 Gerd Knorr [SuSE Labs] + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define __NO_VERSION__ 1 + +#include +#include +#include +#include +#include +#include +#include + +#include "saa7134-reg.h" +#include "saa7134.h" + +/* ------------------------------------------------------------------ */ + +static unsigned int audio_debug = 0; +MODULE_PARM(audio_debug,"i"); +MODULE_PARM_DESC(audio_debug,"enable debug messages [tv audio]"); + +#define dprintk(fmt, arg...) if (audio_debug) \ + printk(KERN_DEBUG "%s/audio: " fmt, dev->name, ## arg) + +#define print_regb(reg) printk("%s: reg 0x%03x [%-16s]: 0x%02x\n", \ + dev->name,(SAA7134_##reg),(#reg),saa_readb((SAA7134_##reg))) + +/* ------------------------------------------------------------------ */ + +static struct saa7134_tvaudio tvaudio[] = { + { + name: "PAL-B/G FM-stereo", + std: V4L2_STD_PAL, + mode: TVAUDIO_FM_BG_STEREO, + carr1: 5500, + carr2: 5742, + },{ + name: "PAL-D/K1 FM-stereo", + std: V4L2_STD_PAL, + carr1: 6500, + carr2: 6258, + mode: TVAUDIO_FM_BG_STEREO, + },{ + name: "PAL-D/K2 FM-stereo", + std: V4L2_STD_PAL, + carr1: 6500, + carr2: 6742, + mode: TVAUDIO_FM_BG_STEREO, + },{ + name: "PAL-D/K3 FM-stereo", + std: V4L2_STD_PAL, + carr1: 6500, + carr2: 5742, + mode: TVAUDIO_FM_BG_STEREO, + },{ + name: "PAL-B/G NICAM", + std: V4L2_STD_PAL, + carr1: 5500, + carr2: 5850, + mode: TVAUDIO_NICAM_FM, + },{ + name: "PAL-I NICAM", + std: V4L2_STD_PAL, + carr1: 6000, + carr2: 6552, + mode: TVAUDIO_NICAM_FM, + },{ + name: "PAL-D/K NICAM", + std: V4L2_STD_PAL, + carr1: 6500, + carr2: 5850, + mode: TVAUDIO_NICAM_FM, + },{ + name: "SECAM-L NICAM", + std: V4L2_STD_SECAM, + carr1: 6500, + carr2: 5850, + mode: TVAUDIO_NICAM_AM, + },{ + name: "NTSC-M", + std: V4L2_STD_NTSC, + carr1: 4500, + carr2: -1, + mode: TVAUDIO_FM_MONO, + },{ + name: "NTSC-A2 FM-stereo", + std: V4L2_STD_NTSC, + carr1: 4500, + carr2: 4724, + mode: TVAUDIO_FM_K_STEREO, + } +}; +#define TVAUDIO (sizeof(tvaudio)/sizeof(struct saa7134_tvaudio)) + +/* ------------------------------------------------------------------ */ + +static void tvaudio_init(struct saa7134_dev *dev) +{ + int clock = saa7134_boards[dev->board].audio_clock; + + /* init all audio registers */ + saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x00); + + saa_writeb(SAA7134_AUDIO_CLOCK0, clock & 0xff); + saa_writeb(SAA7134_AUDIO_CLOCK1, (clock >> 8) & 0xff); + saa_writeb(SAA7134_AUDIO_CLOCK2, (clock >> 16) & 0xff); + saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x01); + + saa_writeb(SAA7134_NICAM_ERROR_LOW, 0x14); + saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50); + saa_writeb(SAA7134_MONITOR_SELECT, 0xa0); + saa_writeb(SAA7134_FM_DEMATRIX, 0x80); +} + +static __u32 tvaudio_carr2reg(__u32 carrier) +{ + __u64 a = carrier; + + a <<= 24; + do_div(a,12288); + return a; +} + +static void tvaudio_setcarrier(struct saa7134_dev *dev, + int primary, int secondary) +{ + if (-1 == secondary) + secondary = primary; + saa_writel(SAA7134_CARRIER1_FREQ0 >> 2, tvaudio_carr2reg(primary)); + saa_writel(SAA7134_CARRIER2_FREQ0 >> 2, tvaudio_carr2reg(secondary)); +} + +static void saa7134_tvaudio_do_mute_input(struct saa7134_dev *dev) +{ + int mute; + struct saa7134_input *in; + int reg = 0; + int mask; + + /* look what is to do ... */ + in = dev->input; + mute = (dev->ctl_mute || dev->automute); + if (!card_has_audio(dev) && card(dev).mute.name) { + /* 7130 - we'll mute using some unconnected audio input */ + if (mute) + in = &card(dev).mute; + } + if (dev->hw_mute == mute && + dev->hw_input == in) + return; + +#if 1 + dprintk("ctl_mute=%d automute=%d input=%s => mute=%d input=%s\n", + dev->ctl_mute,dev->automute,dev->input->name,mute,in->name); +#endif + dev->hw_mute = mute; + dev->hw_input = in; + + if (card_has_audio(dev)) + /* 7134 mute */ + saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ? 0xff : 0xbb); + + /* switch internal audio mux */ + switch (in->amux) { + case TV: reg = 0x02; break; + case LINE1: reg = 0x00; break; + case LINE2: reg = 0x01; break; + } + saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, reg); + + /* switch gpio-connected external audio mux */ + if (0 == card(dev).gpiomask) + return; + mask = card(dev).gpiomask; + saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask); + saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio); + saa7134_track_gpio(dev,in->name); +} + +void saa7134_tvaudio_setmute(struct saa7134_dev *dev) +{ + saa7134_tvaudio_do_mute_input(dev); +} + +void saa7134_tvaudio_setinput(struct saa7134_dev *dev, + struct saa7134_input *in) +{ + dev->input = in; + saa7134_tvaudio_do_mute_input(dev); +} + +void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level) +{ + saa_writeb(SAA7134_CHANNEL1_LEVEL, level & 0x1f); + saa_writeb(SAA7134_CHANNEL2_LEVEL, level & 0x1f); + saa_writeb(SAA7134_NICAM_LEVEL_ADJUST, level & 0x1f); +} + +static void tvaudio_setmode(struct saa7134_dev *dev, + struct saa7134_tvaudio *audio, + char *note) +{ + if (note) + dprintk("tvaudio_setmode: %s %s [%d.%03d/%d.%03d MHz]\n", + note,audio->name, + audio->carr1 / 1000, audio->carr1 % 1000, + audio->carr2 / 1000, audio->carr2 % 1000); + + if (dev->tvnorm->id == V4L2_STD_NTSC) { + saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD0, 0xde); + saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD1, 0x15); + saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD2, 0x02); + } else { + saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD0, 0x00); + saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD1, 0x80); + saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD2, 0x02); + } + tvaudio_setcarrier(dev,audio->carr1,audio->carr2); + + switch (audio->mode) { + case TVAUDIO_FM_MONO: + case TVAUDIO_FM_BG_STEREO: + saa_writeb(SAA7134_DEMODULATOR, 0x00); + saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00); + saa_writeb(SAA7134_FM_DEEMPHASIS, 0x22); + saa_writeb(SAA7134_FM_DEMATRIX, 0x80); + saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa0); + break; + case TVAUDIO_FM_K_STEREO: + saa_writeb(SAA7134_DEMODULATOR, 0x00); + saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x01); + saa_writeb(SAA7134_FM_DEEMPHASIS, 0x22); + saa_writeb(SAA7134_FM_DEMATRIX, 0x80); + saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa0); + break; + case TVAUDIO_NICAM_FM: + saa_writeb(SAA7134_DEMODULATOR, 0x10); + saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00); + saa_writeb(SAA7134_FM_DEEMPHASIS, 0x44); + saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa1); + break; + case TVAUDIO_NICAM_AM: + saa_writeb(SAA7134_DEMODULATOR, 0x12); + saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00); + saa_writeb(SAA7134_FM_DEEMPHASIS, 0x44); + saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa1); + break; + case TVAUDIO_FM_SAT_STEREO: + /* not implemented (yet) */ + break; + } + saa_writel(0x174 >> 2, 0x0001e000); /* FIXME */ +} + +int saa7134_tvaudio_getstereo(struct saa7134_dev *dev, + struct saa7134_tvaudio *audio) +{ + __u32 idp,nicam; + int retval = -1; + + switch (audio->mode) { + case TVAUDIO_FM_MONO: + return V4L2_TUNER_SUB_MONO; + case TVAUDIO_FM_K_STEREO: + case TVAUDIO_FM_BG_STEREO: + idp = (saa_readb(SAA7134_IDENT_SIF) & 0xe0) >> 5; + if (0x03 == (idp & 0x03)) + retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + else if (0x05 == (idp & 0x05)) + retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + else if (0x01 == (idp & 0x01)) + retval = V4L2_TUNER_SUB_MONO; + break; + case TVAUDIO_FM_SAT_STEREO: + /* not implemented (yet) */ + break; + case TVAUDIO_NICAM_FM: + case TVAUDIO_NICAM_AM: + nicam = saa_readb(SAA7134_NICAM_STATUS); + switch (nicam & 0x0b) { + case 0x08: + retval = V4L2_TUNER_SUB_MONO; + break; + case 0x09: + retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + break; + case 0x0a: + retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + break; + } + break; + } + if (retval != -1) + dprintk("found audio subchannels:%s%s%s%s\n", + (retval & V4L2_TUNER_SUB_MONO) ? " mono" : "", + (retval & V4L2_TUNER_SUB_STEREO) ? " stereo" : "", + (retval & V4L2_TUNER_SUB_LANG1) ? " lang1" : "", + (retval & V4L2_TUNER_SUB_LANG2) ? " lang2" : ""); + return retval; +} + +static int tvaudio_sleep(struct saa7134_dev *dev, int timeout) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&dev->thread.wq, &wait); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(timeout); + remove_wait_queue(&dev->thread.wq, &wait); + return dev->thread.scan1 != dev->thread.scan2; +} + +static int tvaudio_checkcarrier(struct saa7134_dev *dev, int carrier) +{ + __s32 left,right,value; + + tvaudio_setcarrier(dev,carrier-100,carrier-100); + if (tvaudio_sleep(dev,HZ/10)) + return -1; + left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); + if (tvaudio_sleep(dev,HZ/10)) + return -1; + left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); + + tvaudio_setcarrier(dev,carrier+100,carrier+100); + if (tvaudio_sleep(dev,HZ/10)) + return -1; + right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); + if (tvaudio_sleep(dev,HZ/10)) + return -1; + right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); + + left >>= 16; + right >>= 16; + value = left > right ? left - right : right - left; + dprintk("scanning %d.%03d MHz => dc is %5d [%d/%d]\n", + carrier/1000,carrier%1000,value,left,right); + return value; +} + +static void sifdebug_dump_regs(struct saa7134_dev *dev) +{ + print_regb(AUDIO_STATUS); + print_regb(IDENT_SIF); + print_regb(LEVEL_READOUT1); + print_regb(LEVEL_READOUT2); + print_regb(DCXO_IDENT_CTRL); + print_regb(DEMODULATOR); + print_regb(AGC_GAIN_SELECT); + print_regb(MONITOR_SELECT); + print_regb(FM_DEEMPHASIS); + print_regb(FM_DEMATRIX); + print_regb(SIF_SAMPLE_FREQ); + print_regb(ANALOG_IO_SELECT); +} + +static int tvaudio_thread(void *data) +{ +#define MAX_SCAN 4 + static const int carr_pal[MAX_SCAN] = { 5500, 6000, 6500 }; + static const int carr_ntsc[MAX_SCAN] = { 4500 }; + static const int carr_secam[MAX_SCAN] = { 6500 }; + static const int carr_default[MAX_SCAN] = { 4500, 5500, 6000, 6500 }; + struct saa7134_dev *dev = data; + const int *carr_scan; + int carr_vals[4]; + int i,max,carrier,audio; + + lock_kernel(); + daemonize(); + sigfillset(¤t->blocked); + sprintf(current->comm, "%s", dev->name); + dev->thread.task = current; + unlock_kernel(); + if (dev->thread.notify != NULL) + up(dev->thread.notify); + + for (;;) { + if (dev->thread.exit || signal_pending(current)) + goto done; + interruptible_sleep_on(&dev->thread.wq); + if (dev->thread.exit || signal_pending(current)) + goto done; + + restart: + dev->thread.scan1 = dev->thread.scan2; + dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1); + dev->tvaudio = NULL; + tvaudio_init(dev); + dev->automute = 1; + saa7134_tvaudio_setmute(dev); + + /* give the tuner some time */ + if (tvaudio_sleep(dev,HZ/2)) + goto restart; + + /* find the main carrier */ + carr_scan = carr_default; + if (dev->tvnorm->id & V4L2_STD_PAL) + carr_scan = carr_pal; + if (dev->tvnorm->id & V4L2_STD_NTSC) + carr_scan = carr_ntsc; + if (dev->tvnorm->id & V4L2_STD_SECAM) + carr_scan = carr_secam; + saa_writeb(SAA7134_MONITOR_SELECT,0x00); + tvaudio_setmode(dev,&tvaudio[0],NULL); + for (i = 0; i < MAX_SCAN; i++) { + if (!carr_scan[i]) + continue; + carr_vals[i] = tvaudio_checkcarrier(dev,carr_scan[i]); + if (dev->thread.scan1 != dev->thread.scan2) + goto restart; + } + for (carrier = 0, max = 0, i = 0; i < MAX_SCAN; i++) { + if (!carr_scan[i]) + continue; + if (max < carr_vals[i]) { + max = carr_vals[i]; + carrier = carr_scan[i]; + } + } + if (0 == carrier) { + /* Oops: autoscan didn't work for some reason :-/ */ + printk("%s/audio: oops: audio carrier scan failed\n", + dev->name); + sifdebug_dump_regs(dev); + } else { + dprintk("found %s main sound carrier @ %d.%03d MHz\n", + dev->tvnorm->name, + carrier/1000,carrier%1000); + } + tvaudio_setcarrier(dev,carrier,carrier); + dev->automute = 0; + saa7134_tvaudio_setmute(dev); + + /* find the exact tv audio norm */ + for (audio = -1, i = 0; i < TVAUDIO; i++) { + if (dev->tvnorm->id != -1 && + dev->tvnorm->id != tvaudio[i].std) + continue; + if (tvaudio[i].carr1 != carrier) + continue; + + if (-1 == audio) + audio = i; + tvaudio_setmode(dev,&tvaudio[i],"trying"); + if (tvaudio_sleep(dev,HZ)) + goto restart; + if (-1 != saa7134_tvaudio_getstereo(dev,&tvaudio[i])) { + audio = i; + break; + } + } + if (-1 == audio) + continue; + tvaudio_setmode(dev,&tvaudio[audio],"using"); + dev->tvaudio = &tvaudio[audio]; + +#if 1 + if (tvaudio_sleep(dev,3*HZ)) + goto restart; + saa7134_tvaudio_getstereo(dev,&tvaudio[i]); +#endif + } + + done: + dev->thread.task = NULL; + if(dev->thread.notify != NULL) + up(dev->thread.notify); + return 0; +} + +/* ------------------------------------------------------------------ */ + +int saa7134_tvaudio_init(struct saa7134_dev *dev) +{ + DECLARE_MUTEX_LOCKED(sem); + + /* enable I2S audio output */ + if (saa7134_boards[dev->board].i2s_rate) { + int rate = (32000 == saa7134_boards[dev->board].i2s_rate) ? 0x01 : 0x03; + + /* set rate */ + saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate); + + /* enable I2S output */ + saa_writeb(SAA7134_DSP_OUTPUT_SELECT, 0x80); + saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80); + saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, 0x01); + saa_writeb(SAA7134_I2S_OUTPUT_LEVEL, 0x00); + saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x01); + } + + /* start tvaudio thread */ + init_waitqueue_head(&dev->thread.wq); + dev->thread.notify = &sem; + kernel_thread(tvaudio_thread,dev,0); + down(&sem); + dev->thread.notify = NULL; + wake_up_interruptible(&dev->thread.wq); + + return 0; +} + +int saa7134_tvaudio_fini(struct saa7134_dev *dev) +{ + DECLARE_MUTEX_LOCKED(sem); + + /* shutdown tvaudio thread */ + if (dev->thread.task) { + dev->thread.notify = &sem; + dev->thread.exit = 1; + wake_up_interruptible(&dev->thread.wq); + down(&sem); + dev->thread.notify = NULL; + } + saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */ + return 0; +} + +int saa7134_tvaudio_do_scan(struct saa7134_dev *dev) +{ + dev->thread.scan2++; + wake_up_interruptible(&dev->thread.wq); + return 0; +} + +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/saa7134/saa7134-vbi.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,265 @@ +/* + * device driver for philips saa7134 based TV cards + * video4linux video interface + * + * (c) 2001,02 Gerd Knorr [SuSE Labs] + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define __NO_VERSION__ 1 + +#include +#include +#include +#include +#include + +#include "saa7134-reg.h" +#include "saa7134.h" + +/* ------------------------------------------------------------------ */ + +static unsigned int vbi_debug = 0; +MODULE_PARM(vbi_debug,"i"); +MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]"); + +static unsigned int vbibufs = 4; +MODULE_PARM(vbibufs,"i"); +MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32"); + +#define dprintk(fmt, arg...) if (vbi_debug) \ + printk(KERN_DEBUG "%s/vbi: " fmt, dev->name, ## arg) + +/* ------------------------------------------------------------------ */ + +#define VBI_LINE_COUNT 16 +#define VBI_LINE_LENGTH 2048 +#define VBI_SCALE 0x200 + +static void task_init(struct saa7134_dev *dev, struct saa7134_buf *buf, + int task) +{ + struct saa7134_tvnorm *norm = dev->tvnorm; + + /* setup video scaler */ + saa_writeb(SAA7134_VBI_H_START1(task), norm->h_start & 0xff); + saa_writeb(SAA7134_VBI_H_START2(task), norm->h_start >> 8); + saa_writeb(SAA7134_VBI_H_STOP1(task), norm->h_stop & 0xff); + saa_writeb(SAA7134_VBI_H_STOP2(task), norm->h_stop >> 8); + saa_writeb(SAA7134_VBI_V_START1(task), norm->vbi_v_start & 0xff); + saa_writeb(SAA7134_VBI_V_START2(task), norm->vbi_v_start >> 8); + saa_writeb(SAA7134_VBI_V_STOP1(task), norm->vbi_v_stop & 0xff); + saa_writeb(SAA7134_VBI_V_STOP2(task), norm->vbi_v_stop >> 8); + + saa_writeb(SAA7134_VBI_H_SCALE_INC1(task), VBI_SCALE & 0xff); + saa_writeb(SAA7134_VBI_H_SCALE_INC2(task), VBI_SCALE >> 8); + saa_writeb(SAA7134_VBI_PHASE_OFFSET_LUMA(task), 0x00); + saa_writeb(SAA7134_VBI_PHASE_OFFSET_CHROMA(task), 0x00); + + saa_writeb(SAA7134_VBI_H_LEN1(task), buf->vb.width & 0xff); + saa_writeb(SAA7134_VBI_H_LEN2(task), buf->vb.width >> 8); + saa_writeb(SAA7134_VBI_V_LEN1(task), buf->vb.height & 0xff); + saa_writeb(SAA7134_VBI_V_LEN2(task), buf->vb.height >> 8); + + saa_andorb(SAA7134_DATA_PATH(task), 0xc0, 0x00); +} + +/* ------------------------------------------------------------------ */ + +static int buffer_activate(struct saa7134_dev *dev, + struct saa7134_buf *buf, + struct saa7134_buf *next) +{ + unsigned long control,base; + + dprintk("buffer_activate [%p]\n",buf); + buf->vb.state = STATE_ACTIVE; + + task_init(dev,buf,TASK_A); + task_init(dev,buf,TASK_B); + saa_writeb(SAA7134_OFMT_DATA_A, 0x06); + saa_writeb(SAA7134_OFMT_DATA_B, 0x06); + + /* DMA: setup channel 2+3 (= VBI Task A+B) */ + base = saa7134_buffer_base(buf); + control = SAA7134_RS_CONTROL_BURST_16 | + SAA7134_RS_CONTROL_ME | + (buf->pt->dma >> 12); + saa_writel(SAA7134_RS_BA1(2),base); + saa_writel(SAA7134_RS_BA2(2),base + buf->vb.size/2); + saa_writel(SAA7134_RS_PITCH(2),buf->vb.width); + saa_writel(SAA7134_RS_CONTROL(2),control); + saa_writel(SAA7134_RS_BA1(3),base); + saa_writel(SAA7134_RS_BA2(3),base + buf->vb.size/2); + saa_writel(SAA7134_RS_PITCH(3),buf->vb.width); + saa_writel(SAA7134_RS_CONTROL(3),control); + + /* start DMA */ + saa7134_set_dmabits(dev); + mod_timer(&dev->vbi_q.timeout, jiffies+BUFFER_TIMEOUT); + + return 0; +} + +static int buffer_prepare(struct file *file, struct videobuf_buffer *vb) +{ + struct saa7134_fh *fh = file->private_data; + struct saa7134_dev *dev = fh->dev; + struct saa7134_buf *buf = (struct saa7134_buf *)vb; + struct saa7134_tvnorm *norm = dev->tvnorm; + int lines, llength, size, err; + + lines = norm->vbi_v_stop - norm->vbi_v_start +1; + if (lines > VBI_LINE_COUNT) + lines = VBI_LINE_COUNT; +#if 1 + llength = VBI_LINE_LENGTH; +#else + llength = (norm->h_stop - norm->h_start +1) * 2; + if (llength > VBI_LINE_LENGTH) + llength = VBI_LINE_LENGTH; +#endif + size = lines * llength * 2; + if (0 != buf->vb.baddr && buf->vb.bsize < size) + return -EINVAL; + + if (buf->vb.size != size) + saa7134_dma_free(dev,buf); + + if (STATE_NEEDS_INIT == buf->vb.state) { + buf->vb.width = llength; + buf->vb.height = lines; + buf->vb.size = size; + buf->pt = &fh->pt_vbi; + + err = videobuf_iolock(dev->pci,&buf->vb); + if (err) + goto oops; + err = saa7134_pgtable_build(dev->pci,buf->pt, + buf->vb.dma.sglist, + buf->vb.dma.sglen, + saa7134_buffer_startpage(buf)); + if (err) + goto oops; + } + buf->vb.state = STATE_PREPARED; + buf->top_seen = 0; + buf->activate = buffer_activate; + buf->vb.field = V4L2_FIELD_SEQ_TB; + return 0; + + oops: + saa7134_dma_free(dev,buf); + return err; +} + +static int +buffer_setup(struct file *file, int *count, int *size) +{ + struct saa7134_fh *fh = file->private_data; + struct saa7134_dev *dev = fh->dev; + int llength,lines; + + lines = dev->tvnorm->vbi_v_stop - dev->tvnorm->vbi_v_start +1; +#if 1 + llength = VBI_LINE_LENGTH; +#else + llength = (norm->h_stop - norm->h_start +1) * 2; + if (llength > VBI_LINE_LENGTH) + llength = VBI_LINE_LENGTH; +#endif + *size = lines * llength * 2; + if (0 == *count) + *count = vbibufs; + *count = saa7134_buffer_count(*size,*count); + return 0; +} + +static void buffer_queue(struct file *file, struct videobuf_buffer *vb) +{ + struct saa7134_fh *fh = file->private_data; + struct saa7134_dev *dev = fh->dev; + struct saa7134_buf *buf = (struct saa7134_buf *)vb; + + saa7134_buffer_queue(dev,&dev->vbi_q,buf); +} + +static void buffer_release(struct file *file, struct videobuf_buffer *vb) +{ + struct saa7134_fh *fh = file->private_data; + struct saa7134_dev *dev = fh->dev; + struct saa7134_buf *buf = (struct saa7134_buf *)vb; + + saa7134_dma_free(dev,buf); +} + +struct videobuf_queue_ops saa7134_vbi_qops = { + buf_setup: buffer_setup, + buf_prepare: buffer_prepare, + buf_queue: buffer_queue, + buf_release: buffer_release, +}; + +/* ------------------------------------------------------------------ */ + +int saa7134_vbi_init(struct saa7134_dev *dev) +{ + INIT_LIST_HEAD(&dev->vbi_q.queue); + dev->vbi_q.timeout.function = saa7134_buffer_timeout; + dev->vbi_q.timeout.data = (unsigned long)(&dev->vbi_q); + dev->vbi_q.dev = dev; + + if (vbibufs < 2) + vbibufs = 2; + if (vbibufs > VIDEO_MAX_FRAME) + vbibufs = VIDEO_MAX_FRAME; + return 0; +} + +int saa7134_vbi_fini(struct saa7134_dev *dev) +{ + /* nothing */ + return 0; +} + +void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status) +{ + spin_lock(&dev->slock); + if (dev->vbi_q.curr) { + dev->vbi_fieldcount++; + /* make sure we have seen both fields */ + if ((status & 0x10) == 0x10) { + dev->vbi_q.curr->top_seen = 1; + goto done; + } + if (!dev->vbi_q.curr->top_seen) + goto done; + + dev->vbi_q.curr->vb.field_count = dev->vbi_fieldcount; + saa7134_buffer_finish(dev,&dev->vbi_q,STATE_DONE); + } + saa7134_buffer_next(dev,&dev->vbi_q); + + done: + spin_unlock(&dev->slock); +} + +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/saa7134/saa7134-video.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,2035 @@ +/* + * device driver for philips saa7134 based TV cards + * video4linux video interface + * + * (c) 2001,02 Gerd Knorr [SuSE Labs] + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define __NO_VERSION__ 1 + +#include +#include +#include +#include +#include + +#include "saa7134-reg.h" +#include "saa7134.h" +#include "tuner.h" +#include "audiochip.h" + +/* ------------------------------------------------------------------ */ + +static unsigned int video_debug = 0; +static unsigned int gbuffers = 8; +static unsigned int gbufsize = 768*576*4; +static unsigned int gbufsize_max = 768*576*4; +MODULE_PARM(video_debug,"i"); +MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); +MODULE_PARM(gbuffers,"i"); +MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32"); + +#define dprintk(fmt, arg...) if (video_debug) \ + printk(KERN_DEBUG "%s/video: " fmt, dev->name, ## arg) + +/* ------------------------------------------------------------------ */ +/* data structs for video */ + +static int video_out[][9] = { + [CCIR656] = { 0x00, 0xb1, 0x00, 0xa1, 0x00, 0x04, 0x06, 0x00, 0x00 }, +}; + +static struct saa7134_format formats[] = { + { + name: "8 bpp gray", + fourcc: V4L2_PIX_FMT_GREY, + depth: 8, + pm: 0x06, + },{ + name: "15 bpp RGB, le", + fourcc: V4L2_PIX_FMT_RGB555, + depth: 16, + pm: 0x13 | 0x80, + },{ + name: "15 bpp RGB, be", + fourcc: V4L2_PIX_FMT_RGB555X, + depth: 16, + pm: 0x13 | 0x80, + bswap: 1, + },{ + name: "16 bpp RGB, le", + fourcc: V4L2_PIX_FMT_RGB565, + depth: 16, + pm: 0x10 | 0x80, + },{ + name: "16 bpp RGB, be", + fourcc: V4L2_PIX_FMT_RGB565X, + depth: 16, + pm: 0x10 | 0x80, + bswap: 1, + },{ + name: "24 bpp RGB, le", + fourcc: V4L2_PIX_FMT_BGR24, + depth: 24, + pm: 0x11, + },{ + name: "32 bpp RGB, le", + fourcc: V4L2_PIX_FMT_BGR32, + depth: 32, + pm: 0x12, + },{ + name: "32 bpp RGB, be", + fourcc: V4L2_PIX_FMT_RGB32, + depth: 32, + pm: 0x12, + bswap: 1, + wswap: 1, + },{ + name: "4:2:2 packed, YUYV", + fourcc: V4L2_PIX_FMT_YUYV, + depth: 16, + pm: 0x00, + bswap: 1, + yuv: 1, + },{ + name: "4:2:2 packed, UYVY", + fourcc: V4L2_PIX_FMT_UYVY, + depth: 16, + pm: 0x00, + yuv: 1, + },{ + name: "4:2:2 planar, Y-Cb-Cr", + fourcc: V4L2_PIX_FMT_YUV422P, + depth: 16, + pm: 0x09, + yuv: 1, + planar: 1, + hshift: 1, + vshift: 0, + },{ + name: "4:2:0 planar, Y-Cb-Cr", + fourcc: V4L2_PIX_FMT_YUV420, + depth: 12, + pm: 0x0a, + yuv: 1, + planar: 1, + hshift: 1, + vshift: 1, + } +}; +#define FORMATS (sizeof(formats)/sizeof(struct saa7134_format)) + + +static struct saa7134_tvnorm tvnorms[] = { + { + name: "PAL-BGHI", + id: V4L2_STD_PAL, + width: 720, + height: 576, + + sync_control: 0x18, + luma_control: 0x40, + chroma_ctrl1: 0x81, + chroma_gain: 0x2a, + chroma_ctrl2: 0x06, + + h_start: 0, + h_stop: 719, + video_v_start: 24, + video_v_stop: 311, + vbi_v_start: 7-3, /* FIXME */ + vbi_v_stop: 22-3, + },{ + name: "NTSC-M", + id: V4L2_STD_NTSC, + width: 720, + height: 480, + + sync_control: 0x59, + luma_control: 0x40, + chroma_ctrl1: 0x89, + chroma_gain: 0x2a, + chroma_ctrl2: 0x0e, + + h_start: 0, + h_stop: 719, + video_v_start: 22, + video_v_stop: 22+240, + vbi_v_start: 10, /* FIXME */ + vbi_v_stop: 21, /* FIXME */ + },{ + name: "SECAM", + id: V4L2_STD_SECAM, + width: 720, + height: 576, + + sync_control: 0x58, + luma_control: 0x1b, + chroma_ctrl1: 0xd1, + chroma_gain: 0x80, + chroma_ctrl2: 0x00, + + h_start: 0, + h_stop: 719, + video_v_start: 24, + video_v_stop: 311, + vbi_v_start: 7, + vbi_v_stop: 22, + },{ + name: "AUTO", + id: -1, + width: 768, + height: 576, + + sync_control: 0x98, + luma_control: 0x40, + chroma_ctrl1: 0x8b, + chroma_gain: 0x00, + chroma_ctrl2: 0x00, + + h_start: 0, + h_stop: 719, + video_v_start: 24, + video_v_stop: 311, + vbi_v_start: 7, + vbi_v_stop: 22, + } +}; +#define TVNORMS (sizeof(tvnorms)/sizeof(struct saa7134_tvnorm)) + + +#define V4L2_CID_PRIVATE_INVERT (V4L2_CID_PRIVATE_BASE + 0) +#define V4L2_CID_PRIVATE_Y_ODD (V4L2_CID_PRIVATE_BASE + 1) +#define V4L2_CID_PRIVATE_Y_EVEN (V4L2_CID_PRIVATE_BASE + 2) +#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 3) + +static const struct v4l2_queryctrl no_ctrl = { + name: "42", + flags: V4L2_CTRL_FLAG_DISABLED, +}; +static const struct v4l2_queryctrl video_ctrls[] = { + /* --- video --- */ + { + id: V4L2_CID_BRIGHTNESS, + name: "Brightness", + minimum: 0, + maximum: 255, + step: 1, + default_value: 128, + type: V4L2_CTRL_TYPE_INTEGER, + },{ + id: V4L2_CID_CONTRAST, + name: "Contrast", + minimum: 0, + maximum: 127, + step: 1, + default_value: 68, + type: V4L2_CTRL_TYPE_INTEGER, + },{ + id: V4L2_CID_SATURATION, + name: "Saturation", + minimum: 0, + maximum: 127, + step: 1, + default_value: 64, + type: V4L2_CTRL_TYPE_INTEGER, + },{ + id: V4L2_CID_HUE, + name: "Hue", + minimum: -128, + maximum: 127, + step: 1, + default_value: 0, + type: V4L2_CTRL_TYPE_INTEGER, + },{ + id: V4L2_CID_VFLIP, + name: "vertical flip", + minimum: 0, + maximum: 1, + type: V4L2_CTRL_TYPE_BOOLEAN, + }, + /* --- audio --- */ + { + id: V4L2_CID_AUDIO_MUTE, + name: "Mute", + minimum: 0, + maximum: 1, + type: V4L2_CTRL_TYPE_BOOLEAN, + },{ + id: V4L2_CID_AUDIO_VOLUME, + name: "Volume", + minimum: -15, + maximum: 15, + step: 1, + default_value: 0, + type: V4L2_CTRL_TYPE_INTEGER, + }, + /* --- private --- */ + { + id: V4L2_CID_PRIVATE_INVERT, + name: "Invert", + minimum: 0, + maximum: 1, + type: V4L2_CTRL_TYPE_BOOLEAN, + },{ + id: V4L2_CID_PRIVATE_Y_ODD, + name: "y offset odd field", + minimum: 0, + maximum: 128, + default_value: 0, + type: V4L2_CTRL_TYPE_INTEGER, + },{ + id: V4L2_CID_PRIVATE_Y_EVEN, + name: "y offset even field", + minimum: 0, + maximum: 128, + default_value: 0, + type: V4L2_CTRL_TYPE_INTEGER, + } +}; +const int CTRLS = (sizeof(video_ctrls)/sizeof(struct v4l2_queryctrl)); + +static const struct v4l2_queryctrl* ctrl_by_id(int id) +{ + int i; + + for (i = 0; i < CTRLS; i++) + if (video_ctrls[i].id == id) + return video_ctrls+i; + return NULL; +} + +static struct saa7134_format* format_by_fourcc(int fourcc) +{ + int i; + + for (i = 0; i < FORMATS; i++) + if (formats[i].fourcc == fourcc) + return formats+i; + return NULL; +} + +/* ----------------------------------------------------------------------- */ +/* resource management */ + +static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, int bit) +{ + if (fh->resources & bit) + /* have it already allocated */ + return 1; + + /* is it free? */ + down(&dev->lock); + if (dev->resources & bit) { + /* no, someone else uses it */ + up(&dev->lock); + return 0; + } + /* it's free, grab it */ + fh->resources |= bit; + dev->resources |= bit; + dprintk("res: get %d\n",bit); + up(&dev->lock); + return 1; +} + +static +int res_check(struct saa7134_fh *fh, int bit) +{ + return (fh->resources & bit); +} + +static +int res_locked(struct saa7134_dev *dev, int bit) +{ + return (dev->resources & bit); +} + +static +void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, int bits) +{ + if ((fh->resources & bits) != bits) + BUG(); + + down(&dev->lock); + fh->resources &= ~bits; + dev->resources &= ~bits; + dprintk("res: put %d\n",bits); + up(&dev->lock); +} + +/* ------------------------------------------------------------------ */ + +static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) +{ + struct video_channel c; + int luma_control,mux; + + dprintk("set tv norm = %s\n",norm->name); + dev->tvnorm = norm; + + mux = card_in(dev,dev->ctl_input).vmux; + luma_control = norm->luma_control; + if (mux > 5) + luma_control |= 0x80; /* svideo */ + + /* setup video decoder */ + saa_writeb(SAA7134_INCR_DELAY, 0x08); + saa_writeb(SAA7134_ANALOG_IN_CTRL1, 0xc0 | mux); + saa_writeb(SAA7134_ANALOG_IN_CTRL2, 0x00); + + saa_writeb(SAA7134_ANALOG_IN_CTRL3, 0x90); + saa_writeb(SAA7134_ANALOG_IN_CTRL4, 0x90); + saa_writeb(SAA7134_HSYNC_START, 0xeb); + saa_writeb(SAA7134_HSYNC_STOP, 0xe0); + + saa_writeb(SAA7134_SYNC_CTRL, norm->sync_control); + saa_writeb(SAA7134_LUMA_CTRL, luma_control); + saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); + saa_writeb(SAA7134_DEC_LUMA_CONTRAST, dev->ctl_contrast); + + saa_writeb(SAA7134_DEC_CHROMA_SATURATION, dev->ctl_saturation); + saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); + saa_writeb(SAA7134_CHROMA_CTRL1, norm->chroma_ctrl1); + saa_writeb(SAA7134_CHROMA_GAIN, norm->chroma_gain); + + saa_writeb(SAA7134_CHROMA_CTRL2, norm->chroma_ctrl2); + saa_writeb(SAA7134_MODE_DELAY_CTRL, 0x00); + + saa_writeb(SAA7134_ANALOG_ADC, 0x01); + saa_writeb(SAA7134_VGATE_START, 0x11); + saa_writeb(SAA7134_VGATE_STOP, 0xfe); + saa_writeb(SAA7134_MISC_VGATE_MSB, 0x18); /* FIXME */ + saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40); + saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80); + + /* pass down info to the i2c chips (v4l1) */ + memset(&c,0,sizeof(c)); + c.channel = dev->ctl_input; + c.norm = VIDEO_MODE_PAL; + if (norm->id & V4L2_STD_NTSC) + c.norm = VIDEO_MODE_NTSC; + if (norm->id & V4L2_STD_SECAM) + c.norm = VIDEO_MODE_SECAM; + saa7134_i2c_call_clients(dev,VIDIOCSCHAN,&c); +} + +static void video_mux(struct saa7134_dev *dev, int input) +{ + dprintk("video input = %d [%s]\n",input,card_in(dev,input).name); + dev->ctl_input = input; + set_tvnorm(dev,dev->tvnorm); + saa7134_tvaudio_setinput(dev,&card_in(dev,input)); +} + +static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale) +{ + static const struct { + int xpsc; + int xacl; + int xc2_1; + int xdcg; + int vpfy; + } vals[] = { + /* XPSC XACL XC2_1 XDCG VPFY */ + { 1, 0, 0, 0, 0 }, + { 2, 2, 1, 2, 2 }, + { 3, 4, 1, 3, 2 }, + { 4, 8, 1, 4, 2 }, + { 5, 8, 1, 4, 2 }, + { 6, 8, 1, 4, 3 }, + { 7, 8, 1, 4, 3 }, + { 8, 15, 0, 4, 3 }, + { 9, 15, 0, 4, 3 }, + { 10, 16, 1, 5, 3 }, + }; + static const int count = sizeof(vals)/sizeof(vals[0]); + int i; + + for (i = 0; i < count; i++) + if (vals[i].xpsc == prescale) + break; + if (i == count) + return; + + saa_writeb(SAA7134_H_PRESCALE(task), vals[i].xpsc); + saa_writeb(SAA7134_ACC_LENGTH(task), vals[i].xacl); + saa_writeb(SAA7134_LEVEL_CTRL(task), + (vals[i].xc2_1 << 3) | (vals[i].xdcg)); + saa_andorb(SAA7134_FIR_PREFILTER_CTRL(task), 0x0f, + (vals[i].vpfy << 2) | vals[i].vpfy); +} + +static void set_v_scale(struct saa7134_dev *dev, int task, int yscale) +{ + int val,mirror; + + saa_writeb(SAA7134_V_SCALE_RATIO1(task), yscale & 0xff); + saa_writeb(SAA7134_V_SCALE_RATIO2(task), yscale >> 8); + + mirror = (dev->ctl_mirror) ? 0x02 : 0x00; + if (yscale < 2048) { + /* LPI */ + dprintk("yscale LPI yscale=%d\n",yscale); + saa_writeb(SAA7134_V_FILTER(task), 0x00 | mirror); + saa_writeb(SAA7134_LUMA_CONTRAST(task), 0x40); + saa_writeb(SAA7134_CHROMA_SATURATION(task), 0x40); + } else { + /* ACM */ + val = 0x40 * 1024 / yscale; + dprintk("yscale ACM yscale=%d val=0x%x\n",yscale,val); + saa_writeb(SAA7134_V_FILTER(task), 0x01 | mirror); + saa_writeb(SAA7134_LUMA_CONTRAST(task), val); + saa_writeb(SAA7134_CHROMA_SATURATION(task), val); + } + saa_writeb(SAA7134_LUMA_BRIGHT(task), 0x80); +} + +static void set_size(struct saa7134_dev *dev, int task, + int width, int height, int interlace) +{ + struct saa7134_tvnorm *norm = dev->tvnorm; + int prescale,xscale,yscale,y_even,y_odd; + int div = interlace ? 2 : 1; + + /* setup video scaler */ + saa_writeb(SAA7134_VIDEO_H_START1(task), norm->h_start & 0xff); + saa_writeb(SAA7134_VIDEO_H_START2(task), norm->h_start >> 8); + saa_writeb(SAA7134_VIDEO_H_STOP1(task), norm->h_stop & 0xff); + saa_writeb(SAA7134_VIDEO_H_STOP2(task), norm->h_stop >> 8); + saa_writeb(SAA7134_VIDEO_V_START1(task), norm->video_v_start & 0xff); + saa_writeb(SAA7134_VIDEO_V_START2(task), norm->video_v_start >> 8); + saa_writeb(SAA7134_VIDEO_V_STOP1(task), norm->video_v_stop & 0xff); + saa_writeb(SAA7134_VIDEO_V_STOP2(task), norm->video_v_stop >> 8); + + prescale = norm->width / width; + if (0 == prescale) + prescale = 1; + xscale = 1024 * norm->width / prescale / width; + yscale = 512 * div * norm->height / height; + dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale); + set_h_prescale(dev,task,prescale); + saa_writeb(SAA7134_H_SCALE_INC1(task), xscale & 0xff); + saa_writeb(SAA7134_H_SCALE_INC2(task), xscale >> 8); + set_v_scale(dev,task,yscale); + + saa_writeb(SAA7134_VIDEO_PIXELS1(task), width & 0xff); + saa_writeb(SAA7134_VIDEO_PIXELS2(task), width >> 8); + saa_writeb(SAA7134_VIDEO_LINES1(task), height/div & 0xff); + saa_writeb(SAA7134_VIDEO_LINES2(task), height/div >> 8); + + /* deinterlace y offsets */ + if (interlace) { + y_odd = dev->ctl_y_odd; + y_even = dev->ctl_y_even + yscale / 32; + saa_writeb(SAA7134_V_PHASE_OFFSET0(task), y_odd); + saa_writeb(SAA7134_V_PHASE_OFFSET1(task), y_even); + saa_writeb(SAA7134_V_PHASE_OFFSET2(task), y_odd); + saa_writeb(SAA7134_V_PHASE_OFFSET3(task), y_even); + } else { + y_odd = dev->ctl_y_odd; + y_even = dev->ctl_y_even + yscale / 64; + saa_writeb(SAA7134_V_PHASE_OFFSET0(task), y_odd); + saa_writeb(SAA7134_V_PHASE_OFFSET1(task), y_even); + saa_writeb(SAA7134_V_PHASE_OFFSET2(task), y_odd); + saa_writeb(SAA7134_V_PHASE_OFFSET3(task), y_even); + } +} + +/* ------------------------------------------------------------------ */ + +struct cliplist { + __u16 position; + __u8 enable; + __u8 disable; +}; + +static void sort_cliplist(struct cliplist *cl, int entries) +{ + struct cliplist swap; + int i,j,n; + + for (i = entries-2; i >= 0; i--) { + for (n = 0, j = 0; j <= i; j++) { + if (cl[j].position > cl[j+1].position) { + swap = cl[j]; + cl[j] = cl[j+1]; + cl[j+1] = swap; + n++; + } + } + if (0 == n) + break; + } +} + +static void set_cliplist(struct saa7134_dev *dev, int reg, + struct cliplist *cl, int entries, char *name) +{ + __u8 winbits = 0; + int i; + + for (i = 0; i < entries; i++) { + winbits |= cl[i].enable; + winbits &= ~cl[i].disable; + if (i < 15 && cl[i].position == cl[i+1].position) + continue; + saa_writeb(reg + 0, winbits); + saa_writeb(reg + 2, cl[i].position & 0xff); + saa_writeb(reg + 3, cl[i].position >> 8); + dprintk("clip: %s winbits=%02x pos=%d\n", + name,winbits,cl[i].position); + reg += 8; + } + for (; reg < 0x400; reg += 8) { + saa_writeb(reg+ 0, 0); + saa_writeb(reg + 1, 0); + saa_writeb(reg + 2, 0); + saa_writeb(reg + 3, 0); + } +} + +static int clip_range(int val) +{ + if (val < 0) + val = 0; + return val; +} + +static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips, + int nclips, int interlace) +{ + struct cliplist col[16], row[16]; + int cols, rows, i; + int div = interlace ? 2 : 1; + + memset(col,0,sizeof(col)); cols = 0; + memset(row,0,sizeof(row)); rows = 0; + for (i = 0; i < nclips && i < 8; i++) { + col[cols].position = clip_range(clips[i].c.left); + col[cols].enable = (1 << i); + cols++; + col[cols].position = clip_range(clips[i].c.left+clips[i].c.width); + col[cols].disable = (1 << i); + cols++; + row[rows].position = clip_range(clips[i].c.top / div); + row[rows].enable = (1 << i); + rows++; + row[rows].position = clip_range((clips[i].c.top + clips[i].c.height) + / div); + row[rows].disable = (1 << i); + rows++; + } + sort_cliplist(col,cols); + sort_cliplist(row,rows); + set_cliplist(dev,0x380,col,cols,"cols"); + set_cliplist(dev,0x384,row,rows,"rows"); + return 0; +} + +static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win) +{ + enum v4l2_field field; + int maxw, maxh; + + if (NULL == dev->ovbuf.base) + return -EINVAL; + if (NULL == dev->ovfmt) + return -EINVAL; + if (win->w.width < 48 || win->w.height < 32) + return -EINVAL; + if (win->clipcount > 2048) + return -EINVAL; + + field = win->field; + maxw = dev->tvnorm->width; + maxh = dev->tvnorm->height; + + if (V4L2_FIELD_ANY == field) { + field = (win->w.height > maxh/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_TOP; + } + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; + default: + return -EINVAL; + } + + win->field = field; + if (win->w.width > maxw) + win->w.width = maxw; + if (win->w.height > maxh) + win->w.height = maxh; + return 0; +} + +static int start_preview(struct saa7134_dev *dev, struct saa7134_fh *fh) +{ + unsigned long base,control,bpl; + int err; + + err = verify_preview(dev,&fh->win); + if (0 != err) + return err; + + dprintk("start_preview %dx%d+%d+%d %s field=%s\n", + fh->win.w.width,fh->win.w.height, + fh->win.w.left,fh->win.w.top, + dev->ovfmt->name,v4l2_field_names[dev->ovfield]); + + /* setup window + clipping */ + set_size(dev,TASK_B,fh->win.w.width,fh->win.w.height, + V4L2_FIELD_HAS_BOTH(dev->ovfield)); + setup_clipping(dev,fh->clips,fh->nclips, + V4L2_FIELD_HAS_BOTH(dev->ovfield)); + if (dev->ovfmt->yuv) + saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x03); + else + saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x01); + saa_writeb(SAA7134_OFMT_VIDEO_B, dev->ovfmt->pm | 0x20); + + /* dma: setup channel 1 (= Video Task B) */ + base = (unsigned long)dev->ovbuf.base; + base += dev->ovbuf.fmt.bytesperline * fh->win.w.top; + base += dev->ovfmt->depth/8 * fh->win.w.left; + bpl = dev->ovbuf.fmt.bytesperline; + control = SAA7134_RS_CONTROL_BURST_16; + if (dev->ovfmt->bswap) + control |= SAA7134_RS_CONTROL_BSWAP; + if (dev->ovfmt->wswap) + control |= SAA7134_RS_CONTROL_WSWAP; + if (V4L2_FIELD_HAS_BOTH(dev->ovfield)) { + saa_writel(SAA7134_RS_BA1(1),base); + saa_writel(SAA7134_RS_BA2(1),base+bpl); + saa_writel(SAA7134_RS_PITCH(1),bpl*2); + saa_writel(SAA7134_RS_CONTROL(1),control); + } else { + saa_writel(SAA7134_RS_BA1(1),base); + saa_writel(SAA7134_RS_BA2(1),base); + saa_writel(SAA7134_RS_PITCH(1),bpl); + saa_writel(SAA7134_RS_CONTROL(1),control); + } + + /* start dma */ + dev->ovenable = 1; + saa7134_set_dmabits(dev); + + return 0; +} + +static int stop_preview(struct saa7134_dev *dev, struct saa7134_fh *fh) +{ + dev->ovenable = 0; + saa7134_set_dmabits(dev); + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int buffer_activate(struct saa7134_dev *dev, + struct saa7134_buf *buf, + struct saa7134_buf *next) +{ + unsigned long base,control,bpl; + unsigned long bpl_uv,lines_uv,base2,base3; /* planar */ + + dprintk("buffer_activate buf=%p\n",buf); + buf->vb.state = STATE_ACTIVE; + + set_size(dev,TASK_A,buf->vb.width,buf->vb.height, + V4L2_FIELD_HAS_BOTH(buf->vb.field)); + if (buf->fmt->yuv) + saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x03); + else + saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x01); + saa_writeb(SAA7134_OFMT_VIDEO_A, buf->fmt->pm); + + /* DMA: setup channel 0 (= Video Task A0) */ + base = saa7134_buffer_base(buf); + if (buf->fmt->planar) + bpl = buf->vb.width; + else + bpl = (buf->vb.width * buf->fmt->depth) / 8; + control = SAA7134_RS_CONTROL_BURST_16 | + SAA7134_RS_CONTROL_ME | + (buf->pt->dma >> 12); + if (buf->fmt->bswap) + control |= SAA7134_RS_CONTROL_BSWAP; + if (buf->fmt->wswap) + control |= SAA7134_RS_CONTROL_WSWAP; + if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) { + /* interlaced */ + saa_writel(SAA7134_RS_BA1(0),base); + saa_writel(SAA7134_RS_BA2(0),base+bpl); + saa_writel(SAA7134_RS_PITCH(0),bpl*2); + } else { + /* non-interlaced */ + saa_writel(SAA7134_RS_BA1(0),base); + saa_writel(SAA7134_RS_BA2(0),base); + saa_writel(SAA7134_RS_PITCH(0),bpl); + } + saa_writel(SAA7134_RS_CONTROL(0),control); + + if (buf->fmt->planar) { + /* DMA: setup channel 4+5 (= planar task A) */ + bpl_uv = bpl >> buf->fmt->hshift; + lines_uv = buf->vb.height >> buf->fmt->vshift; + base2 = base + bpl * buf->vb.height; + base3 = base2 + bpl_uv * lines_uv; + dprintk("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n", + bpl_uv,lines_uv,base2,base3); + if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) { + /* interlaced */ + saa_writel(SAA7134_RS_BA1(4),base2); + saa_writel(SAA7134_RS_BA2(4),base2+bpl_uv); + saa_writel(SAA7134_RS_PITCH(4),bpl_uv*2); + saa_writel(SAA7134_RS_BA1(5),base3); + saa_writel(SAA7134_RS_BA2(5),base3+bpl_uv); + saa_writel(SAA7134_RS_PITCH(5),bpl_uv*2); + } else { + /* non-interlaced */ + saa_writel(SAA7134_RS_BA1(4),base2); + saa_writel(SAA7134_RS_BA2(4),base2); + saa_writel(SAA7134_RS_PITCH(4),bpl_uv); + saa_writel(SAA7134_RS_BA1(5),base3); + saa_writel(SAA7134_RS_BA2(5),base3); + saa_writel(SAA7134_RS_PITCH(5),bpl_uv); + } + saa_writel(SAA7134_RS_CONTROL(4),control); + saa_writel(SAA7134_RS_CONTROL(5),control); + } + + /* start DMA */ + saa7134_set_dmabits(dev); + mod_timer(&dev->video_q.timeout, jiffies+BUFFER_TIMEOUT); + return 0; +} + +static int buffer_prepare(struct file *file, struct videobuf_buffer *vb) +{ + struct saa7134_fh *fh = file->private_data; + struct saa7134_dev *dev = fh->dev; + struct saa7134_buf *buf = (struct saa7134_buf *)vb; + int size,err; + + /* sanity checks */ + if (NULL == fh->fmt) + return -EINVAL; + if (fh->width < 48 || + fh->height < 32 || + fh->width > dev->tvnorm->width || + fh->height > dev->tvnorm->height) + return -EINVAL; + size = (fh->width * fh->height * fh->fmt->depth) >> 3; + if (0 != buf->vb.baddr && buf->vb.bsize < size) + return -EINVAL; + + dprintk("buffer_prepare [size=%dx%d,bytes=%d,fields=%s,%s]\n", + fh->width,fh->height,size,v4l2_field_names[fh->field], + fh->fmt->name); + if (buf->vb.width != fh->width || + buf->vb.height != fh->height || + buf->vb.size != size || + buf->vb.field != fh->field || + buf->fmt != fh->fmt) { + saa7134_dma_free(dev,buf); + } + + if (STATE_NEEDS_INIT == buf->vb.state) { + buf->vb.width = fh->width; + buf->vb.height = fh->height; + buf->vb.size = size; + buf->fmt = fh->fmt; + buf->vb.field = fh->field; + buf->pt = &fh->pt_cap; + + err = videobuf_iolock(dev->pci,&buf->vb); + if (err) + goto oops; + err = saa7134_pgtable_build(dev->pci,buf->pt, + buf->vb.dma.sglist, + buf->vb.dma.sglen, + saa7134_buffer_startpage(buf)); + if (err) + goto oops; + } + buf->vb.state = STATE_PREPARED; + buf->top_seen = 0; + buf->activate = buffer_activate; + return 0; + + oops: + saa7134_dma_free(dev,buf); + return err; +} + +static int +buffer_setup(struct file *file, int *count, int *size) +{ + struct saa7134_fh *fh = file->private_data; + + *size = fh->fmt->depth * fh->width * fh->height >> 3; + if (0 == *count) + *count = gbuffers; + *count = saa7134_buffer_count(*size,*count); + return 0; +} + +static void buffer_queue(struct file *file, struct videobuf_buffer *vb) +{ + struct saa7134_fh *fh = file->private_data; + struct saa7134_buf *buf = (struct saa7134_buf *)vb; + + saa7134_buffer_queue(fh->dev,&fh->dev->video_q,buf); +} + +static void buffer_release(struct file *file, struct videobuf_buffer *vb) +{ + struct saa7134_fh *fh = file->private_data; + struct saa7134_buf *buf = (struct saa7134_buf *)vb; + + saa7134_dma_free(fh->dev,buf); +} + +static struct videobuf_queue_ops video_qops = { + buf_setup: buffer_setup, + buf_prepare: buffer_prepare, + buf_queue: buffer_queue, + buf_release: buffer_release, +}; + +/* ------------------------------------------------------------------ */ + +static int get_control(struct saa7134_dev *dev, struct v4l2_control *c) +{ + const struct v4l2_queryctrl* ctrl; + + ctrl = ctrl_by_id(c->id); + if (NULL == ctrl) + return -EINVAL; + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + c->value = dev->ctl_bright; + break; + case V4L2_CID_HUE: + c->value = dev->ctl_hue; + break; + case V4L2_CID_CONTRAST: + c->value = dev->ctl_contrast; + break; + case V4L2_CID_SATURATION: + c->value = dev->ctl_saturation; + break; + case V4L2_CID_AUDIO_MUTE: + c->value = dev->ctl_mute; + break; + case V4L2_CID_AUDIO_VOLUME: + c->value = dev->ctl_volume; + break; + case V4L2_CID_PRIVATE_INVERT: + c->value = dev->ctl_invert; + break; + case V4L2_CID_VFLIP: + c->value = dev->ctl_mirror; + break; + case V4L2_CID_PRIVATE_Y_EVEN: + c->value = dev->ctl_y_even; + break; + case V4L2_CID_PRIVATE_Y_ODD: + c->value = dev->ctl_y_odd; + break; + default: + return -EINVAL; + } + return 0; +} + +static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh, + struct v4l2_control *c) +{ + const struct v4l2_queryctrl* ctrl; + unsigned long flags; + int restart_overlay = 0; + + ctrl = ctrl_by_id(c->id); + if (NULL == ctrl) + return -EINVAL; + dprintk("set_control name=%s val=%d\n",ctrl->name,c->value); + switch (ctrl->type) { + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_INTEGER: + if (c->value < ctrl->minimum) + c->value = ctrl->minimum; + if (c->value > ctrl->maximum) + c->value = ctrl->maximum; + break; + default: + /* nothing */; + }; + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + dev->ctl_bright = c->value; + saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); + break; + case V4L2_CID_HUE: + dev->ctl_hue = c->value; + saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); + break; + case V4L2_CID_CONTRAST: + dev->ctl_contrast = c->value; + saa_writeb(SAA7134_DEC_LUMA_CONTRAST, + dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); + break; + case V4L2_CID_SATURATION: + dev->ctl_saturation = c->value; + saa_writeb(SAA7134_DEC_CHROMA_SATURATION, + dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); + break; + case V4L2_CID_AUDIO_MUTE: + dev->ctl_mute = c->value; + saa7134_tvaudio_setmute(dev); + break; + case V4L2_CID_AUDIO_VOLUME: + dev->ctl_volume = c->value; + saa7134_tvaudio_setvolume(dev,dev->ctl_volume); + break; + case V4L2_CID_PRIVATE_INVERT: + dev->ctl_invert = c->value; + saa_writeb(SAA7134_DEC_LUMA_CONTRAST, + dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); + saa_writeb(SAA7134_DEC_CHROMA_SATURATION, + dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); + break; + case V4L2_CID_VFLIP: + dev->ctl_mirror = c->value; + restart_overlay = 1; + break; + case V4L2_CID_PRIVATE_Y_EVEN: + dev->ctl_y_even = c->value; + restart_overlay = 1; + break; + case V4L2_CID_PRIVATE_Y_ODD: + dev->ctl_y_odd = c->value; + restart_overlay = 1; + break; + default: + return -EINVAL; + } + if (restart_overlay && res_check(fh, RESOURCE_OVERLAY)) { + spin_lock_irqsave(&dev->slock,flags); + stop_preview(dev,fh); + start_preview(dev,fh); + spin_unlock_irqrestore(&dev->slock,flags); + } + return 0; +} + +/* ------------------------------------------------------------------ */ + +static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh) +{ + struct videobuf_queue* q = NULL; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + q = &fh->cap; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + q = &fh->vbi; + break; + default: + BUG(); + } + return q; +} + +static int saa7134_resource(struct saa7134_fh *fh) +{ + int res = 0; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + res = RESOURCE_VIDEO; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + res = RESOURCE_VBI; + break; + default: + BUG(); + } + return res; +} + +static int video_open(struct inode *inode, struct file *file) +{ + unsigned int minor = minor(inode->i_rdev); + struct saa7134_dev *h,*dev = NULL; + struct saa7134_fh *fh; + struct list_head *list; + enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + int radio = 0; + + list_for_each(list,&saa7134_devlist) { + h = list_entry(list, struct saa7134_dev, devlist); + if (h->video_dev.minor == minor) + dev = h; + if (h->radio_dev.minor == minor) { + radio = 1; + dev = h; + } + if (h->vbi_dev.minor == minor) { + type = V4L2_BUF_TYPE_VBI_CAPTURE; + dev = h; + } + } + if (NULL == dev) + return -ENODEV; + + dprintk("open minor=%d radio=%d type=%s\n",minor,radio, + v4l2_type_names[type]); + + /* allocate + initialize per filehandle data */ + fh = kmalloc(sizeof(*fh),GFP_KERNEL); + if (NULL == fh) + return -ENOMEM; + memset(fh,0,sizeof(*fh)); + file->private_data = fh; + fh->dev = dev; + fh->radio = radio; + fh->type = type; + fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); + fh->width = 320; + fh->height = 240; + + videobuf_queue_init(&fh->cap, &video_qops, + dev->pci, &dev->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + sizeof(struct saa7134_buf)); + init_MUTEX(&fh->cap.lock); + saa7134_pgtable_alloc(dev->pci,&fh->pt_cap); + + videobuf_queue_init(&fh->vbi, &saa7134_vbi_qops, + dev->pci, &dev->slock, + V4L2_BUF_TYPE_VBI_CAPTURE, + sizeof(struct saa7134_buf)); + init_MUTEX(&fh->vbi.lock); + saa7134_pgtable_alloc(dev->pci,&fh->pt_vbi); + + if (fh->radio) { + /* switch to radio mode */ + saa7134_tvaudio_setinput(dev,&card(dev).radio); + saa7134_i2c_call_clients(dev,AUDC_SET_RADIO,NULL); + } else { + /* switch to video/vbi mode */ + set_tvnorm(dev,dev->tvnorm); + video_mux(dev,dev->ctl_input); + } + return 0; +} + +static ssize_t +video_read(struct file *file, char *data, size_t count, loff_t *ppos) +{ + struct saa7134_fh *fh = file->private_data; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return videobuf_read_one(file, saa7134_queue(fh), + data, count, ppos); + case V4L2_BUF_TYPE_VBI_CAPTURE: + return videobuf_read_stream(file, saa7134_queue(fh), + data, count, ppos, 1); + break; + default: + BUG(); + return 0; + } +} + +static unsigned int +video_poll(struct file *file, struct poll_table_struct *wait) +{ + struct saa7134_fh *fh = file->private_data; + struct videobuf_buffer *buf = NULL; + + if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) + return videobuf_poll_stream(file, &fh->vbi, wait); + + if (res_check(fh,RESOURCE_VIDEO)) { + if (!list_empty(&fh->cap.stream)) + buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream); + } else { + down(&fh->cap.lock); + if (-1 == fh->cap.read_off) { + /* need to capture a new frame */ + if (res_locked(fh->dev,RESOURCE_VIDEO)) { + up(&fh->cap.lock); + return POLLERR; + } + if (0 != fh->cap.ops->buf_prepare(file,fh->cap.read_buf)) { + up(&fh->cap.lock); + return POLLERR; + } + fh->cap.ops->buf_queue(file,fh->cap.read_buf); + fh->cap.read_off = 0; + } + up(&fh->cap.lock); + buf = fh->cap.read_buf; + } + + if (!buf) + return POLLERR; + + poll_wait(file, &buf->done, wait); + if (buf->state == STATE_DONE || + buf->state == STATE_ERROR) + return POLLIN|POLLRDNORM; + return 0; +} + +static int video_release(struct inode *inode, struct file *file) +{ + struct saa7134_fh *fh = file->private_data; + struct saa7134_dev *dev = fh->dev; + unsigned long flags; + + if (res_check(fh, RESOURCE_OVERLAY)) { + spin_lock_irqsave(&dev->slock,flags); + stop_preview(dev,fh); + spin_unlock_irqrestore(&dev->slock,flags); + res_free(dev,fh,RESOURCE_OVERLAY); + } + if (res_check(fh, RESOURCE_VIDEO)) { + videobuf_queue_cancel(file,&fh->cap); + res_free(dev,fh,RESOURCE_VIDEO); + } + if (fh->cap.read_buf) { + buffer_release(file,fh->cap.read_buf); + kfree(fh->cap.read_buf); + } + if (fh->vbi.streaming) + videobuf_streamoff(file,&fh->vbi); + if (fh->vbi.reading) + videobuf_read_stop(file,&fh->vbi); + + saa7134_pgtable_free(dev->pci,&fh->pt_cap); + saa7134_pgtable_free(dev->pci,&fh->pt_vbi); + + file->private_data = NULL; + kfree(fh); + return 0; +} + +static int +video_mmap(struct file *file, struct vm_area_struct * vma) +{ + struct saa7134_fh *fh = file->private_data; + + return videobuf_mmap_mapper(vma,saa7134_queue(fh)); +} + +/* ------------------------------------------------------------------ */ + +int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, + struct v4l2_format *f) +{ + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + memset(&f->fmt.pix,0,sizeof(f->fmt.pix)); + f->fmt.pix.width = fh->width; + f->fmt.pix.height = fh->height; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.sizeimage = + (fh->width*fh->height*fh->fmt->depth)/8; + return 0; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + f->fmt.win = fh->win; + return 0; + case V4L2_BUF_TYPE_VBI_CAPTURE: + { + struct saa7134_tvnorm *norm = fh->dev->tvnorm; + + f->fmt.vbi.sampling_rate = 6750000 * 4; + f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */; + f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; + f->fmt.vbi.offset = 64 * 4; + f->fmt.vbi.start[0] = norm->vbi_v_start; + f->fmt.vbi.count[0] = norm->vbi_v_stop - norm->vbi_v_start +1; + f->fmt.vbi.start[1] = norm->video_v_stop + norm->vbi_v_start + 1; + f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; + f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */; + return 0; + } + default: + return -EINVAL; + } +} + +int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, + struct v4l2_format *f) +{ + int err; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + { + struct saa7134_format *fmt; + enum v4l2_field field; + int maxw, maxh; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; + + field = f->fmt.pix.field; + maxw = dev->tvnorm->width; + maxh = dev->tvnorm->height; + + if (V4L2_FIELD_ANY == field) { + field = (f->fmt.pix.height > maxh/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + } + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; + default: + return -EINVAL; + } + + f->fmt.pix.field = field; + if (f->fmt.pix.width > maxw) + f->fmt.pix.width = maxw; + if (f->fmt.pix.height > maxh) + f->fmt.pix.height = maxh; + f->fmt.pix.sizeimage = + (fh->width * fh->height * fmt->depth)/8; + + return 0; + } + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + err = verify_preview(dev,&f->fmt.win); + if (0 != err) + return err; + return 0; + default: + return -EINVAL; + } +} + +int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, + struct v4l2_format *f) +{ + unsigned long flags; + int err; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + err = saa7134_try_fmt(dev,fh,f); + if (0 != err) + return err; + + fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + fh->field = f->fmt.pix.field; + return 0; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + err = verify_preview(dev,&f->fmt.win); + if (0 != err) + return err; + + down(&dev->lock); + fh->win = f->fmt.win; + fh->nclips = f->fmt.win.clipcount; + if (fh->nclips > 8) + fh->nclips = 8; + if (copy_from_user(fh->clips,f->fmt.win.clips, + sizeof(struct v4l2_clip)*fh->nclips)) { + up(&dev->lock); + return -EFAULT; + } + + if (res_check(fh, RESOURCE_OVERLAY)) { + spin_lock_irqsave(&dev->slock,flags); + stop_preview(dev,fh); + start_preview(dev,fh); + spin_unlock_irqrestore(&dev->slock,flags); + } + up(&dev->lock); + return 0; + break; + default: + return -EINVAL; + } +} + +/* + * This function is _not_ called directly, but from + * video_generic_ioctl (and maybe others). userspace + * copying is done already, arg is a kernel pointer. + */ +static int video_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct saa7134_fh *fh = file->private_data; + struct saa7134_dev *dev = fh->dev; + unsigned long flags; + int err; + + if (video_debug > 1) + saa7134_print_ioctl(dev->name,cmd); + switch (cmd) { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *cap = arg; + + memset(cap,0,sizeof(*cap)); + strcpy(cap->driver, "saa7134"); + strncpy(cap->card, saa7134_boards[dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info,"PCI:%s",dev->pci->slot_name); + cap->version = SAA7134_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_TUNER | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + return 0; + } + + /* --- tv standards ------------------------------------------ */ + case VIDIOC_ENUMSTD: + { + struct v4l2_standard *e = arg; + + if (e->index < 0 || e->index >= TVNORMS) + return -EINVAL; + err = v4l2_video_std_construct(e, tvnorms[e->index].id, + tvnorms[e->index].name); + if (err < 0) + return err; + return 0; + } + case VIDIOC_G_STD: + { + v4l2_std_id *id = arg; + + *id = dev->tvnorm->id; + return 0; + } + case VIDIOC_S_STD: + { + v4l2_std_id *id = arg; + int i; + + for(i = 0; i < TVNORMS; i++) + if (*id & tvnorms[i].id) + break; + if (i == TVNORMS) + return -EINVAL; + + down(&dev->lock); + if (res_check(fh, RESOURCE_OVERLAY)) { + spin_lock_irqsave(&dev->slock,flags); + stop_preview(dev,fh); + set_tvnorm(dev,&tvnorms[i]); + start_preview(dev,fh); + spin_unlock_irqrestore(&dev->slock,flags); + } else + set_tvnorm(dev,&tvnorms[i]); + up(&dev->lock); + return 0; + } + + /* --- input switching --------------------------------------- */ + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *i = arg; + + if (i->index >= SAA7134_INPUT_MAX) + return -EINVAL; + if (NULL == card_in(dev,i->index).name) + return -EINVAL; + i->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(i->name,card_in(dev,i->index).name); + if (card_in(dev,i->index).tv) + i->type = V4L2_INPUT_TYPE_TUNER; + return 0; + } + case VIDIOC_G_INPUT: + { + int *i = arg; + *i = dev->ctl_input; + return 0; + } + case VIDIOC_S_INPUT: + { + int *i = arg; + + if (*i < 0 || *i >= SAA7134_INPUT_MAX) + return -EINVAL; + if (NULL == card_in(dev,*i).name) + return -EINVAL; + down(&dev->lock); + video_mux(dev,*i); + up(&dev->lock); + return 0; + } + + /* --- tuner ioctls ------------------------------------------ */ + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *t = arg; + int n; + + memset(t,0,sizeof(*t)); + for (n = 0; n < SAA7134_INPUT_MAX; n++) + if (card_in(dev,n).tv) + break; + if (NULL != card_in(dev,n).name) { + strcpy(t->name, "Television"); + t->capability = V4L2_TUNER_CAP_NORM | + V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | + V4L2_TUNER_CAP_LANG2; + t->rangehigh = 0xffffffffUL; + if (dev->tvaudio) { + t->rxsubchans = saa7134_tvaudio_getstereo + (dev,dev->tvaudio); + } else { + t->rxsubchans = V4L2_TUNER_SUB_MONO; + } +#if 1 + /* fill audmode -- FIXME: allow manual switching */ + t->audmode = V4L2_TUNER_MODE_MONO; + if (t->rxsubchans & V4L2_TUNER_SUB_STEREO) + t->audmode = V4L2_TUNER_MODE_STEREO; + else if (t->rxsubchans & V4L2_TUNER_SUB_LANG1) + t->audmode = V4L2_TUNER_MODE_LANG1; + else if (t->rxsubchans & V4L2_TUNER_SUB_LANG2) + t->audmode = V4L2_TUNER_MODE_LANG2; +#endif + } + if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03)) + t->signal = 0xffff; + return 0; + } + case VIDIOC_S_TUNER: + { +#if 0 + struct v4l2_tuner *t = arg; +#endif + return 0; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + memset(f,0,sizeof(*f)); + f->type = V4L2_TUNER_ANALOG_TV; + f->frequency = dev->ctl_freq; + return 0; + } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + if (0 != f->tuner) + return -EINVAL; + if (V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + down(&dev->lock); + dev->ctl_freq = f->frequency; + saa7134_i2c_call_clients(dev,VIDIOCSFREQ,&dev->ctl_freq); + up(&dev->lock); + return 0; + } + + /* --- control ioctls ---------------------------------------- */ + case VIDIOC_QUERYCTRL: + { + const struct v4l2_queryctrl *ctrl; + struct v4l2_queryctrl *c = arg; + + if ((c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) && + (c->id < V4L2_CID_PRIVATE_BASE || + c->id >= V4L2_CID_PRIVATE_LASTP1)) + return -EINVAL; + ctrl = ctrl_by_id(c->id); + *c = (NULL != ctrl) ? *ctrl : no_ctrl; + return 0; + } + case VIDIOC_G_CTRL: + return get_control(dev,arg); + case VIDIOC_S_CTRL: + { + down(&dev->lock); + err = set_control(dev,fh,arg); + up(&dev->lock); + return err; + } + case VIDIOC_G_AUDIO: + { + struct v4l2_audio *a = arg; + + memset(a,0,sizeof(*a)); + strcpy(a->name,"audio"); + return 0; + } + case VIDIOC_S_AUDIO: + return 0; + case VIDIOC_G_PARM: + { + struct v4l2_captureparm *parm = arg; + memset(parm,0,sizeof(*parm)); + return 0; + } + + /* --- preview ioctls ---------------------------------------- */ + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc *f = arg; + int index; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + index = f->index; + if (index < 0 || index >= FORMATS) + return -EINVAL; + if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY && + formats[index].planar) + return -EINVAL; + memset(f,0,sizeof(*f)); + f->index = index; + strncpy(f->description,formats[index].name,31); + f->pixelformat = formats[index].fourcc; + break; + default: + return -EINVAL; + } + return 0; + } + case VIDIOC_G_FBUF: + { + struct v4l2_framebuffer *fb = arg; + + *fb = dev->ovbuf; + fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; + return 0; + } + case VIDIOC_S_FBUF: + { + struct v4l2_framebuffer *fb = arg; + struct saa7134_format *fmt; + + if(!capable(CAP_SYS_ADMIN) && + !capable(CAP_SYS_RAWIO)) + return -EPERM; + + /* check args */ + fmt = format_by_fourcc(fb->fmt.pixelformat); + if (NULL == fmt) + return -EINVAL; + + /* ok, accept it */ + dev->ovbuf = *fb; + dev->ovfmt = fmt; + if (0 == dev->ovbuf.fmt.bytesperline) + dev->ovbuf.fmt.bytesperline = + dev->ovbuf.fmt.width*fmt->depth/8; + return 0; + } + case VIDIOC_OVERLAY: + { + int *on = arg; + + if (*on) { + if (!res_get(dev,fh,RESOURCE_OVERLAY)) + return -EBUSY; + spin_lock_irqsave(&dev->slock,flags); + start_preview(dev,fh); + spin_unlock_irqrestore(&dev->slock,flags); + } + if (!*on) { + if (!res_check(fh, RESOURCE_OVERLAY)) + return -EINVAL; + spin_lock_irqsave(&dev->slock,flags); + stop_preview(dev,fh); + spin_unlock_irqrestore(&dev->slock,flags); + res_free(dev,fh,RESOURCE_OVERLAY); + } + return 0; + } + + /* --- capture ioctls ---------------------------------------- */ + case VIDIOC_G_FMT: + { + struct v4l2_format *f = arg; + return saa7134_g_fmt(dev,fh,f); + } + case VIDIOC_S_FMT: + { + struct v4l2_format *f = arg; + return saa7134_s_fmt(dev,fh,f); + } + case VIDIOC_TRY_FMT: + { + struct v4l2_format *f = arg; + return saa7134_try_fmt(dev,fh,f); + } + + case VIDIOCGMBUF: + { + struct video_mbuf *mbuf = arg; + struct videobuf_queue *q; + int i; + + q = saa7134_queue(fh); + down(&q->lock); + err = videobuf_mmap_setup(file,q,gbuffers,gbufsize); + if (err < 0) { + up(&q->lock); + return err; + } + memset(mbuf,0,sizeof(*mbuf)); + mbuf->frames = gbuffers; + mbuf->size = gbuffers * gbufsize; + for (i = 0; i < gbuffers; i++) + mbuf->offsets[i] = i * gbufsize; + up(&q->lock); + return 0; + } + case VIDIOC_REQBUFS: + return videobuf_reqbufs(file,saa7134_queue(fh),arg); + + case VIDIOC_QUERYBUF: + return videobuf_querybuf(saa7134_queue(fh),arg); + + case VIDIOC_QBUF: + return videobuf_qbuf(file,saa7134_queue(fh),arg); + + case VIDIOC_DQBUF: + return videobuf_dqbuf(file,saa7134_queue(fh),arg); + + case VIDIOC_STREAMON: + { + int res = saa7134_resource(fh); + + if (!res_get(dev,fh,res)) + return -EBUSY; + return videobuf_streamon(file,saa7134_queue(fh)); + } + case VIDIOC_STREAMOFF: + { + int res = saa7134_resource(fh); + err = videobuf_streamoff(file,saa7134_queue(fh)); + res_free(dev,fh,res); + return 0; + } + + default: + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + video_do_ioctl); + } + return 0; +} + +static int video_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return video_usercopy(inode, file, cmd, arg, video_do_ioctl); +} + +static int radio_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct saa7134_fh *fh = file->private_data; + struct saa7134_dev *dev = fh->dev; + + if (video_debug > 1) + saa7134_print_ioctl(dev->name,cmd); + switch (cmd) { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *cap = arg; + + memset(cap,0,sizeof(*cap)); + strcpy(cap->driver, "saa7134"); + strncpy(cap->card, saa7134_boards[dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info,"PCI:%s",dev->pci->slot_name); + cap->version = SAA7134_VERSION_CODE; + cap->capabilities = V4L2_CAP_TUNER; + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *t = arg; + struct video_tuner vt; + + memset(t,0,sizeof(*t)); + strcpy(t->name, "Radio"); + t->rangelow = (int)(65*16); + t->rangehigh = (int)(108*16); + + memset(&vt,0,sizeof(vt)); + saa7134_i2c_call_clients(dev,VIDIOCGTUNER,&vt); + t->signal = vt.signal; + return 0; + } + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *i = arg; + + if (i->index != 0) + return -EINVAL; + strcpy(i->name,"Radio"); + i->type = V4L2_INPUT_TYPE_TUNER; + return 0; + } + case VIDIOC_G_INPUT: + { + int *i = arg; + *i = 0; + return 0; + } + case VIDIOC_G_AUDIO: + { + struct v4l2_audio *a = arg; + + memset(a,0,sizeof(*a)); + strcpy(a->name,"Radio"); + return 0; + } + case VIDIOC_S_AUDIO: + case VIDIOC_S_TUNER: + case VIDIOC_S_INPUT: + return 0; + + case VIDIOC_QUERYCTRL: + { + const struct v4l2_queryctrl *ctrl; + struct v4l2_queryctrl *c = arg; + + if (c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) + return -EINVAL; + if (c->id == V4L2_CID_AUDIO_MUTE) { + ctrl = ctrl_by_id(c->id); + *c = *ctrl; + } else + *c = no_ctrl; + return 0; + } + + case VIDIOC_G_CTRL: + case VIDIOC_S_CTRL: + case VIDIOC_G_FREQUENCY: + case VIDIOC_S_FREQUENCY: + return video_do_ioctl(inode,file,cmd,arg); + + default: + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + radio_do_ioctl); + } + return 0; +} + +static int radio_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return video_usercopy(inode, file, cmd, arg, radio_do_ioctl); +} + +static struct file_operations video_fops = +{ + owner: THIS_MODULE, + open: video_open, + release: video_release, + read: video_read, + poll: video_poll, + mmap: video_mmap, + ioctl: video_ioctl, + llseek: no_llseek, +}; + +static struct file_operations radio_fops = +{ + owner: THIS_MODULE, + open: video_open, + release: video_release, + ioctl: radio_ioctl, + llseek: no_llseek, +}; + +/* ----------------------------------------------------------- */ +/* exported stuff */ + +struct video_device saa7134_video_template = +{ + name: "saa7134-video", + type: VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY| + VID_TYPE_CLIPPING|VID_TYPE_SCALES, + hardware: 0, + fops: &video_fops, + minor: -1, +}; + +struct video_device saa7134_vbi_template = +{ + name: "saa7134-vbi", + type: VID_TYPE_TUNER|VID_TYPE_TELETEXT, + hardware: 0, + fops: &video_fops, + minor: -1, +}; + +struct video_device saa7134_radio_template = +{ + name: "saa7134-radio", + type: VID_TYPE_TUNER, + hardware: 0, + fops: &radio_fops, + minor: -1, +}; + +int saa7134_video_init(struct saa7134_dev *dev) +{ + /* sanitycheck insmod options */ + if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) + gbuffers = 2; + if (gbufsize < 0 || gbufsize > gbufsize_max) + gbufsize = gbufsize_max; + gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK; + + /* put some sensible defaults into the data structures ... */ + dev->ctl_bright = ctrl_by_id(V4L2_CID_BRIGHTNESS)->default_value; + dev->ctl_contrast = ctrl_by_id(V4L2_CID_CONTRAST)->default_value; + dev->ctl_hue = ctrl_by_id(V4L2_CID_HUE)->default_value; + dev->ctl_saturation = ctrl_by_id(V4L2_CID_SATURATION)->default_value; + dev->ctl_volume = ctrl_by_id(V4L2_CID_AUDIO_VOLUME)->default_value; + + dev->ctl_invert = 0; + dev->ctl_mute = 1; + dev->automute = 0; + + INIT_LIST_HEAD(&dev->video_q.queue); + dev->video_q.timeout.function = saa7134_buffer_timeout; + dev->video_q.timeout.data = (unsigned long)(&dev->video_q); + dev->video_q.dev = dev; + + /* init video hw */ + set_tvnorm(dev,&tvnorms[0]); + video_mux(dev,0); + saa7134_tvaudio_setmute(dev); + saa7134_tvaudio_setvolume(dev,dev->ctl_volume); + + if (saa7134_boards[dev->board].video_out) { + /* enable video output */ + int vo = saa7134_boards[dev->board].video_out; + saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]); + saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_out[vo][1]); + saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]); + saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]); + saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]); + saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_out[vo][5]); + saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_out[vo][6]); + saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]); + saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]); + } + + return 0; +} + +int saa7134_video_fini(struct saa7134_dev *dev) +{ + /* nothing */ + return 0; +} + +void saa7134_irq_video_intl(struct saa7134_dev *dev) +{ + static const char *st[] = { + "no signal", "found NTSC", "found PAL", "found SECAM" }; + int norm; + + norm = saa_readb(SAA7134_STATUS_VIDEO1) & 0x03; + printk("%s/video: DCSDT: %s\n",dev->name,st[norm]); + + if (0 != norm) { + /* wake up tvaudio audio carrier scan thread */ + saa7134_tvaudio_do_scan(dev); + } else { + /* no video signal -> mute audio */ + dev->automute = 1; + saa7134_tvaudio_setmute(dev); + } +} + +void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status) +{ + enum v4l2_field field; + + spin_lock(&dev->slock); + if (dev->video_q.curr) { + field = dev->video_q.curr->vb.field; + + if (V4L2_FIELD_HAS_BOTH(field)) { + /* make sure we have seen both fields */ + if ((status & 0x10) == 0x10) { + dev->video_q.curr->top_seen = 1; + goto done; + } + if (!dev->video_q.curr->top_seen) + goto done; + } else if (field == V4L2_FIELD_TOP) { + if ((status & 0x10) != 0x10) + goto done; + } else if (field == V4L2_FIELD_BOTTOM) { + if ((status & 0x10) != 0x00) + goto done; + } + saa7134_buffer_finish(dev,&dev->video_q,STATE_DONE); + } + saa7134_buffer_next(dev,&dev->video_q); + + done: + spin_unlock(&dev->slock); +} + +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/saa7134/saa7134.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,473 @@ +/* + * v4l2 device driver for philips saa7134 based TV cards + * + * (c) 2001,02 Gerd Knorr + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include "video-buf.h" + +#define SAA7134_VERSION_CODE KERNEL_VERSION(0,2,1) + +#ifndef TRUE +# define TRUE (1==1) +#endif +#ifndef FALSE +# define FALSE (1==0) +#endif + +/* 2.4 / 2.5 driver compatibility stuff */ + +/* ----------------------------------------------------------- */ +/* enums */ + +enum saa7134_tvaudio_mode { + TVAUDIO_FM_MONO = 1, + TVAUDIO_FM_BG_STEREO = 2, + TVAUDIO_FM_SAT_STEREO = 3, + TVAUDIO_FM_K_STEREO = 4, + TVAUDIO_NICAM_AM = 5, + TVAUDIO_NICAM_FM = 6, +}; + +enum saa7134_audio_in { + TV = 1, + LINE1 = 2, + LINE2 = 3, +}; + +enum saa7134_video_out { + CCIR656 = 1, +}; + +/* ----------------------------------------------------------- */ +/* static data */ + +struct saa7134_tvnorm { + char *name; + v4l2_std_id id; + int width; + int height; + + /* video decoder */ + int sync_control; + int luma_control; + int chroma_ctrl1; + int chroma_gain; + int chroma_ctrl2; + + /* video scaler */ + int h_start; + int h_stop; + int video_v_start; + int video_v_stop; + int vbi_v_start; + int vbi_v_stop; +}; + +struct saa7134_tvaudio { + char *name; + int std; + enum saa7134_tvaudio_mode mode; + int carr1; + int carr2; +}; + +struct saa7134_format { + char *name; + int fourcc; + int depth; + int pm; + int vshift; /* vertical downsampling (for planar yuv) */ + int hshift; /* horizontal downsampling (for planar yuv) */ + int bswap:1; + int wswap:1; + int yuv:1; + int planar:1; +}; + +/* ----------------------------------------------------------- */ +/* card configuration */ + +#define SAA7134_BOARD_NOAUTO -1 +#define SAA7134_BOARD_UNKNOWN 0 +#define SAA7134_BOARD_PROTEUS_PRO 1 +#define SAA7134_BOARD_FLYVIDEO3000 2 +#define SAA7134_BOARD_FLYVIDEO2000 3 +#define SAA7134_BOARD_EMPRESS 4 +#define SAA7134_BOARD_MONSTERTV 5 +#define SAA7134_BOARD_MD9717 6 +#define SAA7134_BOARD_TVSTATION_RDS 7 +#define SAA7134_BOARD_CINERGY400 8 +#define SAA7134_BOARD_MD5044 9 + +#define SAA7134_INPUT_MAX 8 + +struct saa7134_input { + char *name; + int vmux; + enum saa7134_audio_in amux; + int gpio; + int tv:1; +}; + +struct saa7134_board { + char *name; + int audio_clock; + + /* input switching */ + int gpiomask; + struct saa7134_input inputs[SAA7134_INPUT_MAX]; + struct saa7134_input radio; + struct saa7134_input mute; + + /* peripheral I/O */ + int i2s_rate; + int has_ts; + enum saa7134_video_out video_out; + + /* i2c chip info */ + int tuner_type; + int need_tda9887:1; +}; + +#define card_has_audio(dev) (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7134) +#define card_has_radio(dev) (NULL != saa7134_boards[dev->board].radio.name) +#define card_has_ts(dev) (saa7134_boards[dev->board].has_ts) +#define card(dev) (saa7134_boards[dev->board]) +#define card_in(dev,n) (saa7134_boards[dev->board].inputs[n]) + +/* ----------------------------------------------------------- */ +/* device / file handle status */ + +#define RESOURCE_OVERLAY 1 +#define RESOURCE_VIDEO 2 +#define RESOURCE_VBI 3 + +#define INTERLACE_AUTO 0 +#define INTERLACE_ON 1 +#define INTERLACE_OFF 2 + +#define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */ + +struct saa7134_dev; +struct saa7134_dma; + +/* saa7134 page table */ +struct saa7134_pgtable { + unsigned int size; + u32 *cpu; + dma_addr_t dma; +}; + +/* tvaudio thread status */ +struct saa7134_thread { + struct task_struct *task; + wait_queue_head_t wq; + struct semaphore *notify; + int exit; + int scan1; + int scan2; +}; + +/* buffer for one video/vbi/ts frame */ +struct saa7134_buf { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + + /* saa7134 specific */ + struct saa7134_format *fmt; + int top_seen; + int (*activate)(struct saa7134_dev *dev, + struct saa7134_buf *buf, + struct saa7134_buf *next); + + /* page tables */ + struct saa7134_pgtable *pt; +}; + +struct saa7134_dmaqueue { + struct saa7134_dev *dev; + struct saa7134_buf *curr; + struct list_head queue; + struct timer_list timeout; +}; + +/* video filehandle status */ +struct saa7134_fh { + struct saa7134_dev *dev; + int radio; + enum v4l2_buf_type type; + + struct v4l2_window win; + struct v4l2_clip clips[8]; + int nclips; + int resources; + + /* video capture */ + struct saa7134_format *fmt; + int width,height; + enum v4l2_field field; + struct videobuf_queue cap; + struct saa7134_pgtable pt_cap; + + /* vbi capture */ + struct videobuf_queue vbi; + struct saa7134_pgtable pt_vbi; +}; + +/* TS status */ +struct saa7134_ts { + int users; + + /* TS capture */ + struct videobuf_queue ts; + struct saa7134_pgtable pt_ts; +}; + +/* oss dsp status */ +struct saa7134_oss { + struct semaphore lock; + int minor_mixer; + int minor_dsp; + int users_dsp; + + /* mixer */ + enum saa7134_audio_in input; + int count; + int line1; + int line2; + + /* dsp */ + int afmt; + int rate; + int channels; + int recording; + int blocks; + int blksize; + int bufsize; + struct saa7134_pgtable pt; + struct videobuf_dmabuf dma; + wait_queue_head_t wq; + int dma_blk; + int read_offset; + int read_count; +}; + +/* global device status */ +struct saa7134_dev { + struct list_head devlist; + struct semaphore lock; + spinlock_t slock; + + /* various device info */ + int resources; + struct video_device video_dev; + struct video_device ts_dev; + struct video_device radio_dev; + struct video_device vbi_dev; + struct saa7134_oss oss; + struct saa7134_ts ts; + + /* pci i/o */ + char name[32]; + struct pci_dev *pci; + unsigned char pci_rev,pci_lat; + __u32 *lmmio; + __u8 *bmmio; + + /* config info */ + int board; + int tuner_type; + + /* i2c i/o */ + struct i2c_adapter i2c_adap; + struct i2c_client i2c_client; + unsigned char eedata[64]; + + /* video overlay */ + struct v4l2_framebuffer ovbuf; + struct saa7134_format *ovfmt; + int ovenable; + enum v4l2_field ovfield; + + /* video+ts+vbi capture */ + struct saa7134_dmaqueue video_q; + struct saa7134_dmaqueue ts_q; + struct saa7134_dmaqueue vbi_q; + int vbi_fieldcount; + + /* various v4l controls */ + struct saa7134_tvnorm *tvnorm; /* video */ + struct saa7134_tvaudio *tvaudio; + int ctl_input; + int ctl_bright; + int ctl_contrast; + int ctl_hue; + int ctl_saturation; + int ctl_freq; + int ctl_mute; /* audio */ + int ctl_volume; + int ctl_invert; /* private */ + int ctl_mirror; + int ctl_y_odd; + int ctl_y_even; + + /* other global state info */ + int automute; + struct saa7134_thread thread; + struct saa7134_input *input; + struct saa7134_input *hw_input; + int hw_mute; +}; + +/* ----------------------------------------------------------- */ + +#define saa_readl(reg) readl(dev->lmmio + (reg)) +#define saa_writel(reg,value) writel((value), dev->lmmio + (reg)); +#define saa_andorl(reg,mask,value) \ + writel((readl(dev->lmmio+(reg)) & ~(mask)) |\ + ((value) & (mask)), dev->lmmio+(reg)) +#define saa_setl(reg,bit) saa_andorl((reg),(bit),(bit)) +#define saa_clearl(reg,bit) saa_andorl((reg),(bit),0) + +#define saa_readb(reg) readb(dev->bmmio + (reg)) +#define saa_writeb(reg,value) writeb((value), dev->bmmio + (reg)); +#define saa_andorb(reg,mask,value) \ + writeb((readb(dev->bmmio+(reg)) & ~(mask)) |\ + ((value) & (mask)), dev->bmmio+(reg)) +#define saa_setb(reg,bit) saa_andorb((reg),(bit),(bit)) +#define saa_clearb(reg,bit) saa_andorb((reg),(bit),0) + + +/* ----------------------------------------------------------- */ +/* saa7134-core.c */ + +extern struct list_head saa7134_devlist; +extern int saa7134_devcount; + +void saa7134_print_ioctl(char *name, unsigned int cmd); +void saa7134_track_gpio(struct saa7134_dev *dev, char *msg); + +#define SAA7134_PGTABLE_SIZE 4096 + +int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt); +int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt, + struct scatterlist *list, int length, + int startpage); +void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt); + +int saa7134_buffer_count(int size, int count); +int saa7134_buffer_startpage(struct saa7134_buf *buf); +unsigned long saa7134_buffer_base(struct saa7134_buf *buf); + +int saa7134_buffer_queue(struct saa7134_dev *dev, struct saa7134_dmaqueue *q, + struct saa7134_buf *buf); +void saa7134_buffer_finish(struct saa7134_dev *dev, struct saa7134_dmaqueue *q, + int state); +void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q); +void saa7134_buffer_timeout(unsigned long data); +void saa7134_dma_free(struct saa7134_dev *dev,struct saa7134_buf *buf); + +int saa7134_set_dmabits(struct saa7134_dev *dev); + +/* ----------------------------------------------------------- */ +/* saa7134-cards.c */ + +extern struct saa7134_board saa7134_boards[]; +extern const int saa7134_bcount; +extern struct pci_device_id __devinitdata saa7134_pci_tbl[]; + + +/* ----------------------------------------------------------- */ +/* saa7134-i2c.c */ + +int saa7134_i2c_register(struct saa7134_dev *dev); +int saa7134_i2c_unregister(struct saa7134_dev *dev); +void saa7134_i2c_call_clients(struct saa7134_dev *dev, + unsigned int cmd, void *arg); + + +/* ----------------------------------------------------------- */ +/* saa7134-video.c */ + +extern struct video_device saa7134_video_template; +extern struct video_device saa7134_radio_template; + +int saa7134_common_ioctl(struct saa7134_dev *dev, + unsigned int cmd, void *arg); + +int saa7134_video_init(struct saa7134_dev *dev); +int saa7134_video_fini(struct saa7134_dev *dev); +void saa7134_irq_video_intl(struct saa7134_dev *dev); +void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status); + + +/* ----------------------------------------------------------- */ +/* saa7134-ts.c */ + +extern struct video_device saa7134_ts_template; +int saa7134_ts_init(struct saa7134_dev *dev); +int saa7134_ts_fini(struct saa7134_dev *dev); +void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status); + + +/* ----------------------------------------------------------- */ +/* saa7134-vbi.c */ + +extern struct videobuf_queue_ops saa7134_vbi_qops; +extern struct video_device saa7134_vbi_template; + +int saa7134_vbi_init(struct saa7134_dev *dev); +int saa7134_vbi_fini(struct saa7134_dev *dev); +void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status); + + +/* ----------------------------------------------------------- */ +/* saa7134-tvaudio.c */ + +void saa7134_tvaudio_setmute(struct saa7134_dev *dev); +void saa7134_tvaudio_setinput(struct saa7134_dev *dev, + struct saa7134_input *in); +void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level); +int saa7134_tvaudio_getstereo(struct saa7134_dev *dev, + struct saa7134_tvaudio *audio); + +int saa7134_tvaudio_init(struct saa7134_dev *dev); +int saa7134_tvaudio_fini(struct saa7134_dev *dev); +int saa7134_tvaudio_do_scan(struct saa7134_dev *dev); + + +/* ----------------------------------------------------------- */ +/* saa7134-oss.c */ + +extern struct file_operations saa7134_dsp_fops; +extern struct file_operations saa7134_mixer_fops; + +int saa7134_oss_init(struct saa7134_dev *dev); +int saa7134_oss_fini(struct saa7134_dev *dev); +void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status); + + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru a/drivers/media/video/tuner.c b/drivers/media/video/tuner.c --- a/drivers/media/video/tuner.c Mon Nov 4 14:31:02 2002 +++ b/drivers/media/video/tuner.c Mon Nov 4 14:31:02 2002 @@ -101,10 +101,16 @@ /* system switching for Philips FI1216MF MK2 from datasheet "1996 Jul 09", + standard BG L L' + picture carrier 38.90 38.90 33.95 + colour 34.47 34.37 38.38 + sound 1 33.40 32.40 40.45 + sound 2 33.16 - - + NICAM 33.05 33.05 39.80 */ #define PHILIPS_MF_SET_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */ -#define PHILIPS_MF_SET_PAL_L 0x03 -#define PHILIPS_MF_SET_PAL_L2 0x02 +#define PHILIPS_MF_SET_PAL_L 0x03 // France +#define PHILIPS_MF_SET_PAL_L2 0x02 // L' /* ---------------------------------------------------------------------- */ @@ -121,7 +127,9 @@ unsigned char VHF_H; unsigned char UHF; unsigned char config; - unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL, 732=16*45.75 NTSC */ + unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL, + 732 =16*45.75 NTSCi, + 940 =58.75 NTSC-Japan */ }; /* @@ -132,16 +140,16 @@ static struct tunertype tuners[] = { { "Temic PAL (4002 FH5)", TEMIC, PAL, 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623}, - { "Philips PAL_I", Philips, PAL_I, + { "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I, 16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, - { "Philips NTSC", Philips, NTSC, + { "Philips NTSC (FI1236 and compatibles)", Philips, NTSC, 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732}, - { "Philips SECAM", Philips, SECAM, + { "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", Philips, SECAM, 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623}, { "NoTuner", NoTuner, NOTUNER, 0,0,0x00,0x00,0x00,0x00,0x00}, - { "Philips PAL", Philips, PAL, + { "Philips PAL_BG (FI1216 and compatibles)", Philips, PAL, 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623}, { "Temic NTSC (4032 FY5)", TEMIC, NTSC, 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732}, @@ -181,7 +189,7 @@ 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732}, { "Temic PAL/SECAM multi (4046 FM5)", TEMIC, PAL, 16*169.00, 16*454.00, 0xa0,0x90,0x30,0x8e,623}, - { "Philips PAL_DK", Philips, PAL, + { "Philips PAL_DK (FI1256 and compatibles)", Philips, PAL, 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, { "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL, @@ -200,7 +208,7 @@ { "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL, 16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}, { "SHARP NTSC_JP (2U5JF5540)", SHARP, NTSC, /* 940=16*58.75 NTSC@Japan */ - 16*137.25,16*317.25,0x01,0x02,0x08,0x8e,940}, + 16*137.25,16*317.25,0x01,0x02,0x08,0x8e,732 }, // Corrected to NTSC=732 (was:940) { "Samsung PAL TCPM9091PD27", Samsung, PAL, /* from sourceforge v3tv */ 16*169,16*464,0xA0,0x90,0x30,0x8e,623}, @@ -215,8 +223,10 @@ 16*158.00, 16*453.00, 0xa0,0x90,0x30,0x8e,732}, { "LG PAL (newer TAPC series)", LGINNOTEK, PAL, 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,623}, - { "Philips PAL/SECAM multi (FM1216ME)", Philips, PAL, + { "Philips PAL/SECAM multi (FM1216ME MK3)", Philips, PAL, 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 }, + { "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC, + 16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732}, }; #define TUNERS (sizeof(tuners)/sizeof(struct tunertype)) @@ -295,6 +305,13 @@ } printk("\n "); } + // Look for MT2032 id: + // part= 0x04(MT2032), 0x06(MT2030), 0x07(MT2040) + if((buf[0x11] != 0x4d) || (buf[0x12] != 0x54) || (buf[0x13] != 0x04)) { + printk("not a MT2032.\n"); + return 0; + } + // Initialize Registers per spec. buf[1]=2; // Index to register 2 @@ -621,7 +638,7 @@ /* tv norm specific stuff for multi-norm tuners */ switch (t->type) { - case TUNER_PHILIPS_SECAM: + case TUNER_PHILIPS_SECAM: // FI1216MF /* 0x01 -> ??? no change ??? */ /* 0x02 -> PAL BDGHI / SECAM L */ /* 0x04 -> ??? PAL others / SECAM others ??? */ @@ -751,7 +768,7 @@ buffer[1] = div & 0xff; buffer[2] = tun->config; switch (t->type) { - case TUNER_PHILIPS_FM1216ME: + case TUNER_PHILIPS_FM1216ME_MK3: buffer[3] = 0x19; break; default: @@ -857,12 +874,14 @@ /* --- configuration --- */ case TUNER_SET_TYPE: - if (t->type != -1) + if (t->type != -1) { + printk("tuner: type already set\n"); return 0; + } if (*iarg < 0 || *iarg >= TUNERS) return 0; t->type = *iarg; - dprintk("tuner: type set to %d (%s)\n", + printk("tuner: type set to %d (%s)\n", t->type,tuners[t->type].name); strncpy(client->name, tuners[t->type].name, sizeof(client->name)); if (t->type == TUNER_MT2032) @@ -965,7 +984,7 @@ }; static struct i2c_client client_template = { - name: "(unset)", + name: "(tuner unset)", flags: I2C_CLIENT_ALLOW_USE, driver: &driver, }; diff -Nru a/drivers/media/video/tuner.h b/drivers/media/video/tuner.h --- a/drivers/media/video/tuner.h Mon Nov 4 14:31:02 2002 +++ b/drivers/media/video/tuner.h Mon Nov 4 14:31:02 2002 @@ -62,7 +62,9 @@ #define TUNER_TEMIC_4012FY5 35 /* 4012 FY5 (3X 0971, 1099)*/ #define TUNER_TEMIC_4136FY5 36 /* 4136 FY5 (3X 7708, 7746)*/ #define TUNER_LG_PAL_NEW_TAPC 37 -#define TUNER_PHILIPS_FM1216ME 38 +#define TUNER_PHILIPS_FM1216ME_MK3 38 +#define TUNER_LG_NTSC_NEW_TAPC 39 + @@ -84,7 +86,9 @@ #define TUNER_SET_TYPE _IOW('t',1,int) /* set tuner type */ #define TUNER_SET_TVFREQ _IOW('t',2,int) /* set tv freq */ -#define TUNER_SET_RADIOFREQ _IOW('t',3,int) /* set radio freq */ -#define TUNER_SET_MODE _IOW('t',4,int) /* set tuner mode */ +#if 0 /* obsolete */ +# define TUNER_SET_RADIOFREQ _IOW('t',3,int) /* set radio freq */ +# define TUNER_SET_MODE _IOW('t',4,int) /* set tuner mode */ +#endif #endif diff -Nru a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/v4l2-common.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,211 @@ +/* + * Video for Linux Two + * + * A generic video device interface for the LINUX operating system + * using a set of device structures/vectors for low level operations. + * + * This file replaces the videodev.c file that comes with the + * regular kernel distribution. + * + * 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. + * + * Author: Bill Dirks + * based on code by Alan Cox, + * + */ + +/* + * Video capture interface for Linux + * + * A generic video device interface for the LINUX operating system + * using a set of device structures/vectors for low level operations. + * + * 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. + * + * Author: Alan Cox, + * + * Fixes: + */ + +/* + * Video4linux 1/2 integration by Justin Schoeman + * + * 2.4 PROCFS support ported from 2.4 kernels by + * Iñaki García Etxebarria + * Makefile fix by "W. Michael Petullo" + * 2.4 devfs support ported from 2.4 kernels by + * Dan Merillat + * Added Gerd Knorrs v4l1 enhancements (Justin Schoeman) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_KMOD +#include +#endif + +#if defined(CONFIG_UST) || defined(CONFIG_UST_MODULE) +#include +#endif + +#include + +MODULE_AUTHOR("Bill Dirks, Justin Schoeman, Gerd Knorr"); +MODULE_DESCRIPTION("misc helper functions for v4l2 device drivers"); +MODULE_LICENSE("GPL"); + +/* + * + * V 4 L 2 D R I V E R H E L P E R A P I + * + */ + +/* + * Video Standard Operations (contributed by Michael Schimek) + */ + +/* This is the recommended method to deal with the framerate fields. More + sophisticated drivers will access the fields directly. */ +unsigned int +v4l2_video_std_fps(struct v4l2_standard *vs) +{ + if (vs->frameperiod.numerator > 0) + return (((vs->frameperiod.denominator << 8) / + vs->frameperiod.numerator) + + (1 << 7)) / (1 << 8); + return 0; +} + +/* Fill in the fields of a v4l2_standard structure according to the + 'id' and 'transmission' parameters. Returns negative on error. */ +int v4l2_video_std_construct(struct v4l2_standard *vs, + int id, char *name) +{ + memset(vs, 0, sizeof(struct v4l2_standard)); + + vs->id = id; + if (id & (V4L2_STD_NTSC | V4L2_STD_PAL_M)) { + vs->frameperiod.numerator = 1001; + vs->frameperiod.denominator = 30000; + vs->framelines = 525; + } else { + vs->frameperiod.numerator = 1; + vs->frameperiod.denominator = 25; + vs->framelines = 625; + } + strncpy(vs->name,name,sizeof(vs->name)); + return 0; +} + + +/* ----------------------------------------------------------------- */ + +char *v4l2_field_names[] = { + [V4L2_FIELD_ANY] = "any", + [V4L2_FIELD_NONE] = "none", + [V4L2_FIELD_TOP] = "top", + [V4L2_FIELD_BOTTOM] = "bottom", + [V4L2_FIELD_INTERLACED] = "interlaced", + [V4L2_FIELD_SEQ_TB] = "seq-tb", + [V4L2_FIELD_SEQ_BT] = "seq-bt", + [V4L2_FIELD_ALTERNATE] = "alternate", +}; + +char *v4l2_type_names[] = { + [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap", + [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over", + [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out", + [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", + [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", +}; + +char *v4l2_ioctl_names[256] = { +#if __GNUC__ >= 3 + [0 ... 255] = "UNKNOWN", +#endif + [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP", + [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED", + [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT", + [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT", + [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT", +#if 0 + [_IOC_NR(VIDIOC_G_COMP)] = "VIDIOC_G_COMP", + [_IOC_NR(VIDIOC_S_COMP)] = "VIDIOC_S_COMP", +#endif + [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS", + [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF", + [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF", + [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF", + [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY", + [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF", + [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF", + [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON", + [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF", + [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM", + [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM", + [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD", + [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD", + [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD", + [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT", + [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL", + [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL", + [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER", + [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER", + [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO", + [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO", + [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL", + [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU", + [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT", + [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT", + [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT", + [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT", + [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT", + [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT", + [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT", + [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR", + [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR", + [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY", + [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY", + [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP", + [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP", + [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP", + [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP", + [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP", + [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD", + [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT", +}; + +/* ----------------------------------------------------------------- */ + +EXPORT_SYMBOL(v4l2_video_std_fps); +EXPORT_SYMBOL(v4l2_video_std_construct); + +EXPORT_SYMBOL(v4l2_field_names); +EXPORT_SYMBOL(v4l2_type_names); +EXPORT_SYMBOL(v4l2_ioctl_names); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c --- a/drivers/media/video/video-buf.c Mon Nov 4 14:31:01 2002 +++ b/drivers/media/video/video-buf.c Mon Nov 4 14:31:01 2002 @@ -26,6 +26,11 @@ #include #include +#ifndef TryLockPage +# include "linux/page-flags.h" +# define TryLockPage TestSetPageLocked +#endif + #include "video-buf.h" static int debug = 0; @@ -65,12 +70,12 @@ return NULL; } -struct scatterlist * +struct scatterlist* videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) { struct scatterlist *sglist; int i = 0; - + if (NULL == pages[0]) return NULL; sglist = kmalloc(sizeof(*sglist) * nr_pages, GFP_KERNEL); @@ -80,21 +85,27 @@ if (PageHighMem(pages[0])) /* DMA to highmem pages might not work */ - goto err; + goto highmem; sglist[0].page = pages[0]; sglist[0].offset = offset; sglist[0].length = PAGE_SIZE - offset; for (i = 1; i < nr_pages; i++) { if (NULL == pages[i]) - goto err; + goto nopage; if (PageHighMem(pages[i])) - goto err; + goto highmem; sglist[i].page = pages[i]; sglist[i].length = PAGE_SIZE; } return sglist; - err: + nopage: + dprintk(2,"sgl: oops - no page\n"); + kfree(sglist); + return NULL; + + highmem: + dprintk(2,"sgl: oops - highmem page\n"); kfree(sglist); return NULL; } @@ -103,14 +114,18 @@ { int i; + dprintk(2,"lock start ...\n"); for (i = 0; i < nr_pages; i++) - if (TestSetPageLocked(pages[i])) + if (TryLockPage(pages[i])) goto err; + dprintk(2,"lock ok\n"); return 0; err: + dprintk(2,"lock failed, unlock ...\n"); while (i > 0) unlock_page(pages[--i]); + dprintk(2,"lock quit\n"); return -EINVAL; } @@ -118,8 +133,10 @@ { int i; + dprintk(2,"unlock start ...\n"); for (i = 0; i < nr_pages; i++) unlock_page(pages[i]); + dprintk(2,"unlock ok\n"); return 0; } @@ -128,6 +145,7 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, unsigned long data, unsigned long size) { + unsigned long first,last; int err, rw = 0; dma->direction = direction; @@ -137,25 +155,35 @@ default: BUG(); } - dma->offset = data & PAGE_MASK; - dma->nr_pages = ((((data+size) & ~PAGE_MASK) - - (data & ~PAGE_MASK)) >> PAGE_SHIFT) +1; - dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*), - GFP_KERNEL); + first = (data & PAGE_MASK) >> PAGE_SHIFT; + last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT; + dma->offset = data & ~PAGE_MASK; + dma->nr_pages = last-first+1; + dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*), + GFP_KERNEL); if (NULL == dma->pages) return -ENOMEM; + dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n", + data,size,dma->nr_pages); + down_read(¤t->mm->mmap_sem); err = get_user_pages(current,current->mm, - data, dma->nr_pages, - rw == READ, 0, /* don't force */ + data & PAGE_MASK, dma->nr_pages, + rw == READ, 1, /* force */ dma->pages, NULL); up_read(¤t->mm->mmap_sem); - return err; + if (err != dma->nr_pages) { + dma->nr_pages = (err >= 0) ? err : 0; + dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages); + return err < 0 ? err : -EINVAL; + } + return 0; } int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, int nr_pages) { + dprintk(1,"init kernel [%d pages]\n",nr_pages); dma->direction = direction; dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT); if (NULL == dma->vmalloc) { @@ -176,13 +204,14 @@ if (dma->pages) { if (0 != (err = videobuf_lock(dma->pages, dma->nr_pages))) { - dprintk(1,"videobuf_lock_pages: %d\n",err); + dprintk(1,"videobuf_lock: %d\n",err); return err; } dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages, dma->offset); + if (NULL == dma->sglist) + videobuf_unlock(dma->pages, dma->nr_pages); } - if (dma->vmalloc) { dma->sglist = videobuf_vmalloc_to_sg (dma->vmalloc,dma->nr_pages); @@ -215,7 +244,7 @@ dma->sglist = NULL; dma->sglen = 0; if (dma->pages) - videobuf_lock(dma->pages, dma->nr_pages); + videobuf_unlock(dma->pages, dma->nr_pages); return 0; } @@ -231,7 +260,6 @@ kfree(dma->pages); dma->pages = NULL; } - if (dma->vmalloc) { vfree(dma->vmalloc); dma->vmalloc = NULL; @@ -286,16 +314,12 @@ if (0 == vb->baddr) { /* no userspace addr -- kernel bounce buffer */ pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; - dprintk(1,"kernel buf size=%ld (%d pages)\n", - vb->size,pages); err = videobuf_dma_init_kernel(&vb->dma,PCI_DMA_FROMDEVICE, pages); if (0 != err) return err; } else { /* dma directly to userspace */ - dprintk(1,"user buf addr=%08lx size=%ld\n", - vb->baddr,vb->bsize); err = videobuf_dma_init_user(&vb->dma,PCI_DMA_FROMDEVICE, vb->baddr,vb->bsize); if (0 != err) @@ -314,7 +338,7 @@ struct videobuf_queue_ops *ops, struct pci_dev *pci, spinlock_t *irqlock, - int type, + enum v4l2_buf_type type, int msize) { memset(q,0,sizeof(*q)); @@ -329,6 +353,30 @@ INIT_LIST_HEAD(&q->stream); } +int +videobuf_queue_is_busy(struct videobuf_queue *q) +{ + int i; + + if (q->reading) + return 1; + if (q->streaming) + return 1; + if (q->read_buf) + return 1; + for (i = 0; i < VIDEO_MAX_FRAME; i++) { + if (NULL == q->bufs[i]) + continue; + if (q->bufs[i]->map) + return 1; + if (q->bufs[i]->state == STATE_QUEUED) + return 1; + if (q->bufs[i]->state == STATE_ACTIVE) + return 1; + } + return 0; +} + void videobuf_queue_cancel(struct file *file, struct videobuf_queue *q) { @@ -358,15 +406,15 @@ /* --------------------------------------------------------------------- */ -#ifdef HAVE_V4L2 void -videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb, int type) +videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb, + enum v4l2_buf_type type) { - b->index = vb->i; - b->type = type; - b->offset = vb->boff; - b->length = vb->bsize; - b->flags = 0; + b->index = vb->i; + b->type = type; + b->m.offset = vb->boff; + b->length = vb->bsize; + b->flags = 0; if (vb->map) b->flags |= V4L2_BUF_FLAG_MAPPED; switch (vb->state) { @@ -384,12 +432,7 @@ /* nothing */ break; } - if (!(vb->field & VBUF_FIELD_INTER)) { - if (vb->field & VBUF_FIELD_ODD) - b->flags |= V4L2_BUF_FLAG_TOPFIELD; - if (vb->field & VBUF_FIELD_EVEN) - b->flags |= V4L2_BUF_FLAG_BOTFIELD; - } + b->field = vb->field; b->timestamp = vb->ts; b->bytesused = vb->size; b->sequence = vb->field_count >> 1; @@ -401,7 +444,7 @@ { int size,count,retval; - if ((req->type & V4L2_BUF_TYPE_field) != q->type) + if (req->type != q->type) return -EINVAL; if (req->count < 1) return -EINVAL; @@ -428,11 +471,11 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) { - if ((b->type & V4L2_BUF_TYPE_field) != q->type) + if (unlikely(b->type != q->type)) return -EINVAL; - if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) + if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) return -EINVAL; - if (NULL == q->bufs[b->index]) + if (unlikely(NULL == q->bufs[b->index])) return -EINVAL; videobuf_status(b,q->bufs[b->index],q->type); return 0; @@ -444,7 +487,6 @@ { struct videobuf_buffer *buf; unsigned long flags; - int field = 0; int retval; down(&q->lock); @@ -452,7 +494,7 @@ if (q->reading) goto done; retval = -EINVAL; - if ((b->type & V4L2_BUF_TYPE_field) != q->type) + if (b->type != q->type) goto done; if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) goto done; @@ -465,11 +507,7 @@ buf->state == STATE_ACTIVE) goto done; - if (b->flags & V4L2_BUF_FLAG_TOPFIELD) - field |= VBUF_FIELD_ODD; - if (b->flags & V4L2_BUF_FLAG_BOTFIELD) - field |= VBUF_FIELD_EVEN; - retval = q->ops->buf_prepare(file,buf,field); + retval = q->ops->buf_prepare(file,buf); if (0 != retval) goto done; @@ -498,7 +536,7 @@ if (q->reading) goto done; retval = -EINVAL; - if ((b->type & V4L2_BUF_TYPE_field) != q->type) + if (b->type != q->type) goto done; if (list_empty(&q->stream)) goto done; @@ -526,7 +564,6 @@ up(&q->lock); return retval; } -#endif /* HAVE_V4L2 */ int videobuf_streamon(struct file *file, struct videobuf_queue *q) { @@ -586,7 +623,7 @@ q->read_buf->baddr = (unsigned long)data; q->read_buf->bsize = count; - retval = q->ops->buf_prepare(file,q->read_buf,0); + retval = q->ops->buf_prepare(file,q->read_buf); if (0 != retval) goto done; @@ -631,7 +668,7 @@ q->read_buf = videobuf_alloc(q->msize); if (NULL == q->read_buf) goto done; - retval = q->ops->buf_prepare(file,q->read_buf,0); + retval = q->ops->buf_prepare(file,q->read_buf); if (0 != retval) goto done; q->ops->buf_queue(file,q->read_buf); @@ -683,7 +720,7 @@ if (err) return err; for (i = 0; i < count; i++) { - err = q->ops->buf_prepare(file,q->bufs[i],0); + err = q->ops->buf_prepare(file,q->bufs[i]); if (err) return err; list_add_tail(&q->bufs[i]->stream, &q->stream); @@ -1008,6 +1045,8 @@ /* --------------------------------------------------------------------- */ EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg); +EXPORT_SYMBOL_GPL(videobuf_lock); +EXPORT_SYMBOL_GPL(videobuf_unlock); EXPORT_SYMBOL_GPL(videobuf_dma_init_user); EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel); @@ -1022,14 +1061,13 @@ EXPORT_SYMBOL_GPL(videobuf_queue_init); EXPORT_SYMBOL_GPL(videobuf_queue_cancel); +EXPORT_SYMBOL_GPL(videobuf_queue_is_busy); -#ifdef HAVE_V4L2 EXPORT_SYMBOL_GPL(videobuf_status); EXPORT_SYMBOL_GPL(videobuf_reqbufs); EXPORT_SYMBOL_GPL(videobuf_querybuf); EXPORT_SYMBOL_GPL(videobuf_qbuf); EXPORT_SYMBOL_GPL(videobuf_dqbuf); -#endif EXPORT_SYMBOL_GPL(videobuf_streamon); EXPORT_SYMBOL_GPL(videobuf_streamoff); diff -Nru a/drivers/media/video/video-buf.h b/drivers/media/video/video-buf.h --- a/drivers/media/video/video-buf.h Mon Nov 4 14:31:02 2002 +++ b/drivers/media/video/video-buf.h Mon Nov 4 14:31:02 2002 @@ -28,12 +28,14 @@ struct scatterlist* videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages); /* - * Return a scatterlist for a an array of userpages (NULL on errors). Memory - * for the scatterlist is allocated using kmalloc. The caller must - * free the memory. + * Return a scatterlist for a an array of userpages (NULL on errors). + * Memory for the scatterlist is allocated using kmalloc. The caller + * must free the memory. */ -struct scatterlist *videobuf_pages_to_sg(struct page **pages, int nr_pages, +struct scatterlist* videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset); +int videobuf_lock(struct page **pages, int nr_pages); +int videobuf_unlock(struct page **pages, int nr_pages); /* --------------------------------------------------------------------- */ @@ -58,8 +60,8 @@ struct videobuf_dmabuf { /* for userland buffer */ - struct page **pages; int offset; + struct page **pages; /* for kernel buffers */ void *vmalloc; @@ -115,10 +117,6 @@ struct videobuf_queue *q; }; -#define VBUF_FIELD_EVEN 1 -#define VBUF_FIELD_ODD 2 -#define VBUF_FIELD_INTER 4 - enum videobuf_state { STATE_NEEDS_INIT = 0, STATE_PREPARED = 1, @@ -136,30 +134,27 @@ int width; int height; long size; - int field; + enum v4l2_field field; enum videobuf_state state; struct videobuf_dmabuf dma; struct list_head stream; /* QBUF/DQBUF list */ /* for mmap'ed buffers */ - unsigned long boff; /* buffer offset (mmap) */ - unsigned long bsize; /* buffer size */ - unsigned long baddr; /* buffer addr (userland ptr!) */ + off_t boff; /* buffer offset (mmap) */ + size_t bsize; /* buffer size */ + unsigned long baddr; /* buffer addr (userland ptr!) */ struct videobuf_mapping *map; /* touched by irq handler */ struct list_head queue; wait_queue_head_t done; int field_count; -#ifdef HAVE_V4L2 - stamp_t ts; -#endif + struct timeval ts; }; struct videobuf_queue_ops { int (*buf_setup)(struct file *file, int *count, int *size); - int (*buf_prepare)(struct file *file,struct videobuf_buffer *vb, - int field); + int (*buf_prepare)(struct file *file,struct videobuf_buffer *vb); void (*buf_queue)(struct file *file,struct videobuf_buffer *vb); void (*buf_release)(struct file *file,struct videobuf_buffer *vb); }; @@ -169,7 +164,7 @@ spinlock_t *irqlock; struct pci_dev *pci; - int type; + enum v4l2_buf_type type; int msize; struct videobuf_buffer *bufs[VIDEO_MAX_FRAME]; struct videobuf_queue_ops *ops; @@ -191,12 +186,12 @@ void videobuf_queue_init(struct videobuf_queue *q, struct videobuf_queue_ops *ops, struct pci_dev *pci, spinlock_t *irqlock, - int type, int msize); + enum v4l2_buf_type type, int msize); +int videobuf_queue_is_busy(struct videobuf_queue *q); void videobuf_queue_cancel(struct file *file, struct videobuf_queue *q); -#ifdef HAVE_V4L2 void videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb, - int type); + enum v4l2_buf_type type); int videobuf_reqbufs(struct file *file, struct videobuf_queue *q, struct v4l2_requestbuffers *req); int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b); @@ -204,7 +199,6 @@ struct v4l2_buffer *b); int videobuf_dqbuf(struct file *file, struct videobuf_queue *q, struct v4l2_buffer *b); -#endif int videobuf_streamon(struct file *file, struct videobuf_queue *q); int videobuf_streamoff(struct file *file, struct videobuf_queue *q); diff -Nru a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig --- a/drivers/mtd/maps/Kconfig Mon Nov 4 14:31:02 2002 +++ b/drivers/mtd/maps/Kconfig Mon Nov 4 14:31:02 2002 @@ -346,5 +346,11 @@ cards are usually around 4-16MiB in size. This does not include Compact Flash cards which are treated as IDE devices. +config MTD_UCLINUX + tristate "Generic uClinux RAM/ROM filesystem support" + depends on MTD_PARTITIONS + help + Map driver to support image based filesystems for uClinux. + endmenu diff -Nru a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile --- a/drivers/mtd/maps/Makefile Mon Nov 4 14:31:00 2002 +++ b/drivers/mtd/maps/Makefile Mon Nov 4 14:31:00 2002 @@ -30,6 +30,7 @@ obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o obj-$(CONFIG_MTD_OCELOT) += ocelot.o +obj-$(CONFIG_MTD_UCLINUX) += uclinux.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o obj-$(CONFIG_MTD_PCI) += pci.o obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o diff -Nru a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/uclinux.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,171 @@ +/****************************************************************************/ + +/* + * uclinux.c -- generic memory mapped MTD driver for uclinux + * + * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) + */ + +/****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************/ + +__u8 uclinux_read8(struct map_info *map, unsigned long ofs) +{ + return(*((__u8 *) (map->map_priv_1 + ofs))); +} + +__u16 uclinux_read16(struct map_info *map, unsigned long ofs) +{ + return(*((__u16 *) (map->map_priv_1 + ofs))); +} + +__u32 uclinux_read32(struct map_info *map, unsigned long ofs) +{ + return(*((__u32 *) (map->map_priv_1 + ofs))); +} + +void uclinux_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy(to, (void *)(map->map_priv_1 + from), len); +} + +void uclinux_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + *((__u8 *) (map->map_priv_1 + adr)) = d; +} + +void uclinux_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + *((__u16 *) (map->map_priv_1 + adr)) = d; +} + +void uclinux_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + *((__u32 *) (map->map_priv_1 + adr)) = d; +} + +void uclinux_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy((void *) (map->map_priv_1 + to), from, len); +} + +/****************************************************************************/ + +struct map_info uclinux_ram_map = { + name: "RAM", + read8: uclinux_read8, + read16: uclinux_read16, + read32: uclinux_read32, + copy_from: uclinux_copy_from, + write8: uclinux_write8, + write16: uclinux_write16, + write32: uclinux_write32, + copy_to: uclinux_copy_to, +}; + +struct mtd_info *uclinux_ram_mtdinfo; + +/****************************************************************************/ + +struct mtd_partition uclinux_romfs[] = { + { name: "ROMfs", offset: 0 } +}; + +#define NUM_PARTITIONS (sizeof(uclinux_romfs) / sizeof(uclinux_romfs[0])) + +/****************************************************************************/ + +int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char **mtdbuf) +{ + struct map_info *map = (struct map_info *) mtd->priv; + *mtdbuf = (u_char *) (map->map_priv_1 + ((int) from)); + *retlen = len; + return(0); +} + +/****************************************************************************/ + +int __init uclinux_mtd_init(void) +{ + struct mtd_info *mtd; + struct map_info *mapp; + extern char _ebss; + + mapp = &uclinux_ram_map; + mapp->map_priv_2 = (unsigned long) &_ebss; + mapp->size = PAGE_ALIGN(*((unsigned long *)((&_ebss) + 8))); + mapp->buswidth = 4; + + printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n", + (int) mapp->map_priv_2, (int) mapp->size); + + mapp->map_priv_1 = (unsigned long) + ioremap_nocache(mapp->map_priv_2, mapp->size); + + if (mapp->map_priv_1 == 0) { + printk("uclinux[mtd]: ioremap_nocache() failed\n"); + return(-EIO); + } + + mtd = do_map_probe("map_ram", mapp); + if (!mtd) { + printk("uclinux[mtd]: failed to find a mapping?\n"); + iounmap((void *) mapp->map_priv_1); + return(-ENXIO); + } + + mtd->module = THIS_MODULE; + mtd->point = uclinux_point; + mtd->priv = mapp; + + uclinux_ram_mtdinfo = mtd; + add_mtd_partitions(mtd, uclinux_romfs, NUM_PARTITIONS); + + printk("uclinux[mtd]: set %s to be root filesystem\n", + uclinux_romfs[0].name); + ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 0); + put_mtd_device(mtd); + + return(0); +} + +/****************************************************************************/ + +void __exit uclinux_mtd_cleanup(void) +{ + if (uclinux_ram_mtdinfo) { + del_mtd_partitions(uclinux_ram_mtdinfo); + map_destroy(uclinux_ram_mtdinfo); + uclinux_ram_mtdinfo = NULL; + } + if (uclinux_ram_map.map_priv_1) { + iounmap((void *) uclinux_ram_map.map_priv_1); + uclinux_ram_map.map_priv_1 = 0; + } +} + +/****************************************************************************/ + +module_init(uclinux_mtd_init); +module_exit(uclinux_mtd_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Greg Ungerer "); +MODULE_DESCRIPTION("Generic RAM based MTD for uClinux"); + +/****************************************************************************/ diff -Nru a/drivers/net/3c509.c b/drivers/net/3c509.c --- a/drivers/net/3c509.c Mon Nov 4 14:31:00 2002 +++ b/drivers/net/3c509.c Mon Nov 4 14:31:00 2002 @@ -51,11 +51,13 @@ - Full duplex support v1.19 16Oct2002 Zwane Mwaikambo - Additional ethtool features + v1.19a 28Oct2002 Davud Ruggiero + - Increase *read_eeprom udelay to workaround oops with 2 cards. */ #define DRV_NAME "3c509" -#define DRV_VERSION "1.19" -#define DRV_RELDATE "16Oct2002" +#define DRV_VERSION "1.19a" +#define DRV_RELDATE "28Oct2002" /* A few values that may be tweaked. */ @@ -570,8 +572,9 @@ static ushort read_eeprom(int ioaddr, int index) { outw(EEPROM_READ + index, ioaddr + 10); - /* Pause for at least 162 us. for the read to take place. */ - udelay (500); + /* Pause for at least 162 us. for the read to take place. + Some chips seem to require much longer */ + mdelay(2); return inw(ioaddr + 12); } @@ -585,7 +588,8 @@ outb(EEPROM_READ + index, id_port); /* Pause for at least 162 us. for the read to take place. */ - udelay (500); + /* Some chips seem to require much longer */ + mdelay(4); for (bit = 15; bit >= 0; bit--) word = (word << 1) + (inb(id_port) & 0x01); diff -Nru a/drivers/net/68360enet.c b/drivers/net/68360enet.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/68360enet.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,953 @@ +/* + * Ethernet driver for Motorola MPC8xx. + * Copyright (c) 2000 Michael Leslie + * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) + * + * I copied the basic skeleton from the lance driver, because I did not + * know how to write the Linux driver, but I did know how the LANCE worked. + * + * This version of the driver is somewhat selectable for the different + * processor/board combinations. It works for the boards I know about + * now, and should be easily modified to include others. Some of the + * configuration information is contained in "commproc.h" and the + * remainder is here. + * + * Buffer descriptors are kept in the CPM dual port RAM, and the frame + * buffers are in the host memory. + * + * Right now, I am very watseful with the buffers. I allocate memory + * pages and then divide them into 2K frame buffers. This way I know I + * have buffers large enough to hold one frame within one buffer descriptor. + * Once I get this working, I will use 64 or 128 byte CPM buffers, which + * will be much more memory efficient and will easily handle lots of + * small packets. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* #include */ +/* #include */ +/* #include */ +#include +/* #include */ +#include + + +/* + * Theory of Operation + * + * The MPC8xx CPM performs the Ethernet processing on SCC1. It can use + * an aribtrary number of buffers on byte boundaries, but must have at + * least two receive buffers to prevent constant overrun conditions. + * + * The buffer descriptors are allocated from the CPM dual port memory + * with the data buffers allocated from host memory, just like all other + * serial communication protocols. The host memory buffers are allocated + * from the free page pool, and then divided into smaller receive and + * transmit buffers. The size of the buffers should be a power of two, + * since that nicely divides the page. This creates a ring buffer + * structure similar to the LANCE and other controllers. + * + * Like the LANCE driver: + * The driver runs as two independent, single-threaded flows of control. One + * is the send-packet routine, which enforces single-threaded use by the + * cep->tx_busy flag. The other thread is the interrupt handler, which is + * single threaded by the hardware and other software. + * + * The send packet thread has partial control over the Tx ring and the + * 'cep->tx_busy' flag. It sets the tx_busy flag whenever it's queuing a Tx + * packet. If the next queue slot is empty, it clears the tx_busy flag when + * finished otherwise it sets the 'lp->tx_full' flag. + * + * The MBX has a control register external to the MPC8xx that has some + * control of the Ethernet interface. Information is in the manual for + * your board. + * + * The RPX boards have an external control/status register. Consult the + * programming documents for details unique to your board. + * + * For the TQM8xx(L) modules, there is no control register interface. + * All functions are directly controlled using I/O pins. See commproc.h. + */ + + +/* The transmitter timeout + */ +#define TX_TIMEOUT (2*HZ) + +/* The number of Tx and Rx buffers. These are allocated statically here. + * We don't need to allocate pages for the transmitter. We just use + * the skbuffer directly. + */ +#ifdef CONFIG_ENET_BIG_BUFFERS +#define RX_RING_SIZE 64 +#define TX_RING_SIZE 64 /* Must be power of two */ +#define TX_RING_MOD_MASK 63 /* for this to work */ +#else +#define RX_RING_SIZE 8 +#define TX_RING_SIZE 8 /* Must be power of two */ +#define TX_RING_MOD_MASK 7 /* for this to work */ +#endif + +#define CPM_ENET_RX_FRSIZE 2048 /* overkill left over from ppc page-based allocation */ +static char rx_buf_pool[RX_RING_SIZE * CPM_ENET_RX_FRSIZE]; + + +/* The CPM stores dest/src/type, data, and checksum for receive packets. + */ +#define PKT_MAXBUF_SIZE 1518 +#define PKT_MINBUF_SIZE 64 +#define PKT_MAXBLR_SIZE 1520 + +/* The CPM buffer descriptors track the ring buffers. The rx_bd_base and + * tx_bd_base always point to the base of the buffer descriptors. The + * cur_rx and cur_tx point to the currently available buffer. + * The dirty_tx tracks the current buffer that is being sent by the + * controller. The cur_tx and dirty_tx are equal under both completely + * empty and completely full conditions. The empty/ready indicator in + * the buffer descriptor determines the actual condition. + */ +struct scc_enet_private { + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + ushort skb_cur; + ushort skb_dirty; + + /* CPM dual port RAM relative addresses. + */ + QUICC_BD *rx_bd_base; /* Address of Rx and Tx buffers. */ + QUICC_BD *tx_bd_base; + QUICC_BD *cur_rx, *cur_tx; /* The next free ring entry */ + QUICC_BD *dirty_tx; /* The ring entries to be free()ed. */ + volatile struct scc_regs *sccp; + /* struct net_device_stats stats; */ + struct net_device_stats stats; + uint tx_full; + /* spinlock_t lock; */ + volatile unsigned int lock; +}; + + + +static int scc_enet_open(struct net_device *dev); +static int scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int scc_enet_rx(struct net_device *dev); +/* static void scc_enet_interrupt(void *dev_id); */ +static void scc_enet_interrupt(int vec, void *dev_id, struct pt_regs *fp); +static int scc_enet_close(struct net_device *dev); +/* static struct net_device_stats *scc_enet_get_stats(struct net_device *dev); */ +static struct net_device_stats *scc_enet_get_stats(struct net_device *dev); +static void set_multicast_list(struct net_device *dev); + +/* Get this from various configuration locations (depends on board). +*/ +/*static ushort my_enet_addr[] = { 0x0800, 0x3e26, 0x1559 };*/ + +/* Typically, 860(T) boards use SCC1 for Ethernet, and other 8xx boards + * use SCC2. This is easily extended if necessary. + */ + +#define CONFIG_SCC1_ENET /* by default */ + +#ifdef CONFIG_SCC1_ENET +#define CPM_CR_ENET CPM_CR_CH_SCC1 +#define PROFF_ENET PROFF_SCC1 +#define SCC_ENET 0 +#define CPMVEC_ENET CPMVEC_SCC1 +#endif + +#ifdef CONFIG_SCC2_ENET +#define CPM_CR_ENET CPM_CR_CH_SCC2 +#define PROFF_ENET PROFF_SCC2 +#define SCC_ENET 1 /* Index, not number! */ +#define CPMVEC_ENET CPMVEC_SCC2 +#endif + +static int +scc_enet_open(struct net_device *dev) +{ + + /* I should reset the ring buffers here, but I don't yet know + * a simple way to do that. + * mleslie: That's no biggie. Worth doing, too. + */ + + /* netif_start_queue(dev); */ + return 0; /* Always succeed */ +} + + +static int +scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv; + volatile QUICC_BD *bdp; + + /* Fill in a Tx ring entry */ + bdp = cep->cur_tx; + +#ifndef final_version + if (bdp->status & BD_ENET_TX_READY) { + /* Ooops. All transmit buffers are full. Bail out. + * This should not happen, since cep->tx_busy should be set. + */ + printk("%s: tx queue full!.\n", dev->name); + return 1; + } +#endif + + /* Clear all of the status flags. + */ + bdp->status &= ~BD_ENET_TX_STATS; + + /* If the frame is short, tell CPM to pad it. + */ + if (skb->len <= ETH_ZLEN) + bdp->status |= BD_ENET_TX_PAD; + else + bdp->status &= ~BD_ENET_TX_PAD; + + /* Set buffer length and buffer pointer. + */ + bdp->length = skb->len; + /* bdp->buf = __pa(skb->data); */ + bdp->buf = skb->data; + + /* Save skb pointer. + */ + cep->tx_skbuff[cep->skb_cur] = skb; + + /* cep->stats.tx_bytes += skb->len; */ /* TODO: It would really be nice... */ + + cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK; + + + /* Push the data cache so the CPM does not get stale memory + * data. + */ +/* flush_dcache_range((unsigned long)(skb->data), */ +/* (unsigned long)(skb->data + skb->len)); */ + + /* spin_lock_irq(&cep->lock); */ /* TODO: SPINLOCK */ + local_irq_disable(); + if (cep->lock > 0) { + printk ("scc_enet_start_xmit() lock == %d\n", cep->lock); + } else { + cep->lock++; + } + + /* Send it on its way. Tell CPM its ready, interrupt when done, + * its the last BD of the frame, and to put the CRC on the end. + */ + bdp->status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC); + + dev->trans_start = jiffies; + + /* If this was the last BD in the ring, start at the beginning again. + */ + if (bdp->status & BD_ENET_TX_WRAP) + bdp = cep->tx_bd_base; + else + bdp++; + + if (bdp->status & BD_ENET_TX_READY) { + /* netif_stop_queue(dev); */ + cep->tx_full = 1; + } + + cep->cur_tx = (QUICC_BD *)bdp; + + /* spin_unlock_irq(&cep->lock); */ /* TODO: SPINLOCK */ + cep->lock--; + sti(); + + return 0; +} + +#if 0 +static void +scc_enet_timeout(struct net_device *dev) +{ + struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv; + + printk("%s: transmit timed out.\n", dev->name); + cep->stats.tx_errors++; +#ifndef final_version + { + int i; + QUICC_BD *bdp; + printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n", + cep->cur_tx, cep->tx_full ? " (full)" : "", + cep->cur_rx); + bdp = cep->tx_bd_base; + for (i = 0 ; i < TX_RING_SIZE; i++, bdp++) + printk("%04x %04x %08x\n", + bdp->status, + bdp->length, + (int)(bdp->buf)); + bdp = cep->rx_bd_base; + for (i = 0 ; i < RX_RING_SIZE; i++, bdp++) + printk("%04x %04x %08x\n", + bdp->status, + bdp->length, + (int)(bdp->buf)); + } +#endif +/* if (!cep->tx_full) */ +/* netif_wake_queue(dev); */ +} +#endif + +/* The interrupt handler. + * This is called from the CPM handler, not the MPC core interrupt. + */ +/* static void scc_enet_interrupt(void *dev_id) */ +static void scc_enet_interrupt(int vec, void *dev_id, struct pt_regs *fp) +{ + struct net_device *dev = (struct net_device *)dev_id; + volatile struct scc_enet_private *cep; + volatile QUICC_BD *bdp; + ushort int_events; + int must_restart; + + cep = (struct scc_enet_private *)dev->priv; + + /* Get the interrupt events that caused us to be here. + */ + int_events = cep->sccp->scc_scce; + cep->sccp->scc_scce = int_events; + must_restart = 0; + + /* Handle receive event in its own function. + */ + if (int_events & SCCE_ENET_RXF) + scc_enet_rx(dev_id); + + /* Check for a transmit error. The manual is a little unclear + * about this, so the debug code until I get it figured out. It + * appears that if TXE is set, then TXB is not set. However, + * if carrier sense is lost during frame transmission, the TXE + * bit is set, "and continues the buffer transmission normally." + * I don't know if "normally" implies TXB is set when the buffer + * descriptor is closed.....trial and error :-). + */ + + /* Transmit OK, or non-fatal error. Update the buffer descriptors. + */ + if (int_events & (SCCE_ENET_TXE | SCCE_ENET_TXB)) { + /* spin_lock(&cep->lock); */ /* TODO: SPINLOCK */ + /* local_irq_disable(); */ + if (cep->lock > 0) { + printk ("scc_enet_interrupt() lock == %d\n", cep->lock); + } else { + cep->lock++; + } + + bdp = cep->dirty_tx; + while ((bdp->status&BD_ENET_TX_READY)==0) { + if ((bdp==cep->cur_tx) && (cep->tx_full == 0)) + break; + + if (bdp->status & BD_ENET_TX_HB) /* No heartbeat */ + cep->stats.tx_heartbeat_errors++; + if (bdp->status & BD_ENET_TX_LC) /* Late collision */ + cep->stats.tx_window_errors++; + if (bdp->status & BD_ENET_TX_RL) /* Retrans limit */ + cep->stats.tx_aborted_errors++; + if (bdp->status & BD_ENET_TX_UN) /* Underrun */ + cep->stats.tx_fifo_errors++; + if (bdp->status & BD_ENET_TX_CSL) /* Carrier lost */ + cep->stats.tx_carrier_errors++; + + + /* No heartbeat or Lost carrier are not really bad errors. + * The others require a restart transmit command. + */ + if (bdp->status & + (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { + must_restart = 1; + cep->stats.tx_errors++; + } + + cep->stats.tx_packets++; + + /* Deferred means some collisions occurred during transmit, + * but we eventually sent the packet OK. + */ + if (bdp->status & BD_ENET_TX_DEF) + cep->stats.collisions++; + + /* Free the sk buffer associated with this last transmit. + */ + /* dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]); */ + dev_kfree_skb (cep->tx_skbuff[cep->skb_dirty]); + cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK; + + /* Update pointer to next buffer descriptor to be transmitted. + */ + if (bdp->status & BD_ENET_TX_WRAP) + bdp = cep->tx_bd_base; + else + bdp++; + + /* I don't know if we can be held off from processing these + * interrupts for more than one frame time. I really hope + * not. In such a case, we would now want to check the + * currently available BD (cur_tx) and determine if any + * buffers between the dirty_tx and cur_tx have also been + * sent. We would want to process anything in between that + * does not have BD_ENET_TX_READY set. + */ + + /* Since we have freed up a buffer, the ring is no longer + * full. + */ + if (cep->tx_full) { + cep->tx_full = 0; +/* if (netif_queue_stopped(dev)) */ +/* netif_wake_queue(dev); */ + } + + cep->dirty_tx = (QUICC_BD *)bdp; + } + + if (must_restart) { + volatile QUICC *cp; + + /* Some transmit errors cause the transmitter to shut + * down. We now issue a restart transmit. Since the + * errors close the BD and update the pointers, the restart + * _should_ pick up without having to reset any of our + * pointers either. + */ + cp = pquicc; + cp->cp_cr = + mk_cr_cmd(CPM_CR_ENET, CPM_CR_RESTART_TX) | CPM_CR_FLG; + while (cp->cp_cr & CPM_CR_FLG); + } + /* spin_unlock(&cep->lock); */ /* TODO: SPINLOCK */ + /* sti(); */ + cep->lock--; + } + + /* Check for receive busy, i.e. packets coming but no place to + * put them. This "can't happen" because the receive interrupt + * is tossing previous frames. + */ + if (int_events & SCCE_ENET_BSY) { + cep->stats.rx_dropped++; + printk("CPM ENET: BSY can't happen.\n"); + } + + return; +} + +/* During a receive, the cur_rx points to the current incoming buffer. + * When we update through the ring, if the next incoming buffer has + * not been given to the system, we just set the empty indicator, + * effectively tossing the packet. + */ +static int +scc_enet_rx(struct net_device *dev) +{ + struct scc_enet_private *cep; + volatile QUICC_BD *bdp; + struct sk_buff *skb; + ushort pkt_len; + + cep = (struct scc_enet_private *)dev->priv; + + /* First, grab all of the stats for the incoming packet. + * These get messed up if we get called due to a busy condition. + */ + bdp = cep->cur_rx; + + for (;;) { + if (bdp->status & BD_ENET_RX_EMPTY) + break; + +#ifndef final_version + /* Since we have allocated space to hold a complete frame, both + * the first and last indicators should be set. + */ + if ((bdp->status & (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) != + (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) + printk("CPM ENET: rcv is not first+last\n"); +#endif + + /* Frame too long or too short. + */ + if (bdp->status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) + cep->stats.rx_length_errors++; + if (bdp->status & BD_ENET_RX_NO) /* Frame alignment */ + cep->stats.rx_frame_errors++; + if (bdp->status & BD_ENET_RX_CR) /* CRC Error */ + cep->stats.rx_crc_errors++; + if (bdp->status & BD_ENET_RX_OV) /* FIFO overrun */ + cep->stats.rx_crc_errors++; + + /* Report late collisions as a frame error. + * On this error, the BD is closed, but we don't know what we + * have in the buffer. So, just drop this frame on the floor. + */ + if (bdp->status & BD_ENET_RX_CL) { + cep->stats.rx_frame_errors++; + } + else { + + /* Process the incoming frame. + */ + cep->stats.rx_packets++; + pkt_len = bdp->length; + /* cep->stats.rx_bytes += pkt_len; */ /* TODO: It would really be nice... */ + + /* This does 16 byte alignment, much more than we need. + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ + skb = dev_alloc_skb(pkt_len-4); + + if (skb == NULL) { + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + cep->stats.rx_dropped++; + } + else { + skb->dev = dev; + skb_put(skb,pkt_len-4); /* Make room */ + eth_copy_and_sum(skb, (unsigned char *)bdp->buf, pkt_len-4, 0); + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + } + } + + /* Clear the status flags for this buffer. + */ + bdp->status &= ~BD_ENET_RX_STATS; + + /* Mark the buffer empty. + */ + bdp->status |= BD_ENET_RX_EMPTY; + + /* Update BD pointer to next entry. + */ + if (bdp->status & BD_ENET_RX_WRAP) + bdp = cep->rx_bd_base; + else + bdp++; + + } + cep->cur_rx = (QUICC_BD *)bdp; + + return 0; +} + +static int +scc_enet_close(struct net_device *dev) +{ + /* Don't know what to do yet. + */ + /* netif_stop_queue(dev); */ + + return 0; +} + +/* static struct net_device_stats *scc_enet_get_stats(struct net_device *dev) */ +static struct net_device_stats *scc_enet_get_stats(struct net_device *dev) +{ + struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv; + + return &cep->stats; +} + +/* Set or clear the multicast filter for this adaptor. + * Skeleton taken from sunlance driver. + * The CPM Ethernet implementation allows Multicast as well as individual + * MAC address filtering. Some of the drivers check to make sure it is + * a group multicast address, and discard those that are not. I guess I + * will do the same for now, but just remove the test if you want + * individual filtering as well (do the upper net layers want or support + * this kind of feature?). + */ + +static void set_multicast_list(struct net_device *dev) +{ + struct scc_enet_private *cep; + struct dev_mc_list *dmi; + u_char *mcptr, *tdptr; + volatile scc_enet_t *ep; + int i, j; + volatile QUICC *cp = pquicc; + + cep = (struct scc_enet_private *)dev->priv; + + /* Get pointer to SCC area in parameter RAM. + */ + ep = (scc_enet_t *)dev->base_addr; + + if (dev->flags&IFF_PROMISC) { + + /* Log any net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + cep->sccp->scc_psmr |= ETHER_PRO; + } else { + + cep->sccp->scc_psmr &= ~ETHER_PRO; + + if (dev->flags & IFF_ALLMULTI) { + /* Catch all multicast addresses, so set the + * filter to all 1's. + */ + ep->sen_gaddr1 = 0xffff; + ep->sen_gaddr2 = 0xffff; + ep->sen_gaddr3 = 0xffff; + ep->sen_gaddr4 = 0xffff; + } + else { + /* Clear filter and add the addresses in the list. + */ + ep->sen_gaddr1 = 0; + ep->sen_gaddr2 = 0; + ep->sen_gaddr3 = 0; + ep->sen_gaddr4 = 0; + + dmi = dev->mc_list; + + for (i=0; imc_count; i++) { + + /* Only support group multicast for now. + */ + if (!(dmi->dmi_addr[0] & 1)) + continue; + + /* The address in dmi_addr is LSB first, + * and taddr is MSB first. We have to + * copy bytes MSB first from dmi_addr. + */ + mcptr = (u_char *)dmi->dmi_addr + 5; + tdptr = (u_char *)&ep->sen_taddrh; + for (j=0; j<6; j++) + *tdptr++ = *mcptr--; + + /* Ask CPM to run CRC and set bit in + * filter mask. + */ + cp->cp_cr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_SET_GADDR) | CPM_CR_FLG; + /* this delay is necessary here -- Cort */ + udelay(10); + while (cp->cp_cr & CPM_CR_FLG); + } + } + } +} + + +/* Initialize the CPM Ethernet on SCC. + */ +int scc_enet_init(void) +{ + struct net_device *dev; + struct scc_enet_private *cep; + int i, j; + unsigned char *eap; + /* unsigned long mem_addr; */ + /* pte_t *pte; */ + /* bd_t *bd; */ /* `board tag' used by ppc - TODO: integrate uC bootloader vars */ + volatile QUICC_BD *bdp; + volatile QUICC *cp; + volatile struct scc_regs *sccp; + volatile struct ethernet_pram *ep; + /* volatile immap_t *immap; */ + + cp = pquicc; /* Get pointer to Communication Processor */ + + /* immap = (immap_t *)IMAP_ADDR; */ /* and to internal registers */ + + /* bd = (bd_t *)__res; */ + + /* Allocate some private information. + */ + cep = (struct scc_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL); + memset(cep, 0, sizeof(*cep)); + /* __clear_user(cep,sizeof(*cep)); */ + /* spin_lock_init(&cep->lock); */ /* TODO: SPINLOCK */ + + /* Create an Ethernet device instance. + */ + dev = init_etherdev(0, 0); + + /* Get pointer to SCC area in parameter RAM. + */ + /* ep = (ethernet_pram *)(&cp->cp_dparam[PROFF_ENET]); */ + ep = &pquicc->pram[SCC_ENET].enet_scc; + + /* And another to the SCC register area. + */ + sccp = &pquicc->scc_regs[SCC_ENET]; + cep->sccp = sccp; /* Keep the pointer handy */ + + /* Disable receive and transmit in case EPPC-Bug started it. + */ + sccp->scc_gsmr.w.low &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + /* Set up 360 pins for SCC interface to ethernet transceiver. + * Pin mappings (PA_xx and PC_xx) are defined in commproc.h + */ + + /* Configure port A pins for Txd and Rxd. + */ + pquicc->pio_papar |= (PA_ENET_RXD | PA_ENET_TXD); + pquicc->pio_padir &= ~(PA_ENET_RXD | PA_ENET_TXD); + pquicc->pio_paodr &= ~PA_ENET_TXD; + + /* Configure port C pins to enable CLSN and RENA. + */ + pquicc->pio_pcpar &= ~(PC_ENET_CLSN | PC_ENET_RENA); + pquicc->pio_pcdir &= ~(PC_ENET_CLSN | PC_ENET_RENA); + pquicc->pio_pcso |= (PC_ENET_CLSN | PC_ENET_RENA); + + /* Configure port A for TCLK and RCLK. + */ + pquicc->pio_papar |= (PA_ENET_TCLK | PA_ENET_RCLK); + pquicc->pio_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK); + + /* Configure Serial Interface clock routing. + * First, clear all SCC bits to zero, then set the ones we want. + */ + pquicc->si_sicr &= ~SICR_ENET_MASK; + pquicc->si_sicr |= SICR_ENET_CLKRT; + + + /* Allocate space for the buffer descriptors in the DP ram. + * These are relative offsets in the DP ram address space. + * Initialize base addresses for the buffer descriptors. + */ + i = m360_cpm_dpalloc(sizeof(QUICC_BD) * RX_RING_SIZE); + ep->rbase = i; + cep->rx_bd_base = (QUICC_BD *)((uint)pquicc + i); + + i = m360_cpm_dpalloc(sizeof(QUICC_BD) * TX_RING_SIZE); + ep->tbase = i; + cep->tx_bd_base = (QUICC_BD *)((uint)pquicc + i); + + cep->dirty_tx = cep->cur_tx = cep->tx_bd_base; + cep->cur_rx = cep->rx_bd_base; + + /* Issue init Rx BD command for SCC. + * Manual says to perform an Init Rx parameters here. We have + * to perform both Rx and Tx because the SCC may have been + * already running. [In uCquicc's case, I don't think that is so - mles] + * In addition, we have to do it later because we don't yet have + * all of the BD control/status set properly. + cp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_INIT_RX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + */ + + /* Initialize function code registers for big-endian. + */ + ep->rfcr = (SCC_EB | SCC_FC_DMA); + ep->tfcr = (SCC_EB | SCC_FC_DMA); + + /* Set maximum bytes per receive buffer. + * This appears to be an Ethernet frame size, not the buffer + * fragment size. It must be a multiple of four. + */ + ep->mrblr = PKT_MAXBLR_SIZE; + + /* Set CRC preset and mask. + */ + ep->c_pres = 0xffffffff; + ep->c_mask = 0xdebb20e3; /* see 360UM p. 7-247 */ + + ep->crcec = 0; /* CRC Error counter */ + ep->alec = 0; /* alignment error counter */ + ep->disfc = 0; /* discard frame counter */ + + ep->pads = 0x8888; /* Tx short frame pad character */ + ep->ret_lim = 0x000f; /* Retry limit threshold */ + + ep->mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */ + ep->minflr = PKT_MINBUF_SIZE; /* minimum frame length register */ + + ep->maxd1 = PKT_MAXBLR_SIZE; /* maximum DMA1 length */ + ep->maxd2 = PKT_MAXBLR_SIZE; /* maximum DMA2 length */ + + /* Clear hash tables, group and individual. + */ + ep->gaddr1 = ep->gaddr2 = ep->gaddr3 = ep->gaddr4 = 0; + ep->iaddr1 = ep->iaddr2 = ep->iaddr3 = ep->iaddr4 = 0; + + /* Set Ethernet station address. + * + * The uCbootloader provides a hook to the kernel to retrieve + * stuff like the MAC address. This is retrieved in config_BSP() + */ +#if defined (CONFIG_UCQUICC) + { + extern unsigned char *scc1_hwaddr; + + eap = (char *)ep->paddr.b; + for (i=5; i>=0; i--) + *eap++ = dev->dev_addr[i] = scc1_hwaddr[i]; + } +#endif + + +/* #ifndef CONFIG_MBX */ +/* eap = (unsigned char *)&(ep->paddrh); */ + +/* for (i=5; i>=0; i--) */ +/* *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; */ +/* #else */ +/* for (i=5; i>=0; i--) */ +/* dev->dev_addr[i] = *eap++; */ +/* #endif */ + + ep->p_per = 0; /* 'cause the book says so */ + ep->taddr_l = 0; /* temp address (LSB) */ + ep->taddr_m = 0; + ep->taddr_h = 0; /* temp address (MSB) */ + + /* Now allocate the host memory pages and initialize the + * buffer descriptors. + */ + /* initialize rx buffer descriptors */ + bdp = cep->tx_bd_base; + for (j=0; j<(TX_RING_SIZE-1); j++) { + bdp->buf = 0; + bdp->status = 0; + bdp++; + } + bdp->buf = 0; + bdp->status = BD_SC_WRAP; + + + /* initialize rx buffer descriptors */ + bdp = cep->rx_bd_base; + for (j=0; j<(RX_RING_SIZE-1); j++) { + bdp->buf = &rx_buf_pool[j * CPM_ENET_RX_FRSIZE]; + bdp->status = BD_SC_EMPTY | BD_SC_INTRPT; + bdp++; + } + bdp->buf = &rx_buf_pool[j * CPM_ENET_RX_FRSIZE]; + bdp->status = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; + + + + /* Let's re-initialize the channel now. We have to do it later + * than the manual describes because we have just now finished + * the BD initialization. + */ + cp->cp_cr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cr & CPM_CR_FLG); + + cep->skb_cur = cep->skb_dirty = 0; + + sccp->scc_scce = 0xffff; /* Clear any pending events */ + + /* Enable interrupts for transmit error, complete frame + * received, and any transmit buffer we have also set the + * interrupt flag. + */ + sccp->scc_sccm = (SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); + + /* Install our interrupt handler. + */ + /* cpm_install_handler(CPMVEC_ENET, scc_enet_interrupt, dev); */ + request_irq(CPMVEC_ENET, scc_enet_interrupt, + IRQ_FLG_LOCK, dev->name, (void *)dev); + + /* Set GSMR_H to enable all normal operating modes. + * Set GSMR_L to enable Ethernet to MC68160. + */ + sccp->scc_gsmr.w.high = 0; + sccp->scc_gsmr.w.low = (SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | + SCC_GSMRL_TPP_10 | SCC_GSMRL_MODE_ENET); + + /* Set sync/delimiters. + */ + sccp->scc_dsr = 0xd555; + + /* Set processing mode. Use Ethernet CRC, catch broadcast, and + * start frame search 22 bit times after RENA. + */ + sccp->scc_psmr = (SCC_PMSR_ENCRC /* Ethernet CRC mode */ + /* | SCC_PSMR_HBC */ /* Enable heartbeat */ + /* | SCC_PMSR_PRO */ /* Promiscuous mode */ + /* | SCC_PMSR_FDE */ /* Full duplex enable */ + | ETHER_NIB_22); + /* sccp->scc_psmr = (SCC_PMSR_PRO | ETHER_CRC_32 | ETHER_NIB_22); */ + + + /* It is now OK to enable the Ethernet transmitter. + * Unfortunately, there are board implementation differences here. + */ +#if defined(CONFIG_UCQUICC) +/* immap->im_ioport.iop_pcpar |= PC_ENET_TENA; */ +/* immap->im_ioport.iop_pcdir &= ~PC_ENET_TENA; */ + cp->pio_pcpar |= PC_ENET_TENA; /* t_en */ + cp->pio_pcdir &= ~PC_ENET_TENA; + + cp->pip_pbpar &= ~(0x00000200); /* power up ethernet transceiver */ + cp->pip_pbdir |= (0x00000200); + cp->pip_pbdat |= (0x00000200); +#endif + + + dev->base_addr = (unsigned long)ep; + dev->priv = cep; +#if 0 + dev->name = "CPM_ENET"; +#endif + + /* The CPM Ethernet specific entries in the device structure. */ + dev->open = scc_enet_open; + dev->hard_start_xmit = scc_enet_start_xmit; + /* dev->tx_timeout = scc_enet_timeout; */ + /* dev->watchdog_timeo = TX_TIMEOUT; */ + dev->stop = scc_enet_close; + dev->get_stats = scc_enet_get_stats; + dev->set_multicast_list = set_multicast_list; + + /* And last, enable the transmit and receive processing. + */ + sccp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + printk("%s: CPM ENET Version 0.3, ", dev->name); + for (i=0; i<5; i++) + printk("%02x:", dev->dev_addr[i]); + printk("%02x\n", dev->dev_addr[5]); + + return 0; +} + + + +int m68360_enet_probe(struct device *dev) +{ + return(scc_enet_init ()); +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig --- a/drivers/net/Kconfig Mon Nov 4 14:31:02 2002 +++ b/drivers/net/Kconfig Mon Nov 4 14:31:02 2002 @@ -1541,6 +1541,20 @@ MIPS-32-based Baget embedded system. This chipset is better known via the NE2100 cards. +config 68360_ENET + bool "Motorola 68360 ethernet controller" + depends on M68360 + help + Say Y here if you want to use the built-in ethernet controller of + the Motorola 68360 processor. + +config FEC + bool "FEC ethernet controller (of ColdFire 5272)" + depends on M5272 + help + Say Y here if you want to use the built-in 10/100 Fast ethernet + controller on the Motorola ColdFire 5272 processor. + endmenu # diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile --- a/drivers/net/Makefile Mon Nov 4 14:31:01 2002 +++ b/drivers/net/Makefile Mon Nov 4 14:31:01 2002 @@ -76,13 +76,15 @@ obj-$(CONFIG_SEEQ8005) += seeq8005.o obj-$(CONFIG_ETHERTAP) += ethertap.o obj-$(CONFIG_NET_SB1000) += sb1000.o -obj-$(CONFIG_MAC8390) += daynaport.o 8390.o +obj-$(CONFIG_MAC8390) += mac8390.o 8390.o obj-$(CONFIG_APNE) += apne.o 8390.o obj-$(CONFIG_PCMCIA_PCNET) += 8390.o obj-$(CONFIG_SHAPER) += shaper.o obj-$(CONFIG_SK_G16) += sk_g16.o obj-$(CONFIG_HP100) += hp100.o obj-$(CONFIG_SMC9194) += smc9194.o +obj-$(CONFIG_FEC) += fec.o +obj-$(CONFIG_68360_ENET) += 68360enet.o obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o obj-$(CONFIG_ARM_ETHERH) += 8390.o obj-$(CONFIG_WD80x3) += wd.o 8390.o diff -Nru a/drivers/net/daynaport.c b/drivers/net/daynaport.c --- a/drivers/net/daynaport.c Mon Nov 4 14:31:02 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,922 +0,0 @@ -/* daynaport.c: A Macintosh 8390 based ethernet driver for linux. */ -/* - Derived from code: - - Written 1993-94 by Donald Becker. - - Copyright 1993 United States Government as represented by the - Director, National Security Agency. - - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - - TODO: - - The block output routines may be wrong for non Dayna - cards - - Fix this driver so that it will attempt to use the info - (i.e. iobase, iosize) given to it by the new and improved - NuBus code. - - Despite its misleading filename, this driver is not Dayna-specific - anymore. */ -/* Cabletron E6100 card support added by Tony Mantler (eek@escape.ca) April 1999 */ - -static const char *version = - "daynaport.c: v0.02 1999-05-17 Alan Cox (Alan.Cox@linux.org) and others\n"; -static int version_printed; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "8390.h" - -static int ns8390_probe1(struct net_device *dev, int word16, char *name, int id, - int prom, struct nubus_dev *ndev); - -static int ns8390_open(struct net_device *dev); -static void ns8390_no_reset(struct net_device *dev); -static int ns8390_close_card(struct net_device *dev); - -/* Interlan */ -static void interlan_reset(struct net_device *dev); - -/* Dayna */ -static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, - int ring_page); -static void dayna_block_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset); -static void dayna_block_output(struct net_device *dev, int count, - const unsigned char *buf, const int start_page); - -/* Sane (32-bit chunk memory read/write) */ -static void sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, - int ring_page); -static void sane_block_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset); -static void sane_block_output(struct net_device *dev, int count, - const unsigned char *buf, const int start_page); - -/* Slow Sane (16-bit chunk memory read/write) */ -static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, - int ring_page); -static void slow_sane_block_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset); -static void slow_sane_block_output(struct net_device *dev, int count, - const unsigned char *buf, const int start_page); - - -#define WD_START_PG 0x00 /* First page of TX buffer */ -#define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */ -#define WD13_STOP_PG 0x40 /* Last page +1 of RX ring */ - -#define CABLETRON_RX_START_PG 0x00 /* First page of RX buffer */ -#define CABLETRON_RX_STOP_PG 0x30 /* Last page +1 of RX ring */ -#define CABLETRON_TX_START_PG CABLETRON_RX_STOP_PG /* First page of TX buffer */ - - -#define DAYNA_MAC_BASE 0xf0007 -#define DAYNA_8390_BASE 0x80000 /* 3 */ -#define DAYNA_8390_MEM 0x00000 -#define DAYNA_MEMSIZE 0x04000 /* First word of each long ! */ - -#define APPLE_8390_BASE 0xE0000 -#define APPLE_8390_MEM 0xD0000 -#define APPLE_MEMSIZE 8192 /* FIXME: need to dynamically check */ - -#define KINETICS_MAC_BASE 0xf0004 /* first byte of each long */ -#define KINETICS_8390_BASE 0x80000 -#define KINETICS_8390_MEM 0x00000 /* first word of each long */ -#define KINETICS_MEMSIZE 8192 /* FIXME: need to dynamically check */ -/*#define KINETICS_MEMSIZE (0x10000/2) * CSA: on the board I have, at least */ - -#define CABLETRON_8390_BASE 0x90000 -#define CABLETRON_8390_MEM 0x00000 - -static int test_8390(volatile char *ptr, int scale) -{ - int regd; - int v; - - if(hwreg_present(&ptr[0x00])==0) - return -EIO; - if(hwreg_present(&ptr[0x0D<dr_sw == NUBUS_DRSW_DAYNA) - return NS8390_DAYNA; - if(ndev->dr_sw == NUBUS_DRSW_ASANTE) - return NS8390_ASANTE; - if(ndev->dr_sw == NUBUS_DRSW_FARALLON) /* farallon or sonic systems */ - return NS8390_FARALLON; - if(ndev->dr_sw == NUBUS_DRSW_KINETICS) - return NS8390_KINETICS; - /* My ATI Engineering card with this combination crashes the */ - /* driver trying to xmit packets. Best not touch it for now. */ - /* - 1999-05-20 (funaho@jurai.org) */ - if(ndev->dr_sw == NUBUS_DRSW_FOCUS) - return -1; - - /* Check the HW on this one, because it shares the same DrSW as - the on-board SONIC chips */ - if(ndev->dr_hw == NUBUS_DRHW_CABLETRON) - return NS8390_CABLETRON; - /* does anyone have one of these? */ - if(ndev->dr_hw == NUBUS_DRHW_INTERLAN) - return NS8390_INTERLAN; - - /* FIXME: what do genuine Apple boards look like? */ - return -1; -} - -/* - * Memory probe for 8390 cards - */ - -static int __init apple_8390_mem_probe(volatile unsigned short *p) -{ - int i, j; - /* - * Algorithm. - * 1. Check each block size of memory doesn't fault - * 2. Write a value to it - * 3. Check all previous blocks are unaffected - */ - - for(i=0;i<2;i++) - { - volatile unsigned short *m=p+4096*i; - /* Unwriteable - we have a fully decoded card and the - RAM end located */ - - if(hwreg_present(m)==0) - return 8192*i; - - *m=0xA5A0|i; - - for(j=0;jmem_start points - * at the memory ring, dev->mem_end gives the end of it. - */ - -int __init mac8390_probe(struct net_device *dev) -{ - static int slots; - volatile unsigned short *i; - volatile unsigned char *p; - int plen; - int id; - static struct nubus_dev* ndev; - - /* Find the first card that hasn't already been seen */ - while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, - NUBUS_TYPE_ETHERNET, ndev)) != NULL) { - /* Have we seen it already? */ - if (slots & (1<board->slot)) - continue; - slots |= 1<board->slot; - - /* Is it one of ours? */ - if ((id = ns8390_ident(ndev)) != -1) - break; - } - - /* Hm. No more cards, then */ - if (ndev == NULL) - return -ENODEV; - - dev = init_etherdev(dev, 0); - if (!dev) - return -ENOMEM; - SET_MODULE_OWNER(dev); - - if (!version_printed) { - printk(KERN_INFO "%s", version); - version_printed = 1; - } - - /* - * Dayna specific init - */ - if(id==NS8390_DAYNA) - { - dev->base_addr = (int)(ndev->board->slot_addr+DAYNA_8390_BASE); - dev->mem_start = (int)(ndev->board->slot_addr+DAYNA_8390_MEM); - dev->mem_end = dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */ - - printk(KERN_INFO "%s: daynaport. testing board: ", dev->name); - - printk("memory - "); - - i = (void *)dev->mem_start; - memset((void *)i,0xAA, DAYNA_MEMSIZE); - while(i<(volatile unsigned short *)dev->mem_end) - { - if(*i!=0xAAAA) - goto membad; - *i=0x5678; /* make sure we catch byte smearing */ - if(*i!=0x5678) - goto membad; - i+=2; /* Skip a word */ - } - - printk("controller - "); - - p=(void *)dev->base_addr; - plen=0; - - while(plen<0x3FF00) - { - if(test_8390(p,0)==0) - break; - if(test_8390(p,1)==0) - break; - if(test_8390(p,2)==0) - break; - if(test_8390(p,3)==0) - break; - plen++; - p++; - } - if(plen==0x3FF00) - goto membad; - printk("OK\n"); - dev->irq = SLOT2IRQ(ndev->board->slot); - if(ns8390_probe1(dev, 0, "dayna", id, -1, ndev)==0) - return 0; - } - /* Cabletron */ - if (id==NS8390_CABLETRON) { - int memsize = 16<<10; /* fix this */ - - dev->base_addr=(int)(ndev->board->slot_addr+CABLETRON_8390_BASE); - dev->mem_start=(int)(ndev->board->slot_addr+CABLETRON_8390_MEM); - dev->mem_end=dev->mem_start+memsize; - dev->irq = SLOT2IRQ(ndev->board->slot); - - /* The base address is unreadable if 0x00 has been written to the command register */ - /* Reset the chip by writing E8390_NODMA+E8390_PAGE0+E8390_STOP just to be sure */ - i = (void *)dev->base_addr; - *i = 0x21; - - printk(KERN_INFO "%s: cabletron: testing board: ", dev->name); - printk("%dK memory - ", memsize>>10); - i=(void *)dev->mem_start; - while(i<(volatile unsigned short *)(dev->mem_start+memsize)) - { - *i=0xAAAA; - if(*i!=0xAAAA) - goto membad; - *i=0x5555; - if(*i!=0x5555) - goto membad; - i+=2; /* Skip a word */ - } - printk("OK\n"); - - if(ns8390_probe1(dev, 1, "cabletron", id, -1, ndev)==0) - return 0; - } - /* Apple, Farallon, Asante */ - if(id==NS8390_APPLE || id==NS8390_FARALLON || id==NS8390_ASANTE) - { - int memsize; - - dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE); - dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM); - - memsize = apple_8390_mem_probe((void *)dev->mem_start); - - dev->mem_end=dev->mem_start+memsize; - dev->irq = SLOT2IRQ(ndev->board->slot); - - switch(id) - { - case NS8390_FARALLON: - printk(KERN_INFO "%s: farallon: testing board: ", dev->name); - break; - case NS8390_ASANTE: - printk(KERN_INFO "%s: asante: testing board: ", dev->name); - break; - case NS8390_APPLE: - default: - printk(KERN_INFO "%s: apple/clone: testing board: ", dev->name); - break; - } - - printk("%dK memory - ", memsize>>10); - - i=(void *)dev->mem_start; - memset((void *)i,0xAA, memsize); - while(i<(volatile unsigned short *)dev->mem_end) - { - if(*i!=0xAAAA) - goto membad; - *i=0x5555; - if(*i!=0x5555) - goto membad; - i+=2; /* Skip a word */ - } - printk("OK\n"); - - switch (id) - { - case NS8390_FARALLON: - if(ns8390_probe1(dev, 1, "farallon", id, -1, ndev)==0) - return 0; - break; - case NS8390_ASANTE: - if(ns8390_probe1(dev, 1, "asante", id, -1, ndev)==0) - return 0; - break; - case NS8390_APPLE: - default: - if(ns8390_probe1(dev, 1, "apple/clone", id, -1, ndev)==0) - return 0; - break; - } - } - /* Interlan */ - if(id==NS8390_INTERLAN) - { - /* As apple and asante */ - dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE); - dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM); - dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */ - dev->irq = SLOT2IRQ(ndev->board->slot); - if(ns8390_probe1(dev, 1, "interlan", id, -1, ndev)==0) - return 0; - } - /* Kinetics (Shiva Etherport) */ - if(id==NS8390_KINETICS) - { - dev->base_addr=(int)(ndev->board->slot_addr+KINETICS_8390_BASE); - dev->mem_start=(int)(ndev->board->slot_addr+KINETICS_8390_MEM); - dev->mem_end=dev->mem_start+KINETICS_MEMSIZE; /* 8K it seems */ - dev->irq = SLOT2IRQ(ndev->board->slot); - if(ns8390_probe1(dev, 0, "kinetics", id, -1, ndev)==0) - return 0; - } - - /* We should hopefully not get here */ - printk(KERN_ERR "Probe unsuccessful.\n"); - return -ENODEV; - - membad: - printk(KERN_ERR "failed at %p in %p - %p.\n", i, - (void *)dev->mem_start, (void *)dev->mem_end); - return -ENODEV; -} - -static int __init mac8390_ethernet_addr(struct nubus_dev* ndev, unsigned char addr[6]) -{ - struct nubus_dir dir; - struct nubus_dirent ent; - - /* Get the functional resource for this device */ - if (nubus_get_func_dir(ndev, &dir) == -1) - return -1; - if (nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent) == -1) - return -1; - - nubus_get_rsrc_mem(addr, &ent, 6); - return 0; -} - -static int __init ns8390_probe1(struct net_device *dev, int word16, char *model_name, - int type, int promoff, struct nubus_dev *ndev) -{ - static u32 fwrd4_offsets[16]={ - 0, 4, 8, 12, - 16, 20, 24, 28, - 32, 36, 40, 44, - 48, 52, 56, 60 - }; - static u32 back4_offsets[16]={ - 60, 56, 52, 48, - 44, 40, 36, 32, - 28, 24, 20, 16, - 12, 8, 4, 0 - }; - static u32 fwrd2_offsets[16]={ - 0, 2, 4, 6, - 8, 10, 12, 14, - 16, 18, 20, 22, - 24, 26, 28, 30 - }; - - unsigned char *prom = (unsigned char*) ndev->board->slot_addr + promoff; - - /* Allocate dev->priv and fill in 8390 specific dev fields. */ - if (ethdev_init(dev)) - { - printk ("%s: unable to get memory for dev->priv.\n", dev->name); - return -ENOMEM; - } - - /* OK, we are certain this is going to work. Setup the device. */ - - ei_status.name = model_name; - ei_status.word16 = word16; - - if (type==NS8390_CABLETRON) { - /* Cabletron card puts the RX buffer before the TX buffer */ - ei_status.tx_start_page = CABLETRON_TX_START_PG; - ei_status.rx_start_page = CABLETRON_RX_START_PG; - ei_status.stop_page = CABLETRON_RX_STOP_PG; - ei_status.rmem_start = dev->mem_start; - ei_status.rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256; - } else { - ei_status.tx_start_page = WD_START_PG; - ei_status.rx_start_page = WD_START_PG + TX_PAGES; - ei_status.stop_page = (dev->mem_end - dev->mem_start)/256; - ei_status.rmem_start = dev->mem_start + TX_PAGES*256; - ei_status.rmem_end = dev->mem_end; - } - - if(promoff==-1) /* Use nubus resources ? */ - { - if(mac8390_ethernet_addr(ndev, dev->dev_addr)) - { - printk("mac_ns8390: MAC address not in resources!\n"); - return -ENODEV; - } - } - else /* Pull it off the card */ - { - int i=0; - int x=1; - /* These should go in the end I hope */ - if(type==NS8390_DAYNA) - x=2; - if(type==NS8390_INTERLAN || type==NS8390_KINETICS) - x=4; - while(i<6) - { - dev->dev_addr[i]=*prom; - prom+=x; - if(i) - printk(":"); - printk("%02X",dev->dev_addr[i++]); - } - } - - printk(KERN_INFO "%s: %s in slot %X (type %s)\n", - dev->name, ndev->board->name, ndev->board->slot, model_name); - printk(KERN_INFO "MAC "); - { - int i; - for (i = 0; i < 6; i++) { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - } - printk(" IRQ %d, shared memory at %#lx-%#lx.\n", - dev->irq, dev->mem_start, dev->mem_end-1); - - switch(type) - { - case NS8390_DAYNA: /* Dayna card */ - case NS8390_KINETICS: /* Kinetics -- 8 bit config, but 16 bit mem */ - /* 16 bit, 4 word offsets */ - ei_status.reset_8390 = &ns8390_no_reset; - ei_status.block_input = &dayna_block_input; - ei_status.block_output = &dayna_block_output; - ei_status.get_8390_hdr = &dayna_get_8390_hdr; - ei_status.reg_offset = fwrd4_offsets; - break; - case NS8390_CABLETRON: /* Cabletron */ - /* 16 bit card, register map is short forward */ - ei_status.reset_8390 = &ns8390_no_reset; - /* Ctron card won't accept 32bit values read or written to it */ - ei_status.block_input = &slow_sane_block_input; - ei_status.block_output = &slow_sane_block_output; - ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; - ei_status.reg_offset = fwrd2_offsets; - break; - case NS8390_FARALLON: - case NS8390_APPLE: /* Apple/Asante/Farallon */ - /* 16 bit card, register map is reversed */ - ei_status.reset_8390 = &ns8390_no_reset; - ei_status.block_input = &slow_sane_block_input; - ei_status.block_output = &slow_sane_block_output; - ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; - ei_status.reg_offset = back4_offsets; - break; - case NS8390_ASANTE: - /* 16 bit card, register map is reversed */ - ei_status.reset_8390 = &ns8390_no_reset; - ei_status.block_input = &sane_block_input; - ei_status.block_output = &sane_block_output; - ei_status.get_8390_hdr = &sane_get_8390_hdr; - ei_status.reg_offset = back4_offsets; - break; - case NS8390_INTERLAN: /* Interlan */ - /* 16 bit card, map is forward */ - ei_status.reset_8390 = &interlan_reset; - ei_status.block_input = &sane_block_input; - ei_status.block_output = &sane_block_output; - ei_status.get_8390_hdr = &sane_get_8390_hdr; - ei_status.reg_offset = back4_offsets; - break; -#if 0 /* i think this suffered code rot. my kinetics card has much - * different settings. -- CSA [22-May-1999] */ - case NS8390_KINETICS: /* Kinetics */ - /* 8bit card, map is forward */ - ei_status.reset_8390 = &ns8390_no_reset; - ei_status.block_input = &sane_block_input; - ei_status.block_output = &sane_block_output; - ei_status.get_8390_hdr = &sane_get_8390_hdr; - ei_status.reg_offset = back4_offsets; - break; -#endif - default: - panic("Detected a card I can't drive - whoops\n"); - } - dev->open = &ns8390_open; - dev->stop = &ns8390_close_card; - - NS8390_init(dev, 0); - - return 0; -} - -static int ns8390_open(struct net_device *dev) -{ - int ret; - - ei_open(dev); - - /* At least on my card (a Focus Enhancements PDS card) I start */ - /* getting interrupts right away, so the driver needs to be */ - /* completely initialized before enabling the interrupt. */ - /* - funaho@jurai.org (1999-05-17) */ - - /* Non-slow interrupt, works around issues with the SONIC driver */ - ret = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev); - if (ret) { - printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq); - return ret; - } - return 0; -} - -static void ns8390_no_reset(struct net_device *dev) -{ - if (ei_debug > 1) - printk("Need to reset the NS8390 t=%lu...", jiffies); - ei_status.txing = 0; - if (ei_debug > 1) printk("reset not supported\n"); -} - -static int ns8390_close_card(struct net_device *dev) -{ - if (ei_debug > 1) - printk("%s: Shutting down ethercard.\n", dev->name); - free_irq(dev->irq, dev); - ei_close(dev); - return 0; -} - -/* - * Interlan Specific Code Starts Here - */ - -static void interlan_reset(struct net_device *dev) -{ - unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq)); - if (ei_debug > 1) - printk("Need to reset the NS8390 t=%lu...", jiffies); - ei_status.txing = 0; - /* This write resets the card */ - target[0xC0000]=0; - if (ei_debug > 1) printk("reset complete\n"); - return; -} - -/* - * Daynaport code (some is used by other drivers) - */ - - -/* Grab the 8390 specific header. Similar to the block_input routine, but - we don't need to be concerned with ring wrap as the header will be at - the start of a page, so we optimize accordingly. */ - - -/* Block input and output are easy on shared memory ethercards, and trivial - on the Daynaport card where there is no choice of how to do it. - The only complications are that the ring buffer wraps. -*/ - -static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count) -{ - volatile unsigned short *ptr; - unsigned short *target=to; - from<<=1; /* word, skip overhead */ - ptr=(unsigned short *)(dev->mem_start+from); - /* - * Leading byte? - */ - if (from&2) { - *((char *)target)++ = *(((char *)ptr++)-1); - count--; - } - while(count>=2) - { - *target++=*ptr++; /* Copy and */ - ptr++; /* skip cruft */ - count-=2; - } - /* - * Trailing byte ? - */ - if(count) - { - /* Big endian */ - unsigned short v=*ptr; - *((char *)target)=v>>8; - } -} - -static void dayna_memcpy_tocard(struct net_device *dev, int to, const void *from, int count) -{ - volatile unsigned short *ptr; - const unsigned short *src=from; - to<<=1; /* word, skip overhead */ - ptr=(unsigned short *)(dev->mem_start+to); - /* - * Leading byte? - */ - if (to&2) { /* avoid a byte write (stomps on other data) */ - ptr[-1] = (ptr[-1]&0xFF00)|*((unsigned char *)src)++; - ptr++; - count--; - } - while(count>=2) - { - *ptr++=*src++; /* Copy and */ - ptr++; /* skip cruft */ - count-=2; - } - /* - * Trailing byte ? - */ - if(count) - { - /* Big endian */ - unsigned short v=*src; - /* card doesn't like byte writes */ - *ptr=(*ptr&0x00FF)|(v&0xFF00); - } -} - -static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) -{ - unsigned long hdr_start = (ring_page - WD_START_PG)<<8; - dayna_memcpy_fromcard(dev, (void *)hdr, hdr_start, 4); - /* Register endianism - fix here rather than 8390.c */ - hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8); -} - -static void dayna_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) -{ - unsigned long xfer_base = ring_offset - (WD_START_PG<<8); - unsigned long xfer_start = xfer_base+dev->mem_start; - - /* - * Note the offset maths is done in card memory space which - * is word per long onto our space. - */ - - if (xfer_start + count > ei_status.rmem_end) - { - /* We must wrap the input move. */ - int semi_count = ei_status.rmem_end - xfer_start; - dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count); - count -= semi_count; - dayna_memcpy_fromcard(dev, skb->data + semi_count, - ei_status.rmem_start - dev->mem_start, count); - } - else - { - dayna_memcpy_fromcard(dev, skb->data, xfer_base, count); - } -} - -static void dayna_block_output(struct net_device *dev, int count, const unsigned char *buf, - int start_page) -{ - long shmem = (start_page - WD_START_PG)<<8; - - dayna_memcpy_tocard(dev, shmem, buf, count); -} - -/* - * Cards with full width memory - */ - - -static void sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) -{ - unsigned long hdr_start = (ring_page - WD_START_PG)<<8; - memcpy((void *)hdr, (char *)dev->mem_start+hdr_start, 4); - /* Register endianism - fix here rather than 8390.c */ - hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8); -} - -static void sane_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) -{ - unsigned long xfer_base = ring_offset - (WD_START_PG<<8); - unsigned long xfer_start = xfer_base+dev->mem_start; - - if (xfer_start + count > ei_status.rmem_end) - { - /* We must wrap the input move. */ - int semi_count = ei_status.rmem_end - xfer_start; - memcpy(skb->data, (char *)dev->mem_start+xfer_base, semi_count); - count -= semi_count; - memcpy(skb->data + semi_count, - (char *)ei_status.rmem_start, count); - } - else - { - memcpy(skb->data, (char *)dev->mem_start+xfer_base, count); - } -} - - -static void sane_block_output(struct net_device *dev, int count, const unsigned char *buf, - int start_page) -{ - long shmem = (start_page - WD_START_PG)<<8; - - memcpy((char *)dev->mem_start+shmem, buf, count); -} - -static void word_memcpy_tocard(void *tp, const void *fp, int count) -{ - volatile unsigned short *to = tp; - const unsigned short *from = fp; - - count++; - count/=2; - - while(count--) - *to++=*from++; -} - -static void word_memcpy_fromcard(void *tp, const void *fp, int count) -{ - unsigned short *to = tp; - const volatile unsigned short *from = fp; - - count++; - count/=2; - - while(count--) - *to++=*from++; -} - -static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) -{ - unsigned long hdr_start = (ring_page - WD_START_PG)<<8; - word_memcpy_fromcard((void *)hdr, (char *)dev->mem_start+hdr_start, 4); - /* Register endianism - fix here rather than 8390.c */ - hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8); -} - -static void slow_sane_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) -{ - unsigned long xfer_base = ring_offset - (WD_START_PG<<8); - unsigned long xfer_start = xfer_base+dev->mem_start; - - if (xfer_start + count > ei_status.rmem_end) - { - /* We must wrap the input move. */ - int semi_count = ei_status.rmem_end - xfer_start; - word_memcpy_fromcard(skb->data, (char *)dev->mem_start+xfer_base, semi_count); - count -= semi_count; - word_memcpy_fromcard(skb->data + semi_count, - (char *)ei_status.rmem_start, count); - } - else - { - word_memcpy_fromcard(skb->data, (char *)dev->mem_start+xfer_base, count); - } -} - -static void slow_sane_block_output(struct net_device *dev, int count, const unsigned char *buf, - int start_page) -{ - long shmem = (start_page - WD_START_PG)<<8; - - word_memcpy_tocard((char *)dev->mem_start+shmem, buf, count); -#if 0 - long shmem = (start_page - WD_START_PG)<<8; - volatile unsigned short *to=(unsigned short *)(dev->mem_start+shmem); - volatile int p; - unsigned short *bp=(unsigned short *)buf; - - count=(count+1)/2; - - while(count--) - { - *to++=*bp++; - for(p=0;p<10;p++) - p++; - } -#endif -} - -MODULE_LICENSE("GPL"); diff -Nru a/drivers/net/dl2k.c b/drivers/net/dl2k.c --- a/drivers/net/dl2k.c Mon Nov 4 14:31:01 2002 +++ b/drivers/net/dl2k.c Mon Nov 4 14:31:01 2002 @@ -535,7 +535,7 @@ { long ioaddr = dev->base_addr; - printk (KERN_INFO "%s: Tx timed out (%4.4lx), is buffer full?\n", + printk (KERN_INFO "%s: Tx timed out (%4.4x), is buffer full?\n", dev->name, readl (ioaddr + TxStatus)); rio_free_tx(dev, 0); dev->if_port = 0; diff -Nru a/drivers/net/fealnx.c b/drivers/net/fealnx.c --- a/drivers/net/fealnx.c Mon Nov 4 14:31:02 2002 +++ b/drivers/net/fealnx.c Mon Nov 4 14:31:02 2002 @@ -1155,8 +1155,8 @@ unsigned int old_linkok = np->linkok; if (debug) - printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x " - "config %8.8x.\n", dev->name, readl(ioaddr + ISR), + printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8lx " + "config %8.8lx.\n", dev->name, readl(ioaddr + ISR), readl(ioaddr + TCRRCR)); if (np->flags == HAS_MII_XCVR) { @@ -1184,7 +1184,7 @@ long ioaddr = dev->base_addr; int i; - printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," + printk(KERN_WARNING "%s: Transmit timed out, status %8.8lx," " resetting...\n", dev->name, readl(ioaddr + ISR)); { @@ -1555,7 +1555,7 @@ np->stats.rx_crc_errors += (readl(ioaddr + TALLY) & 0x7fff0000) >> 16; if (debug) - printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", + printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4lx.\n", dev->name, readl(ioaddr + ISR)); writel(np->imrvalue, ioaddr + IMR); diff -Nru a/drivers/net/fec.c b/drivers/net/fec.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/fec.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,1926 @@ +/* + * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx. + * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) + * + * This version of the driver is specific to the FADS implementation, + * since the board contains control registers external to the processor + * for the control of the LevelOne LXT970 transceiver. The MPC860T manual + * describes connections using the internal parallel port I/O, which + * is basically all of Port D. + * + * Right now, I am very watseful with the buffers. I allocate memory + * pages and then divide them into 2K frame buffers. This way I know I + * have buffers large enough to hold one frame within one buffer descriptor. + * Once I get this working, I will use 64 or 128 byte CPM buffers, which + * will be much more memory efficient and will easily handle lots of + * small packets. + * + * Much better multiple PHY support by Magnus Damm. + * Copyright (c) 2000 Ericsson Radio Systems AB. + * + * Support for FEC controller of ColdFire/5272. + * Copyrught (c) 2001-2002 Greg Ungerer (gerg@snapgear.com) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_M5272 +#include +#include +#include "fec.h" +#else +#include +#include +#include "commproc.h" +#endif + +static int opened = 0; +static int found = 0; + +/* + * Define the fixed address of the FEC hardware. + */ +#ifdef CONFIG_M5272 +static volatile fec_t *fec_hwp = (volatile fec_t *) (MCF_MBAR + 0x840); +static ushort my_enet_addr[] = { 0x00d0, 0xcf00, 0x0072 }; +#else +static volatile fec_t *fec_hwp = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec) +static ushort my_enet_addr[3]; +#endif /* CONFIG_M5272 */ + +/* + * Some hardware gets it MAC address out of local flash memory. + * if this is non-zero then assume it is the address to get MAC from. + */ +#if defined(CONFIG_NETtel) +#define FEC_FLASHMAC 0xf0006006 +#elif defined(CONFIG_GILBARCONAP) +#define FEC_FLASHMAC 0xf0006000 +#elif defined (CONFIG_MTD_KeyTechnology) +#define FEC_FLASHMAC 0xffe04000 +#else +#define FEC_FLASHMAC 0 +#endif + +unsigned char *fec_flashmac = (unsigned char *) FEC_FLASHMAC; + +/* Forward declarations of some structures to support different PHYs +*/ + +typedef struct { + uint mii_data; + void (*funct)(uint mii_reg, struct net_device *dev); +} phy_cmd_t; + +typedef struct { + uint id; + char *name; + + const phy_cmd_t *config; + const phy_cmd_t *startup; + const phy_cmd_t *ack_int; + const phy_cmd_t *shutdown; +} phy_info_t; + +/* The number of Tx and Rx buffers. These are allocated from the page + * pool. The code may assume these are power of two, so it it best + * to keep them that size. + * We don't need to allocate pages for the transmitter. We just use + * the skbuffer directly. + */ +#if 1 +#define FEC_ENET_RX_PAGES 4 +#define FEC_ENET_RX_FRSIZE 2048 +#define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE) +#define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES) +#define TX_RING_SIZE 8 /* Must be power of two */ +#define TX_RING_MOD_MASK 7 /* for this to work */ +#else +#define FEC_ENET_RX_PAGES 16 +#define FEC_ENET_RX_FRSIZE 2048 +#define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE) +#define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES) +#define TX_RING_SIZE 16 /* Must be power of two */ +#define TX_RING_MOD_MASK 15 /* for this to work */ +#endif + +/* Interrupt events/masks. +*/ +#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */ +#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */ +#define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */ +#define FEC_ENET_GRA ((uint)0x10000000) /* Graceful stop complete */ +#define FEC_ENET_TXF ((uint)0x08000000) /* Full frame transmitted */ +#define FEC_ENET_TXB ((uint)0x04000000) /* A buffer was transmitted */ +#define FEC_ENET_RXF ((uint)0x02000000) /* Full frame received */ +#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */ +#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */ +#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */ + +/* The FEC stores dest/src/type, data, and checksum for receive packets. + */ +#define PKT_MAXBUF_SIZE 1518 +#define PKT_MINBUF_SIZE 64 +#define PKT_MAXBLR_SIZE 1520 + +/* The FEC buffer descriptors track the ring buffers. The rx_bd_base and + * tx_bd_base always point to the base of the buffer descriptors. The + * cur_rx and cur_tx point to the currently available buffer. + * The dirty_tx tracks the current buffer that is being sent by the + * controller. The cur_tx and dirty_tx are equal under both completely + * empty and completely full conditions. The empty/ready indicator in + * the buffer descriptor determines the actual condition. + */ +struct fec_enet_private { + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + ushort skb_cur; + ushort skb_dirty; + + /* CPM dual port RAM relative addresses. + */ + cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ + cbd_t *tx_bd_base; + cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ + cbd_t *dirty_tx; /* The ring entries to be free()ed. */ + struct net_device_stats stats; + uint tx_full; + spinlock_t lock; + + uint phy_id; + uint phy_id_done; + uint phy_status; + uint phy_speed; + phy_info_t *phy; + struct work_struct phy_task; + + uint sequence_done; + + uint phy_addr; + + int link; + int old_link; + int full_duplex; +}; + +static int fec_enet_open(struct net_device *dev); +static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void fec_enet_mii(struct net_device *dev); +static void fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); +static void fec_enet_tx(struct net_device *dev); +static void fec_enet_rx(struct net_device *dev); +static int fec_enet_close(struct net_device *dev); +static struct net_device_stats *fec_enet_get_stats(struct net_device *dev); +static void set_multicast_list(struct net_device *dev); +static void fec_restart(struct net_device *dev, int duplex); +static void fec_stop(struct net_device *dev); + + +/* MII processing. We keep this as simple as possible. Requests are + * placed on the list (if there is room). When the request is finished + * by the MII, an optional function may be called. + */ +typedef struct mii_list { + uint mii_regval; + void (*mii_func)(uint val, struct net_device *dev); + struct mii_list *mii_next; +} mii_list_t; + +#define NMII 20 +mii_list_t mii_cmds[NMII]; +mii_list_t *mii_free; +mii_list_t *mii_head; +mii_list_t *mii_tail; + +static int mii_queue(struct net_device *dev, int request, + void (*func)(uint, struct net_device *)); + +/* Make MII read/write commands for the FEC. +*/ +#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) +#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | \ + (VAL & 0xffff)) +#define mk_mii_end 0 + +/* Transmitter timeout. +*/ +#define TX_TIMEOUT (2*HZ) + +/* Register definitions for the PHY. +*/ + +#define MII_REG_CR 0 /* Control Register */ +#define MII_REG_SR 1 /* Status Register */ +#define MII_REG_PHYIR1 2 /* PHY Identification Register 1 */ +#define MII_REG_PHYIR2 3 /* PHY Identification Register 2 */ +#define MII_REG_ANAR 4 /* A-N Advertisement Register */ +#define MII_REG_ANLPAR 5 /* A-N Link Partner Ability Register */ +#define MII_REG_ANER 6 /* A-N Expansion Register */ +#define MII_REG_ANNPTR 7 /* A-N Next Page Transmit Register */ +#define MII_REG_ANLPRNPR 8 /* A-N Link Partner Received Next Page Reg. */ + +/* values for phy_status */ + +#define PHY_CONF_ANE 0x0001 /* 1 auto-negotiation enabled */ +#define PHY_CONF_LOOP 0x0002 /* 1 loopback mode enabled */ +#define PHY_CONF_SPMASK 0x00f0 /* mask for speed */ +#define PHY_CONF_10HDX 0x0010 /* 10 Mbit half duplex supported */ +#define PHY_CONF_10FDX 0x0020 /* 10 Mbit full duplex supported */ +#define PHY_CONF_100HDX 0x0040 /* 100 Mbit half duplex supported */ +#define PHY_CONF_100FDX 0x0080 /* 100 Mbit full duplex supported */ + +#define PHY_STAT_LINK 0x0100 /* 1 up - 0 down */ +#define PHY_STAT_FAULT 0x0200 /* 1 remote fault */ +#define PHY_STAT_ANC 0x0400 /* 1 auto-negotiation complete */ +#define PHY_STAT_SPMASK 0xf000 /* mask for speed */ +#define PHY_STAT_10HDX 0x1000 /* 10 Mbit half duplex selected */ +#define PHY_STAT_10FDX 0x2000 /* 10 Mbit full duplex selected */ +#define PHY_STAT_100HDX 0x4000 /* 100 Mbit half duplex selected */ +#define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */ + + +static int +fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct fec_enet_private *fep; + volatile fec_t *fecp; + volatile cbd_t *bdp; + + fep = dev->priv; + fecp = (volatile fec_t*)dev->base_addr; + + if (!fep->link) { + /* Link is down or autonegotiation is in progress. */ + return 1; + } + + /* Fill in a Tx ring entry */ + bdp = fep->cur_tx; + +#ifndef final_version + if (bdp->cbd_sc & BD_ENET_TX_READY) { + /* Ooops. All transmit buffers are full. Bail out. + * This should not happen, since dev->tbusy should be set. + */ + printk("%s: tx queue full!.\n", dev->name); + return 1; + } +#endif + + /* Clear all of the status flags. + */ + bdp->cbd_sc &= ~BD_ENET_TX_STATS; + + /* Set buffer length and buffer pointer. + */ + bdp->cbd_bufaddr = __pa(skb->data); + bdp->cbd_datlen = skb->len; + + /* Save skb pointer. + */ + fep->tx_skbuff[fep->skb_cur] = skb; + + fep->stats.tx_bytes += skb->len; + fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK; + + /* Push the data cache so the CPM does not get stale memory + * data. + */ + flush_dcache_range((unsigned long)skb->data, + (unsigned long)skb->data + skb->len); + + spin_lock_irq(&fep->lock); + + /* Send it on its way. Tell FEC its ready, interrupt when done, + * its the last BD of the frame, and to put the CRC on the end. + */ + + bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR + | BD_ENET_TX_LAST | BD_ENET_TX_TC); + + dev->trans_start = jiffies; + + /* Trigger transmission start */ + fecp->fec_x_des_active = 0x01000000; + + /* If this was the last BD in the ring, start at the beginning again. + */ + if (bdp->cbd_sc & BD_ENET_TX_WRAP) { + bdp = fep->tx_bd_base; + } else { + bdp++; + } + + if (bdp == fep->dirty_tx) { + fep->tx_full = 1; + netif_stop_queue(dev); + } + + fep->cur_tx = (cbd_t *)bdp; + + spin_unlock_irq(&fep->lock); + + return 0; +} + +static void +fec_timeout(struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + + printk("%s: transmit timed out.\n", dev->name); + fep->stats.tx_errors++; +#ifndef final_version + { + int i; + cbd_t *bdp; + + printk("Ring data dump: cur_tx %lx%s, dirty_tx %lx cur_rx: %lx\n", + (unsigned long)fep->cur_tx, fep->tx_full ? " (full)" : "", + (unsigned long)fep->dirty_tx, + (unsigned long)fep->cur_rx); + + bdp = fep->tx_bd_base; + printk(" tx: %u buffers\n", TX_RING_SIZE); + for (i = 0 ; i < TX_RING_SIZE; i++) { + printk(" %08x: %04x %04x %08x\n", + (uint) bdp, + bdp->cbd_sc, + bdp->cbd_datlen, + (int) bdp->cbd_bufaddr); + bdp++; + } + + bdp = fep->rx_bd_base; + printk(" rx: %lu buffers\n", (unsigned long) RX_RING_SIZE); + for (i = 0 ; i < RX_RING_SIZE; i++) { + printk(" %08x: %04x %04x %08x\n", + (uint) bdp, + bdp->cbd_sc, + bdp->cbd_datlen, + (int) bdp->cbd_bufaddr); + bdp++; + } + } +#endif + fec_restart(dev, 0); + netif_wake_queue(dev); +} + +/* The interrupt handler. + * This is called from the MPC core interrupt. + */ +static void +fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + volatile fec_t *fecp; + uint int_events; + + fecp = (volatile fec_t*)dev->base_addr; + + /* Get the interrupt events that caused us to be here. + */ + while ((int_events = fecp->fec_ievent) != 0) { + fecp->fec_ievent = int_events; + if ((int_events & (FEC_ENET_HBERR | FEC_ENET_BABR | + FEC_ENET_BABT | FEC_ENET_EBERR)) != 0) { + printk("FEC ERROR %x\n", int_events); + } + + /* Handle receive event in its own function. + */ + if (int_events & FEC_ENET_RXF) + fec_enet_rx(dev); + + /* Transmit OK, or non-fatal error. Update the buffer + descriptors. FEC handles all errors, we just discover + them as part of the transmit process. + */ + if (int_events & FEC_ENET_TXF) + fec_enet_tx(dev); + + if (int_events & FEC_ENET_MII) + fec_enet_mii(dev); + + } +} + + +static void +fec_enet_tx(struct net_device *dev) +{ + struct fec_enet_private *fep; + volatile cbd_t *bdp; + struct sk_buff *skb; + + fep = dev->priv; + spin_lock(&fep->lock); + bdp = fep->dirty_tx; + + while ((bdp->cbd_sc&BD_ENET_TX_READY) == 0) { + if (bdp == fep->cur_tx && fep->tx_full == 0) break; + + skb = fep->tx_skbuff[fep->skb_dirty]; + /* Check for errors. */ + if (bdp->cbd_sc & (BD_ENET_TX_HB | BD_ENET_TX_LC | + BD_ENET_TX_RL | BD_ENET_TX_UN | + BD_ENET_TX_CSL)) { + fep->stats.tx_errors++; + if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */ + fep->stats.tx_heartbeat_errors++; + if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */ + fep->stats.tx_window_errors++; + if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */ + fep->stats.tx_aborted_errors++; + if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */ + fep->stats.tx_fifo_errors++; + if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */ + fep->stats.tx_carrier_errors++; + } else { + fep->stats.tx_packets++; + } + +#ifndef final_version + if (bdp->cbd_sc & BD_ENET_TX_READY) + printk("HEY! Enet xmit interrupt and TX_READY.\n"); +#endif + /* Deferred means some collisions occurred during transmit, + * but we eventually sent the packet OK. + */ + if (bdp->cbd_sc & BD_ENET_TX_DEF) + fep->stats.collisions++; + + /* Free the sk buffer associated with this last transmit. + */ + dev_kfree_skb_any(skb); + fep->tx_skbuff[fep->skb_dirty] = NULL; + fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK; + + /* Update pointer to next buffer descriptor to be transmitted. + */ + if (bdp->cbd_sc & BD_ENET_TX_WRAP) + bdp = fep->tx_bd_base; + else + bdp++; + + /* Since we have freed up a buffer, the ring is no longer + * full. + */ + if (fep->tx_full) { + fep->tx_full = 0; + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + } + } + fep->dirty_tx = (cbd_t *)bdp; + spin_unlock(&fep->lock); +} + + +/* During a receive, the cur_rx points to the current incoming buffer. + * When we update through the ring, if the next incoming buffer has + * not been given to the system, we just set the empty indicator, + * effectively tossing the packet. + */ +static void +fec_enet_rx(struct net_device *dev) +{ + struct fec_enet_private *fep; + volatile fec_t *fecp; + volatile cbd_t *bdp; + struct sk_buff *skb; + ushort pkt_len; + __u8 *data; + + fep = dev->priv; + fecp = (volatile fec_t*)dev->base_addr; + + /* First, grab all of the stats for the incoming packet. + * These get messed up if we get called due to a busy condition. + */ + bdp = fep->cur_rx; + +while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { + +#ifndef final_version + /* Since we have allocated space to hold a complete frame, + * the last indicator should be set. + */ + if ((bdp->cbd_sc & BD_ENET_RX_LAST) == 0) + printk("FEC ENET: rcv is not +last\n"); +#endif + + if (!opened) + goto rx_processing_done; + + /* Check for errors. */ + if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | + BD_ENET_RX_CR | BD_ENET_RX_OV)) { + fep->stats.rx_errors++; + if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { + /* Frame too long or too short. */ + fep->stats.rx_length_errors++; + } + if (bdp->cbd_sc & BD_ENET_RX_NO) /* Frame alignment */ + fep->stats.rx_frame_errors++; + if (bdp->cbd_sc & BD_ENET_RX_CR) /* CRC Error */ + fep->stats.rx_crc_errors++; + if (bdp->cbd_sc & BD_ENET_RX_OV) /* FIFO overrun */ + fep->stats.rx_crc_errors++; + } + + /* Report late collisions as a frame error. + * On this error, the BD is closed, but we don't know what we + * have in the buffer. So, just drop this frame on the floor. + */ + if (bdp->cbd_sc & BD_ENET_RX_CL) { + fep->stats.rx_errors++; + fep->stats.rx_frame_errors++; + goto rx_processing_done; + } + + /* Process the incoming frame. + */ + fep->stats.rx_packets++; + pkt_len = bdp->cbd_datlen; + fep->stats.rx_bytes += pkt_len; + data = (__u8*)__va(bdp->cbd_bufaddr); + + /* This does 16 byte alignment, exactly what we need. + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ + skb = dev_alloc_skb(pkt_len-4); + + if (skb == NULL) { + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + fep->stats.rx_dropped++; + } else { + skb->dev = dev; + skb_put(skb,pkt_len-4); /* Make room */ + eth_copy_and_sum(skb, + (unsigned char *)__va(bdp->cbd_bufaddr), + pkt_len-4, 0); + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + } + rx_processing_done: + + /* Clear the status flags for this buffer. + */ + bdp->cbd_sc &= ~BD_ENET_RX_STATS; + + /* Mark the buffer empty. + */ + bdp->cbd_sc |= BD_ENET_RX_EMPTY; + + /* Update BD pointer to next entry. + */ + if (bdp->cbd_sc & BD_ENET_RX_WRAP) + bdp = fep->rx_bd_base; + else + bdp++; + +#if 1 + /* Doing this here will keep the FEC running while we process + * incoming frames. On a heavily loaded network, we should be + * able to keep up at the expense of system resources. + */ + fecp->fec_r_des_active = 0x01000000; +#endif + } /* while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) */ + fep->cur_rx = (cbd_t *)bdp; + +#if 0 + /* Doing this here will allow us to process all frames in the + * ring before the FEC is allowed to put more there. On a heavily + * loaded network, some frames may be lost. Unfortunately, this + * increases the interrupt overhead since we can potentially work + * our way back to the interrupt return only to come right back + * here. + */ + fecp->fec_r_des_active = 0x01000000; +#endif +} + + +static void +fec_enet_mii(struct net_device *dev) +{ + struct fec_enet_private *fep; + volatile fec_t *ep; + mii_list_t *mip; + uint mii_reg; + + fep = (struct fec_enet_private *)dev->priv; + ep = fec_hwp; + mii_reg = ep->fec_mii_data; + + if ((mip = mii_head) == NULL) { + printk("MII and no head!\n"); + return; + } + + if (mip->mii_func != NULL) + (*(mip->mii_func))(mii_reg, dev); + + mii_head = mip->mii_next; + mip->mii_next = mii_free; + mii_free = mip; + + if ((mip = mii_head) != NULL) + ep->fec_mii_data = mip->mii_regval; +} + +static int +mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_device *)) +{ + struct fec_enet_private *fep; + unsigned long flags; + mii_list_t *mip; + int retval; + + /* Add PHY address to register command. + */ + fep = dev->priv; + regval |= fep->phy_addr << 23; + + retval = 0; + + save_flags(flags); + cli(); + + if ((mip = mii_free) != NULL) { + mii_free = mip->mii_next; + mip->mii_regval = regval; + mip->mii_func = func; + mip->mii_next = NULL; + if (mii_head) { + mii_tail->mii_next = mip; + mii_tail = mip; + } + else { + mii_head = mii_tail = mip; + fec_hwp->fec_mii_data = regval; + } + } + else { + retval = 1; + } + + restore_flags(flags); + + return(retval); +} + +static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c) +{ + int k; + + if(!c) + return; + + for(k = 0; (c+k)->mii_data != mk_mii_end; k++) { + mii_queue(dev, (c+k)->mii_data, (c+k)->funct); + } +} + +static void mii_parse_sr(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); + + *s &= ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC); + + if (mii_reg & 0x0004) + *s |= PHY_STAT_LINK; + if (mii_reg & 0x0010) + *s |= PHY_STAT_FAULT; + if (mii_reg & 0x0020) + *s |= PHY_STAT_ANC; +} + +static void mii_parse_cr(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); + + *s &= ~(PHY_CONF_ANE | PHY_CONF_LOOP); + + if (mii_reg & 0x1000) + *s |= PHY_CONF_ANE; + if (mii_reg & 0x4000) + *s |= PHY_CONF_LOOP; +} + +static void mii_parse_anar(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); + + *s &= ~(PHY_CONF_SPMASK); + + if (mii_reg & 0x0020) + *s |= PHY_CONF_10HDX; + if (mii_reg & 0x0040) + *s |= PHY_CONF_10FDX; + if (mii_reg & 0x0080) + *s |= PHY_CONF_100HDX; + if (mii_reg & 0x00100) + *s |= PHY_CONF_100FDX; +} + +/* ------------------------------------------------------------------------- */ +/* The Level one LXT970 is used by many boards */ + +#define MII_LXT970_MIRROR 16 /* Mirror register */ +#define MII_LXT970_IER 17 /* Interrupt Enable Register */ +#define MII_LXT970_ISR 18 /* Interrupt Status Register */ +#define MII_LXT970_CONFIG 19 /* Configuration Register */ +#define MII_LXT970_CSR 20 /* Chip Status Register */ + +static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); + + *s &= ~(PHY_STAT_SPMASK); + + if (mii_reg & 0x0800) { + if (mii_reg & 0x1000) + *s |= PHY_STAT_100FDX; + else + *s |= PHY_STAT_100HDX; + } else { + if (mii_reg & 0x1000) + *s |= PHY_STAT_10FDX; + else + *s |= PHY_STAT_10HDX; + } +} + +static phy_info_t phy_info_lxt970 = { + 0x07810000, + "LXT970", + + (const phy_cmd_t []) { /* config */ + { mk_mii_read(MII_REG_CR), mii_parse_cr }, + { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* startup - enable interrupts */ + { mk_mii_write(MII_LXT970_IER, 0x0002), NULL }, + { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* ack_int */ + /* read SR and ISR to acknowledge */ + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_read(MII_LXT970_ISR), NULL }, + + /* find out the current status */ + { mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* shutdown - disable interrupts */ + { mk_mii_write(MII_LXT970_IER, 0x0000), NULL }, + { mk_mii_end, } + }, +}; + +/* ------------------------------------------------------------------------- */ +/* The Level one LXT971 is used on some of my custom boards */ + +/* register definitions for the 971 */ + +#define MII_LXT971_PCR 16 /* Port Control Register */ +#define MII_LXT971_SR2 17 /* Status Register 2 */ +#define MII_LXT971_IER 18 /* Interrupt Enable Register */ +#define MII_LXT971_ISR 19 /* Interrupt Status Register */ +#define MII_LXT971_LCR 20 /* LED Control Register */ +#define MII_LXT971_TCR 30 /* Transmit Control Register */ + +/* + * I had some nice ideas of running the MDIO faster... + * The 971 should support 8MHz and I tried it, but things acted really + * wierd, so 2.5 MHz ought to be enough for anyone... + */ + +static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); + + *s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); + + if (mii_reg & 0x0400) { + fep->link = 1; + *s |= PHY_STAT_LINK; + } else { + fep->link = 0; + } + if (mii_reg & 0x0080) + *s |= PHY_STAT_ANC; + if (mii_reg & 0x4000) { + if (mii_reg & 0x0200) + *s |= PHY_STAT_100FDX; + else + *s |= PHY_STAT_100HDX; + } else { + if (mii_reg & 0x0200) + *s |= PHY_STAT_10FDX; + else + *s |= PHY_STAT_10HDX; + } + if (mii_reg & 0x0008) + *s |= PHY_STAT_FAULT; +} + +static phy_info_t phy_info_lxt971 = { + 0x0001378e, + "LXT971", + + (const phy_cmd_t []) { /* config */ + /* limit to 10MBit because my protorype board + * doesn't work with 100. */ + { mk_mii_read(MII_REG_CR), mii_parse_cr }, + { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, + { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* startup - enable interrupts */ + { mk_mii_write(MII_LXT971_IER, 0x00f2), NULL }, + { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ + { mk_mii_write(MII_LXT971_LCR, 0xd422), NULL }, /* LED config */ + /* Somehow does the 971 tell me that the link is down + * the first read after power-up. + * read here to get a valid value in ack_int */ + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* ack_int */ + /* find out the current status */ + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 }, + /* we only need to read ISR to acknowledge */ + { mk_mii_read(MII_LXT971_ISR), NULL }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* shutdown - disable interrupts */ + { mk_mii_write(MII_LXT971_IER, 0x0000), NULL }, + { mk_mii_end, } + }, +}; + +/* ------------------------------------------------------------------------- */ +/* The Quality Semiconductor QS6612 is used on the RPX CLLF */ + +/* register definitions */ + +#define MII_QS6612_MCR 17 /* Mode Control Register */ +#define MII_QS6612_FTR 27 /* Factory Test Register */ +#define MII_QS6612_MCO 28 /* Misc. Control Register */ +#define MII_QS6612_ISR 29 /* Interrupt Source Register */ +#define MII_QS6612_IMR 30 /* Interrupt Mask Register */ +#define MII_QS6612_PCR 31 /* 100BaseTx PHY Control Reg. */ + +static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); + + *s &= ~(PHY_STAT_SPMASK); + + switch((mii_reg >> 2) & 7) { + case 1: *s |= PHY_STAT_10HDX; break; + case 2: *s |= PHY_STAT_100HDX; break; + case 5: *s |= PHY_STAT_10FDX; break; + case 6: *s |= PHY_STAT_100FDX; break; + } +} + +static phy_info_t phy_info_qs6612 = { + 0x00181440, + "QS6612", + + (const phy_cmd_t []) { /* config */ + /* The PHY powers up isolated on the RPX, + * so send a command to allow operation. + */ + { mk_mii_write(MII_QS6612_PCR, 0x0dc0), NULL }, + + /* parse cr and anar to get some info */ + { mk_mii_read(MII_REG_CR), mii_parse_cr }, + { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* startup - enable interrupts */ + { mk_mii_write(MII_QS6612_IMR, 0x003a), NULL }, + { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* ack_int */ + /* we need to read ISR, SR and ANER to acknowledge */ + { mk_mii_read(MII_QS6612_ISR), NULL }, + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_read(MII_REG_ANER), NULL }, + + /* read pcr to get info */ + { mk_mii_read(MII_QS6612_PCR), mii_parse_qs6612_pcr }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* shutdown - disable interrupts */ + { mk_mii_write(MII_QS6612_IMR, 0x0000), NULL }, + { mk_mii_end, } + }, +}; + +/* ------------------------------------------------------------------------- */ +/* AMD AM79C874 phy */ + +/* register definitions for the 874 */ + +#define MII_AM79C874_MFR 16 /* Miscellaneous Feature Register */ +#define MII_AM79C874_ICSR 17 /* Interrupt/Status Register */ +#define MII_AM79C874_DR 18 /* Diagnostic Register */ +#define MII_AM79C874_PMLR 19 /* Power and Loopback Register */ +#define MII_AM79C874_MCR 21 /* ModeControl Register */ +#define MII_AM79C874_DC 23 /* Disconnect Counter */ +#define MII_AM79C874_REC 24 /* Recieve Error Counter */ + +static void mii_parse_am79c874_dr(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); + + *s &= ~(PHY_STAT_SPMASK | PHY_STAT_ANC); + + if (mii_reg & 0x0080) + *s |= PHY_STAT_ANC; + if (mii_reg & 0x0400) + *s |= ((mii_reg & 0x0800) ? PHY_STAT_100FDX : PHY_STAT_100HDX); + else + *s |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX); +} + +static phy_info_t phy_info_am79c874 = { + 0x00022561, + "AM79C874", + + (const phy_cmd_t []) { /* config */ + /* limit to 10MBit because my protorype board + * doesn't work with 100. */ + { mk_mii_read(MII_REG_CR), mii_parse_cr }, + { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, + { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* startup - enable interrupts */ + { mk_mii_write(MII_AM79C874_ICSR, 0xff00), NULL }, + { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* ack_int */ + /* find out the current status */ + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr }, + /* we only need to read ISR to acknowledge */ + { mk_mii_read(MII_AM79C874_ICSR), NULL }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* shutdown - disable interrupts */ + { mk_mii_write(MII_AM79C874_ICSR, 0x0000), NULL }, + { mk_mii_end, } + }, +}; + +/* ------------------------------------------------------------------------- */ + +static phy_info_t *phy_info[] = { + &phy_info_lxt970, + &phy_info_lxt971, + &phy_info_qs6612, + &phy_info_am79c874, + NULL +}; + +/* ------------------------------------------------------------------------- */ + +static void +#ifdef CONFIG_RPXCLASSIC +mii_link_interrupt(void *dev_id); +#else +mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs); +#endif + +#ifdef CONFIG_M5272 + +/* + * Code specific to Coldfire 5272 setup. + */ +static void __inline__ fec_request_intrs(struct net_device *dev, volatile fec_t *fecp) +{ + volatile unsigned long *icrp; + + /* Setup interrupt handlers. */ + if (request_irq(86, fec_enet_interrupt, 0, "fec(RX)", dev) != 0) + printk("FEC: Could not allocate FEC(RC) IRQ(86)!\n"); + if (request_irq(87, fec_enet_interrupt, 0, "fec(TX)", dev) != 0) + printk("FEC: Could not allocate FEC(RC) IRQ(87)!\n"); + if (request_irq(88, fec_enet_interrupt, 0, "fec(OTHER)", dev) != 0) + printk("FEC: Could not allocate FEC(OTHER) IRQ(88)!\n"); + if (request_irq(66, mii_link_interrupt, 0, "fec(MII)", dev) != 0) + printk("FEC: Could not allocate MII IRQ(66)!\n"); + + /* Unmask interrupt at ColdFire 5272 SIM */ + icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR3); + *icrp = 0x00000ddd; + icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); + *icrp = (*icrp & 0x70777777) | 0x0d000000; +} + +static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep) +{ + volatile fec_t *fecp; + fecp = fec_hwp; + + fecp->fec_r_cntrl = 0x04; + fecp->fec_x_cntrl = 0x00; + + /* Set MII speed to 2.5 MHz + */ + fecp->fec_mii_speed = fep->phy_speed = 0x0e; + + fec_restart(dev, 0); +} + +static void __inline__ fec_get_mac(struct net_device *dev, struct fec_enet_private *fep) +{ + volatile fec_t *fecp; + unsigned char *eap, *iap, tmpaddr[6]; + int i; + + fecp = fec_hwp; + eap = (unsigned char *) my_enet_addr; + + if (fec_flashmac) { + /* + * Get MAC address from FLASH. + * If it is all 1's or 0's, use the default. + */ + iap = fec_flashmac; + if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && + (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) + iap = eap; + if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) && + (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) + iap = eap; + } else { + *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low; + *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16); + iap = &tmpaddr[0]; + } + + for (i=0; i<6; i++) + dev->dev_addr[i] = *eap++ = *iap++; +} + +static void __inline__ fec_enable_phy_intr(void) +{ +} + +static void __inline__ fec_disable_phy_intr(void) +{ + volatile unsigned long *icrp; + icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); + *icrp = (*icrp & 0x70777777) | 0x08000000; +} + +static void __inline__ fec_phy_ack_intr(void) +{ + volatile unsigned long *icrp; + /* Acknowledge the interrupt */ + icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); + *icrp = (*icrp & 0x77777777) | 0x08000000; +} + +static void __inline__ fec_localhw_setup(void) +{ +} + +/* + * Do not need to make region uncached on 5272. + */ +static void __inline__ fec_uncache(unsigned long addr) +{ +} + +/* ------------------------------------------------------------------------- */ + +#else + +/* + * Code sepcific to the MPC860T setup. + */ +static void __inline__ fec_request_intrs(struct net_device *dev, volatile fec_t *fecp) +{ + volatile immap_t *immap; + + immap = (immap_t *)IMAP_ADDR; /* pointer to internal registers */ + + if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0) + panic("Could not allocate FEC IRQ!"); + +#ifdef CONFIG_RPXCLASSIC + /* Make Port C, bit 15 an input that causes interrupts. + */ + immap->im_ioport.iop_pcpar &= ~0x0001; + immap->im_ioport.iop_pcdir &= ~0x0001; + immap->im_ioport.iop_pcso &= ~0x0001; + immap->im_ioport.iop_pcint |= 0x0001; + cpm_install_handler(CPMVEC_PIO_PC15, mii_link_interrupt, dev); + + /* Make LEDS reflect Link status. + */ + *((uint *) RPX_CSR_ADDR) &= ~BCSR2_FETHLEDMODE; +#endif +#ifdef CONFIG_FADS + if (request_8xxirq(SIU_IRQ2, mii_link_interrupt, 0, "mii", dev) != 0) + panic("Could not allocate MII IRQ!"); +#endif +} + +static void __inline__ fec_get_mac(struct net_device *dev, struct fec_enet_private *fep) +{ + unsigned char *eap, *iap, tmpaddr[6]; + bd_t *bd; + int i; + + eap = (unsigned char *)my_enet_addr; + iap = bd->bi_enetaddr; + bd = (bd_t *)__res; + +#ifdef CONFIG_RPXCLASSIC + /* The Embedded Planet boards have only one MAC address in + * the EEPROM, but can have two Ethernet ports. For the + * FEC port, we create another address by setting one of + * the address bits above something that would have (up to + * now) been allocated. + */ + for (i=0; i<6; i++) + tmpaddr[i] = *iap++; + tmpaddr[3] |= 0x80; + iap = tmpaddr; +#endif + + for (i=0; i<6; i++) + dev->dev_addr[i] = *eap++ = *iap++; +} + +static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep) +{ + extern uint _get_IMMR(void); + volatile immap_t *immap; + volatile fec_t *fecp; + + fecp = fec_hwp; + immap = (immap_t *)IMAP_ADDR; /* pointer to internal registers */ + + /* Configure all of port D for MII. + */ + immap->im_ioport.iop_pdpar = 0x1fff; + + /* Bits moved from Rev. D onward. + */ + if ((_get_IMMR() & 0xffff) < 0x0501) + immap->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */ + else + immap->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */ + + /* Set MII speed to 2.5 MHz + */ + fecp->fec_mii_speed = fep->phy_speed = + ((bd->bi_busfreq * 1000000) / 2500000) & 0x7e; +} + +static void __inline__ fec_enable_phy_intr(void) +{ + volatile fec_t *fecp; + fecp = fec_hwp; + + /* Enable MII command finished interrupt + */ + fecp->fec_ivec = (FEC_INTERRUPT/2) << 29; +} + +static void __inline__ fec_disable_phy_intr(void) +{ +} + +static void __inline__ fec_phy_ack_intr(void) +{ +} + +static void __inline__ fec_localhw_setup(void) +{ + volatile fec_t *fecp; + fecp = fec_hwp; + + fecp->fec_r_hash = PKT_MAXBUF_SIZE; + /* Enable big endian and don't care about SDMA FC. + */ + fecp->fec_fun_code = 0x78000000; +} + +static void __inline__ fec_uncache(unsigned long addr) +{ + pte_t *pte; + pte = va_to_pte(mem_addr); + pte_val(*pte) |= _PAGE_NO_CACHE; + flush_tlb_page(init_mm.mmap, mem_addr); +} + +#endif + +/* ------------------------------------------------------------------------- */ + +static void mii_display_status(struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); + + if (!fep->link && !fep->old_link) { + /* Link is still down - don't print anything */ + return; + } + + printk("%s: status: ", dev->name); + + if (!fep->link) { + printk("link down"); + } else { + printk("link up"); + + switch(*s & PHY_STAT_SPMASK) { + case PHY_STAT_100FDX: printk(", 100MBit Full Duplex"); break; + case PHY_STAT_100HDX: printk(", 100MBit Half Duplex"); break; + case PHY_STAT_10FDX: printk(", 10MBit Full Duplex"); break; + case PHY_STAT_10HDX: printk(", 10MBit Half Duplex"); break; + default: + printk(", Unknown speed/duplex"); + } + + if (*s & PHY_STAT_ANC) + printk(", auto-negotiation complete"); + } + + if (*s & PHY_STAT_FAULT) + printk(", remote fault"); + + printk(".\n"); +} + +static void mii_display_config(struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); + + printk("%s: config: auto-negotiation ", dev->name); + + if (*s & PHY_CONF_ANE) + printk("on"); + else + printk("off"); + + if (*s & PHY_CONF_100FDX) + printk(", 100FDX"); + if (*s & PHY_CONF_100HDX) + printk(", 100HDX"); + if (*s & PHY_CONF_10FDX) + printk(", 10FDX"); + if (*s & PHY_CONF_10HDX) + printk(", 10HDX"); + if (!(*s & PHY_CONF_SPMASK)) + printk(", No speed/duplex selected?"); + + if (*s & PHY_CONF_LOOP) + printk(", loopback enabled"); + + printk(".\n"); + + fep->sequence_done = 1; +} + +static void mii_relink(struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + int duplex; + + fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0; + mii_display_status(dev); + fep->old_link = fep->link; + + if (fep->link) { + duplex = 0; + if (fep->phy_status + & (PHY_STAT_100FDX | PHY_STAT_10FDX)) + duplex = 1; + fec_restart(dev, duplex); + } + else + fec_stop(dev); + +#if 0 + enable_irq(fep->mii_irq); +#endif + +} + +static void mii_queue_relink(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + + INIT_WORK(&fep->phy_task, (void*)mii_relink, dev); + schedule_work(&fep->phy_task); +} + +static void mii_queue_config(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + + INIT_WORK(&fep->phy_task, (void*)mii_display_config, dev); + schedule_work(&fep->phy_task); +} + + + +phy_cmd_t phy_cmd_relink[] = { { mk_mii_read(MII_REG_CR), mii_queue_relink }, + { mk_mii_end, } }; +phy_cmd_t phy_cmd_config[] = { { mk_mii_read(MII_REG_CR), mii_queue_config }, + { mk_mii_end, } }; + + + +/* Read remainder of PHY ID. +*/ +static void +mii_discover_phy3(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep; + int i; + + fep = dev->priv; + fep->phy_id |= (mii_reg & 0xffff); + printk("fec: PHY @ 0x%x, ID 0x%08x", fep->phy_addr, fep->phy_id); + + for(i = 0; phy_info[i]; i++) { + if(phy_info[i]->id == (fep->phy_id >> 4)) + break; + } + + if (phy_info[i]) + printk(" -- %s\n", phy_info[i]->name); + else + printk(" -- unknown PHY!\n"); + + fep->phy = phy_info[i]; + fep->phy_id_done = 1; +} + +/* Scan all of the MII PHY addresses looking for someone to respond + * with a valid ID. This usually happens quickly. + */ +static void +mii_discover_phy(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep; + volatile fec_t *fecp; + uint phytype; + + fep = dev->priv; + fecp = fec_hwp; + + if (fep->phy_addr < 32) { + if ((phytype = (mii_reg & 0xffff)) != 0xffff && phytype != 0) { + + /* Got first part of ID, now get remainder. + */ + fep->phy_id = phytype << 16; + mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), + mii_discover_phy3); + } + else { + fep->phy_addr++; + mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), + mii_discover_phy); + } + } else { + printk("FEC: No PHY device found.\n"); + /* Disable external MII interface */ + fecp->fec_mii_speed = fep->phy_speed = 0; + fec_disable_phy_intr(); + } +} + +/* This interrupt occurs when the PHY detects a link change. +*/ +static void +#ifdef CONFIG_RPXCLASSIC +mii_link_interrupt(void *dev_id) +#else +mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs) +#endif +{ + struct net_device *dev = dev_id; + struct fec_enet_private *fep = dev->priv; + + fec_phy_ack_intr(); + +#if 0 + disable_irq(fep->mii_irq); /* disable now, enable later */ +#endif + + mii_do_cmd(dev, fep->phy->ack_int); + mii_do_cmd(dev, phy_cmd_relink); /* restart and display status */ + +} + +static int +fec_enet_open(struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + + /* I should reset the ring buffers here, but I don't yet know + * a simple way to do that. + */ + + fep->sequence_done = 0; + fep->link = 0; + + if (fep->phy) { + mii_do_cmd(dev, fep->phy->ack_int); + mii_do_cmd(dev, fep->phy->config); + mii_do_cmd(dev, phy_cmd_config); /* display configuration */ + + while(!fep->sequence_done) + schedule(); + + mii_do_cmd(dev, fep->phy->startup); + } else { + fep->link = 1; /* lets just try it and see */ + /* no phy, go full duplex, it's most likely a hub chip */ + fec_restart(dev, 1); + } + + netif_start_queue(dev); + opened = 1; + return 0; /* Success */ +} + +static int +fec_enet_close(struct net_device *dev) +{ + /* Don't know what to do yet. + */ + opened = 0; + netif_stop_queue(dev); + fec_stop(dev); + + return 0; +} + +static struct net_device_stats *fec_enet_get_stats(struct net_device *dev) +{ + struct fec_enet_private *fep = (struct fec_enet_private *)dev->priv; + + return &fep->stats; +} + +/* Set or clear the multicast filter for this adaptor. + * Skeleton taken from sunlance driver. + * The CPM Ethernet implementation allows Multicast as well as individual + * MAC address filtering. Some of the drivers check to make sure it is + * a group multicast address, and discard those that are not. I guess I + * will do the same for now, but just remove the test if you want + * individual filtering as well (do the upper net layers want or support + * this kind of feature?). + */ + +#define HASH_BITS 6 /* #bits in hash */ +#define CRC32_POLY 0xEDB88320 + +static void set_multicast_list(struct net_device *dev) +{ + struct fec_enet_private *fep; + volatile fec_t *ep; + struct dev_mc_list *dmi; + unsigned int i, j, bit, data, crc; + unsigned char hash; + + fep = (struct fec_enet_private *)dev->priv; + ep = fec_hwp; + + if (dev->flags&IFF_PROMISC) { + /* Log any net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + ep->fec_r_cntrl |= 0x0008; + } else { + + ep->fec_r_cntrl &= ~0x0008; + + if (dev->flags & IFF_ALLMULTI) { + /* Catch all multicast addresses, so set the + * filter to all 1's. + */ + ep->fec_hash_table_high = 0xffffffff; + ep->fec_hash_table_low = 0xffffffff; + } else { + /* Clear filter and add the addresses in hash register. + */ + ep->fec_hash_table_high = 0; + ep->fec_hash_table_low = 0; + + dmi = dev->mc_list; + + for (j = 0; j < dev->mc_count; j++, dmi = dmi->next) + { + /* Only support group multicast for now. + */ + if (!(dmi->dmi_addr[0] & 1)) + continue; + + /* calculate crc32 value of mac address + */ + crc = 0xffffffff; + + for (i = 0; i < dmi->dmi_addrlen; i++) + { + data = dmi->dmi_addr[i]; + for (bit = 0; bit < 8; bit++, data >>= 1) + { + crc = (crc >> 1) ^ + (((crc ^ data) & 1) ? CRC32_POLY : 0); + } + } + + /* only upper 6 bits (HASH_BITS) are used + which point to specific bit in he hash registers + */ + hash = (crc >> (32 - HASH_BITS)) & 0x3f; + + if (hash > 31) + ep->fec_hash_table_high |= 1 << (hash - 32); + else + ep->fec_hash_table_low |= 1 << hash; + } + } + } +} + +/* Initialize the FEC Ethernet on 860T (or ColdFire 5272). + */ +int __init fec_enet_init(struct net_device *dev) +{ + struct fec_enet_private *fep; + unsigned long mem_addr; + volatile cbd_t *bdp; + cbd_t *cbd_base; + volatile fec_t *fecp; + int i, j; + + /* Only allow us to be probed once. */ + if (found) + return(-ENXIO); + + /* Allocate some private information. + */ + fep = (struct fec_enet_private *)kmalloc(sizeof(*fep), GFP_KERNEL); + memset(fep, 0, sizeof(*fep)); + + /* Create an Ethernet device instance. + */ + fecp = fec_hwp; + + /* Whack a reset. We should wait for this. + */ + fecp->fec_ecntrl = 1; + udelay(10); + + /* Clear and enable interrupts */ + fecp->fec_ievent = 0xffc0; + fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | + FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); + fecp->fec_hash_table_high = 0; + fecp->fec_hash_table_low = 0; + fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; + fecp->fec_ecntrl = 2; + fecp->fec_r_des_active = 0x01000000; + + /* Set the Ethernet address. If using multiple Enets on the 8xx, + * this needs some work to get unique addresses. + */ + fec_get_mac(dev, fep); + + /* Allocate memory for buffer descriptors. + */ + if (((RX_RING_SIZE + TX_RING_SIZE) * sizeof(cbd_t)) > PAGE_SIZE) { + printk("FEC init error. Need more space.\n"); + printk("FEC initialization failed.\n"); + return 1; + } + mem_addr = __get_free_page(GFP_KERNEL); + cbd_base = (cbd_t *)mem_addr; + + fec_uncache(mem_addr); + + /* Set receive and transmit descriptor base. + */ + fep->rx_bd_base = cbd_base; + fep->tx_bd_base = cbd_base + RX_RING_SIZE; + + fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; + fep->cur_rx = fep->rx_bd_base; + + fep->skb_cur = fep->skb_dirty = 0; + + /* Initialize the receive buffer descriptors. + */ + bdp = fep->rx_bd_base; + for (i=0; icbd_sc = BD_ENET_RX_EMPTY; + bdp->cbd_bufaddr = __pa(mem_addr); + mem_addr += FEC_ENET_RX_FRSIZE; + bdp++; + } + } + + /* Set the last buffer to wrap. + */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + /* ...and the same for transmmit. + */ + bdp = fep->tx_bd_base; + for (i=0; icbd_sc = 0; + bdp->cbd_bufaddr = 0; + bdp++; + } + + /* Set the last buffer to wrap. + */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + /* Set receive and transmit descriptor base. + */ + fecp->fec_r_des_start = __pa((uint)(fep->rx_bd_base)); + fecp->fec_x_des_start = __pa((uint)(fep->tx_bd_base)); + + /* Install our interrupt handlers. This varies depending on + * the architecture. + */ + fec_request_intrs(dev, fecp); + + dev->base_addr = (unsigned long)fecp; + dev->priv = fep; + + ether_setup(dev); + + /* The FEC Ethernet specific entries in the device structure. */ + dev->open = fec_enet_open; + dev->hard_start_xmit = fec_enet_start_xmit; + dev->tx_timeout = fec_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + dev->stop = fec_enet_close; + dev->get_stats = fec_enet_get_stats; + dev->set_multicast_list = set_multicast_list; + + for (i=0; iname); + for (i=0; i<5; i++) + printk("%02x:", dev->dev_addr[i]); + printk("%02x\n", dev->dev_addr[5]); + + /* Queue up command to detect the PHY and initialize the + * remainder of the interface. + */ + fep->phy_id_done = 0; + fep->phy_addr = 0; + mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy); + + found++; + return 0; +} + +/* This function is called to start or restart the FEC during a link + * change. This only happens when switching between half and full + * duplex. + */ +static void +fec_restart(struct net_device *dev, int duplex) +{ + struct fec_enet_private *fep; + int i; + unsigned char *eap; + volatile cbd_t *bdp; + volatile fec_t *fecp; + + fecp = fec_hwp; + + fep = dev->priv; + + /* Whack a reset. We should wait for this. + */ + fecp->fec_ecntrl = 1; + udelay(10); + + /* Enable interrupts we wish to service. + */ + fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | + FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); + + /* Clear any outstanding interrupt. + */ + fecp->fec_ievent = 0xffc0; + fec_enable_phy_intr(); + + /* Set station address. + */ + fecp->fec_addr_low = (my_enet_addr[0] << 16) | my_enet_addr[1]; + fecp->fec_addr_high = (my_enet_addr[2] << 16); + + eap = (unsigned char *)&my_enet_addr[0]; + for (i=0; i<6; i++) + dev->dev_addr[i] = *eap++; + + /* Reset all multicast. + */ + fecp->fec_hash_table_high = 0; + fecp->fec_hash_table_low = 0; + + /* Set maximum receive buffer size. + */ + fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; + + fec_localhw_setup(); + + /* Set receive and transmit descriptor base. + */ + fecp->fec_r_des_start = __pa((uint)(fep->rx_bd_base)); + fecp->fec_x_des_start = __pa((uint)(fep->tx_bd_base)); + + fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; + fep->cur_rx = fep->rx_bd_base; + + /* Reset SKB transmit buffers. + */ + fep->skb_cur = fep->skb_dirty = 0; + for (i=0; i<=TX_RING_MOD_MASK; i++) { + if (fep->tx_skbuff[i] != NULL) { + dev_kfree_skb_any(fep->tx_skbuff[i]); + fep->tx_skbuff[i] = NULL; + } + } + + /* Initialize the receive buffer descriptors. + */ + bdp = fep->rx_bd_base; + for (i=0; icbd_sc = BD_ENET_RX_EMPTY; + bdp++; + } + + /* Set the last buffer to wrap. + */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + /* ...and the same for transmmit. + */ + bdp = fep->tx_bd_base; + for (i=0; icbd_sc = 0; + bdp->cbd_bufaddr = 0; + bdp++; + } + + /* Set the last buffer to wrap. + */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + /* Enable MII mode. + */ + if (duplex) { + fecp->fec_r_cntrl = 0x04; /* MII enable */ + fecp->fec_x_cntrl = 0x04; /* FD enable */ + } + else { + fecp->fec_r_cntrl = 0x06; /* MII enable|No Rcv on Xmit */ + fecp->fec_x_cntrl = 0x00; + } + fep->full_duplex = duplex; + + /* Set MII speed. + */ + fecp->fec_mii_speed = fep->phy_speed; + + /* And last, enable the transmit and receive processing. + */ + fecp->fec_ecntrl = 2; + fecp->fec_r_des_active = 0x01000000; +} + +static void +fec_stop(struct net_device *dev) +{ + volatile fec_t *fecp; + struct fec_enet_private *fep; + + fecp = fec_hwp; + fep = dev->priv; + + fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */ + + while(!(fecp->fec_ievent & 0x10000000)); + + /* Whack a reset. We should wait for this. + */ + fecp->fec_ecntrl = 1; + udelay(10); + + /* Clear outstanding MII command interrupts. + */ + fecp->fec_ievent = FEC_ENET_MII; + fec_enable_phy_intr(); + + fecp->fec_imask = FEC_ENET_MII; + fecp->fec_mii_speed = fep->phy_speed; +} + +static struct net_device fec_dev = { + .init = fec_enet_init, +}; + +static int __init fec_enet_module_init(void) +{ + if (register_netdev(&fec_dev) != 0) + return -EIO; + return(0); +} + +module_init(fec_enet_module_init); + +MODULE_LICENSE("GPL"); diff -Nru a/drivers/net/fec.h b/drivers/net/fec.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/fec.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,115 @@ +/****************************************************************************/ + +/* + * fec.h -- Fast Ethernet Controller for Motorola ColdFire 5272. + * + * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com) + * (C) Copyright 2000-2001, Lineo (www.lineo.com) + */ + +/****************************************************************************/ +#ifndef FEC_H +#define FEC_H +/****************************************************************************/ + +/* + * Define device register set address map. + */ +typedef struct fec { + unsigned long fec_ecntrl; /* Ethernet control reg */ + unsigned long fec_ievent; /* Interrupt even reg */ + unsigned long fec_imask; /* Interrupt mask reg */ + unsigned long fec_ivec; /* Interrupt vec status reg */ + unsigned long fec_r_des_active; /* Receive descriptor reg */ + unsigned long fec_x_des_active; /* Transmit descriptor reg */ + unsigned long fec_reserved1[10]; + unsigned long fec_mii_data; /* MII manage frame reg */ + unsigned long fec_mii_speed; /* MII speed control reg */ + unsigned long fec_reserved2[17]; + unsigned long fec_r_bound; /* FIFO receive bound reg */ + unsigned long fec_r_fstart; /* FIFO receive start reg */ + unsigned long fec_reserved3[4]; + unsigned long fec_x_wmrk; /* FIFO transmit water mark */ + unsigned long fec_reserved4; + unsigned long fec_x_fstart; /* FIFO transmit start reg */ + unsigned long fec_reserved5[21]; + unsigned long fec_r_cntrl; /* Receive control reg */ + unsigned long fec_max_frm_len; /* Maximum frame length reg */ + unsigned long fec_reserved6[14]; + unsigned long fec_x_cntrl; /* Transmit Control reg */ + unsigned long fec_reserved7[158]; + unsigned long fec_addr_low; /* Low 32bits MAC address */ + unsigned long fec_addr_high; /* High 16bits MAC address */ + unsigned long fec_hash_table_high; /* High 32bits hash table */ + unsigned long fec_hash_table_low; /* Low 32bits hash table */ + unsigned long fec_r_des_start; /* Receive descriptor ring */ + unsigned long fec_x_des_start; /* Transmit descriptor ring */ + unsigned long fec_r_buff_size; /* Maximum receive buff size */ + unsigned long reserved8[9]; + unsigned long fec_fifo_ram[112]; /* FIFO RAM buffer */ +} fec_t; + + +/* + * Define the buffer descriptor structure. + */ +typedef struct bufdesc { + unsigned short cbd_sc; /* Control and status info */ + unsigned short cbd_datlen; /* Data length */ + unsigned long cbd_bufaddr; /* Buffer address */ +} cbd_t; + + +/* + * The following definitions courtesy of commproc.h, which where + * Copyright (c) 1997 Dan Malek (dmalek@jlc.net). + */ +#define BD_SC_EMPTY ((ushort)0x8000) /* Recieve is empty */ +#define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */ +#define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */ +#define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */ +#define BD_SC_CM ((ushort)0x0200) /* Continous mode */ +#define BD_SC_ID ((ushort)0x0100) /* Rec'd too many idles */ +#define BD_SC_P ((ushort)0x0100) /* xmt preamble */ +#define BD_SC_BR ((ushort)0x0020) /* Break received */ +#define BD_SC_FR ((ushort)0x0010) /* Framing error */ +#define BD_SC_PR ((ushort)0x0008) /* Parity error */ +#define BD_SC_OV ((ushort)0x0002) /* Overrun */ +#define BD_SC_CD ((ushort)0x0001) /* ?? */ + +/* Buffer descriptor control/status used by Ethernet receive. +*/ +#define BD_ENET_RX_EMPTY ((ushort)0x8000) +#define BD_ENET_RX_WRAP ((ushort)0x2000) +#define BD_ENET_RX_INTR ((ushort)0x1000) +#define BD_ENET_RX_LAST ((ushort)0x0800) +#define BD_ENET_RX_FIRST ((ushort)0x0400) +#define BD_ENET_RX_MISS ((ushort)0x0100) +#define BD_ENET_RX_LG ((ushort)0x0020) +#define BD_ENET_RX_NO ((ushort)0x0010) +#define BD_ENET_RX_SH ((ushort)0x0008) +#define BD_ENET_RX_CR ((ushort)0x0004) +#define BD_ENET_RX_OV ((ushort)0x0002) +#define BD_ENET_RX_CL ((ushort)0x0001) +#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */ + +/* Buffer descriptor control/status used by Ethernet transmit. +*/ +#define BD_ENET_TX_READY ((ushort)0x8000) +#define BD_ENET_TX_PAD ((ushort)0x4000) +#define BD_ENET_TX_WRAP ((ushort)0x2000) +#define BD_ENET_TX_INTR ((ushort)0x1000) +#define BD_ENET_TX_LAST ((ushort)0x0800) +#define BD_ENET_TX_TC ((ushort)0x0400) +#define BD_ENET_TX_DEF ((ushort)0x0200) +#define BD_ENET_TX_HB ((ushort)0x0100) +#define BD_ENET_TX_LC ((ushort)0x0080) +#define BD_ENET_TX_RL ((ushort)0x0040) +#define BD_ENET_TX_RCMASK ((ushort)0x003c) +#define BD_ENET_TX_UN ((ushort)0x0002) +#define BD_ENET_TX_CSL ((ushort)0x0001) +#define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */ + + +/****************************************************************************/ +#endif /* FEC_H */ diff -Nru a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c --- a/drivers/net/ibmlana.c Mon Nov 4 14:31:01 2002 +++ b/drivers/net/ibmlana.c Mon Nov 4 14:31:01 2002 @@ -260,7 +260,7 @@ else tda.link = addr + sizeof(tda_t); tda.link |= 1; - isa_memcpy_to_io(dev->mem_start + addr, &tda, sizeof(tda_t)); + isa_memcpy_toio(dev->mem_start + addr, &tda, sizeof(tda_t)); addr += sizeof(tda_t); baddr += PKTSIZE; } @@ -280,7 +280,7 @@ rra.starthi = 0; rra.cntlo = PKTSIZE >> 1; rra.cnthi = 0; - isa_memcpy_to_io(dev->mem_start + raddr, &rra, sizeof(rra_t)); + isa_memcpy_toio(dev->mem_start + raddr, &rra, sizeof(rra_t)); rda.status = 0; rda.length = 0; @@ -292,7 +292,7 @@ else rda.link = 1; rda.inuse = 1; - isa_memcpy_to_io(dev->mem_start + addr, &rda, sizeof(rda_t)); + isa_memcpy_toio(dev->mem_start + addr, &rda, sizeof(rda_t)); baddr += PKTSIZE; raddr += sizeof(rra_t); @@ -429,8 +429,8 @@ /* feed CDA into SONIC, initialize RCR value (always get broadcasts) */ - isa_memcpy_to_io(dev->mem_start, cams, sizeof(camentry_t) * camcnt); - isa_memcpy_to_io(dev->mem_start + (sizeof(camentry_t) * camcnt), &cammask, sizeof(cammask)); + isa_memcpy_toio(dev->mem_start, cams, sizeof(camentry_t) * camcnt); + isa_memcpy_toio(dev->mem_start + (sizeof(camentry_t) * camcnt), &cammask, sizeof(cammask)); #ifdef DEBUG printk("CAM setup:\n"); @@ -627,14 +627,14 @@ rda.link = 1; rda.inuse = 1; - isa_memcpy_to_io(dev->mem_start + rdaaddr, &rda, + isa_memcpy_toio(dev->mem_start + rdaaddr, &rda, sizeof(rda_t)); /* set up link and EOL = 0 in currently last descriptor. Only write the link field since the SONIC may currently already access the other fields. */ - isa_memcpy_to_io(dev->mem_start + lrdaaddr + 20, &rdaaddr, 4); + isa_memcpy_toio(dev->mem_start + lrdaaddr + 20, &rdaaddr, 4); /* advance indices */ @@ -833,7 +833,7 @@ if (tmplen < 60) tmplen = 60; baddr = priv->txbufstart + (priv->nexttxdescr * PKTSIZE); - isa_memcpy_to_io(dev->mem_start + baddr, skb->data, skb->len); + isa_memcpy_toio(dev->mem_start + baddr, skb->data, skb->len); /* copy filler into RAM - in case we're filling up... we're filling a bit more than necessary, but that doesn't harm @@ -845,7 +845,7 @@ unsigned int destoffs = skb->len, l = strlen(fill); while (destoffs < tmplen) { - isa_memcpy_to_io(dev->mem_start + baddr + destoffs, fill, l); + isa_memcpy_toio(dev->mem_start + baddr + destoffs, fill, l); destoffs += l; } } @@ -854,7 +854,7 @@ addr = priv->tdastart + (priv->nexttxdescr * sizeof(tda_t)); isa_memcpy_fromio(&tda, dev->mem_start + addr, sizeof(tda_t)); tda.length = tda.fraglength = tmplen; - isa_memcpy_to_io(dev->mem_start + addr, &tda, sizeof(tda_t)); + isa_memcpy_toio(dev->mem_start + addr, &tda, sizeof(tda_t)); /* if there were no active descriptors, trigger the SONIC */ spin_lock_irqsave(&priv->lock, flags); diff -Nru a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c --- a/drivers/net/irda/sa1100_ir.c Mon Nov 4 14:31:01 2002 +++ b/drivers/net/irda/sa1100_ir.c Mon Nov 4 14:31:01 2002 @@ -42,6 +42,8 @@ #include #include +#include +#include #ifndef GPIO_IRDA_FIR #define GPIO_IRDA_FIR (0) diff -Nru a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c --- a/drivers/net/lasi_82596.c Mon Nov 4 14:31:00 2002 +++ b/drivers/net/lasi_82596.c Mon Nov 4 14:31:00 2002 @@ -93,7 +93,6 @@ #include #include -#include #include static char version[] __devinitdata = diff -Nru a/drivers/net/mac8390.c b/drivers/net/mac8390.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/mac8390.c Mon Nov 4 14:31:02 2002 @@ -0,0 +1,752 @@ +/* mac8390.c: New driver for 8390-based Nubus (or Nubus-alike) + Ethernet cards on Linux */ +/* Based on the former daynaport.c driver, by Alan Cox. Some code + taken from or inspired by skeleton.c by Donald Becker, acenic.c by + Jes Sorensen, and ne2k-pci.c by Donald Becker and Paul Gortmaker. + + This software may be used and distributed according to the terms of + the GNU Public License, incorporated herein by reference. */ + +/* 2000-02-28: support added for Dayna and Kinetics cards by + A.G.deWijn@phys.uu.nl */ +/* 2000-04-04: support added for Dayna2 by bart@etpmod.phys.tue.nl */ +/* 2001-04-18: support for DaynaPort E/LC-M by rayk@knightsmanor.org */ +/* 2001-05-15: support for Cabletron ported from old daynaport driver + * and fixed access to Sonic Sys card which masquerades as a Farallon + * by rayk@knightsmanor.org */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "8390.h" + +#if (LINUX_VERSION_CODE < 0x02030e) +#define net_device device +#endif + +#define WD_START_PG 0x00 /* First page of TX buffer */ +#define CABLETRON_RX_START_PG 0x00 /* First page of RX buffer */ +#define CABLETRON_RX_STOP_PG 0x30 /* Last page +1 of RX ring */ +#define CABLETRON_TX_START_PG CABLETRON_RX_STOP_PG /* First page of TX buffer */ + +/* Unfortunately it seems we have to hardcode these for the moment */ +/* Shouldn't the card know about this? Does anyone know where to read it off the card? Do we trust the data provided by the card? */ + +#define DAYNA_8390_BASE 0x80000 +#define DAYNA_8390_MEM 0x00000 + +#define KINETICS_8390_BASE 0x80000 +#define KINETICS_8390_MEM 0x00000 + +#define CABLETRON_8390_BASE 0x90000 +#define CABLETRON_8390_MEM 0x00000 + +enum mac8390_type { + MAC8390_NONE = -1, + MAC8390_APPLE, + MAC8390_ASANTE, + MAC8390_FARALLON, /* Apple, Asante, and Farallon are all compatible */ + MAC8390_CABLETRON, + MAC8390_DAYNA, + MAC8390_INTERLAN, + MAC8390_KINETICS, + MAC8390_FOCUS, + MAC8390_SONICSYS, + MAC8390_DAYNA2, + MAC8390_DAYNA3, +}; + +static const char * cardname[] = { + "apple", + "asante", + "farallon", + "cabletron", + "dayna", + "interlan", + "kinetics", + "focus", + "sonic systems", + "dayna2", + "dayna_lc", +}; + +static int word16[] = { + 1, /* apple */ + 1, /* asante */ + 1, /* farallon */ + 1, /* cabletron */ + 0, /* dayna */ + 1, /* interlan */ + 0, /* kinetics */ + 1, /* focus (??) */ + 1, /* sonic systems */ + 1, /* dayna2 */ + 1, /* dayna-lc */ +}; + +/* on which cards do we use NuBus resources? */ +static int useresources[] = { + 1, /* apple */ + 1, /* asante */ + 1, /* farallon */ + 0, /* cabletron */ + 0, /* dayna */ + 0, /* interlan */ + 0, /* kinetics */ + 0, /* focus (??) */ + 1, /* sonic systems */ + 1, /* dayna2 */ + 1, /* dayna-lc */ +}; + +static const char __initdata * version = + "mac8390.c: v0.4 2001-05-15 David Huggins-Daines and others\n"; + +extern int mac8390_probe(struct net_device * dev); +extern enum mac8390_type mac8390_ident(struct nubus_dev * dev); +extern int mac8390_memsize(unsigned long membase); +extern int mac8390_memtest(struct net_device * dev); +extern int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, + enum mac8390_type type); + +static int mac8390_open(struct net_device * dev); +static int mac8390_close(struct net_device * dev); +static void mac8390_no_reset(struct net_device *dev); + +/* Sane (32-bit chunk memory read/write) - Apple/Asante/Farallon do this*/ +static void sane_get_8390_hdr(struct net_device *dev, + struct e8390_pkt_hdr *hdr, int ring_page); +static void sane_block_input(struct net_device * dev, int count, + struct sk_buff * skb, int ring_offset); +static void sane_block_output(struct net_device * dev, int count, + const unsigned char * buf, const int start_page); + +/* dayna_memcpy to and from card */ +static void dayna_memcpy_fromcard(struct net_device *dev, void *to, + int from, int count); +static void dayna_memcpy_tocard(struct net_device *dev, int to, + const void *from, int count); + +/* Dayna - Dayna/Kinetics use this */ +static void dayna_get_8390_hdr(struct net_device *dev, + struct e8390_pkt_hdr *hdr, int ring_page); +static void dayna_block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset); +static void dayna_block_output(struct net_device *dev, int count, + const unsigned char *buf, int start_page); + +#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) +#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c)) + +/* Slow Sane (16-bit chunk memory read/write) Cabletron uses this */ +static void slow_sane_get_8390_hdr(struct net_device *dev, + struct e8390_pkt_hdr *hdr, int ring_page); +static void slow_sane_block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset); +static void slow_sane_block_output(struct net_device *dev, int count, + const unsigned char *buf, int start_page); +static void word_memcpy_tocard(void *tp, const void *fp, int count); +static void word_memcpy_fromcard(void *tp, const void *fp, int count); + +enum mac8390_type __init mac8390_ident(struct nubus_dev * dev) +{ + if (dev->dr_sw == NUBUS_DRSW_ASANTE) + return MAC8390_ASANTE; + if (dev->dr_sw == NUBUS_DRSW_FARALLON) + return MAC8390_FARALLON; + if (dev->dr_sw == NUBUS_DRSW_KINETICS) + return MAC8390_KINETICS; + if (dev->dr_sw == NUBUS_DRSW_DAYNA) + return MAC8390_DAYNA; + if (dev->dr_sw == NUBUS_DRSW_DAYNA2) + return MAC8390_DAYNA2; + if (dev->dr_sw == NUBUS_DRSW_DAYNA_LC) + return MAC8390_DAYNA3; + if (dev->dr_hw == NUBUS_DRHW_CABLETRON) + return MAC8390_CABLETRON; + return MAC8390_NONE; +} + +int __init mac8390_memsize(unsigned long membase) +{ + unsigned long flags; + int i, j; + + save_flags(flags); cli(); + /* Check up to 32K in 4K increments */ + for (i = 0; i < 8; i++) { + volatile unsigned short *m = (unsigned short *) (membase + (i * 0x1000)); + + /* Unwriteable - we have a fully decoded card and the + RAM end located */ + if (hwreg_present(m) == 0) + break; + + /* write a distinctive byte */ + *m = 0xA5A0 | i; + /* check that we read back what we wrote */ + if (*m != (0xA5A0 | i)) + break; + + /* check for partial decode and wrap */ + for (j = 0; j < i; j++) { + volatile unsigned short *p = (unsigned short *) (membase + (j * 0x1000)); + if (*p != (0xA5A0 | j)) + break; + } + } + restore_flags(flags); + /* in any case, we stopped once we tried one block too many, + or once we reached 32K */ + return i * 0x1000; +} + +static int probed __initdata = 0; + +int __init mac8390_probe(struct net_device * dev) +{ + volatile unsigned short *i; + int boards_found = 0; + int version_disp = 0; + struct nubus_dev * ndev = NULL; + + struct nubus_dir dir; + struct nubus_dirent ent; + int offset; + + enum mac8390_type cardtype; + + if (probed) + return -ENODEV; + probed++; + + /* probably should check for Nubus instead */ + + if (!MACH_IS_MAC) + return -ENODEV; + + while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev))) { + + dev = NULL; + + if ((cardtype = mac8390_ident(ndev)) == MAC8390_NONE) + continue; + + dev = init_etherdev(dev, 0); + if (dev == NULL) { + printk(KERN_ERR "Unable to allocate etherdev" + "structure!\n"); + return -ENOMEM; + } + + if (version_disp == 0) { + version_disp = 1; + printk(version); + } + + dev->irq = SLOT2IRQ(ndev->board->slot); + /* This is getting to be a habit */ + dev->base_addr = ndev->board->slot_addr | ((ndev->board->slot&0xf) << 20); + + /* Get some Nubus info - we will trust the card's idea + of where its memory and registers are. */ + + if (nubus_get_func_dir(ndev, &dir) == -1) { + printk(KERN_ERR "%s: Unable to get Nubus functional" + " directory for slot %X!\n", + dev->name, ndev->board->slot); + continue; + } + + /* Get the MAC address */ + if ((nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent)) == -1) { + printk(KERN_INFO "%s: Couldn't get MAC address!\n", + dev->name); + continue; + } else { + nubus_get_rsrc_mem(dev->dev_addr, &ent, 6); + /* Some Sonic Sys cards masquerade as Farallon */ + if (cardtype == MAC8390_FARALLON && + dev->dev_addr[0] == 0x0 && + dev->dev_addr[1] == 0x40 && + dev->dev_addr[2] == 0x10) { + /* This is really Sonic Sys card */ + cardtype = MAC8390_SONICSYS; + } + } + + if (useresources[cardtype] == 1) { + nubus_rewinddir(&dir); + if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_BASEOS, &ent) == -1) { + printk(KERN_ERR "%s: Memory offset resource" + " for slot %X not found!\n", + dev->name, ndev->board->slot); + continue; + } + nubus_get_rsrc_mem(&offset, &ent, 4); + dev->mem_start = dev->base_addr + offset; + /* yes, this is how the Apple driver does it */ + dev->base_addr = dev->mem_start + 0x10000; + nubus_rewinddir(&dir); + if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_LENGTH, &ent) == -1) { + printk(KERN_INFO "%s: Memory length resource" + " for slot %X not found" + ", probing\n", + dev->name, ndev->board->slot); + offset = mac8390_memsize(dev->mem_start); + } else { + nubus_get_rsrc_mem(&offset, &ent, 4); + } + dev->mem_end = dev->mem_start + offset; + } else { + switch (cardtype) { + case MAC8390_KINETICS: + case MAC8390_DAYNA: /* it's the same */ + dev->base_addr = + (int)(ndev->board->slot_addr + + DAYNA_8390_BASE); + dev->mem_start = + (int)(ndev->board->slot_addr + + DAYNA_8390_MEM); + dev->mem_end = + dev->mem_start + + mac8390_memsize(dev->mem_start); + break; + case MAC8390_CABLETRON: + dev->base_addr = + (int)(ndev->board->slot_addr + + CABLETRON_8390_BASE); + dev->mem_start = + (int)(ndev->board->slot_addr + + CABLETRON_8390_MEM); + /* The base address is unreadable if 0x00 + * has been written to the command register + * Reset the chip by writing E8390_NODMA + + * E8390_PAGE0 + E8390_STOP just to be + * sure + */ + i = (void *)dev->base_addr; + *i = 0x21; + dev->mem_end = + dev->mem_start + + mac8390_memsize(dev->mem_start); + break; + + default: + printk(KERN_ERR "Card type %s is" + " unsupported, sorry\n", + cardname[cardtype]); + return -ENODEV; + } + } + + /* Do the nasty 8390 stuff */ + if (mac8390_initdev(dev, ndev, cardtype)) + continue; + boards_found++; + } + + /* We're outta here */ + if (boards_found > 0) + return 0; + else + return -ENODEV; +} + +#ifdef MODULE +#if LINUX_VERSION_CODE > 0x20118 +MODULE_AUTHOR("David Huggins-Daines and others"); +MODULE_DESCRIPTION("Macintosh NS8390-based Nubus Ethernet driver"); +MODUEL_LICENSE("GPL"); +#endif + +int init_module(void) +{ + if (mac8390_probe(NULL)) { + printk(KERN_NOTICE "mac8390.c: No useable cards found, driver NOT installed.\n"); + return -ENODEV; + } + lock_8390_module(); + return 0; +} + +void cleanup_module(void) +{ + /* FIXME: should probably keep track of net_device structs + somewhere and unregister them here? */ + unlock_8390_module(); +} + +#endif /* MODULE */ + +int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, + enum mac8390_type type) +{ + static u32 fwrd4_offsets[16]={ + 0, 4, 8, 12, + 16, 20, 24, 28, + 32, 36, 40, 44, + 48, 52, 56, 60 + }; + static u32 back4_offsets[16]={ + 60, 56, 52, 48, + 44, 40, 36, 32, + 28, 24, 20, 16, + 12, 8, 4, 0 + }; + static u32 fwrd2_offsets[16]={ + 0, 2, 4, 6, + 8, 10, 12, 14, + 16, 18, 20, 22, + 24, 26, 28, 30 + }; + + int access_bitmode; + + /* 8390 specific init for dev - allocates dev->priv */ + if (ethdev_init(dev)) { + printk(KERN_ERR "%s: Unable to allocate memory for dev->priv!\n", dev->name); + return -ENOMEM; + } + + /* Now fill in our stuff */ + dev->open = &mac8390_open; + dev->stop = &mac8390_close; + + /* GAR, ei_status is actually a macro even though it looks global */ + ei_status.name = cardname[type]; + ei_status.word16 = word16[type]; + + /* Cabletron's TX/RX buffers are backwards */ + if (type == MAC8390_CABLETRON) { + ei_status.tx_start_page = CABLETRON_TX_START_PG; + ei_status.rx_start_page = CABLETRON_RX_START_PG; + ei_status.stop_page = CABLETRON_RX_STOP_PG; + dev->rmem_start = dev->mem_start; + dev->rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256; + } else { + ei_status.tx_start_page = WD_START_PG; + ei_status.rx_start_page = WD_START_PG + TX_PAGES; + ei_status.stop_page = (dev->mem_end - dev->mem_start)/256; + dev->rmem_start = dev->mem_start + TX_PAGES*256; + dev->rmem_end = dev->mem_end; + } + + /* Fill in model-specific information and functions */ + switch(type) { + case MAC8390_SONICSYS: + /* 16 bit card, register map is reversed */ + ei_status.reset_8390 = &mac8390_no_reset; + ei_status.block_input = &slow_sane_block_input; + ei_status.block_output = &slow_sane_block_output; + ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; + ei_status.reg_offset = back4_offsets; + access_bitmode = 0; + break; + case MAC8390_FARALLON: + case MAC8390_APPLE: + case MAC8390_ASANTE: + case MAC8390_DAYNA2: + case MAC8390_DAYNA3: + /* 32 bit card, register map is reversed */ + /* sane */ + ei_status.reset_8390 = &mac8390_no_reset; + ei_status.block_input = &sane_block_input; + ei_status.block_output = &sane_block_output; + ei_status.get_8390_hdr = &sane_get_8390_hdr; + ei_status.reg_offset = back4_offsets; + access_bitmode = 1; + break; + case MAC8390_CABLETRON: + /* 16 bit card, register map is short forward */ + ei_status.reset_8390 = &mac8390_no_reset; + ei_status.block_input = &slow_sane_block_input; + ei_status.block_output = &slow_sane_block_output; + ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; + ei_status.reg_offset = fwrd2_offsets; + access_bitmode = 0; + break; + case MAC8390_DAYNA: + case MAC8390_KINETICS: + /* 16 bit memory */ + /* dayna and similar */ + ei_status.reset_8390 = &mac8390_no_reset; + ei_status.block_input = &dayna_block_input; + ei_status.block_output = &dayna_block_output; + ei_status.get_8390_hdr = &dayna_get_8390_hdr; + ei_status.reg_offset = fwrd4_offsets; + access_bitmode = 0; + break; + default: + printk(KERN_ERR "Card type %s is unsupported, sorry\n", cardname[type]); + return -ENODEV; + } + + NS8390_init(dev, 0); + + /* Good, done, now spit out some messages */ + printk(KERN_INFO "%s: %s in slot %X (type %s)\n", + dev->name, ndev->board->name, ndev->board->slot, cardname[type]); + printk(KERN_INFO "MAC "); + { + int i; + for (i = 0; i < 6; i++) { + printk("%2.2x", dev->dev_addr[i]); + if (i < 5) + printk(":"); + } + } + printk(" IRQ %d, shared memory at %#lx-%#lx, %d-bit access.\n", + dev->irq, dev->mem_start, dev->mem_end-1, + access_bitmode?32:16); + return 0; +} + +static int mac8390_open(struct net_device *dev) +{ + ei_open(dev); + if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev)) { + printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq); + return -EAGAIN; + } + MOD_INC_USE_COUNT; + return 0; +} + +static int mac8390_close(struct net_device *dev) +{ + free_irq(dev->irq, dev); + ei_close(dev); + MOD_DEC_USE_COUNT; + return 0; +} + +static void mac8390_no_reset(struct net_device *dev) +{ + ei_status.txing = 0; + if (ei_debug > 1) + printk("reset not supported\n"); + return; +} + +/* dayna_memcpy_fromio/dayna_memcpy_toio */ +/* directly from daynaport.c by Alan Cox */ +static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count) +{ + volatile unsigned short *ptr; + unsigned short *target=to; + from<<=1; /* word, skip overhead */ + ptr=(unsigned short *)(dev->mem_start+from); + /* Leading byte? */ + if (from&2) { + *((char *)target)++ = *(((char *)ptr++)-1); + count--; + } + while(count>=2) + { + *target++=*ptr++; /* Copy and */ + ptr++; /* skip cruft */ + count-=2; + } + /* Trailing byte? */ + if(count) + { + /* Big endian */ + unsigned short v=*ptr; + *((char *)target)=v>>8; + } +} + +static void dayna_memcpy_tocard(struct net_device *dev, int to, const void *from, int count) +{ + volatile unsigned short *ptr; + const unsigned short *src=from; + to<<=1; /* word, skip overhead */ + ptr=(unsigned short *)(dev->mem_start+to); + /* Leading byte? */ + if (to&2) { /* avoid a byte write (stomps on other data) */ + ptr[-1] = (ptr[-1]&0xFF00)|*((unsigned char *)src)++; + ptr++; + count--; + } + while(count>=2) + { + *ptr++=*src++; /* Copy and */ + ptr++; /* skip cruft */ + count-=2; + } + /* Trailing byte? */ + if(count) + { + /* Big endian */ + unsigned short v=*src; + /* card doesn't like byte writes */ + *ptr=(*ptr&0x00FF)|(v&0xFF00); + } +} + +/* sane block input/output */ +static void sane_get_8390_hdr(struct net_device *dev, + struct e8390_pkt_hdr *hdr, int ring_page) +{ + unsigned long hdr_start = (ring_page - WD_START_PG)<<8; + memcpy_fromio((void *)hdr, (char *)dev->mem_start + hdr_start, 4); + /* Fix endianness */ + hdr->count = swab16(hdr->count); +} + +static void sane_block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset) +{ + unsigned long xfer_base = ring_offset - (WD_START_PG<<8); + unsigned long xfer_start = xfer_base + dev->mem_start; + + if (xfer_start + count > dev->rmem_end) { + /* We must wrap the input move. */ + int semi_count = dev->rmem_end - xfer_start; + memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, semi_count); + count -= semi_count; + memcpy_toio(skb->data + semi_count, (char *)dev->rmem_start, count); + } else { + memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, count); + } +} + +static void sane_block_output(struct net_device *dev, int count, + const unsigned char *buf, int start_page) +{ + long shmem = (start_page - WD_START_PG)<<8; + + memcpy_toio((char *)dev->mem_start + shmem, buf, count); +} + +/* dayna block input/output */ +static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) +{ + unsigned long hdr_start = (ring_page - WD_START_PG)<<8; + + dayna_memcpy_fromcard(dev, (void *)hdr, hdr_start, 4); + /* Fix endianness */ + hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8); +} + +static void dayna_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) +{ + unsigned long xfer_base = ring_offset - (WD_START_PG<<8); + unsigned long xfer_start = xfer_base+dev->mem_start; + + /* Note the offset math is done in card memory space which is word + per long onto our space. */ + + if (xfer_start + count > dev->rmem_end) + { + /* We must wrap the input move. */ + int semi_count = dev->rmem_end - xfer_start; + dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count); + count -= semi_count; + dayna_memcpy_fromcard(dev, skb->data + semi_count, + dev->rmem_start - dev->mem_start, count); + } + else + { + dayna_memcpy_fromcard(dev, skb->data, xfer_base, count); + } +} + +static void dayna_block_output(struct net_device *dev, int count, const unsigned char *buf, + int start_page) +{ + long shmem = (start_page - WD_START_PG)<<8; + + dayna_memcpy_tocard(dev, shmem, buf, count); +} + +/* Cabletron block I/O */ +static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, + int ring_page) +{ + unsigned long hdr_start = (ring_page - WD_START_PG)<<8; + word_memcpy_fromcard((void *)hdr, (char *)dev->mem_start+hdr_start, 4); + /* Register endianism - fix here rather than 8390.c */ + hdr->count = (hdr->count&0xFF)<<8|(hdr->count>>8); +} + +static void slow_sane_block_input(struct net_device *dev, int count, struct sk_buff *skb, + int ring_offset) +{ + unsigned long xfer_base = ring_offset - (WD_START_PG<<8); + unsigned long xfer_start = xfer_base+dev->mem_start; + + if (xfer_start + count > dev->rmem_end) + { + /* We must wrap the input move. */ + int semi_count = dev->rmem_end - xfer_start; + word_memcpy_fromcard(skb->data, (char *)dev->mem_start + + xfer_base, semi_count); + count -= semi_count; + word_memcpy_fromcard(skb->data + semi_count, + (char *)dev->rmem_start, count); + } + else + { + word_memcpy_fromcard(skb->data, (char *)dev->mem_start + + xfer_base, count); + } +} + +static void slow_sane_block_output(struct net_device *dev, int count, const unsigned char *buf, + int start_page) +{ + long shmem = (start_page - WD_START_PG)<<8; + + word_memcpy_tocard((char *)dev->mem_start + shmem, buf, count); +} + +static void word_memcpy_tocard(void *tp, const void *fp, int count) +{ + volatile unsigned short *to = tp; + const unsigned short *from = fp; + + count++; + count/=2; + + while(count--) + *to++=*from++; +} + +static void word_memcpy_fromcard(void *tp, const void *fp, int count) +{ + unsigned short *to = tp; + const volatile unsigned short *from = fp; + + count++; + count/=2; + + while(count--) + *to++=*from++; +} + + diff -Nru a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c --- a/drivers/net/sun3_82586.c Mon Nov 4 14:31:02 2002 +++ b/drivers/net/sun3_82586.c Mon Nov 4 14:31:02 2002 @@ -279,14 +279,14 @@ int __init sun3_82586_probe(struct net_device *dev) { - unsigned long ioaddr, iopte; + unsigned long ioaddr; static int found = 0; - /* check that this machine has an onboard lance */ + /* check that this machine has an onboard 82586 */ switch(idprom->id_machtype) { case SM_SUN3|SM_3_160: case SM_SUN3|SM_3_260: - /* these machines have lance */ + /* these machines have 82586 */ break; default: @@ -296,22 +296,8 @@ if(found) return -ENODEV; - for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 + - SUN3_PMEG_SIZE); ioaddr += SUN3_PTE_SIZE) { - - iopte = sun3_get_pte(ioaddr); - if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */ - continue; - - if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) == - IE_OBIO) { - found = 1; - break; - } - } - - if(!found) - return 0; + ioaddr = (unsigned long)ioremap(IE_OBIO, PAGE_SIZE); + found = 1; SET_MODULE_OWNER(dev); diff -Nru a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c --- a/drivers/net/sun3lance.c Mon Nov 4 14:31:02 2002 +++ b/drivers/net/sun3lance.c Mon Nov 4 14:31:02 2002 @@ -279,33 +279,16 @@ static int __init lance_probe( struct net_device *dev) { - unsigned long ioaddr, iopte; + unsigned long ioaddr; struct lance_private *lp; int i; static int did_version; - int found = 0; volatile unsigned short *ioaddr_probe; unsigned short tmp1, tmp2; #ifdef CONFIG_SUN3 - /* LANCE_OBIO can be found within the IO pmeg with some effort */ - for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 + - SUN3_PMEG_SIZE); ioaddr += SUN3_PTE_SIZE) { - - iopte = sun3_get_pte(ioaddr); - if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */ - continue; - - if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) == - LANCE_OBIO) { - found = 1; - break; - } - } - - if(!found) - return 0; + ioaddr = (unsigned long)ioremap(LANCE_OBIO, PAGE_SIZE); #else ioaddr = SUN3X_LANCE; #endif diff -Nru a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c --- a/drivers/net/tulip/de2104x.c Mon Nov 4 14:31:02 2002 +++ b/drivers/net/tulip/de2104x.c Mon Nov 4 14:31:02 2002 @@ -2216,7 +2216,7 @@ .name = DRV_NAME, .id_table = de_pci_tbl, .probe = de_init_one, - .remove = de_remove_one, + .remove = __devexit_p(de_remove_one), #ifdef CONFIG_PM .suspend = de_suspend, .resume = de_resume, diff -Nru a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c --- a/drivers/net/tulip/de4x5.c Mon Nov 4 14:31:00 2002 +++ b/drivers/net/tulip/de4x5.c Mon Nov 4 14:31:00 2002 @@ -874,6 +874,7 @@ struct de4x5_srom srom; int autosense; int useSROM; + struct pci_dev *pdev; } bus; /* @@ -1151,8 +1152,7 @@ if (lp->bus == EISA) { outb(WAKEUP, PCI_CFPM); } else { - pcibios_write_config_byte(lp->bus_num, lp->device << 3, - PCI_CFDA_PSM, WAKEUP); + pci_write_config_byte(lp->pdev, PCI_CFDA_PSM, WAKEUP); } mdelay(10); @@ -2222,11 +2222,12 @@ } /* Get the chip configuration revision register */ - pcibios_read_config_dword(pb, pdev->devfn, PCI_REVISION_ID, &cfrv); + pci_read_config_dword(pdev, PCI_REVISION_ID, &cfrv); /* Set the device number information */ lp->device = dev_num; lp->bus_num = pb; + lp->pdev = pdev; /* Set the chipset information */ if (is_DC2114x) { @@ -2242,27 +2243,27 @@ if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue; /* Check if I/O accesses and Bus Mastering are enabled */ - pcibios_read_config_word(pb, pdev->devfn, PCI_COMMAND, &status); + pci_read_config_word(pdev, PCI_COMMAND, &status); #ifdef __powerpc__ if (!(status & PCI_COMMAND_IO)) { status |= PCI_COMMAND_IO; - pcibios_write_config_word(pb, pdev->devfn, PCI_COMMAND, status); - pcibios_read_config_word(pb, pdev->devfn, PCI_COMMAND, &status); + pci_write_config_word(pdev, PCI_COMMAND, status); + pci_read_config_word(pdev, PCI_COMMAND, &status); } #endif /* __powerpc__ */ if (!(status & PCI_COMMAND_IO)) continue; if (!(status & PCI_COMMAND_MASTER)) { status |= PCI_COMMAND_MASTER; - pcibios_write_config_word(pb, pdev->devfn, PCI_COMMAND, status); - pcibios_read_config_word(pb, pdev->devfn, PCI_COMMAND, &status); + pci_write_config_word(pdev, PCI_COMMAND, status); + pci_read_config_word(pdev, PCI_COMMAND, &status); } if (!(status & PCI_COMMAND_MASTER)) continue; /* Check the latency timer for values >= 0x60 */ - pcibios_read_config_byte(pb, pdev->devfn, PCI_LATENCY_TIMER, &timer); + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &timer); if (timer < 0x60) { - pcibios_write_config_byte(pb, pdev->devfn, PCI_LATENCY_TIMER, 0x60); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x60); } DevicePresent(DE4X5_APROM); @@ -2314,7 +2315,7 @@ /* Get the chip configuration revision register */ pb = this_dev->bus->number; - pcibios_read_config_dword(pb, this_dev->devfn, PCI_REVISION_ID, &cfrv); + pci_read_config_dword(this_dev, PCI_REVISION_ID, &cfrv); /* Set the device number information */ lp->device = PCI_SLOT(this_dev->devfn); @@ -2334,7 +2335,7 @@ if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue; /* Check if I/O accesses are enabled */ - pcibios_read_config_word(pb, this_dev->devfn, PCI_COMMAND, &status); + pci_read_config_word(this_dev, PCI_COMMAND, &status); if (!(status & PCI_COMMAND_IO)) continue; /* Search for a valid SROM attached to this DECchip */ @@ -5325,20 +5326,17 @@ } else { switch(state) { case WAKEUP: - pcibios_write_config_byte(lp->bus_num, lp->device << 3, - PCI_CFDA_PSM, WAKEUP); + pci_write_config_byte(lp->pdev, PCI_CFDA_PSM, WAKEUP); mdelay(10); break; case SNOOZE: - pcibios_write_config_byte(lp->bus_num, lp->device << 3, - PCI_CFDA_PSM, SNOOZE); + pci_write_config_byte(lp->pdev, PCI_CFDA_PSM, SNOOZE); break; case SLEEP: outl(0, DE4X5_SICR); - pcibios_write_config_byte(lp->bus_num, lp->device << 3, - PCI_CFDA_PSM, SLEEP); + pci_write_config_byte(lp->pdev, PCI_CFDA_PSM, SLEEP); break; } } diff -Nru a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c --- a/drivers/net/tulip/winbond-840.c Mon Nov 4 14:31:01 2002 +++ b/drivers/net/tulip/winbond-840.c Mon Nov 4 14:31:01 2002 @@ -1428,8 +1428,9 @@ memset(mc_filter, 0, sizeof(mc_filter)); for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { - set_bit((ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F, - mc_filter); + int filterbit = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F; + filterbit &= 0x3f; + mc_filter[filterbit >> 5] |= cpu_to_le32(1 << (filterbit & 31)); } rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; } diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c --- a/drivers/net/wireless/airo.c Mon Nov 4 14:31:00 2002 +++ b/drivers/net/wireless/airo.c Mon Nov 4 14:31:00 2002 @@ -97,12 +97,12 @@ infront of the label, that statistic will not be included in the list of statistics in the /proc filesystem */ -#define IGNLABEL 0&(int) +#define IGNLABEL(comment) 0 static char *statsLabels[] = { "RxOverrun", - IGNLABEL "RxPlcpCrcErr", - IGNLABEL "RxPlcpFormatErr", - IGNLABEL "RxPlcpLengthErr", + IGNLABEL("RxPlcpCrcErr"), + IGNLABEL("RxPlcpFormatErr"), + IGNLABEL("RxPlcpLengthErr"), "RxMacCrcErr", "RxMacCrcOk", "RxWepErr", @@ -146,15 +146,15 @@ "HostRxBc", "HostRxUc", "HostRxDiscard", - IGNLABEL "HmacTxMc", - IGNLABEL "HmacTxBc", - IGNLABEL "HmacTxUc", - IGNLABEL "HmacTxFail", - IGNLABEL "HmacRxMc", - IGNLABEL "HmacRxBc", - IGNLABEL "HmacRxUc", - IGNLABEL "HmacRxDiscard", - IGNLABEL "HmacRxAccepted", + IGNLABEL("HmacTxMc"), + IGNLABEL("HmacTxBc"), + IGNLABEL("HmacTxUc"), + IGNLABEL("HmacTxFail"), + IGNLABEL("HmacRxMc"), + IGNLABEL("HmacRxBc"), + IGNLABEL("HmacRxUc"), + IGNLABEL("HmacRxDiscard"), + IGNLABEL("HmacRxAccepted"), "SsidMismatch", "ApMismatch", "RatesMismatch", @@ -162,26 +162,26 @@ "AuthTimeout", "AssocReject", "AssocTimeout", - IGNLABEL "ReasonOutsideTable", - IGNLABEL "ReasonStatus1", - IGNLABEL "ReasonStatus2", - IGNLABEL "ReasonStatus3", - IGNLABEL "ReasonStatus4", - IGNLABEL "ReasonStatus5", - IGNLABEL "ReasonStatus6", - IGNLABEL "ReasonStatus7", - IGNLABEL "ReasonStatus8", - IGNLABEL "ReasonStatus9", - IGNLABEL "ReasonStatus10", - IGNLABEL "ReasonStatus11", - IGNLABEL "ReasonStatus12", - IGNLABEL "ReasonStatus13", - IGNLABEL "ReasonStatus14", - IGNLABEL "ReasonStatus15", - IGNLABEL "ReasonStatus16", - IGNLABEL "ReasonStatus17", - IGNLABEL "ReasonStatus18", - IGNLABEL "ReasonStatus19", + IGNLABEL("ReasonOutsideTable"), + IGNLABEL("ReasonStatus1"), + IGNLABEL("ReasonStatus2"), + IGNLABEL("ReasonStatus3"), + IGNLABEL("ReasonStatus4"), + IGNLABEL("ReasonStatus5"), + IGNLABEL("ReasonStatus6"), + IGNLABEL("ReasonStatus7"), + IGNLABEL("ReasonStatus8"), + IGNLABEL("ReasonStatus9"), + IGNLABEL("ReasonStatus10"), + IGNLABEL("ReasonStatus11"), + IGNLABEL("ReasonStatus12"), + IGNLABEL("ReasonStatus13"), + IGNLABEL("ReasonStatus14"), + IGNLABEL("ReasonStatus15"), + IGNLABEL("ReasonStatus16"), + IGNLABEL("ReasonStatus17"), + IGNLABEL("ReasonStatus18"), + IGNLABEL("ReasonStatus19"), "RxMan", "TxMan", "RxRefresh", diff -Nru a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c --- a/drivers/nubus/nubus.c Mon Nov 4 14:31:01 2002 +++ b/drivers/nubus/nubus.c Mon Nov 4 14:31:01 2002 @@ -8,7 +8,6 @@ */ #include -#include #include #include #include diff -Nru a/drivers/nubus/proc.c b/drivers/nubus/proc.c --- a/drivers/nubus/proc.c Mon Nov 4 14:31:02 2002 +++ b/drivers/nubus/proc.c Mon Nov 4 14:31:02 2002 @@ -17,7 +17,6 @@ icons) these files will provide "cooked" data. Otherwise they will simply provide raw access (read-only of course) to the ROM. */ -#include #include #include #include diff -Nru a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c --- a/drivers/oprofile/buffer_sync.c Mon Nov 4 14:31:01 2002 +++ b/drivers/oprofile/buffer_sync.c Mon Nov 4 14:31:01 2002 @@ -118,13 +118,13 @@ * because we cannot reach this code without at least one * dcookie user still being registered (namely, the reader * of the event buffer). */ -static inline u32 fast_get_dcookie(struct dentry * dentry, +static inline unsigned long fast_get_dcookie(struct dentry * dentry, struct vfsmount * vfsmnt) { - u32 cookie; + unsigned long cookie; if (dentry->d_cookie) - return (u32)dentry; + return (unsigned long)dentry; get_dcookie(dentry, vfsmnt, &cookie); return cookie; } @@ -135,9 +135,9 @@ * not strictly necessary but allows oprofile to associate * shared-library samples with particular applications */ -static u32 get_exec_dcookie(struct mm_struct * mm) +static unsigned long get_exec_dcookie(struct mm_struct * mm) { - u32 cookie = 0; + unsigned long cookie = 0; struct vm_area_struct * vma; if (!mm) @@ -163,9 +163,9 @@ * sure to do this lookup before a mm->mmap modification happens so * we don't lose track. */ -static u32 lookup_dcookie(struct mm_struct * mm, unsigned long addr, off_t * offset) +static unsigned long lookup_dcookie(struct mm_struct * mm, unsigned long addr, off_t * offset) { - u32 cookie = 0; + unsigned long cookie = 0; struct vm_area_struct * vma; for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) { @@ -188,7 +188,7 @@ } -static u32 last_cookie = ~0UL; +static unsigned long last_cookie = ~0UL; static void add_cpu_switch(int i) { @@ -199,7 +199,7 @@ } -static void add_ctx_switch(pid_t pid, u32 cookie) +static void add_ctx_switch(pid_t pid, unsigned long cookie) { add_event_entry(ESCAPE_CODE); add_event_entry(CTX_SWITCH_CODE); @@ -208,7 +208,7 @@ } -static void add_cookie_switch(u32 cookie) +static void add_cookie_switch(unsigned long cookie) { add_event_entry(ESCAPE_CODE); add_event_entry(COOKIE_SWITCH_CODE); @@ -225,7 +225,7 @@ static void add_us_sample(struct mm_struct * mm, struct op_sample * s) { - u32 cookie; + unsigned long cookie; off_t offset; cookie = lookup_dcookie(mm, s->eip, &offset); @@ -317,7 +317,7 @@ { struct mm_struct * mm = 0; struct task_struct * new; - u32 cookie; + unsigned long cookie; int i; for (i=0; i < cpu_buf->pos; ++i) { diff -Nru a/drivers/parisc/Kconfig b/drivers/parisc/Kconfig --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/Kconfig Mon Nov 4 14:31:04 2002 @@ -0,0 +1,103 @@ +menu "Bus options (PCI, PCMCIA, EISA, GSC, ISA)" + +config GSC + bool "VSC/GSC/HSC bus support" + default y + help + The VSC, GSC and HSC busses were used from the earliest 700-series + workstations up to and including the C360/J2240 workstations. They + were also used in servers from the E-class to the K-class. They + are not found in B1000, C3000, J5000, A500, L1000, N4000 and upwards. + If in doubt, say "Y". + +config IOMMU_CCIO + bool "U2/Uturn I/O MMU" + depends on GSC + help + Say Y here to enable DMA management routines for the first + generation of PA-RISC cache-coherent machines. Programs the + U2/Uturn chip in "Virtual Mode" and use the I/O MMU. + +config GSC_LASI + bool "Lasi I/O support" + depends on GSC + help + Say Y here to directly support the Lasi controller chip found on + PA-RISC workstations. Linux-oriented documentation for this chip + can be found at . + +config GSC_WAX + bool "Wax I/O support" + depends on GSC + help + Say Y here to support the Wax GSC to EISA Bridge found in some older + systems, including B/C/D/R class. Some machines use Wax for other + purposes, such as providing one of the serial ports or being an + interface chip for an X.25 GSC card. + +config EISA + bool "EISA support" + depends on GSC + help + Say Y here if you have an EISA bus in your machine. This code + supports both the Mongoose & Wax EISA adapters. It is sadly + incomplete and lacks support for card-to-host DMA. + +config ISA + bool + depends on EISA + +config PCI + bool "PCI support" + help + All recent HP machines have PCI slots, and you should say Y here + if you have a recent machine. If you are convinced you do not have + PCI slots in your machine (eg a 712), then you may say "N" here. + Beware that some GSC cards have a Dino onboard and PCI inside them, + so it may be safest to say "Y" anyway. + +config GSC_DINO + bool "GSCtoPCI/Dino PCI support" + depends on PCI && GSC + help + Say Y here to support the Dino & Cujo GSC to PCI bridges found in + machines from the B132 to the C360, the J2240 and the A180. Some + GSC/HSC cards (eg gigabit & dual 100 Mbit Ethernet) have a Dino on + the card, and you also need to say Y here if you have such a card. + If in doubt, say Y. + +config PCI_LBA + bool "LBA/Elroy PCI support" + depends on PCI + help + Say Y here to support the Elroy PCI Lower Bus Adapter. This is + present on B, C, J, L and N-class machines with 4-digit model + numbers and the A400/A500. + +config IOSAPIC + bool + depends on PCI_LBA + default y + +config IOMMU_SBA + bool + depends on PCI_LBA + default y + +#config PCI_EPIC +# bool "EPIC/SAGA PCI support" +# depends on PCI + +config SUPERIO + bool + depends on PCI + help + Say Y here to support the SuperIO chip found in Bxxxx, C3xxx and + J5xxx+ machines. + +source "drivers/pci/Kconfig" + +config CHASSIS_LCD_LED + bool "Chassis LCD and LED support" + +endmenu diff -Nru a/drivers/parisc/Makefile b/drivers/parisc/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/Makefile Mon Nov 4 14:31:03 2002 @@ -0,0 +1,25 @@ +# +# Makefile for most of the non-PCI devices in PA-RISC machines +# + +export-objs := gsc.o superio.o + +obj-y := gsc.o power.o +obj-m := +obj-n := +obj- := + +obj-$(CONFIG_GSC_DINO) += dino.o +obj-$(CONFIG_GSC_LASI) += lasi.o asp.o +obj-$(CONFIG_GSC_WAX) += wax.o +obj-$(CONFIG_EISA) += eisa.o eisa_enumerator.o eisa_eeprom.o +obj-$(CONFIG_SUPERIO) += superio.o +obj-$(CONFIG_PCI_LBA) += lba_pci.o +# I/O SAPIC is also on IA64 platforms. +# The two could be merged into a common source some day. +obj-$(CONFIG_IOSAPIC) += iosapic.o +obj-$(CONFIG_IOMMU_SBA) += sba_iommu.o +# Only use one of them: ccio-rm-dma is for PCX-W systems *only* +# obj-$(CONFIG_IOMMU_CCIO) += ccio-rm-dma.o +obj-$(CONFIG_IOMMU_CCIO) += ccio-dma.o +obj-$(CONFIG_CHASSIS_LCD_LED) += led.o diff -Nru a/drivers/parisc/README.dino b/drivers/parisc/README.dino --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/README.dino Mon Nov 4 14:31:03 2002 @@ -0,0 +1,28 @@ +/* +** HP VISUALIZE Workstation PCI Bus Defect +** +** "HP has discovered a potential system defect that can affect +** the behavior of five models of HP VISUALIZE workstations when +** equipped with third-party or customer-installed PCI I/O expansion +** cards. The defect is limited to the HP C180, C160, C160L, B160L, +** and B132L VISUALIZE workstations, and will only be encountered +** when data is transmitted through PCI I/O expansion cards on the +** PCI bus. HP-supplied graphics cards that utilize the PCI bus are +** not affected." +** +** REVISIT: "go/pci_defect" link below is stale. +** HP Internal can use +** +** Product First Good Serial Number +** C200/C240 (US) US67350000 +**B132L+/B180 (US) US67390000 +** C200 (Europe) 3713G01000 +** B180L (Europe) 3720G01000 +** +** Note that many boards were fixed/replaced under a free replacement +** program. Assume a machine is only "suspect" until proven otherwise. +** +** "The pci_check program will also be available as application +** patch PHSS_12295" +*/ + diff -Nru a/drivers/parisc/asp.c b/drivers/parisc/asp.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/asp.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,131 @@ +/* + * ASP Device Driver + * + * (c) Copyright 2000 The Puffin Group Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * by Helge Deller + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gsc.h" + +#define ASP_GSC_IRQ 3 /* hardcoded interrupt for GSC */ + +#define ASP_VER_OFFSET 0x20 /* offset of ASP version */ + +#define ASP_LED_ADDR 0xf0800020 + +#define VIPER_INT_WORD 0xFFFBF088 /* addr of viper interrupt word */ + +static int asp_choose_irq(struct parisc_device *dev) +{ + int irq = -1; + + switch (dev->id.sversion) { + case 0x71: irq = 22; break; /* SCSI */ + case 0x72: irq = 23; break; /* LAN */ + case 0x73: irq = 30; break; /* HIL */ + case 0x74: irq = 24; break; /* Centronics */ + case 0x75: irq = (dev->hw_path == 4) ? 26 : 25; break; /* RS232 */ + case 0x76: irq = 21; break; /* EISA BA */ + case 0x77: irq = 20; break; /* Graphics1 */ + case 0x7a: irq = 18; break; /* Audio (Bushmaster) */ + case 0x7b: irq = 18; break; /* Audio (Scorpio) */ + case 0x7c: irq = 28; break; /* FW SCSI */ + case 0x7d: irq = 27; break; /* FDDI */ + case 0x7f: irq = 18; break; /* Audio (Outfield) */ + } + return irq; +} + +/* There are two register ranges we're interested in. Interrupt / + * Status / LED are at 0xf080xxxx and Asp special registers are at + * 0xf082fxxx. PDC only tells us that Asp is at 0xf082f000, so for + * the purposes of interrupt handling, we have to tell other bits of + * the kernel to look at the other registers. + */ +#define ASP_INTERRUPT_ADDR 0xf0800000 + +int __init +asp_init_chip(struct parisc_device *dev) +{ + struct busdevice *asp; + struct gsc_irq gsc_irq; + int irq, ret; + + asp = kmalloc(sizeof(struct busdevice), GFP_KERNEL); + if(!asp) + return -ENOMEM; + + asp->version = gsc_readb(dev->hpa + ASP_VER_OFFSET) & 0xf; + asp->name = (asp->version == 1) ? "Asp" : "Cutoff"; + asp->hpa = ASP_INTERRUPT_ADDR; + + printk(KERN_INFO "%s version %d at 0x%lx found.\n", + asp->name, asp->version, dev->hpa); + + /* the IRQ ASP should use */ + ret = -EBUSY; + irq = gsc_claim_irq(&gsc_irq, ASP_GSC_IRQ); + if (irq < 0) { + printk(KERN_ERR "%s(): cannot get GSC irq\n", __FUNCTION__); + goto out; + } + + ret = request_irq(gsc_irq.irq, busdev_barked, 0, "asp", asp); + if (ret < 0) + goto out; + + /* Save this for debugging later */ + asp->parent_irq = gsc_irq.irq; + asp->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data; + + /* Program VIPER to interrupt on the ASP irq */ + gsc_writel((1 << (31 - ASP_GSC_IRQ)),VIPER_INT_WORD); + + /* Done init'ing, register this driver */ + ret = gsc_common_irqsetup(dev, asp); + if (ret) + goto out; + + fixup_child_irqs(dev, asp->busdev_region->data.irqbase, asp_choose_irq); + /* Mongoose is a sibling of Asp, not a child... */ + fixup_child_irqs(dev->parent, asp->busdev_region->data.irqbase, + asp_choose_irq); + + /* initialize the chassis LEDs */ +#ifdef CONFIG_CHASSIS_LCD_LED + register_led_driver(DISPLAY_MODEL_OLD_ASP, LED_CMD_REG_NONE, + (char *)ASP_LED_ADDR); +#endif + + return 0; + +out: + kfree(asp); + return ret; +} + +static struct parisc_device_id asp_tbl[] = { + { HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00070 }, + { 0, } +}; + +struct parisc_driver asp_driver = { + name: "Asp", + id_table: asp_tbl, + probe: asp_init_chip, +}; diff -Nru a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/ccio-dma.c Mon Nov 4 14:31:01 2002 @@ -0,0 +1,1613 @@ +/* +** ccio-dma.c: +** DMA management routines for first generation cache-coherent machines. +** Program U2/Uturn in "Virtual Mode" and use the I/O MMU. +** +** (c) Copyright 2000 Grant Grundler +** (c) Copyright 2000 Ryan Bradetich +** (c) Copyright 2000 Hewlett-Packard Company +** +** 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. +** +** +** "Real Mode" operation refers to U2/Uturn chip operation. +** U2/Uturn were designed to perform coherency checks w/o using +** the I/O MMU - basically what x86 does. +** +** Philipp Rumpf has a "Real Mode" driver for PCX-W machines at: +** CVSROOT=:pserver:anonymous@198.186.203.37:/cvsroot/linux-parisc +** cvs -z3 co linux/arch/parisc/kernel/dma-rm.c +** +** I've rewritten his code to work under TPG's tree. See ccio-rm-dma.c. +** +** Drawbacks of using Real Mode are: +** o outbound DMA is slower - U2 won't prefetch data (GSC+ XQL signal). +** o Inbound DMA less efficient - U2 can't use DMA_FAST attribute. +** o Ability to do scatter/gather in HW is lost. +** o Doesn't work under PCX-U/U+ machines since they didn't follow +** the coherency design originally worked out. Only PCX-W does. +*/ + +#include +#include +#include +#include +#include +#include +#include +#define PCI_DEBUG +#include +#undef PCI_DEBUG + +#include +#include /* for L1_CACHE_BYTES */ +#include +#include +#include +#include +#include +#include /* for register_module() */ + +/* +** Choose "ccio" since that's what HP-UX calls it. +** Make it easier for folks to migrate from one to the other :^) +*/ +#define MODULE_NAME "ccio" + +#undef DEBUG_CCIO_RES +#undef DEBUG_CCIO_RUN +#undef DEBUG_CCIO_INIT +#undef DEBUG_CCIO_RUN_SG + +#include +#include /* for proc_runway_root */ + +#ifdef DEBUG_CCIO_INIT +#define DBG_INIT(x...) printk(x) +#else +#define DBG_INIT(x...) +#endif + +#ifdef DEBUG_CCIO_RUN +#define DBG_RUN(x...) printk(x) +#else +#define DBG_RUN(x...) +#endif + +#ifdef DEBUG_CCIO_RES +#define DBG_RES(x...) printk(x) +#else +#define DBG_RES(x...) +#endif + +#ifdef DEBUG_CCIO_RUN_SG +#define DBG_RUN_SG(x...) printk(x) +#else +#define DBG_RUN_SG(x...) +#endif + +#define CCIO_INLINE /* inline */ +#define WRITE_U32(value, addr) gsc_writel(value, (u32 *)(addr)) +#define READ_U32(addr) gsc_readl((u32 *)(addr)) + +#define U2_IOA_RUNWAY 0x580 +#define U2_BC_GSC 0x501 +#define UTURN_IOA_RUNWAY 0x581 +#define UTURN_BC_GSC 0x502 + +#define IOA_NORMAL_MODE 0x00020080 /* IO_CONTROL to turn on CCIO */ +#define CMD_TLB_DIRECT_WRITE 35 /* IO_COMMAND for I/O TLB Writes */ +#define CMD_TLB_PURGE 33 /* IO_COMMAND to Purge I/O TLB entry */ + +struct ioa_registers { + /* Runway Supervisory Set */ + volatile int32_t unused1[12]; + volatile uint32_t io_command; /* Offset 12 */ + volatile uint32_t io_status; /* Offset 13 */ + volatile uint32_t io_control; /* Offset 14 */ + volatile int32_t unused2[1]; + + /* Runway Auxiliary Register Set */ + volatile uint32_t io_err_resp; /* Offset 0 */ + volatile uint32_t io_err_info; /* Offset 1 */ + volatile uint32_t io_err_req; /* Offset 2 */ + volatile uint32_t io_err_resp_hi; /* Offset 3 */ + volatile uint32_t io_tlb_entry_m; /* Offset 4 */ + volatile uint32_t io_tlb_entry_l; /* Offset 5 */ + volatile uint32_t unused3[1]; + volatile uint32_t io_pdir_base; /* Offset 7 */ + volatile uint32_t io_io_low_hv; /* Offset 8 */ + volatile uint32_t io_io_high_hv; /* Offset 9 */ + volatile uint32_t unused4[1]; + volatile uint32_t io_chain_id_mask; /* Offset 11 */ + volatile uint32_t unused5[2]; + volatile uint32_t io_io_low; /* Offset 14 */ + volatile uint32_t io_io_high; /* Offset 15 */ +}; + +struct ioc { + struct ioa_registers *ioc_hpa; /* I/O MMU base address */ + u8 *res_map; /* resource map, bit == pdir entry */ + u64 *pdir_base; /* physical base address */ + u32 res_hint; /* next available IOVP - + circular search */ + u32 res_size; /* size of resource map in bytes */ + spinlock_t res_lock; + +#ifdef CONFIG_PROC_FS +#define CCIO_SEARCH_SAMPLE 0x100 + unsigned long avg_search[CCIO_SEARCH_SAMPLE]; + unsigned long avg_idx; /* current index into avg_search */ + unsigned long used_pages; + unsigned long msingle_calls; + unsigned long msingle_pages; + unsigned long msg_calls; + unsigned long msg_pages; + unsigned long usingle_calls; + unsigned long usingle_pages; + unsigned long usg_calls; + unsigned long usg_pages; + + unsigned short cujo20_bug; +#endif + + /* STUFF We don't need in performance path */ + u32 pdir_size; /* in bytes, determined by IOV Space size */ + u32 chainid_shift; /* specify bit location of chain_id */ + struct ioc *next; /* Linked list of discovered iocs */ + const char *name; /* device name from firmware */ + unsigned int hw_path; /* the hardware path this ioc is associatd with */ + struct pci_dev *fake_pci_dev; /* the fake pci_dev for non-pci devs */ + struct resource mmio_region[2]; /* The "routed" MMIO regions */ +}; + +/* Ratio of Host MEM to IOV Space size */ +static unsigned long ccio_mem_ratio = 4; +static struct ioc *ioc_list; +static int ioc_count; + +/************************************************************** +* +* I/O Pdir Resource Management +* +* Bits set in the resource map are in use. +* Each bit can represent a number of pages. +* LSbs represent lower addresses (IOVA's). +* +* This was was copied from sba_iommu.c. Don't try to unify +* the two resource managers unless a way to have different +* allocation policies is also adjusted. We'd like to avoid +* I/O TLB thrashing by having resource allocation policy +* match the I/O TLB replacement policy. +* +***************************************************************/ +#define IOVP_SIZE PAGE_SIZE +#define IOVP_SHIFT PAGE_SHIFT +#define IOVP_MASK PAGE_MASK + +/* Convert from IOVP to IOVA and vice versa. */ +#define CCIO_IOVA(iovp,offset) ((iovp) | (offset)) +#define CCIO_IOVP(iova) ((iova) & IOVP_MASK) + +#define PDIR_INDEX(iovp) ((iovp)>>IOVP_SHIFT) +#define MKIOVP(pdir_idx) ((long)(pdir_idx) << IOVP_SHIFT) +#define MKIOVA(iovp,offset) (dma_addr_t)((long)iovp | (long)offset) +#define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1)) + +/* +** Don't worry about the 150% average search length on a miss. +** If the search wraps around, and passes the res_hint, it will +** cause the kernel to panic anyhow. +*/ +#define CCIO_SEARCH_LOOP(ioc, res_idx, mask_ptr, size) \ + for(; res_ptr < res_end; ++res_ptr) { \ + if(0 == (*res_ptr & *mask_ptr)) { \ + *res_ptr |= *mask_ptr; \ + res_idx = (int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \ + ioc->res_hint = res_idx + (size >> 3); \ + goto resource_found; \ + } \ + } + +#define CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, size) \ + u##size *res_ptr = (u##size *)&((ioc)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \ + u##size *res_end = (u##size *)&(ioc)->res_map[ioa->res_size]; \ + u##size *mask_ptr = (u##size *)&mask; \ + CCIO_SEARCH_LOOP(ioc, res_idx, mask_ptr, size); \ + res_ptr = (u##size *)&(ioc)->res_map[0]; \ + CCIO_SEARCH_LOOP(ioa, res_idx, mask_ptr, size); + +/* +** Find available bit in this ioa's resource map. +** Use a "circular" search: +** o Most IOVA's are "temporary" - avg search time should be small. +** o keep a history of what happened for debugging +** o KISS. +** +** Perf optimizations: +** o search for log2(size) bits at a time. +** o search for available resource bits using byte/word/whatever. +** o use different search for "large" (eg > 4 pages) or "very large" +** (eg > 16 pages) mappings. +*/ + +/** + * ccio_alloc_range - Allocate pages in the ioc's resource map. + * @ioc: The I/O Controller. + * @pages_needed: The requested number of pages to be mapped into the + * I/O Pdir... + * + * This function searches the resource map of the ioc to locate a range + * of available pages for the requested size. + */ +static int +ccio_alloc_range(struct ioc *ioc, unsigned long pages_needed) +{ + int res_idx; + unsigned long mask; +#ifdef CONFIG_PROC_FS + unsigned long cr_start = mfctl(16); +#endif + + ASSERT(pages_needed); + ASSERT((pages_needed * IOVP_SIZE) <= DMA_CHUNK_SIZE); + ASSERT(pages_needed <= BITS_PER_LONG); + + mask = ~(~0UL >> pages_needed); + + DBG_RES("%s() size: %d pages_needed %d mask 0x%08lx\n", + __FUNCTION__, size, pages_needed, mask); + + /* + ** "seek and ye shall find"...praying never hurts either... + ** ggg sacrifices another 710 to the computer gods. + */ + + if(pages_needed <= 8) { + CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 8); + } else if(pages_needed <= 16) { + CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 16); + } else if(pages_needed <= 32) { + CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 32); +#ifdef __LP64__ + } else if(pages_needed <= 64) { + CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 64); +#endif + } else { + panic(__FILE__ ": %s() Too many pages to map. pages_needed: %ld\n", + __FUNCTION__, pages_needed); + } + + panic(__FILE__ ": %s() I/O MMU is out of mapping resources.\n", + __FUNCTION__); + +resource_found: + + DBG_RES("%s() res_idx %d mask 0x%08lx res_hint: %d\n", + __FUNCTION__, res_idx, mask, ioc->res_hint); + +#ifdef CONFIG_PROC_FS + { + unsigned long cr_end = mfctl(16); + unsigned long tmp = cr_end - cr_start; + /* check for roll over */ + cr_start = (cr_end < cr_start) ? -(tmp) : (tmp); + } + ioc->avg_search[ioc->avg_idx++] = cr_start; + ioc->avg_idx &= CCIO_SEARCH_SAMPLE - 1; + + ioc->used_pages += pages_needed; +#endif + + /* + ** return the bit address. + */ + return res_idx << 3; +} + +#define CCIO_FREE_MAPPINGS(ioc, res_idx, mask, size) \ + u##size *res_ptr = (u##size *)&((ioc)->res_map[res_idx]); \ + u##size *mask_ptr = (u##size *)&mask; \ + ASSERT((*res_ptr & *mask_ptr) == *mask_ptr); \ + *res_ptr &= ~(*mask_ptr); + +/** + * ccio_free_range - Free pages from the ioc's resource map. + * @ioc: The I/O Controller. + * @iova: The I/O Virtual Address. + * @pages_mapped: The requested number of pages to be freed from the + * I/O Pdir. + * + * This function frees the resouces allocated for the iova. + */ +static void +ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped) +{ + unsigned long mask; + unsigned long iovp = CCIO_IOVP(iova); + unsigned int res_idx = PDIR_INDEX(iovp) >> 3; + + ASSERT(pages_mapped); + ASSERT((pages_mapped * IOVP_SIZE) <= DMA_CHUNK_SIZE); + ASSERT(pages_mapped <= BITS_PER_LONG); + + mask = ~(~0UL >> pages_mapped); + + DBG_RES("%s(): res_idx: %d pages_mapped %d mask 0x%08lx\n", + __FUNCTION__, res_idx, pages_mapped, mask); + +#ifdef CONFIG_PROC_FS + ioc->used_pages -= pages_mapped; +#endif + + if(pages_mapped <= 8) { + CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 8); + } else if(pages_mapped <= 16) { + CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 16); + } else if(pages_mapped <= 32) { + CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 32); +#ifdef __LP64__ + } else if(pages_mapped <= 64) { + CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 64); +#endif + } else { + panic(__FILE__ ":%s() Too many pages to unmap.\n", + __FUNCTION__); + } +} + +/**************************************************************** +** +** CCIO dma_ops support routines +** +*****************************************************************/ + +typedef unsigned long space_t; +#define KERNEL_SPACE 0 + +/* +** DMA "Page Type" and Hints +** o if SAFE_DMA isn't set, mapping is for FAST_DMA. SAFE_DMA should be +** set for subcacheline DMA transfers since we don't want to damage the +** other part of a cacheline. +** o SAFE_DMA must be set for "memory" allocated via pci_alloc_consistent(). +** This bit tells U2 to do R/M/W for partial cachelines. "Streaming" +** data can avoid this if the mapping covers full cache lines. +** o STOP_MOST is needed for atomicity across cachelines. +** Apperently only "some EISA devices" need this. +** Using CONFIG_ISA is hack. Only the IOA with EISA under it needs +** to use this hint iff the EISA devices needs this feature. +** According to the U2 ERS, STOP_MOST enabled pages hurt performance. +** o PREFETCH should *not* be set for cases like Multiple PCI devices +** behind GSCtoPCI (dino) bus converter. Only one cacheline per GSC +** device can be fetched and multiply DMA streams will thrash the +** prefetch buffer and burn memory bandwidth. See 6.7.3 "Prefetch Rules +** and Invalidation of Prefetch Entries". +** +** FIXME: the default hints need to be per GSC device - not global. +** +** HP-UX dorks: linux device driver programming model is totally different +** than HP-UX's. HP-UX always sets HINT_PREFETCH since it's drivers +** do special things to work on non-coherent platforms...linux has to +** be much more careful with this. +*/ +#define IOPDIR_VALID 0x01UL +#define HINT_SAFE_DMA 0x02UL /* used for pci_alloc_consistent() pages */ +#ifdef CONFIG_ISA /* EISA support really */ +#define HINT_STOP_MOST 0x04UL /* LSL support */ +#else +#define HINT_STOP_MOST 0x00UL /* only needed for "some EISA devices" */ +#endif +#define HINT_UDPATE_ENB 0x08UL /* not used/supported by U2 */ +#define HINT_PREFETCH 0x10UL /* for outbound pages which are not SAFE */ + + +/* +** Use direction (ie PCI_DMA_TODEVICE) to pick hint. +** ccio_alloc_consistent() depends on this to get SAFE_DMA +** when it passes in BIDIRECTIONAL flag. +*/ +static u32 hint_lookup[] = { + [PCI_DMA_BIDIRECTIONAL] HINT_STOP_MOST | HINT_SAFE_DMA | IOPDIR_VALID, + [PCI_DMA_TODEVICE] HINT_STOP_MOST | HINT_PREFETCH | IOPDIR_VALID, + [PCI_DMA_FROMDEVICE] HINT_STOP_MOST | IOPDIR_VALID, + [PCI_DMA_NONE] 0, /* not valid */ +}; + +/** + * ccio_io_pdir_entry - Initialize an I/O Pdir. + * @pdir_ptr: A pointer into I/O Pdir. + * @sid: The Space Identifier. + * @vba: The virtual address. + * @hints: The DMA Hint. + * + * Given a virtual address (vba, arg2) and space id, (sid, arg1), + * load the I/O PDIR entry pointed to by pdir_ptr (arg0). Each IO Pdir + * entry consists of 8 bytes as shown below (MSB == bit 0): + * + * + * WORD 0: + * +------+----------------+-----------------------------------------------+ + * | Phys | Virtual Index | Phys | + * | 0:3 | 0:11 | 4:19 | + * |4 bits| 12 bits | 16 bits | + * +------+----------------+-----------------------------------------------+ + * WORD 1: + * +-----------------------+-----------------------------------------------+ + * | Phys | Rsvd | Prefetch |Update |Rsvd |Lock |Safe |Valid | + * | 20:39 | | Enable |Enable | |Enable|DMA | | + * | 20 bits | 5 bits | 1 bit |1 bit |2 bits|1 bit |1 bit |1 bit | + * +-----------------------+-----------------------------------------------+ + * + * The virtual index field is filled with the results of the LCI + * (Load Coherence Index) instruction. The 8 bits used for the virtual + * index are bits 12:19 of the value returned by LCI. + */ +void CCIO_INLINE +ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, void * vba, unsigned long hints) +{ + register unsigned long pa = (volatile unsigned long) vba; + register unsigned long ci; /* coherent index */ + + /* We currently only support kernel addresses */ + ASSERT(sid == KERNEL_SPACE); + + mtsp(sid,1); + + /* + ** WORD 1 - low order word + ** "hints" parm includes the VALID bit! + ** "dep" clobbers the physical address offset bits as well. + */ + pa = virt_to_phys(vba); + asm volatile("depw %1,31,12,%0" : "+r" (pa) : "r" (hints)); + ((u32 *)pdir_ptr)[1] = (u32) pa; + + /* + ** WORD 0 - high order word + */ + +#ifdef __LP64__ + /* + ** get bits 12:15 of physical address + ** shift bits 16:31 of physical address + ** and deposit them + */ + asm volatile ("extrd,u %1,15,4,%0" : "=r" (ci) : "r" (pa)); + asm volatile ("extrd,u %1,31,16,%0" : "+r" (pa) : "r" (pa)); + asm volatile ("depd %1,35,4,%0" : "+r" (pa) : "r" (ci)); +#else + pa = 0; +#endif + /* + ** get CPU coherency index bits + ** Grab virtual index [0:11] + ** Deposit virt_idx bits into I/O PDIR word + */ + asm volatile ("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba)); + asm volatile ("extru %1,19,12,%0" : "+r" (ci) : "r" (ci)); + asm volatile ("depw %1,15,12,%0" : "+r" (pa) : "r" (ci)); + + ((u32 *)pdir_ptr)[0] = (u32) pa; + + + /* FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360) + ** PCX-U/U+ do. (eg C200/C240) + ** PCX-T'? Don't know. (eg C110 or similar K-class) + ** + ** See PDC_MODEL/option 0/SW_CAP word for "Non-coherent IO-PDIR bit". + ** Hopefully we can patch (NOP) these out at boot time somehow. + ** + ** "Since PCX-U employs an offset hash that is incompatible with + ** the real mode coherence index generation of U2, the PDIR entry + ** must be flushed to memory to retain coherence." + */ + asm volatile("fdc 0(%0)" : : "r" (pdir_ptr)); + asm volatile("sync"); +} + +/** + * ccio_clear_io_tlb - Remove stale entries from the I/O TLB. + * @ioc: The I/O Controller. + * @iovp: The I/O Virtual Page. + * @byte_cnt: The requested number of bytes to be freed from the I/O Pdir. + * + * Purge invalid I/O PDIR entries from the I/O TLB. + * + * FIXME: Can we change the byte_cnt to pages_mapped? + */ +static CCIO_INLINE void +ccio_clear_io_tlb(struct ioc *ioc, dma_addr_t iovp, size_t byte_cnt) +{ + u32 chain_size = 1 << ioc->chainid_shift; + + iovp &= IOVP_MASK; /* clear offset bits, just want pagenum */ + byte_cnt += chain_size; + + while(byte_cnt > chain_size) { + WRITE_U32(CMD_TLB_PURGE | iovp, &ioc->ioc_hpa->io_command); + iovp += chain_size; + byte_cnt -= chain_size; + } +} + +/** + * ccio_mark_invalid - Mark the I/O Pdir entries invalid. + * @ioc: The I/O Controller. + * @iova: The I/O Virtual Address. + * @byte_cnt: The requested number of bytes to be freed from the I/O Pdir. + * + * Mark the I/O Pdir entries invalid and blow away the corresponding I/O + * TLB entries. + * + * FIXME: at some threshhold it might be "cheaper" to just blow + * away the entire I/O TLB instead of individual entries. + * + * FIXME: Uturn has 256 TLB entries. We don't need to purge every + * PDIR entry - just once for each possible TLB entry. + * (We do need to maker I/O PDIR entries invalid regardless). + * + * FIXME: Can we change byte_cnt to pages_mapped? + */ +static CCIO_INLINE void +ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) +{ + u32 iovp = (u32)CCIO_IOVP(iova); + size_t saved_byte_cnt; + + /* round up to nearest page size */ + saved_byte_cnt = byte_cnt = ROUNDUP(byte_cnt, IOVP_SIZE); + + while(byte_cnt > 0) { + /* invalidate one page at a time */ + unsigned int idx = PDIR_INDEX(iovp); + char *pdir_ptr = (char *) &(ioc->pdir_base[idx]); + + ASSERT(idx < (ioc->pdir_size / sizeof(u64))); + pdir_ptr[7] = 0; /* clear only VALID bit */ + /* + ** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360) + ** PCX-U/U+ do. (eg C200/C240) + ** See PDC_MODEL/option 0/SW_CAP for "Non-coherent IO-PDIR bit". + ** + ** Hopefully someone figures out how to patch (NOP) the + ** FDC/SYNC out at boot time. + */ + asm volatile("fdc 0(%0)" : : "r" (pdir_ptr[7])); + + iovp += IOVP_SIZE; + byte_cnt -= IOVP_SIZE; + } + + asm volatile("sync"); + ccio_clear_io_tlb(ioc, CCIO_IOVP(iova), saved_byte_cnt); +} + +/**************************************************************** +** +** CCIO dma_ops +** +*****************************************************************/ + +/** + * ccio_dma_supported - Verify the IOMMU supports the DMA address range. + * @dev: The PCI device. + * @mask: A bit mask describing the DMA address range of the device. + * + * This function implements the pci_dma_supported function. + */ +static int +ccio_dma_supported(struct pci_dev *dev, u64 mask) +{ + if(dev == NULL) { + printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n"); + BUG(); + return 0; + } + + dev->dma_mask = mask; /* save it */ + + /* only support 32-bit devices (ie PCI/GSC) */ + return (int)(mask == 0xffffffffUL); +} + +/** + * ccio_map_single - Map an address range into the IOMMU. + * @dev: The PCI device. + * @addr: The start address of the DMA region. + * @size: The length of the DMA region. + * @direction: The direction of the DMA transaction (to/from device). + * + * This function implements the pci_map_single function. + */ +static dma_addr_t +ccio_map_single(struct pci_dev *dev, void *addr, size_t size, int direction) +{ + int idx; + struct ioc *ioc; + unsigned long flags; + dma_addr_t iovp; + dma_addr_t offset; + u64 *pdir_start; + unsigned long hint = hint_lookup[direction]; + + ASSERT(dev); + ASSERT(dev->sysdata); + ASSERT(HBA_DATA(dev->sysdata)->iommu); + ioc = GET_IOC(dev); + + ASSERT(size > 0); + + /* save offset bits */ + offset = ((unsigned long) addr) & ~IOVP_MASK; + + /* round up to nearest IOVP_SIZE */ + size = ROUNDUP(size + offset, IOVP_SIZE); + spin_lock_irqsave(&ioc->res_lock, flags); + +#ifdef CONFIG_PROC_FS + ioc->msingle_calls++; + ioc->msingle_pages += size >> IOVP_SHIFT; +#endif + + idx = ccio_alloc_range(ioc, (size >> IOVP_SHIFT)); + iovp = (dma_addr_t)MKIOVP(idx); + + pdir_start = &(ioc->pdir_base[idx]); + + DBG_RUN("%s() 0x%p -> 0x%lx size: %0x%x\n", + __FUNCTION__, addr, (long)iovp | offset, size); + + /* If not cacheline aligned, force SAFE_DMA on the whole mess */ + if((size % L1_CACHE_BYTES) || ((unsigned long)addr % L1_CACHE_BYTES)) + hint |= HINT_SAFE_DMA; + + while(size > 0) { + ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, addr, hint); + + DBG_RUN(" pdir %p %08x%08x\n", + pdir_start, + (u32) (((u32 *) pdir_start)[0]), + (u32) (((u32 *) pdir_start)[1])); + ++pdir_start; + addr += IOVP_SIZE; + size -= IOVP_SIZE; + } + + spin_unlock_irqrestore(&ioc->res_lock, flags); + + /* form complete address */ + return CCIO_IOVA(iovp, offset); +} + +/** + * ccio_unmap_single - Unmap an address range from the IOMMU. + * @dev: The PCI device. + * @addr: The start address of the DMA region. + * @size: The length of the DMA region. + * @direction: The direction of the DMA transaction (to/from device). + * + * This function implements the pci_unmap_single function. + */ +static void +ccio_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, + int direction) +{ + struct ioc *ioc; + unsigned long flags; + dma_addr_t offset = iova & ~IOVP_MASK; + + ASSERT(dev); + ASSERT(dev->sysdata); + ASSERT(HBA_DATA(dev->sysdata)->iommu); + ioc = GET_IOC(dev); + + DBG_RUN("%s() iovp 0x%lx/%x\n", + __FUNCTION__, (long)iova, size); + + iova ^= offset; /* clear offset bits */ + size += offset; + size = ROUNDUP(size, IOVP_SIZE); + + spin_lock_irqsave(&ioc->res_lock, flags); + +#ifdef CONFIG_PROC_FS + ioc->usingle_calls++; + ioc->usingle_pages += size >> IOVP_SHIFT; +#endif + + ccio_mark_invalid(ioc, iova, size); + ccio_free_range(ioc, iova, (size >> IOVP_SHIFT)); + spin_unlock_irqrestore(&ioc->res_lock, flags); +} + +/** + * ccio_alloc_consistent - Allocate a consistent DMA mapping. + * @dev: The PCI device. + * @size: The length of the DMA region. + * @dma_handle: The DMA address handed back to the device (not the cpu). + * + * This function implements the pci_alloc_consistent function. + */ +static void * +ccio_alloc_consistent(struct pci_dev *dev, size_t size, dma_addr_t *dma_handle) +{ + void *ret; +#if 0 +/* GRANT Need to establish hierarchy for non-PCI devs as well +** and then provide matching gsc_map_xxx() functions for them as well. +*/ + if(!hwdev) { + /* only support PCI */ + *dma_handle = 0; + return 0; + } +#endif + ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size)); + + if (ret) { + memset(ret, 0, size); + *dma_handle = ccio_map_single(dev, ret, size, PCI_DMA_BIDIRECTIONAL); + } + + return ret; +} + +/** + * ccio_free_consistent - Free a consistent DMA mapping. + * @dev: The PCI device. + * @size: The length of the DMA region. + * @cpu_addr: The cpu address returned from the ccio_alloc_consistent. + * @dma_handle: The device address returned from the ccio_alloc_consistent. + * + * This function implements the pci_free_consistent function. + */ +static void +ccio_free_consistent(struct pci_dev *dev, size_t size, void *cpu_addr, + dma_addr_t dma_handle) +{ + ccio_unmap_single(dev, dma_handle, size, 0); + free_pages((unsigned long)cpu_addr, get_order(size)); +} + +/* +** Since 0 is a valid pdir_base index value, can't use that +** to determine if a value is valid or not. Use a flag to indicate +** the SG list entry contains a valid pdir index. +*/ +#define PIDE_FLAG 0x80000000UL + +/** + * ccio_fill_pdir - Insert coalesced scatter/gather chunks into the I/O Pdir. + * @ioc: The I/O Controller. + * @startsg: The scatter/gather list of coalesced chunks. + * @nents: The number of entries in the scatter/gather list. + * @hint: The DMA Hint. + * + * This function inserts the coalesced scatter/gather list chunks into the + * I/O Controller's I/O Pdir. + */ +static CCIO_INLINE int +ccio_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents, + unsigned long hint) +{ + struct scatterlist *dma_sg = startsg; /* pointer to current DMA */ + int n_mappings = 0; + u64 *pdirp = 0; + unsigned long dma_offset = 0; + + dma_sg--; + while (nents-- > 0) { + int cnt = sg_dma_len(startsg); + sg_dma_len(startsg) = 0; + + DBG_RUN_SG(" %d : %08lx/%05x %08lx/%05x\n", nents, + (unsigned long)sg_dma_address(startsg), cnt, + sg_virt_addr(startsg), startsg->length + ); + + /* + ** Look for the start of a new DMA stream + */ + if(sg_dma_address(startsg) & PIDE_FLAG) { + u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG; + dma_offset = (unsigned long) pide & ~IOVP_MASK; + sg_dma_address(startsg) = 0; + dma_sg++; + sg_dma_address(dma_sg) = pide; + pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]); + n_mappings++; + } + + /* + ** Look for a VCONTIG chunk + */ + if (cnt) { + unsigned long vaddr = sg_virt_addr(startsg); + ASSERT(pdirp); + + /* Since multiple Vcontig blocks could make up + ** one DMA stream, *add* cnt to dma_len. + */ + sg_dma_len(dma_sg) += cnt; + cnt += dma_offset; + dma_offset=0; /* only want offset on first chunk */ + cnt = ROUNDUP(cnt, IOVP_SIZE); +#ifdef CONFIG_PROC_FS + ioc->msg_pages += cnt >> IOVP_SHIFT; +#endif + do { + ccio_io_pdir_entry(pdirp, KERNEL_SPACE, + (void *)vaddr, hint); + vaddr += IOVP_SIZE; + cnt -= IOVP_SIZE; + pdirp++; + } while (cnt > 0); + } + startsg++; + } + return(n_mappings); +} + +/* +** First pass is to walk the SG list and determine where the breaks are +** in the DMA stream. Allocates PDIR entries but does not fill them. +** Returns the number of DMA chunks. +** +** Doing the fill seperate from the coalescing/allocation keeps the +** code simpler. Future enhancement could make one pass through +** the sglist do both. +*/ + +static CCIO_INLINE int +ccio_coalesce_chunks(struct ioc *ioc, struct scatterlist *startsg, int nents) +{ + struct scatterlist *vcontig_sg; /* VCONTIG chunk head */ + unsigned long vcontig_len; /* len of VCONTIG chunk */ + unsigned long vcontig_end; + struct scatterlist *dma_sg; /* next DMA stream head */ + unsigned long dma_offset, dma_len; /* start/len of DMA stream */ + int n_mappings = 0; + + while (nents > 0) { + + /* + ** Prepare for first/next DMA stream + */ + dma_sg = vcontig_sg = startsg; + dma_len = vcontig_len = vcontig_end = startsg->length; + vcontig_end += sg_virt_addr(startsg); + dma_offset = sg_virt_addr(startsg) & ~IOVP_MASK; + + /* PARANOID: clear entries */ + sg_dma_address(startsg) = 0; + sg_dma_len(startsg) = 0; + + /* + ** This loop terminates one iteration "early" since + ** it's always looking one "ahead". + */ + while(--nents > 0) { + unsigned long startsg_end; + + startsg++; + startsg_end = sg_virt_addr(startsg) + + startsg->length; + + /* PARANOID: clear entries */ + sg_dma_address(startsg) = 0; + sg_dma_len(startsg) = 0; + + /* + ** First make sure current dma stream won't + ** exceed DMA_CHUNK_SIZE if we coalesce the + ** next entry. + */ + if(ROUNDUP(dma_len + dma_offset + startsg->length, + IOVP_SIZE) > DMA_CHUNK_SIZE) + break; + + /* + ** Append the next transaction? + */ + if (vcontig_end == sg_virt_addr(startsg)) { + vcontig_len += startsg->length; + vcontig_end += startsg->length; + dma_len += startsg->length; + continue; + } + + /* + ** Not virtually contigous. + ** Terminate prev chunk. + ** Start a new chunk. + ** + ** Once we start a new VCONTIG chunk, dma_offset + ** can't change. And we need the offset from the first + ** chunk - not the last one. Ergo Successive chunks + ** must start on page boundaries and dove tail + ** with it's predecessor. + */ + sg_dma_len(vcontig_sg) = vcontig_len; + + vcontig_sg = startsg; + vcontig_len = startsg->length; + break; + } + + /* + ** End of DMA Stream + ** Terminate last VCONTIG block. + ** Allocate space for DMA stream. + */ + sg_dma_len(vcontig_sg) = vcontig_len; + dma_len = ROUNDUP(dma_len + dma_offset, IOVP_SIZE); + sg_dma_address(dma_sg) = + PIDE_FLAG + | (ccio_alloc_range(ioc, (dma_len >> IOVP_SHIFT)) << IOVP_SHIFT) + | dma_offset; + n_mappings++; + } + + return n_mappings; +} + +/** + * ccio_map_sg - Map the scatter/gather list into the IOMMU. + * @dev: The PCI device. + * @sglist: The scatter/gather list to be mapped in the IOMMU. + * @nents: The number of entries in the scatter/gather list. + * @direction: The direction of the DMA transaction (to/from device). + * + * This function implements the pci_map_sg function. + */ +static int +ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, + int direction) +{ + struct ioc *ioc; + int coalesced, filled = 0; + unsigned long flags; + unsigned long hint = hint_lookup[direction]; + + ASSERT(dev); + ASSERT(dev->sysdata); + ASSERT(HBA_DATA(dev->sysdata)->iommu); + ioc = GET_IOC(dev); + + DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents); + + /* Fast path single entry scatterlists. */ + if (nents == 1) { + sg_dma_address(sglist) = ccio_map_single(dev, + (void *)sg_virt_addr(sglist), sglist->length, + direction); + sg_dma_len(sglist) = sglist->length; + return 1; + } + + spin_lock_irqsave(&ioc->res_lock, flags); + +#ifdef CONFIG_PROC_FS + ioc->msg_calls++; +#endif + + /* + ** First coalesce the chunks and allocate I/O pdir space + ** + ** If this is one DMA stream, we can properly map using the + ** correct virtual address associated with each DMA page. + ** w/o this association, we wouldn't have coherent DMA! + ** Access to the virtual address is what forces a two pass algorithm. + */ + coalesced = ccio_coalesce_chunks(ioc, sglist, nents); + + /* + ** Program the I/O Pdir + ** + ** map the virtual addresses to the I/O Pdir + ** o dma_address will contain the pdir index + ** o dma_len will contain the number of bytes to map + ** o page/offset contain the virtual address. + */ + filled = ccio_fill_pdir(ioc, sglist, nents, hint); + + spin_unlock_irqrestore(&ioc->res_lock, flags); + + ASSERT(coalesced == filled); + DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled); + + return filled; +} + +/** + * ccio_unmap_sg - Unmap the scatter/gather list from the IOMMU. + * @dev: The PCI device. + * @sglist: The scatter/gather list to be unmapped from the IOMMU. + * @nents: The number of entries in the scatter/gather list. + * @direction: The direction of the DMA transaction (to/from device). + * + * This function implements the pci_unmap_sg function. + */ +static void +ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, + int direction) +{ + struct ioc *ioc; + + ASSERT(dev); + ASSERT(dev->sysdata); + ASSERT(HBA_DATA(dev->sysdata)->iommu); + ioc = GET_IOC(dev); + + DBG_RUN_SG("%s() START %d entries, %08lx,%x\n", + __FUNCTION__, nents, sg_virt_addr(sglist), sglist->length); + +#ifdef CONFIG_PROC_FS + ioc->usg_calls++; +#endif + + while(sg_dma_len(sglist) && nents--) { + +#ifdef CONFIG_PROC_FS + ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT; +#endif + ccio_unmap_single(dev, sg_dma_address(sglist), + sg_dma_len(sglist), direction); + ++sglist; + } + + DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__, nents); +} + +static struct pci_dma_ops ccio_ops = { + ccio_dma_supported, + ccio_alloc_consistent, + ccio_free_consistent, + ccio_map_single, + ccio_unmap_single, + ccio_map_sg, + ccio_unmap_sg, + NULL, /* dma_sync_single : NOP for U2/Uturn */ + NULL, /* dma_sync_sg : ditto */ +}; + +#ifdef CONFIG_PROC_FS +static int proc_append(char *src, int len, char **dst, off_t *offset, int *max) +{ + if (len < *offset) { + *offset -= len; + return 0; + } + if (*offset > 0) { + src += *offset; + len -= *offset; + *offset = 0; + } + if (len > *max) { + len = *max; + } + memcpy(*dst, src, len); + *dst += len; + *max -= len; + return (*max == 0); +} + +static int ccio_proc_info(char *buf, char **start, off_t offset, int count, + int *eof, void *data) +{ + int max = count; + char tmp[80]; /* width of an ANSI-standard terminal */ + struct ioc *ioc = ioc_list; + + while (ioc != NULL) { + unsigned int total_pages = ioc->res_size << 3; + unsigned long avg = 0, min, max; + int j, len; + + len = sprintf(tmp, "%s\n", ioc->name); + if (proc_append(tmp, len, &buf, &offset, &count)) + break; + + len = sprintf(tmp, "Cujo 2.0 bug : %s\n", + (ioc->cujo20_bug ? "yes" : "no")); + if (proc_append(tmp, len, &buf, &offset, &count)) + break; + + len = sprintf(tmp, "IO PDIR size : %d bytes (%d entries)\n", + total_pages * 8, total_pages); + if (proc_append(tmp, len, &buf, &offset, &count)) + break; + + len = sprintf(tmp, "IO PDIR entries : %ld free %ld used (%d%%)\n", + total_pages - ioc->used_pages, ioc->used_pages, + (int)(ioc->used_pages * 100 / total_pages)); + if (proc_append(tmp, len, &buf, &offset, &count)) + break; + + len = sprintf(tmp, "Resource bitmap : %d bytes (%d pages)\n", + ioc->res_size, total_pages); + if (proc_append(tmp, len, &buf, &offset, &count)) + break; + + min = max = ioc->avg_search[0]; + for(j = 0; j < CCIO_SEARCH_SAMPLE; ++j) { + avg += ioc->avg_search[j]; + if(ioc->avg_search[j] > max) + max = ioc->avg_search[j]; + if(ioc->avg_search[j] < min) + min = ioc->avg_search[j]; + } + avg /= CCIO_SEARCH_SAMPLE; + len = sprintf(tmp, " Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n", + min, avg, max); + if (proc_append(tmp, len, &buf, &offset, &count)) + break; + + len = sprintf(tmp, "pci_map_single(): %8ld calls %8ld pages (avg %d/1000)\n", + ioc->msingle_calls, ioc->msingle_pages, + (int)((ioc->msingle_pages * 1000)/ioc->msingle_calls)); + if (proc_append(tmp, len, &buf, &offset, &count)) + break; + + + /* KLUGE - unmap_sg calls unmap_single for each mapped page */ + min = ioc->usingle_calls - ioc->usg_calls; + max = ioc->usingle_pages - ioc->usg_pages; + len = sprintf(tmp, "pci_unmap_single: %8ld calls %8ld pages (avg %d/1000)\n", + min, max, (int)((max * 1000)/min)); + if (proc_append(tmp, len, &buf, &offset, &count)) + break; + + len = sprintf(tmp, "pci_map_sg() : %8ld calls %8ld pages (avg %d/1000)\n", + ioc->msg_calls, ioc->msg_pages, + (int)((ioc->msg_pages * 1000)/ioc->msg_calls)); + if (proc_append(tmp, len, &buf, &offset, &count)) + break; + len = sprintf(tmp, "pci_unmap_sg() : %8ld calls %8ld pages (avg %d/1000)\n\n\n", + ioc->usg_calls, ioc->usg_pages, + (int)((ioc->usg_pages * 1000)/ioc->usg_calls)); + if (proc_append(tmp, len, &buf, &offset, &count)) + break; + + ioc = ioc->next; + } + + if (count == 0) { + *eof = 1; + } + return (max - count); +} + +static int ccio_resource_map(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + struct ioc *ioc = ioc_list; + + buf[0] = '\0'; + while (ioc != NULL) { + u32 *res_ptr = (u32 *)ioc->res_map; + int j; + + for (j = 0; j < (ioc->res_size / sizeof(u32)); j++) { + if ((j & 7) == 0) + strcat(buf,"\n "); + sprintf(buf, "%s %08x", buf, *res_ptr); + res_ptr++; + } + strcat(buf, "\n\n"); + ioc = ioc->next; + break; /* XXX - remove me */ + } + + return strlen(buf); +} +#endif + +/** + * ccio_find_ioc - Find the ioc in the ioc_list + * @hw_path: The hardware path of the ioc. + * + * This function searches the ioc_list for an ioc that matches + * the provide hardware path. + */ +static struct ioc * ccio_find_ioc(int hw_path) +{ + int i; + struct ioc *ioc; + + ioc = ioc_list; + for (i = 0; i < ioc_count; i++) { + if (ioc->hw_path == hw_path) + return ioc; + + ioc = ioc->next; + } + + return NULL; +} + +/** + * ccio_get_iommu - Find the iommu which controls this device + * @dev: The parisc device. + * + * This function searches through the registerd IOMMU's and returns the + * appropriate IOMMU for the device based upon the devices hardware path. + */ +void * ccio_get_iommu(const struct parisc_device *dev) +{ + dev = find_pa_parent_type(dev, HPHW_IOA); + if (!dev) + return NULL; + + return ccio_find_ioc(dev->hw_path); +} + +#define CUJO_20_STEP 0x10000000 /* inc upper nibble */ + +/* Cujo 2.0 has a bug which will silently corrupt data being transferred + * to/from certain pages. To avoid this happening, we mark these pages + * as `used', and ensure that nothing will try to allocate from them. + */ +void ccio_cujo20_fixup(struct parisc_device *dev, u32 iovp) +{ + unsigned int idx; + struct ioc *ioc = ccio_get_iommu(dev); + u8 *res_ptr; + +#ifdef CONFIG_PROC_FS + ioc->cujo20_bug = 1; +#endif + res_ptr = ioc->res_map; + idx = PDIR_INDEX(iovp) >> 3; + + while (idx < ioc->res_size) { + res_ptr[idx] |= 0xff; + idx += PDIR_INDEX(CUJO_20_STEP) >> 3; + } +} + +#if 0 +/* GRANT - is this needed for U2 or not? */ + +/* +** Get the size of the I/O TLB for this I/O MMU. +** +** If spa_shift is non-zero (ie probably U2), +** then calculate the I/O TLB size using spa_shift. +** +** Otherwise we are supposed to get the IODC entry point ENTRY TLB +** and execute it. However, both U2 and Uturn firmware supplies spa_shift. +** I think only Java (K/D/R-class too?) systems don't do this. +*/ +static int +ccio_get_iotlb_size(struct parisc_device *dev) +{ + if (dev->spa_shift == 0) { + panic("%s() : Can't determine I/O TLB size.\n", __FUNCTION__); + } + return (1 << dev->spa_shift); +} +#else + +/* Uturn supports 256 TLB entries */ +#define CCIO_CHAINID_SHIFT 8 +#define CCIO_CHAINID_MASK 0xff +#endif /* 0 */ + +/** + * ccio_ioc_init - Initalize the I/O Controller + * @ioc: The I/O Controller. + * + * Initalize the I/O Controller which includes setting up the + * I/O Page Directory, the resource map, and initalizing the + * U2/Uturn chip into virtual mode. + */ +static void +ccio_ioc_init(struct ioc *ioc) +{ + int i, iov_order; + u32 iova_space_size; + unsigned long physmem; + + /* + ** Determine IOVA Space size from memory size. + ** + ** Ideally, PCI drivers would register the maximum number + ** of DMA they can have outstanding for each device they + ** own. Next best thing would be to guess how much DMA + ** can be outstanding based on PCI Class/sub-class. Both + ** methods still require some "extra" to support PCI + ** Hot-Plug/Removal of PCI cards. (aka PCI OLARD). + */ + + /* limit IOVA space size to 1MB-1GB */ + + physmem = num_physpages << PAGE_SHIFT; + if(physmem < (ccio_mem_ratio * 1024 * 1024)) { + iova_space_size = 1024 * 1024; +#ifdef __LP64__ + } else if(physmem > (ccio_mem_ratio * 512 * 1024 * 1024)) { + iova_space_size = 512 * 1024 * 1024; +#endif + } else { + iova_space_size = (u32)(physmem / ccio_mem_ratio); + } + + /* + ** iova space must be log2() in size. + ** thus, pdir/res_map will also be log2(). + */ + + /* We could use larger page sizes in order to *decrease* the number + ** of mappings needed. (ie 8k pages means 1/2 the mappings). + ** + ** Note: Grant Grunder says "Using 8k I/O pages isn't trivial either + ** since the pages must also be physically contiguous - typically + ** this is the case under linux." + */ + + iov_order = get_order(iova_space_size) >> (IOVP_SHIFT - PAGE_SHIFT); + ASSERT(iov_order <= (30 - IOVP_SHIFT)); /* iova_space_size <= 1GB */ + ASSERT(iov_order >= (20 - IOVP_SHIFT)); /* iova_space_size >= 1MB */ + iova_space_size = 1 << (iov_order + IOVP_SHIFT); + + ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64); + + ASSERT(ioc->pdir_size < 4 * 1024 * 1024); /* max pdir size < 4MB */ + + /* Verify it's a power of two */ + ASSERT((1 << get_order(ioc->pdir_size)) == (ioc->pdir_size >> PAGE_SHIFT)); + + DBG_INIT("%s() hpa 0x%p mem %luMB IOV %dMB (%d bits) PDIR size 0x%0x", + __FUNCTION__, ioc->ioc_hpa, physmem>>20, iova_space_size>>20, + iov_order + PAGE_SHIFT, ioc->pdir_size); + + ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL, + get_order(ioc->pdir_size)); + if(NULL == ioc->pdir_base) { + panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__); + } + memset(ioc->pdir_base, 0, ioc->pdir_size); + + ASSERT((((unsigned long)ioc->pdir_base) & PAGE_MASK) == (unsigned long)ioc->pdir_base); + DBG_INIT(" base %p", ioc->pdir_base); + + /* resource map size dictated by pdir_size */ + ioc->res_size = (ioc->pdir_size / sizeof(u64)) >> 3; + DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, ioc->res_size); + + ioc->res_map = (u8 *)__get_free_pages(GFP_KERNEL, + get_order(ioc->res_size)); + if(NULL == ioc->res_map) { + panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__); + } + memset(ioc->res_map, 0, ioc->res_size); + + /* Initialize the res_hint to 16 */ + ioc->res_hint = 16; + + /* Initialize the spinlock */ + spin_lock_init(&ioc->res_lock); + + /* + ** Chainid is the upper most bits of an IOVP used to determine + ** which TLB entry an IOVP will use. + */ + ioc->chainid_shift = get_order(iova_space_size) + PAGE_SHIFT - CCIO_CHAINID_SHIFT; + DBG_INIT(" chainid_shift 0x%x\n", ioc->chainid_shift); + + /* + ** Initialize IOA hardware + */ + WRITE_U32(CCIO_CHAINID_MASK << ioc->chainid_shift, + &ioc->ioc_hpa->io_chain_id_mask); + + WRITE_U32(virt_to_phys(ioc->pdir_base), + &ioc->ioc_hpa->io_pdir_base); + + /* + ** Go to "Virtual Mode" + */ + WRITE_U32(IOA_NORMAL_MODE, &ioc->ioc_hpa->io_control); + + /* + ** Initialize all I/O TLB entries to 0 (Valid bit off). + */ + WRITE_U32(0, &ioc->ioc_hpa->io_tlb_entry_m); + WRITE_U32(0, &ioc->ioc_hpa->io_tlb_entry_l); + + for(i = 1 << CCIO_CHAINID_SHIFT; i ; i--) { + WRITE_U32((CMD_TLB_DIRECT_WRITE | (i << ioc->chainid_shift)), + &ioc->ioc_hpa->io_command); + } +} + +static void +ccio_init_resource(struct resource *res, char *name, unsigned long ioaddr) +{ + int result; + + res->flags = IORESOURCE_MEM; + res->start = (unsigned long)(signed) __raw_readl(ioaddr) << 16; + res->end = (unsigned long)(signed) (__raw_readl(ioaddr + 4) << 16) - 1; + if (res->end + 1 == res->start) + return; + res->name = name; + result = request_resource(&iomem_resource, res); + if (result < 0) { + printk(KERN_ERR "%s: failed to claim CCIO bus address space (%08lx,%08lx)\n", + __FILE__, res->start, res->end); + } +} + +static void __init ccio_init_resources(struct ioc *ioc) +{ + struct resource *res = ioc->mmio_region; + char *name = kmalloc(14, GFP_KERNEL); + + sprintf(name, "GSC Bus [%d/]", ioc->hw_path); + + ccio_init_resource(res, name, (unsigned long)&ioc->ioc_hpa->io_io_low); + ccio_init_resource(res + 1, name, + (unsigned long)&ioc->ioc_hpa->io_io_low_hv); +} + +static void expand_ioc_area(struct ioc *ioc, unsigned long size, + unsigned long min, unsigned long max, unsigned long align) +{ +#ifdef NASTY_HACK_FOR_K_CLASS + __raw_writel(0xfffff600, (unsigned long)&(ioc->ioc_hpa->io_io_high)); + ioc->mmio_region[0].end = 0xf5ffffff; +#endif +} + +static struct resource *ccio_get_resource(struct ioc* ioc, + const struct parisc_device *dev) +{ + if (!ioc) { + return &iomem_resource; + } else if ((ioc->mmio_region->start <= dev->hpa) && + (dev->hpa < ioc->mmio_region->end)) { + return ioc->mmio_region; + } else if (((ioc->mmio_region + 1)->start <= dev->hpa) && + (dev->hpa < (ioc->mmio_region + 1)->end)) { + return ioc->mmio_region + 1; + } else { + return NULL; + } +} + +int ccio_allocate_resource(const struct parisc_device *dev, + struct resource *res, unsigned long size, + unsigned long min, unsigned long max, unsigned long align, + void (*alignf)(void *, struct resource *, unsigned long, unsigned long), + void *alignf_data) +{ + struct ioc *ioc = ccio_get_iommu(dev); + struct resource *parent = ccio_get_resource(ioc, dev); + if (!parent) + return -EBUSY; + + if (!allocate_resource(parent, res, size, min, max, align, alignf, + alignf_data)) + return 0; + + expand_ioc_area(ioc, size, min, max, align); + return allocate_resource(parent, res, size, min, max, align, alignf, + alignf_data); +} + +int ccio_request_resource(const struct parisc_device *dev, + struct resource *res) +{ + struct ioc *ioc = ccio_get_iommu(dev); + struct resource *parent = ccio_get_resource(ioc, dev); + + return request_resource(parent, res); +} +/** + * ccio_probe - Determine if ccio should claim this device. + * @dev: The device which has been found + * + * Determine if ccio should claim this chip (return 0) or not (return 1). + * If so, initialize the chip and tell other partners in crime they + * have work to do. + */ +static int ccio_probe(struct parisc_device *dev) +{ + int i; + struct ioc *ioc, **ioc_p = &ioc_list; + + ioc = kmalloc(sizeof(struct ioc), GFP_KERNEL); + if (ioc == NULL) { + printk(KERN_ERR MODULE_NAME ": memory allocation failure\n"); + return 1; + } + memset(ioc, 0, sizeof(struct ioc)); + + ioc->name = dev->id.hversion == U2_IOA_RUNWAY ? "U2" : "UTurn"; + + printk(KERN_INFO "Found %s at 0x%lx\n", ioc->name, dev->hpa); + + for (i = 0; i < ioc_count; i++) { + ioc_p = &(*ioc_p)->next; + } + *ioc_p = ioc; + + ioc->hw_path = dev->hw_path; + ioc->ioc_hpa = (struct ioa_registers *)dev->hpa; + ccio_ioc_init(ioc); + ccio_init_resources(ioc); + hppa_dma_ops = &ccio_ops; + + if (ioc_count == 0) { + /* XXX: Create separate entries for each ioc */ + create_proc_read_entry(MODULE_NAME, S_IRWXU, proc_runway_root, + ccio_proc_info, NULL); + create_proc_read_entry(MODULE_NAME"-bitmap", S_IRWXU, + proc_runway_root, ccio_resource_map, NULL); + } + + ioc_count++; + return 0; +} + +struct pci_dev * ccio_get_fake(const struct parisc_device *dev) +{ + struct ioc *ioc; + + dev = find_pa_parent_type(dev, HPHW_IOA); + if(!dev) + return NULL; + + ioc = ccio_find_ioc(dev->hw_path); + if(!ioc) + return NULL; + + if(ioc->fake_pci_dev) + return ioc->fake_pci_dev; + + ioc->fake_pci_dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL); + if(ioc->fake_pci_dev == NULL) { + printk(KERN_ERR MODULE_NAME ": memory allocation failure\n"); + return NULL; + } + memset(ioc->fake_pci_dev, 0, sizeof(struct pci_dev)); + + ioc->fake_pci_dev->sysdata = kmalloc(sizeof(struct pci_hba_data), GFP_KERNEL); + if(ioc->fake_pci_dev->sysdata == NULL) { + printk(KERN_ERR MODULE_NAME ": memory allocation failure\n"); + return NULL; + } + + HBA_DATA(ioc->fake_pci_dev->sysdata)->iommu = ioc; + return ioc->fake_pci_dev; +} + +/* We *can't* support JAVA (T600). Venture there at your own risk. */ +static struct parisc_device_id ccio_tbl[] = { + { HPHW_IOA, HVERSION_REV_ANY_ID, U2_IOA_RUNWAY, 0xb }, /* U2 */ + { HPHW_IOA, HVERSION_REV_ANY_ID, UTURN_IOA_RUNWAY, 0xb }, /* UTurn */ + { 0, } +}; + +static struct parisc_driver ccio_driver = { + name: "U2/Uturn", + id_table: ccio_tbl, + probe: ccio_probe, +}; + +/** + * ccio_init - ccio initalization procedure. + * + * Register this driver. + */ +void __init ccio_init(void) +{ + register_parisc_driver(&ccio_driver); +} + diff -Nru a/drivers/parisc/ccio-rm-dma.c b/drivers/parisc/ccio-rm-dma.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/ccio-rm-dma.c Mon Nov 4 14:31:01 2002 @@ -0,0 +1,202 @@ +/* + * ccio-rm-dma.c: + * DMA management routines for first generation cache-coherent machines. + * "Real Mode" operation refers to U2/Uturn chip operation. The chip + * can perform coherency checks w/o using the I/O MMU. That's all we + * need until support for more than 4GB phys mem is needed. + * + * This is the trivial case - basically what x86 does. + * + * Drawbacks of using Real Mode are: + * o outbound DMA is slower since one isn't using the prefetching + * U2 can do for outbound DMA. + * o Ability to do scatter/gather in HW is also lost. + * o only known to work with PCX-W processor. (eg C360) + * (PCX-U/U+ are not coherent with U2 in real mode.) + * + * + * 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. + * + * + * Original version/author: + * CVSROOT=:pserver:anonymous@198.186.203.37:/cvsroot/linux-parisc + * cvs -z3 co linux/arch/parisc/kernel/dma-rm.c + * + * (C) Copyright 2000 Philipp Rumpf + * + * + * Adopted for The Puffin Group's parisc-linux port by Grant Grundler. + * (C) Copyright 2000 Grant Grundler + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +/* Only chose "ccio" since that's what HP-UX calls it.... +** Make it easier for folks to migrate from one to the other :^) +*/ +#define MODULE_NAME "ccio" + +#define U2_IOA_RUNWAY 0x580 +#define U2_BC_GSC 0x501 +#define UTURN_IOA_RUNWAY 0x581 +#define UTURN_BC_GSC 0x502 + +#define IS_U2(id) ( \ + (((id)->hw_type == HPHW_IOA) && ((id)->hversion == U2_IOA_RUNWAY)) || \ + (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == U2_BC_GSC)) \ +) + +#define IS_UTURN(id) ( \ + (((id)->hw_type == HPHW_IOA) && ((id)->hversion == UTURN_IOA_RUNWAY)) || \ + (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == UTURN_BC_GSC)) \ +) + +static int ccio_dma_supported( struct pci_dev *dev, u64 mask) +{ + if (dev == NULL) { + printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n"); + BUG(); + return(0); + } + + dev->dma_mask = mask; /* save it */ + + /* only support 32-bit devices (ie PCI/GSC) */ + return((int) (mask >= 0xffffffffUL)); +} + + +static void *ccio_alloc_consistent(struct pci_dev *dev, size_t size, + dma_addr_t *handle) +{ + void *ret; + + ret = (void *)__get_free_pages(GFP_ATOMIC, get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *handle = virt_to_phys(ret); + } + return ret; +} + +static void ccio_free_consistent(struct pci_dev *dev, size_t size, + void *vaddr, dma_addr_t handle) +{ + free_pages((unsigned long)vaddr, get_order(size)); +} + +static dma_addr_t ccio_map_single(struct pci_dev *dev, void *ptr, size_t size, + int direction) +{ + return virt_to_phys(ptr); +} + +static void ccio_unmap_single(struct pci_dev *dev, dma_addr_t dma_addr, + size_t size, int direction) +{ + /* Nothing to do */ +} + + +static int ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +{ + int tmp = nents; + + /* KISS: map each buffer seperately. */ + while (nents) { + sg_dma_address(sglist) = ccio_map_single(dev, sglist->address, sglist->length, direction); + sg_dma_len(sglist) = sglist->length; + nents--; + sglist++; + } + + return tmp; +} + + +static void ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +{ +#if 0 + while (nents) { + ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); + nents--; + sglist++; + } + return; +#else + /* Do nothing (copied from current ccio_unmap_single() :^) */ +#endif +} + + +static struct pci_dma_ops ccio_ops = { + ccio_dma_supported, + ccio_alloc_consistent, + ccio_free_consistent, + ccio_map_single, + ccio_unmap_single, + ccio_map_sg, + ccio_unmap_sg, + NULL, /* dma_sync_single : NOP for U2 */ + NULL, /* dma_sync_sg : ditto */ +}; + + +/* +** Determine if u2 should claim this chip (return 0) or not (return 1). +** If so, initialize the chip and tell other partners in crime they +** have work to do. +*/ +static int +ccio_probe(struct parisc_device *dev) +{ + printk(KERN_INFO "%s found %s at 0x%lx\n", MODULE_NAME, + dev->id.hversion == U2_BC_GSC ? "U2" : "UTurn", + dev->hpa); + +/* +** FIXME - should check U2 registers to verify it's really running +** in "Real Mode". +*/ + +#if 0 +/* will need this for "Virtual Mode" operation */ + ccio_hw_init(ccio_dev); + ccio_common_init(ccio_dev); +#endif + hppa_dma_ops = &ccio_ops; + return 0; +} + +static struct parisc_device_id ccio_tbl[] = { + { HPHW_BCPORT, HVERSION_REV_ANY_ID, U2_BC_GSC, 0xc }, + { HPHW_BCPORT, HVERSION_REV_ANY_ID, UTURN_BC_GSC, 0xc }, + { 0, } +}; + +static struct parisc_driver ccio_driver = { + name: "U2/Uturn", + id_table: ccio_tbl, + probe: ccio_probe, +}; + +void __init ccio_init(void) +{ + register_parisc_driver(&ccio_driver); +} diff -Nru a/drivers/parisc/dino.c b/drivers/parisc/dino.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/dino.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,935 @@ +/* +** DINO manager +** +** (c) Copyright 1999 Red Hat Software +** (c) Copyright 1999 SuSE GmbH +** (c) Copyright 1999,2000 Hewlett-Packard Company +** (c) Copyright 2000 Grant Grundler +** +** 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 module provides access to Dino PCI bus (config/IOport spaces) +** and helps manage Dino IRQ lines. +** +** Dino interrupt handling is a bit complicated. +** Dino always writes to the broadcast EIR via irr0 for now. +** (BIG WARNING: using broadcast EIR is a really bad thing for SMP!) +** Only one processor interrupt is used for the 11 IRQ line +** inputs to dino. +** +** The different between Built-in Dino and Card-Mode +** dino is in chip initialization and pci device initialization. +** +** Linux drivers can only use Card-Mode Dino if pci devices I/O port +** BARs are configured and used by the driver. Programming MMIO address +** requires substantial knowledge of available Host I/O address ranges +** is currently not supported. Port/Config accessor functions are the +** same. "BIOS" differences are handled within the existing routines. +*/ + +/* Changes : +** 2001-06-14 : Clement Moyroud (moyroudc@esiee.fr) +** - added support for the integrated RS232. +*/ + +/* +** TODO: create a virtual address for each Dino HPA. +** GSC code might be able to do this since IODC data tells us +** how many pages are used. PCI subsystem could (must?) do this +** for PCI drivers devices which implement/use MMIO registers. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for struct irqaction */ +#include /* for spinlock_t and prototypes */ + +#include +#include +#include +#include +#include +#include + +#include "gsc.h" + +#undef DINO_DEBUG + +#ifdef DINO_DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +/* +** Config accessor functions only pass in the 8-bit bus number +** and not the 8-bit "PCI Segment" number. Each Dino will be +** assigned a PCI bus number based on "when" it's discovered. +** +** The "secondary" bus number is set to this before calling +** pci_scan_bus(). If any PPB's are present, the scan will +** discover them and update the "secondary" and "subordinate" +** fields in Dino's pci_bus structure. +** +** Changes in the configuration *will* result in a different +** bus number for each dino. +*/ + +#define is_card_dino(id) ((id)->hw_type == HPHW_A_DMA) + +#define DINO_IAR0 0x004 +#define DINO_IODC_ADDR 0x008 +#define DINO_IODC_DATA_0 0x008 +#define DINO_IODC_DATA_1 0x008 +#define DINO_IRR0 0x00C +#define DINO_IAR1 0x010 +#define DINO_IRR1 0x014 +#define DINO_IMR 0x018 +#define DINO_IPR 0x01C +#define DINO_TOC_ADDR 0x020 +#define DINO_ICR 0x024 +#define DINO_ILR 0x028 +#define DINO_IO_COMMAND 0x030 +#define DINO_IO_STATUS 0x034 +#define DINO_IO_CONTROL 0x038 +#define DINO_IO_GSC_ERR_RESP 0x040 +#define DINO_IO_ERR_INFO 0x044 +#define DINO_IO_PCI_ERR_RESP 0x048 +#define DINO_IO_FBB_EN 0x05c +#define DINO_IO_ADDR_EN 0x060 +#define DINO_PCI_ADDR 0x064 +#define DINO_CONFIG_DATA 0x068 +#define DINO_IO_DATA 0x06c +#define DINO_MEM_DATA 0x070 /* Dino 3.x only */ +#define DINO_GSC2X_CONFIG 0x7b4 +#define DINO_GMASK 0x800 +#define DINO_PAMR 0x804 +#define DINO_PAPR 0x808 +#define DINO_DAMODE 0x80c +#define DINO_PCICMD 0x810 +#define DINO_PCISTS 0x814 +#define DINO_MLTIM 0x81c +#define DINO_BRDG_FEAT 0x820 +#define DINO_PCIROR 0x824 +#define DINO_PCIWOR 0x828 +#define DINO_TLTIM 0x830 + +#define DINO_IRQS 11 /* bits 0-10 are architected */ +#define DINO_IRR_MASK 0x5ff /* only 10 bits are implemented */ + +#define DINO_MASK_IRQ(x) (1<<(x)) + +#define PCIINTA 0x001 +#define PCIINTB 0x002 +#define PCIINTC 0x004 +#define PCIINTD 0x008 +#define PCIINTE 0x010 +#define PCIINTF 0x020 +#define GSCEXTINT 0x040 +/* #define xxx 0x080 - bit 7 is "default" */ +/* #define xxx 0x100 - bit 8 not used */ +/* #define xxx 0x200 - bit 9 not used */ +#define RS232INT 0x400 + +struct dino_device +{ + struct pci_hba_data hba; /* 'C' inheritance - must be first */ + spinlock_t dinosaur_pen; + unsigned long txn_addr; /* EIR addr to generate interrupt */ + u32 txn_data; /* EIR data assign to each dino */ + int irq; /* Virtual IRQ dino uses */ + struct irq_region *dino_region; /* region for this Dino */ + + u32 imr; /* IRQ's which are enabled */ +#ifdef DINO_DEBUG + unsigned int dino_irr0; /* save most recent IRQ line stat */ +#endif +}; + +/* Looks nice and keeps the compiler happy */ +#define DINO_DEV(d) ((struct dino_device *) d) + + +/* + * Dino Configuration Space Accessor Functions + */ + +#define DINO_CFG_TOK(bus,dfn,pos) ((u32) ((bus)<<16 | (dfn)<<8 | (pos))) + +static int dino_cfg_read(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *val) +{ + struct dino_device *d = DINO_DEV(bus->sysdata); + u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary; + u32 v = DINO_CFG_TOK(local_bus, devfn, where & ~3); + unsigned long base_addr = d->hba.base_addr; + unsigned long flags; + + spin_lock_irqsave(&d->dinosaur_pen, flags); + + /* tell HW which CFG address */ + gsc_writel(v, base_addr + DINO_PCI_ADDR); + + /* generate cfg read cycle */ + if (size == 1) { + *val = gsc_readb(base_addr + DINO_CONFIG_DATA + (where & 3)); + } else if (size == 2) { + *val = le16_to_cpu(gsc_readw(base_addr + + DINO_CONFIG_DATA + (where & 2))); + } else if (size == 4) { + *val = le32_to_cpu(gsc_readl(base_addr + DINO_CONFIG_DATA)); + } + + spin_unlock_irqrestore(&d->dinosaur_pen, flags); + return 0; +} + +/* + * Dino address stepping "feature": + * When address stepping, Dino attempts to drive the bus one cycle too soon + * even though the type of cycle (config vs. MMIO) might be different. + * The read of Ven/Prod ID is harmless and avoids Dino's address stepping. + */ +static int dino_cfg_write(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 val) +{ + struct dino_device *d = DINO_DEV(bus->sysdata); + u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary; + u32 v = DINO_CFG_TOK(local_bus, devfn, where & ~3); + unsigned long base_addr = d->hba.base_addr; + unsigned long flags; + + spin_lock_irqsave(&d->dinosaur_pen, flags); + + /* avoid address stepping feature */ + gsc_writel(v & 0xffffff00, base_addr + DINO_PCI_ADDR); + gsc_readl(base_addr + DINO_CONFIG_DATA); + + /* tell HW which CFG address */ + gsc_writel(v, base_addr + DINO_PCI_ADDR); + /* generate cfg read cycle */ + if (size == 1) { + gsc_writeb(val, base_addr + DINO_CONFIG_DATA + (where & 3)); + } else if (size == 2) { + gsc_writew(cpu_to_le16(val), + base_addr + DINO_CONFIG_DATA + (where & 2)); + } else if (size == 4) { + gsc_writel(cpu_to_le32(val), base_addr + DINO_CONFIG_DATA); + } + + spin_unlock_irqrestore(&d->dinosaur_pen, flags); + return 0; +} + +static struct pci_ops dino_cfg_ops = { + .read = dino_cfg_read, + .write = dino_cfg_write, +}; + + +/* + * Dino "I/O Port" Space Accessor Functions + * + * Many PCI devices don't require use of I/O port space (eg Tulip, + * NCR720) since they export the same registers to both MMIO and + * I/O port space. Performance is going to stink if drivers use + * I/O port instead of MMIO. + */ + +#define cpu_to_le8(x) (x) +#define le8_to_cpu(x) (x) + +#define DINO_PORT_IN(type, size, mask) \ +static u##size dino_in##size (struct pci_hba_data *d, u16 addr) \ +{ \ + u##size v; \ + unsigned long flags; \ + spin_lock_irqsave(&(DINO_DEV(d)->dinosaur_pen), flags); \ + /* tell HW which IO Port address */ \ + gsc_writel((u32) addr & ~3, d->base_addr + DINO_PCI_ADDR); \ + /* generate I/O PORT read cycle */ \ + v = gsc_read##type(d->base_addr+DINO_IO_DATA+(addr&mask)); \ + spin_unlock_irqrestore(&(DINO_DEV(d)->dinosaur_pen), flags); \ + return le##size##_to_cpu(v); \ +} + +DINO_PORT_IN(b, 8, 3) +DINO_PORT_IN(w, 16, 2) +DINO_PORT_IN(l, 32, 0) + +#define DINO_PORT_OUT(type, size, mask) \ +static void dino_out##size (struct pci_hba_data *d, u16 addr, u##size val) \ +{ \ + unsigned long flags; \ + spin_lock_irqsave(&(DINO_DEV(d)->dinosaur_pen), flags); \ + /* tell HW which CFG address */ \ + gsc_writel((u32) addr, d->base_addr + DINO_PCI_ADDR); \ + /* generate cfg write cycle */ \ + gsc_write##type(cpu_to_le##size(val), d->base_addr+DINO_IO_DATA+(addr&mask)); \ + spin_unlock_irqrestore(&(DINO_DEV(d)->dinosaur_pen), flags); \ +} + +DINO_PORT_OUT(b, 8, 3) +DINO_PORT_OUT(w, 16, 2) +DINO_PORT_OUT(l, 32, 0) + +struct pci_port_ops dino_port_ops = { + inb: dino_in8, + inw: dino_in16, + inl: dino_in32, + outb: dino_out8, + outw: dino_out16, + outl: dino_out32 +}; + +static void +dino_mask_irq(void *irq_dev, int irq) +{ + struct dino_device *dino_dev = DINO_DEV(irq_dev); + + DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, irq_dev, irq); + + if (NULL == irq_dev || irq > DINO_IRQS || irq < 0) { + printk(KERN_WARNING "%s(0x%lx, %d) - not a dino irq?\n", + __FUNCTION__, (long) irq_dev, irq); + BUG(); + } else { + /* + ** Clear the matching bit in the IMR register + */ + dino_dev->imr &= ~(DINO_MASK_IRQ(irq)); + gsc_writel(dino_dev->imr, dino_dev->hba.base_addr+DINO_IMR); + } +} + + +static void +dino_unmask_irq(void *irq_dev, int irq) +{ + struct dino_device *dino_dev = DINO_DEV(irq_dev); + u32 tmp; + + DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, irq_dev, irq); + + if (NULL == irq_dev || irq > DINO_IRQS) { + printk(KERN_WARNING "%s(): %d not a dino irq?\n", + __FUNCTION__, irq); + BUG(); + return; + } + + /* set the matching bit in the IMR register */ + dino_dev->imr |= DINO_MASK_IRQ(irq); /* used in dino_isr() */ + gsc_writel( dino_dev->imr, dino_dev->hba.base_addr+DINO_IMR); + + /* Emulate "Level Triggered" Interrupt + ** Basically, a driver is blowing it if the IRQ line is asserted + ** while the IRQ is disabled. But tulip.c seems to do that.... + ** Give 'em a kluge award and a nice round of applause! + ** + ** The gsc_write will generate an interrupt which invokes dino_isr(). + ** dino_isr() will read IPR and find nothing. But then catch this + ** when it also checks ILR. + */ + tmp = gsc_readl(dino_dev->hba.base_addr+DINO_ILR); + if (tmp & DINO_MASK_IRQ(irq)) { + DBG(KERN_WARNING "%s(): IRQ asserted! (ILR 0x%x)\n", + __FUNCTION__, tmp); + gsc_writel(dino_dev->txn_data, dino_dev->txn_addr); + } +} + + + +static void +dino_enable_irq(void *irq_dev, int irq) +{ + struct dino_device *dino_dev = DINO_DEV(irq_dev); + + /* + ** clear pending IRQ bits + ** + ** This does NOT change ILR state! + ** See comments in dino_unmask_irq() for ILR usage. + */ + gsc_readl(dino_dev->hba.base_addr+DINO_IPR); + + dino_unmask_irq(irq_dev, irq); +} + + +static struct irq_region_ops dino_irq_ops = { + disable_irq: dino_mask_irq, /* ??? */ + enable_irq: dino_enable_irq, + mask_irq: dino_mask_irq, + unmask_irq: dino_unmask_irq +}; + + +/* + * Handle a Processor interrupt generated by Dino. + * + * ilr_loop counter is a kluge to prevent a "stuck" IRQ line from + * wedging the CPU. Could be removed or made optional at some point. + */ +static void +dino_isr(int irq, void *intr_dev, struct pt_regs *regs) +{ + struct dino_device *dino_dev = DINO_DEV(intr_dev); + u32 mask; + int ilr_loop = 100; + extern void do_irq(struct irqaction *a, int i, struct pt_regs *p); + + + /* read and acknowledge pending interrupts */ +#ifdef DINO_DEBUG + dino_dev->dino_irr0 = +#endif + mask = gsc_readl(dino_dev->hba.base_addr+DINO_IRR0) & DINO_IRR_MASK; + +ilr_again: + while (mask) + { + int irq; + + /* + * Perform a binary search on set bits. + * `Less than Fatal' and PS2 interupts aren't supported. + */ + if (mask & 0xf) { + if (mask & 0x3) { + irq = (mask & 0x1) ? 0 : 1; /* PCI INT A, B */ + } else { + irq = (mask & 0x4) ? 2 : 3; /* PCI INT C, D */ + } + } else { + if (mask & 0x30) { + irq = (mask & 0x10) ? 4 : 5; /* PCI INT E, F */ + } else { + irq = (mask & 0x40) ? 6 : 10; /* GSC, RS232 */ + } + } + + mask &= ~(1<dino_region->action[irq], + dino_dev->dino_region->data.irqbase + irq, + regs); + + } + + /* Support for level triggered IRQ lines. + ** + ** Dropping this support would make this routine *much* faster. + ** But since PCI requires level triggered IRQ line to share lines... + ** device drivers may assume lines are level triggered (and not + ** edge triggered like EISA/ISA can be). + */ + mask = gsc_readl(dino_dev->hba.base_addr+DINO_ILR) & dino_dev->imr; + if (mask) { + if (--ilr_loop > 0) + goto ilr_again; + printk("Dino %lx: stuck interrupt %d\n", dino_dev->hba.base_addr, mask); + } +} + +static int dino_choose_irq(struct parisc_device *dev) +{ + int irq = -1; + + switch (dev->id.sversion) { + case 0x00084: irq = 8; break; /* PS/2 */ + case 0x0008c: irq = 10; break; /* RS232 */ + case 0x00096: irq = 8; break; /* PS/2 */ + } + + return irq; +} + +static void __init +dino_bios_init(void) +{ + DBG("dino_bios_init\n"); +} + +/* + * dino_card_setup - Set up the memory space for a Dino in card mode. + * @bus: the bus under this dino + * + * Claim an 8MB chunk of unused IO space and call the generic PCI routines + * to set up the addresses of the devices on this bus. + */ +#define _8MB 0x00800000UL +static void __init +dino_card_setup(struct pci_bus *bus, unsigned long base_addr) +{ + int i; + struct dino_device *dino_dev = DINO_DEV(bus->sysdata); + struct resource *res; + + res = &dino_dev->hba.lmmio_space; + res->flags = IORESOURCE_MEM; + + if (ccio_allocate_resource(dino_dev->hba.dev, res, _8MB, + (unsigned long) 0xfffffffff0000000UL | _8MB, + 0xffffffffffffffffUL &~ _8MB, _8MB, + NULL, NULL) < 0) { + printk(KERN_WARNING "Dino: Failed to allocate memory region\n"); + return; + } + bus->resource[1] = res; + bus->resource[0] = &(dino_dev->hba.io_space); + + /* Now tell dino what range it has */ + for (i = 1; i < 31; i++) { + if (res->start == (0xfffffffff0000000UL | i * _8MB)) + break; + } + gsc_writel(1 << i, base_addr + DINO_IO_ADDR_EN); + + pcibios_assign_unassigned_resources(bus); +} + +static void __init +dino_card_fixup(struct pci_dev *dev) +{ + u32 irq_pin; + + /* + ** REVISIT: card-mode PCI-PCI expansion chassis do exist. + ** Not sure they were ever productized. + ** Die here since we'll die later in dino_inb() anyway. + */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + panic("Card-Mode Dino: PCI-PCI Bridge not supported\n"); + } + + /* + ** Set Latency Timer to 0xff (not a shared bus) + ** Set CACHELINE_SIZE. + */ + dino_cfg_write(dev->bus, dev->devfn, PCI_CACHE_LINE_SIZE, 16, 0xff00 | L1_CACHE_BYTES/4); + + /* + ** Program INT_LINE for card-mode devices. + ** The cards are hardwired according to this algorithm. + ** And it doesn't matter if PPB's are present or not since + ** the IRQ lines bypass the PPB. + ** + ** "-1" converts INTA-D (1-4) to PCIINTA-D (0-3) range. + ** The additional "-1" adjusts for skewing the IRQ<->slot. + */ + dino_cfg_read(dev->bus, dev->devfn, PCI_INTERRUPT_PIN, 8, &irq_pin); + dev->irq = (irq_pin + PCI_SLOT(dev->devfn) - 1) % 4 ; + + /* Shouldn't really need to do this but it's in case someone tries + ** to bypass PCI services and look at the card themselves. + */ + dino_cfg_write(dev->bus, dev->devfn, PCI_INTERRUPT_LINE, 8, dev->irq); +} + + +static void __init +dino_fixup_bus(struct pci_bus *bus) +{ + struct list_head *ln; + struct pci_dev *dev; + struct dino_device *dino_dev = DINO_DEV(bus->sysdata); + int port_base = HBA_PORT_BASE(dino_dev->hba.hba_num); + + DBG(KERN_WARNING "%s(0x%p) bus %d sysdata 0x%p\n", + __FUNCTION__, bus, bus->secondary, bus->sysdata); + + /* Firmware doesn't set up card-mode dino, so we have to */ + if (is_card_dino(&dino_dev->hba.dev->id)) + dino_card_setup(bus, dino_dev->hba.base_addr); + + /* If this is a PCI-PCI Bridge, read the window registers etc */ + if (bus->self) + pci_read_bridge_bases(bus); + + list_for_each(ln, &bus->devices) { + int i; + + dev = pci_dev_b(ln); + if (is_card_dino(&dino_dev->hba.dev->id)) + dino_card_fixup(dev); + + /* + ** P2PB's only have 2 BARs, no IRQs. + ** I'd like to just ignore them for now. + */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) + continue; + + /* Adjust the I/O Port space addresses */ + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *res = &dev->resource[i]; + if (res->flags & IORESOURCE_IO) { + res->start |= port_base; + res->end |= port_base; + } +#ifdef __LP64__ + /* Sign Extend MMIO addresses */ + else if (res->flags & IORESOURCE_MEM) { + res->start |= 0xffffffff00000000UL; + res->end |= 0xffffffff00000000UL; + } +#endif + } + + /* Adjust INT_LINE for that busses region */ + dev->irq = dino_dev->dino_region->data.irqbase + dev->irq; + } +} + + +struct pci_bios_ops dino_bios_ops = { + .init = dino_bios_init, + .fixup_bus = dino_fixup_bus +}; + + +/* + * Initialise a DINO controller chip + */ +static void __init +dino_card_init(struct dino_device *dino_dev) +{ + u32 brdg_feat = 0x00784e05; + + gsc_writel(0x00000000, dino_dev->hba.base_addr+DINO_GMASK); + gsc_writel(0x00000001, dino_dev->hba.base_addr+DINO_IO_FBB_EN); + gsc_writel(0x00000000, dino_dev->hba.base_addr+DINO_ICR); + +#if 1 +/* REVISIT - should be a runtime check (eg if (CPU_IS_PCX_L) ...) */ + /* + ** PCX-L processors don't support XQL like Dino wants it. + ** PCX-L2 ignore XQL signal and it doesn't matter. + */ + brdg_feat &= ~0x4; /* UXQL */ +#endif + gsc_writel( brdg_feat, dino_dev->hba.base_addr+DINO_BRDG_FEAT); + + /* + ** Don't enable address decoding until we know which I/O range + ** currently is available from the host. Only affects MMIO + ** and not I/O port space. + */ + gsc_writel(0x00000000, dino_dev->hba.base_addr+DINO_IO_ADDR_EN); + + gsc_writel(0x00000000, dino_dev->hba.base_addr+DINO_DAMODE); + gsc_writel(0x00222222, dino_dev->hba.base_addr+DINO_PCIROR); + gsc_writel(0x00222222, dino_dev->hba.base_addr+DINO_PCIWOR); + + gsc_writel(0x00000040, dino_dev->hba.base_addr+DINO_MLTIM); + gsc_writel(0x00000080, dino_dev->hba.base_addr+DINO_IO_CONTROL); + gsc_writel(0x0000008c, dino_dev->hba.base_addr+DINO_TLTIM); + + /* Disable PAMR before writing PAPR */ + gsc_writel(0x0000007e, dino_dev->hba.base_addr+DINO_PAMR); + gsc_writel(0x0000007f, dino_dev->hba.base_addr+DINO_PAPR); + gsc_writel(0x00000000, dino_dev->hba.base_addr+DINO_PAMR); + + /* + ** Dino ERS encourages enabling FBB (0x6f). + ** We can't until we know *all* devices below us can support it. + ** (Something in device configuration header tells us). + */ + gsc_writel(0x0000004f, dino_dev->hba.base_addr+DINO_PCICMD); + + /* Somewhere, the PCI spec says give devices 1 second + ** to recover from the #RESET being de-asserted. + ** Experience shows most devices only need 10ms. + ** This short-cut speeds up booting significantly. + */ + mdelay(pci_post_reset_delay); +} + +static int __init +dino_bridge_init(struct dino_device *dino_dev, const char *name) +{ + unsigned long io_addr, bpos; + int result; + struct resource *res; + /* + * Decoding IO_ADDR_EN only works for Built-in Dino + * since PDC has already initialized this. + */ + + io_addr = gsc_readl(dino_dev->hba.base_addr + DINO_IO_ADDR_EN); + if (io_addr == 0) { + printk(KERN_WARNING "%s: No PCI devices enabled.\n", name); + return -ENODEV; + } + + for (bpos = 0; (io_addr & (1 << bpos)) == 0; bpos++) + ; + + res = &dino_dev->hba.lmmio_space; + res->flags = IORESOURCE_MEM; + + res->start = (unsigned long)(signed int)(0xf0000000 | (bpos << 23)); + res->end = res->start + 8 * 1024 * 1024 - 1; + + result = ccio_request_resource(dino_dev->hba.dev, res); + if (result < 0) { + printk(KERN_ERR "%s: failed to claim PCI Bus address space!\n", name); + return result; + } + + return 0; +} + +static int __init dino_common_init(struct parisc_device *dev, + struct dino_device *dino_dev, const char *name) +{ + int status; + u32 eim; + struct gsc_irq gsc_irq; + struct resource *res; + + pcibios_register_hba(&dino_dev->hba); + + pci_bios = &dino_bios_ops; /* used by pci_scan_bus() */ + pci_port = &dino_port_ops; + + /* + ** Note: SMP systems can make use of IRR1/IAR1 registers + ** But it won't buy much performance except in very + ** specific applications/configurations. Note Dino + ** still only has 11 IRQ input lines - just map some of them + ** to a different processor. + */ + dino_dev->irq = gsc_alloc_irq(&gsc_irq); + dino_dev->txn_addr = gsc_irq.txn_addr; + dino_dev->txn_data = gsc_irq.txn_data; + eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data; + + /* + ** Dino needs a PA "IRQ" to get a processor's attention. + ** arch/parisc/kernel/irq.c returns an EIRR bit. + */ + if (dino_dev->irq < 0) { + printk(KERN_WARNING "%s: gsc_alloc_irq() failed\n", name); + return 1; + } + + status = request_irq(dino_dev->irq, dino_isr, 0, name, dino_dev); + if (status) { + printk(KERN_WARNING "%s: request_irq() failed with %d\n", + name, status); + return 1; + } + + /* + ** Tell generic interrupt support we have 11 bits which need + ** be checked in the interrupt handler. + */ + dino_dev->dino_region = alloc_irq_region(DINO_IRQS, &dino_irq_ops, + name, dino_dev); + + if (NULL == dino_dev->dino_region) { + printk(KERN_WARNING "%s: alloc_irq_region() failed\n", name); + return 1; + } + + /* Support the serial port which is sometimes attached on built-in + * Dino / Cujo chips. + */ + + fixup_child_irqs(dev, dino_dev->dino_region->data.irqbase, + dino_choose_irq); + + /* + ** This enables DINO to generate interrupts when it sees + ** any of it's inputs *change*. Just asserting an IRQ + ** before it's enabled (ie unmasked) isn't good enough. + */ + gsc_writel(eim, dino_dev->hba.base_addr+DINO_IAR0); + + /* + ** Some platforms don't clear Dino's IRR0 register at boot time. + ** Reading will clear it now. + */ + gsc_readl(dino_dev->hba.base_addr+DINO_IRR0); + + /* allocate I/O Port resource region */ + res = &dino_dev->hba.io_space; + if (dev->id.hversion == 0x680 || is_card_dino(&dev->id)) { + res->name = "Dino I/O Port"; + dino_dev->hba.lmmio_space.name = "Dino LMMIO"; + } else { + res->name = "Cujo I/O Port"; + dino_dev->hba.lmmio_space.name = "Cujo LMMIO"; + } + res->start = HBA_PORT_BASE(dino_dev->hba.hba_num); + res->end = res->start + (HBA_PORT_SPACE_SIZE - 1); + res->flags = IORESOURCE_IO; /* do not mark it busy ! */ + if (request_resource(&ioport_resource, res) < 0) { + printk(KERN_ERR "%s: request I/O Port region failed 0x%lx/%lx (hpa 0x%lx)\n", + name, res->start, res->end, dino_dev->hba.base_addr); + return 1; + } + + return 0; +} + +#define CUJO_RAVEN_ADDR 0xfffffffff1000000UL +#define CUJO_FIREHAWK_ADDR 0xfffffffff1604000UL +#define CUJO_RAVEN_BADPAGE 0x01003000UL +#define CUJO_FIREHAWK_BADPAGE 0x01607000UL + +static const char *dino_vers[] = { + "2.0", + "2.1", + "3.0", + "3.1" +}; + +static const char *cujo_vers[] = { + "1.0", + "2.0" +}; + +void ccio_cujo20_fixup(struct parisc_device *dev, u32 iovp); + +/* +** Determine if dino should claim this chip (return 0) or not (return 1). +** If so, initialize the chip appropriately (card-mode vs bridge mode). +** Much of the initialization is common though. +*/ +static int __init +dino_driver_callback(struct parisc_device *dev) +{ + struct dino_device *dino_dev; // Dino specific control struct + const char *version = "unknown"; + const char *name = "Dino"; + int is_cujo = 0; + + if (is_card_dino(&dev->id)) { + version = "3.x (card mode)"; + } else { + if(dev->id.hversion == 0x680) { + if (dev->id.hversion_rev < 4) { + version = dino_vers[dev->id.hversion_rev]; + } + } else { + name = "Cujo"; + is_cujo = 1; + if (dev->id.hversion_rev < 2) { + version = cujo_vers[dev->id.hversion_rev]; + } + } + } + + printk("%s version %s found at 0x%lx\n", name, version, dev->hpa); + + if (!request_mem_region(dev->hpa, PAGE_SIZE, name)) { + printk(KERN_ERR "DINO: Hey! Someone took my MMIO space (0x%ld)!\n", + dev->hpa); + return 1; + } + + /* Check for bugs */ + if (is_cujo && dev->id.hversion_rev == 1) { +#ifdef CONFIG_IOMMU_CCIO + printk(KERN_WARNING "Enabling Cujo 2.0 bug workaround\n"); + if (dev->hpa == (unsigned long)CUJO_RAVEN_ADDR) { + ccio_cujo20_fixup(dev->parent, CUJO_RAVEN_BADPAGE); + } else if (dev->hpa == (unsigned long)CUJO_FIREHAWK_ADDR) { + ccio_cujo20_fixup(dev->parent, CUJO_FIREHAWK_BADPAGE); + } else { + printk("Don't recognise Cujo at address 0x%lx, not enabling workaround\n", dev->hpa); + } +#endif + } else if (!is_cujo && !is_card_dino(&dev->id) && + dev->id.hversion_rev < 3) { + printk(KERN_WARNING +"The GSCtoPCI (Dino hrev %d) bus converter found may exhibit\n" +"data corruption. See Service Note Numbers: A4190A-01, A4191A-01.\n" +"Systems shipped after Aug 20, 1997 will not exhibit this problem.\n" +"Models affected: C180, C160, C160L, B160L, and B132L workstations.\n\n", + dev->id.hversion_rev); +/* REVISIT: why are C200/C240 listed in the README table but not +** "Models affected"? Could be an omission in the original literature. +*/ + } + + dino_dev = kmalloc(sizeof(struct dino_device), GFP_KERNEL); + if (!dino_dev) { + printk("dino_init_chip - couldn't alloc dino_device\n"); + return 1; + } + + memset(dino_dev, 0, sizeof(struct dino_device)); + + dino_dev->hba.dev = dev; + dino_dev->hba.base_addr = dev->hpa; /* faster access */ + dino_dev->hba.lmmio_space_offset = 0; /* CPU addrs == bus addrs */ + dino_dev->dinosaur_pen = SPIN_LOCK_UNLOCKED; + dino_dev->hba.iommu = ccio_get_iommu(dev); + + if (is_card_dino(&dev->id)) { + dino_card_init(dino_dev); + } else { + dino_bridge_init(dino_dev, name); + } + + if (dino_common_init(dev, dino_dev, name)) + return 1; + + /* + ** It's not used to avoid chicken/egg problems + ** with configuration accessor functions. + */ + dino_dev->hba.hba_bus = pci_scan_bus(dino_dev->hba.hba_num, + &dino_cfg_ops, dino_dev); + + return 0; +} + +/* + * Normally, we would just test sversion. But the Elroy PCI adapter has + * the same sversion as Dino, so we have to check hversion as well. + * Unfortunately, the J2240 PDC reports the wrong hversion for the first + * Dino, so we have to test for Dino, Cujo and Dino-in-a-J2240. + */ +static struct parisc_device_id dino_tbl[] = { + { HPHW_A_DMA, HVERSION_REV_ANY_ID, 0x004, 0x0009D }, /* Card-mode Dino. */ + { HPHW_A_DMA, HVERSION_REV_ANY_ID, 0x444, 0x08080 }, /* Same card in a 715. Bug? */ + { HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x680, 0xa }, /* Bridge-mode Dino */ + { HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x682, 0xa }, /* Bridge-mode Cujo */ + { HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x05d, 0xa }, /* Dino in a J2240 */ + { 0, } +}; + +static struct parisc_driver dino_driver = { + .name = "Dino", + .id_table = dino_tbl, + .probe = dino_driver_callback, +}; + +/* + * One time initialization to let the world know Dino is here. + * This is the only routine which is NOT static. + * Must be called exactly once before pci_init(). + */ +int __init dino_init(void) +{ + register_parisc_driver(&dino_driver); + return 0; +} + diff -Nru a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/eisa.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,454 @@ +/* + * eisa.c - provide support for EISA adapters in PA-RISC machines + * + * 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. + * + * Copyright (c) 2001 Matthew Wilcox for Hewlett Packard + * Copyright (c) 2001 Daniel Engstrom <5116@telia.com> + * + * There are two distinct EISA adapters. Mongoose is found in machines + * before the 712; then the Wax ASIC is used. To complicate matters, the + * Wax ASIC also includes a PS/2 and RS-232 controller, but those are + * dealt with elsewhere; this file is concerned only with the EISA portions + * of Wax. + * + * + * HINT: + * ----- + * To allow an ISA card to work properly in the EISA slot you need to + * set an edge trigger level. This may be done on the palo command line + * by adding the kernel parameter "eisa_irq_edge=n,n2,[...]]", with + * n and n2 as the irq levels you want to use. + * + * Example: "eisa_irq_edge=10,11" allows ISA cards to operate at + * irq levels 10 and 11. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if 0 +#define EISA_DBG(msg, arg... ) printk(KERN_DEBUG "eisa: " msg , ## arg ) +#else +#define EISA_DBG(msg, arg... ) +#endif + +#define SNAKES_EEPROM_BASE_ADDR 0xF0810400 +#define MIRAGE_EEPROM_BASE_ADDR 0xF00C0400 + +static spinlock_t eisa_irq_lock = SPIN_LOCK_UNLOCKED; + +/* We can only have one EISA adapter in the system because neither + * implementation can be flexed. + */ +static struct eisa_ba { + struct pci_hba_data hba; + unsigned long eeprom_addr; +} eisa_dev; + +/* Port ops */ + +static inline unsigned long eisa_permute(unsigned short port) +{ + if (port & 0x300) { + return 0xfc000000 | ((port & 0xfc00) >> 6) + | ((port & 0x3f8) << 9) | (port & 7); + } else { + return 0xfc000000 | port; + } +} + +unsigned char eisa_in8(unsigned short port) +{ + if (EISA_bus) + return gsc_readb(eisa_permute(port)); + return 0xff; +} + +unsigned short eisa_in16(unsigned short port) +{ + if (EISA_bus) + return le16_to_cpu(gsc_readw(eisa_permute(port))); + return 0xffff; +} + +unsigned int eisa_in32(unsigned short port) +{ + if (EISA_bus) + return le32_to_cpu(gsc_readl(eisa_permute(port))); + return 0xffffffff; +} + +void eisa_out8(unsigned char data, unsigned short port) +{ + if (EISA_bus) + gsc_writeb(data, eisa_permute(port)); +} + +void eisa_out16(unsigned short data, unsigned short port) +{ + if (EISA_bus) + gsc_writew(cpu_to_le16(data), eisa_permute(port)); +} + +void eisa_out32(unsigned int data, unsigned short port) +{ + if (EISA_bus) + gsc_writel(cpu_to_le32(data), eisa_permute(port)); +} + +/* Interrupt handling */ + +/* cached interrupt mask registers */ +static int master_mask; +static int slave_mask; + +/* the trig level can be set with the + * eisa_irq_edge=n,n,n commandline parameter + * We should really read this from the EEPROM + * in the furure. + */ +/* irq 13,8,2,1,0 must be edge */ +static unsigned int eisa_irq_level; /* default to edge triggered */ + + +/* called by free irq */ +static void eisa_disable_irq(void *irq_dev, int irq) +{ + unsigned long flags; + + EISA_DBG("disable irq %d\n", irq); + /* just mask for now */ + spin_lock_irqsave(&eisa_irq_lock, flags); + if (irq & 8) { + slave_mask |= (1 << (irq&7)); + eisa_out8(slave_mask, 0xa1); + } else { + master_mask |= (1 << (irq&7)); + eisa_out8(master_mask, 0x21); + } + spin_unlock_irqrestore(&eisa_irq_lock, flags); + EISA_DBG("pic0 mask %02x\n", eisa_in8(0x21)); + EISA_DBG("pic1 mask %02x\n", eisa_in8(0xa1)); +} + +/* called by request irq */ +static void eisa_enable_irq(void *irq_dev, int irq) +{ + unsigned long flags; + EISA_DBG("enable irq %d\n", irq); + + spin_lock_irqsave(&eisa_irq_lock, flags); + if (irq & 8) { + slave_mask &= ~(1 << (irq&7)); + eisa_out8(slave_mask, 0xa1); + } else { + master_mask &= ~(1 << (irq&7)); + eisa_out8(master_mask, 0x21); + } + spin_unlock_irqrestore(&eisa_irq_lock, flags); + EISA_DBG("pic0 mask %02x\n", eisa_in8(0x21)); + EISA_DBG("pic1 mask %02x\n", eisa_in8(0xa1)); +} + +static void eisa_mask_irq(void *irq_dev, int irq) +{ + unsigned long flags; + EISA_DBG("mask irq %d\n", irq); + + /* mask irq */ + spin_lock_irqsave(&eisa_irq_lock, flags); + if (irq & 8) { + slave_mask |= (1 << (irq&7)); + eisa_out8(slave_mask, 0xa1); + } else { + master_mask |= (1 << (irq&7)); + eisa_out8(master_mask, 0x21); + } + spin_unlock_irqrestore(&eisa_irq_lock, flags); +} + +static void eisa_unmask_irq(void *irq_dev, int irq) +{ + unsigned long flags; + EISA_DBG("unmask irq %d\n", irq); + + /* unmask */ + spin_lock_irqsave(&eisa_irq_lock, flags); + if (irq & 8) { + slave_mask &= ~(1 << (irq&7)); + eisa_out8(slave_mask, 0xa1); + } else { + master_mask &= ~(1 << (irq&7)); + eisa_out8(master_mask, 0x21); + } + spin_unlock_irqrestore(&eisa_irq_lock, flags); +} + +static struct irqaction action[IRQ_PER_REGION]; + +/* EISA needs to be fixed at IRQ region #0 (EISA_IRQ_REGION) */ +static struct irq_region eisa_irq_region = { + ops: { eisa_disable_irq, eisa_enable_irq, eisa_mask_irq, eisa_unmask_irq }, + data: { name: "EISA", irqbase: 0 }, + action: action, +}; + +static void eisa_irq(int _, void *intr_dev, struct pt_regs *regs) +{ + extern void do_irq(struct irqaction *a, int i, struct pt_regs *p); + int irq = gsc_readb(0xfc01f000); /* EISA supports 16 irqs */ + unsigned long flags; + + spin_lock_irqsave(&eisa_irq_lock, flags); + /* read IRR command */ + eisa_out8(0x0a, 0x20); + eisa_out8(0x0a, 0xa0); + + EISA_DBG("irq IAR %02x 8259-1 irr %02x 8259-2 irr %02x\n", + irq, eisa_in8(0x20), eisa_in8(0xa0)); + + /* read ISR command */ + eisa_out8(0x0a, 0x20); + eisa_out8(0x0a, 0xa0); + EISA_DBG("irq 8259-1 isr %02x imr %02x 8259-2 isr %02x imr %02x\n", + eisa_in8(0x20), eisa_in8(0x21), eisa_in8(0xa0), eisa_in8(0xa1)); + + irq &= 0xf; + + /* mask irq and write eoi */ + if (irq & 8) { + slave_mask |= (1 << (irq&7)); + eisa_out8(slave_mask, 0xa1); + eisa_out8(0x60 | (irq&7),0xa0);/* 'Specific EOI' to slave */ + eisa_out8(0x62,0x20); /* 'Specific EOI' to master-IRQ2 */ + + } else { + master_mask |= (1 << (irq&7)); + eisa_out8(master_mask, 0x21); + eisa_out8(0x60|irq,0x20); /* 'Specific EOI' to master */ + } + spin_unlock_irqrestore(&eisa_irq_lock, flags); + + + do_irq(&eisa_irq_region.action[irq], EISA_IRQ_REGION + irq, regs); + + spin_lock_irqsave(&eisa_irq_lock, flags); + /* unmask */ + if (irq & 8) { + slave_mask &= ~(1 << (irq&7)); + eisa_out8(slave_mask, 0xa1); + } else { + master_mask &= ~(1 << (irq&7)); + eisa_out8(master_mask, 0x21); + } + spin_unlock_irqrestore(&eisa_irq_lock, flags); +} + +static void dummy_irq2_handler(int _, void *dev, struct pt_regs *regs) +{ + printk(KERN_ALERT "eisa: uhh, irq2?\n"); +} + +static void init_eisa_pic(void) +{ + unsigned long flags; + + spin_lock_irqsave(&eisa_irq_lock, flags); + + eisa_out8(0xff, 0x21); /* mask during init */ + eisa_out8(0xff, 0xa1); /* mask during init */ + + /* master pic */ + eisa_out8(0x11,0x20); /* ICW1 */ + eisa_out8(0x00,0x21); /* ICW2 */ + eisa_out8(0x04,0x21); /* ICW3 */ + eisa_out8(0x01,0x21); /* ICW4 */ + eisa_out8(0x40,0x20); /* OCW2 */ + + /* slave pic */ + eisa_out8(0x11,0xa0); /* ICW1 */ + eisa_out8(0x08,0xa1); /* ICW2 */ + eisa_out8(0x02,0xa1); /* ICW3 */ + eisa_out8(0x01,0xa1); /* ICW4 */ + eisa_out8(0x40,0xa0); /* OCW2 */ + + udelay(100); + + slave_mask = 0xff; + master_mask = 0xfb; + eisa_out8(slave_mask, 0xa1); /* OCW1 */ + eisa_out8(master_mask, 0x21); /* OCW1 */ + + /* setup trig level */ + EISA_DBG("EISA edge/level %04x\n", eisa_irq_level); + + eisa_out8(eisa_irq_level&0xff, 0x4d0); /* Set all irq's to edge */ + eisa_out8((eisa_irq_level >> 8) & 0xff, 0x4d1); + + EISA_DBG("pic0 mask %02x\n", eisa_in8(0x21)); + EISA_DBG("pic1 mask %02x\n", eisa_in8(0xa1)); + EISA_DBG("pic0 edge/level %02x\n", eisa_in8(0x4d0)); + EISA_DBG("pic1 edge/level %02x\n", eisa_in8(0x4d1)); + + spin_unlock_irqrestore(&eisa_irq_lock, flags); +} + +/* Device initialisation */ + +#define is_mongoose(dev) (dev->id.sversion == 0x00076) + +static int __devinit eisa_probe(struct parisc_device *dev) +{ + int result; + + char *name = is_mongoose(dev) ? "Mongoose" : "Wax"; + + printk(KERN_INFO "%s EISA Adapter found at 0x%08lx\n", + name, dev->hpa); + + eisa_dev.hba.dev = dev; + eisa_dev.hba.iommu = ccio_get_iommu(dev); + + eisa_dev.hba.lmmio_space.name = "EISA"; + eisa_dev.hba.lmmio_space.start = (unsigned long) 0xfffffffffc000000; + eisa_dev.hba.lmmio_space.end = (unsigned long) 0xffffffffffbfffff; + eisa_dev.hba.lmmio_space.flags = IORESOURCE_MEM; + result = ccio_request_resource(dev, &eisa_dev.hba.lmmio_space); + if (result < 0) { + printk(KERN_ERR "EISA: failed to claim EISA Bus address space!\n"); + return result; + } + eisa_dev.hba.io_space.name = "EISA"; + eisa_dev.hba.io_space.start = 0; + eisa_dev.hba.io_space.end = 0xffff; + eisa_dev.hba.lmmio_space.flags = IORESOURCE_IO; + result = request_resource(&ioport_resource, &eisa_dev.hba.io_space); + if (result < 0) { + printk(KERN_ERR "EISA: failed to claim EISA Bus port space!\n"); + return result; + } + pcibios_register_hba(&eisa_dev.hba); + + result = request_irq(dev->irq, eisa_irq, SA_SHIRQ, "EISA", NULL); + if (result) { + printk(KERN_ERR "EISA: request_irq failed!\n"); + return result; + } + + /* Reserve IRQ2 */ + action[2].handler = dummy_irq2_handler; + action[2].name = "cascade"; + + eisa_irq_region.data.dev = dev; + irq_region[0] = &eisa_irq_region; + + EISA_bus = 1; + if (dev->num_addrs) { + /* newer firmware hand out the eeprom address */ + eisa_dev.eeprom_addr = dev->addr[0]; + } else { + /* old firmware, need to figure out the box */ + if (is_mongoose(dev)) { + eisa_dev.eeprom_addr = SNAKES_EEPROM_BASE_ADDR; + } else { + eisa_dev.eeprom_addr = MIRAGE_EEPROM_BASE_ADDR; + } + } + eisa_eeprom_init(eisa_dev.eeprom_addr); + eisa_enumerator(eisa_dev.eeprom_addr, &eisa_dev.hba.io_space, &eisa_dev.hba.lmmio_space); + init_eisa_pic(); + + return 0; +} + +static struct parisc_device_id __devinitdata eisa_tbl[] = { + { HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00076 }, /* Mongoose */ + { HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00090 }, /* Wax EISA */ + { 0, } +}; + +MODULE_DEVICE_TABLE(parisc, eisa_tbl); + +static struct parisc_driver eisa_driver = { + name: "EISA Bus Adapter", + id_table: eisa_tbl, + probe: eisa_probe, +}; + +void __init eisa_init(void) +{ + register_parisc_driver(&eisa_driver); +} + + +static unsigned int eisa_irq_configured; +void eisa_make_irq_level(int num) +{ + if (eisa_irq_configured& (1< 15 || val < 0) { + printk(KERN_ERR "eisa: EISA irq value are 0-15\n"); + continue; + } + if (val == 2) { + val = 9; + } + eisa_make_irq_edge(val); /* clear the corresponding bit */ + EISA_DBG("setting IRQ %d to edge-triggered mode\n", val); + + if ((cur = strchr(cur, ','))) { + cur++; + } else { + break; + } + } + return 1; +} + +__setup("eisa_irq_edge=", eisa_irq_setup); + diff -Nru a/drivers/parisc/eisa_eeprom.c b/drivers/parisc/eisa_eeprom.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/eisa_eeprom.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,107 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EISA_EEPROM_MINOR 241 + +static unsigned long eeprom_addr; + +static long long eisa_eeprom_llseek(struct file *file, loff_t offset, int origin ) +{ + switch (origin) { + case 0: + /* nothing to do */ + break; + case 1: + offset += file->f_pos; + break; + case 2: + offset += HPEE_MAX_LENGTH; + break; + } + return (offset >= 0 && offset < HPEE_MAX_LENGTH) ? (file->f_pos = offset) : -EINVAL; +} + +static ssize_t eisa_eeprom_read(struct file * file, + char *buf, size_t count, loff_t *ppos ) +{ + unsigned char *tmp; + ssize_t ret; + int i; + + if (*ppos >= HPEE_MAX_LENGTH) + return 0; + + count = *ppos + count < HPEE_MAX_LENGTH ? count : HPEE_MAX_LENGTH - *ppos; + tmp = kmalloc(count, GFP_KERNEL); + if (tmp) { + for (i = 0; i < count; i++) + tmp[i] = gsc_readb(eeprom_addr+(*ppos)++); + + if (copy_to_user (buf, tmp, count)) + ret = -EFAULT; + else + ret = count; + kfree (tmp); + } else + ret = -ENOMEM; + + return ret; +} + +static int eisa_eeprom_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, + unsigned long arg) +{ + return -ENOTTY; +} + +static int eisa_eeprom_open(struct inode *inode, struct file *file) +{ + if (file->f_mode & 2 || eeprom_addr == 0) + return -EINVAL; + + return 0; +} + +static int eisa_eeprom_release(struct inode *inode, struct file *file) +{ + return 0; +} + +/* + * The various file operations we support. + */ +static struct file_operations eisa_eeprom_fops = { + owner: THIS_MODULE, + llseek: eisa_eeprom_llseek, + read: eisa_eeprom_read, + ioctl: eisa_eeprom_ioctl, + open: eisa_eeprom_open, + release: eisa_eeprom_release, +}; + +static struct miscdevice eisa_eeprom_dev= +{ + EISA_EEPROM_MINOR, + "eisa eeprom", + &eisa_eeprom_fops +}; + +int __init eisa_eeprom_init(unsigned long addr) +{ + if (addr) { + eeprom_addr = addr; + misc_register(&eisa_eeprom_dev); + printk(KERN_INFO "EISA EEPROM at 0x%lx\n", eeprom_addr); + } + return 0; +} + +MODULE_LICENSE("GPL"); diff -Nru a/drivers/parisc/eisa_enumerator.c b/drivers/parisc/eisa_enumerator.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/eisa_enumerator.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,518 @@ +/* + * eisa_enumerator.c - provide support for EISA adapters in PA-RISC machines + * + * 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. + * + * Copyright (c) 2002 Daniel Engstrom <5116@telia.com> + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* + * Todo: + * + * PORT init with MASK attr and other size than byte + * MEMORY with other decode than 20 bit + * CRC stuff + * FREEFORM stuff + */ + +#define EPI 0xc80 +#define NUM_SLOT 16 +#define SLOT2PORT(x) (x<<12) + + +/* macros to handle unaligned accesses and + * byte swapping. The data in the EEPROM is + * little-endian on the big-endian PAROSC */ +#define get_8(x) (*(u_int8_t*)(x)) + +static inline u_int16_t get_16(const unsigned char *x) +{ + return (x[1] << 8) | x[0]; +} + +static inline u_int32_t get_32(const unsigned char *x) +{ + return (x[3] << 24) | (x[2] << 16) | (x[1] << 8) | x[0]; +} + +static inline u_int32_t get_24(const unsigned char *x) +{ + return (x[2] << 24) | (x[1] << 16) | (x[0] << 8); +} + +static void print_eisa_id(char *s, u_int32_t id) +{ + char vendor[4]; + int rev; + int device; + + rev = id & 0xff; + id >>= 8; + device = id & 0xff; + id >>= 8; + vendor[3] = '\0'; + vendor[2] = '@' + (id & 0x1f); + id >>= 5; + vendor[1] = '@' + (id & 0x1f); + id >>= 5; + vendor[0] = '@' + (id & 0x1f); + id >>= 5; + + sprintf(s, "%s%02X%02X", vendor, device, rev); +} + +static int configure_memory(const unsigned char *buf, + struct resource *mem_parent, + char *name) +{ + int len; + u_int8_t c; + int i; + struct resource *res; + + len=0; + + for (i=0;iname = name; + res->start = mem_parent->start + get_24(buf+len+2); + res->end = res->start + get_16(buf+len+5)*1024; + res->flags = IORESOURCE_MEM; + printk("memory %lx-%lx ", res->start, res->end); + result = request_resource(mem_parent, res); + if (result < 0) { + printk("\n" KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n"); + return result; + } + } + + len+=7; + + if (!(c & HPEE_MEMORY_MORE)) { + break; + } + } + + return len; +} + + +static int configure_irq(const unsigned char *buf) +{ + int len; + u_int8_t c; + int i; + + len=0; + + for (i=0;iname = board; + res->start = get_16(buf+len+1); + res->end = get_16(buf+len+1)+(c&HPEE_PORT_SIZE_MASK)+1; + res->flags = IORESOURCE_IO; + printk("ioports %lx-%lx ", res->start, res->end); + result = request_resource(io_parent, res); + if (result < 0) { + printk("\n" KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n"); + return result; + } + } + + len+=3; + if (!(c & HPEE_PORT_MORE)) { + break; + } + } + + return len; +} + + +/* byte 1 and 2 is the port number to write + * and at byte 3 the value to write starts. + * I assume that there are and- and or- masks + * here when HPEE_PORT_INIT_MASK is set but I have + * not yet encountered this. */ +static int configure_port_init(const unsigned char *buf) +{ + int len=0; + u_int8_t c; + + while (len 80) { + printk("\n" KERN_ERR "eisa_enumerator: type info field too long (%d, max is 80)\n", len); + } + + return 1+len; +} + +static int configure_function(const unsigned char *buf, int *more) +{ + /* the init field seems to be a two-byte field + * which is non-zero if there are an other function following + * I think it is the length of the function def + */ + *more = get_16(buf); + + return 2; +} + +static int parse_slot_config(int slot, + const unsigned char *buf, + struct eeprom_eisa_slot_info *es, + struct resource *io_parent, + struct resource *mem_parent) +{ + int res=0; + int function_len; + unsigned int pos=0; + unsigned int maxlen; + int num_func=0; + u_int8_t flags; + int p0; + + char *board; + int id_string_used=0; + + if (NULL == (board = kmalloc(8, GFP_KERNEL))) { + return -1; + } + print_eisa_id(board, es->eisa_slot_id); + printk(KERN_INFO "EISA slot %d: %s %s ", + slot, board, es->flags&HPEE_FLAG_BOARD_IS_ISA ? "ISA" : "EISA"); + + maxlen = es->config_data_length < HPEE_MAX_LENGTH ? + es->config_data_length : HPEE_MAX_LENGTH; + while ((pos < maxlen) && (num_func <= es->num_functions)) { + pos+=configure_function(buf+pos, &function_len); + + if (!function_len) { + break; + } + num_func++; + p0 = pos; + pos += configure_choise(buf+pos, &flags); + + if (flags & HPEE_FUNCTION_INFO_F_DISABLED) { + /* function disabled, skip silently */ + pos = p0 + function_len; + continue; + } + if (flags & HPEE_FUNCTION_INFO_CFG_FREE_FORM) { + /* I have no idea how to handle this */ + printk("function %d have free-form confgiuration, skipping ", + num_func); + pos = p0 + function_len; + continue; + } + + /* the ordering of the sections need + * more investigation. + * Currently I think that memory comaed before IRQ + * I assume the order is LSB to MSB in the + * info flags + * eg type, memory, irq, dma, port, HPEE_PORT_init + */ + + if (flags & HPEE_FUNCTION_INFO_HAVE_TYPE) { + pos += configure_type_string(buf+pos); + } + + if (flags & HPEE_FUNCTION_INFO_HAVE_MEMORY) { + id_string_used=1; + pos += configure_memory(buf+pos, mem_parent, board); + } + + if (flags & HPEE_FUNCTION_INFO_HAVE_IRQ) { + pos += configure_irq(buf+pos); + } + + if (flags & HPEE_FUNCTION_INFO_HAVE_DMA) { + pos += configure_dma(buf+pos); + } + + if (flags & HPEE_FUNCTION_INFO_HAVE_PORT) { + id_string_used=1; + pos += configure_port(buf+pos, io_parent, board); + } + + if (flags & HPEE_FUNCTION_INFO_HAVE_PORT_INIT) { + pos += configure_port_init(buf+pos); + } + + if (p0 + function_len < pos) { + printk("\n" KERN_ERR "eisa_enumerator: function %d length mis-match " + "got %d, expected %d\n", + num_func, pos-p0, function_len); + res=-1; + break; + } + pos = p0 + function_len; + } + printk("\n"); + if (!id_string_used) { + kfree(board); + } + + if (pos != es->config_data_length) { + printk(KERN_ERR "eisa_enumerator: config data length mis-match got %d, expected %d\n", + pos, es->config_data_length); + res=-1; + } + + if (num_func != es->num_functions) { + printk(KERN_ERR "eisa_enumerator: number of functions mis-match got %d, expected %d\n", + num_func, es->num_functions); + res=-2; + } + + return res; + +} + +static int init_slot(int slot, struct eeprom_eisa_slot_info *es) +{ + unsigned int id; + + char id_string[8]; + + if (!(es->slot_info&HPEE_SLOT_INFO_NO_READID)) { + /* try to read the id of the board in the slot */ + id = le32_to_cpu(inl(SLOT2PORT(slot)+EPI)); + + if (0xffffffff == id) { + /* this board is not here or it does not + * support readid + */ + printk(KERN_ERR "EISA slot %d a configured board was not detected (", + slot); + + print_eisa_id(id_string, es->eisa_slot_id); + printk(" expected %s)\n", id_string); + + return -1; + + } + if (es->eisa_slot_id != id) { + print_eisa_id(id_string, id); + printk(KERN_ERR "EISA slot %d id mis-match: got %s", + slot, id_string); + + print_eisa_id(id_string, es->eisa_slot_id); + printk(" expected %s \n", id_string); + + return -1; + + } + } + + /* now: we need to enable the board if + * it supports enabling and run through + * the port init sction if present + * and finally record any interrupt polarity + */ + if (es->slot_features & HPEE_SLOT_FEATURES_ENABLE) { + /* enable board */ + outb(0x01| inb(SLOT2PORT(slot)+EPI+4), + SLOT2PORT(slot)+EPI+4); + } + + return 0; +} + + +int eisa_enumerator(unsigned long eeprom_addr, + struct resource *io_parent, struct resource *mem_parent) +{ + int i; + struct eeprom_header *eh; + static char eeprom_buf[HPEE_MAX_LENGTH]; + + for (i=0; i < HPEE_MAX_LENGTH; i++) { + eeprom_buf[i] = gsc_readb(eeprom_addr+i); + } + + printk(KERN_INFO "Enumerating EISA bus\n"); + + eh = (struct eeprom_header*)(eeprom_buf); + for (i=0;inum_slots;i++) { + struct eeprom_eisa_slot_info *es; + + es = (struct eeprom_eisa_slot_info*) + (&eeprom_buf[HPEE_SLOT_INFO(i)]); + + if (-1==init_slot(i+1, es)) { + return -1; + + } + + if (es->config_data_offset < HPEE_MAX_LENGTH) { + if (parse_slot_config(i+1, &eeprom_buf[es->config_data_offset], + es, io_parent, mem_parent)) { + return -1; + } + } else { + printk (KERN_WARNING "EISA EEPROM offset 0x%x out of range\n",es->config_data_offset); + return -1; + } + } + return 0; +} + diff -Nru a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/gsc.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,205 @@ +/* + * Interrupt management for most GSC and related devices. + * + * (c) Copyright 1999 Alex deVries for The Puffin Group + * (c) Copyright 1999 Grant Grundler for Hewlett-Packard + * (c) Copyright 1999 Matthew Wilcox + * (c) Copyright 2000 Helge Deller + * (c) Copyright 2001 Matthew Wilcox for Hewlett-Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "gsc.h" + +#undef DEBUG + +#ifdef DEBUG +#define DEBPRINTK printk +#else +#define DEBPRINTK(x,...) +#endif + +int gsc_alloc_irq(struct gsc_irq *i) +{ + int irq = txn_alloc_irq(); + if (irq < 0) { + printk("cannot get irq\n"); + return irq; + } + + i->txn_addr = txn_alloc_addr(irq); + i->txn_data = txn_alloc_data(irq, GSC_EIM_WIDTH); + i->irq = irq; + + return irq; +} + +int gsc_claim_irq(struct gsc_irq *i, int irq) +{ + int c = irq; + + irq += IRQ_FROM_REGION(CPU_IRQ_REGION); /* virtualize the IRQ first */ + + irq = txn_claim_irq(irq); + if (irq < 0) { + printk("cannot claim irq %d\n", c); + return irq; + } + + i->txn_addr = txn_alloc_addr(irq); + i->txn_data = txn_alloc_data(irq, GSC_EIM_WIDTH); + i->irq = irq; + + return irq; +} + +EXPORT_SYMBOL(gsc_alloc_irq); +EXPORT_SYMBOL(gsc_claim_irq); + +/* IRQ bits must be numbered from Most Significant Bit */ +#define GSC_FIX_IRQ(x) (31-(x)) +#define GSC_MASK_IRQ(x) (1<<(GSC_FIX_IRQ(x))) + +/* Common interrupt demultiplexer used by Asp, Lasi & Wax. */ +void busdev_barked(int busdev_irq, void *dev, struct pt_regs *regs) +{ + unsigned long irq; + struct busdevice *busdev = (struct busdevice *) dev; + + /* + Don't need to protect OFFSET_IRR with spinlock since this is + the only place it's touched. + Protect busdev_region by disabling this region's interrupts, + modifying the region, and then re-enabling the region. + */ + + irq = gsc_readl(busdev->hpa+OFFSET_IRR); + if (irq == 0) { + printk(KERN_ERR "%s: barking without apparent reason.\n", busdev->name); + } else { + DEBPRINTK ("%s (0x%x) barked, mask=0x%x, irq=%d\n", + busdev->name, busdev->busdev_region->data.irqbase, + irq, GSC_FIX_IRQ(ffs(irq))+1 ); + + do_irq_mask(irq, busdev->busdev_region, regs); + } +} + +static void +busdev_disable_irq(void *irq_dev, int irq) +{ + /* Disable the IRQ line by clearing the bit in the IMR */ + u32 imr = gsc_readl(BUSDEV_DEV(irq_dev)->hpa+OFFSET_IMR); + imr &= ~(GSC_MASK_IRQ(irq)); + + DEBPRINTK( KERN_WARNING "%s(%p, %d) %s: IMR 0x%x\n", + __FUNCTION__, irq_dev, irq, BUSDEV_DEV(irq_dev)->name, imr); + + gsc_writel(imr, BUSDEV_DEV(irq_dev)->hpa+OFFSET_IMR); +} + + +static void +busdev_enable_irq(void *irq_dev, int irq) +{ + /* Enable the IRQ line by setting the bit in the IMR */ + unsigned long addr = BUSDEV_DEV(irq_dev)->hpa + OFFSET_IMR; + u32 imr = gsc_readl(addr); + imr |= GSC_MASK_IRQ(irq); + + DEBPRINTK (KERN_WARNING "%s(%p, %d) %s: IMR 0x%x\n", + __FUNCTION__, irq_dev, irq, BUSDEV_DEV(irq_dev)->name, imr); + + gsc_writel(imr, addr); +// gsc_writel(~0L, addr); + +/* FIXME: read IPR to make sure the IRQ isn't already pending. +** If so, we need to read IRR and manually call do_irq_mask(). +** This code should be shared with busdev_unmask_irq(). +*/ +} + +static void +busdev_mask_irq(void *irq_dev, int irq) +{ +/* FIXME: Clear the IMR bit in busdev for that IRQ */ +} + +static void +busdev_unmask_irq(void *irq_dev, int irq) +{ +/* FIXME: Read IPR. Set the IMR bit in busdev for that IRQ. + call do_irq_mask() if IPR is non-zero +*/ +} + +struct irq_region_ops busdev_irq_ops = { + disable_irq: busdev_disable_irq, + enable_irq: busdev_enable_irq, + mask_irq: busdev_mask_irq, + unmask_irq: busdev_unmask_irq +}; + + +int gsc_common_irqsetup(struct parisc_device *parent, struct busdevice *busdev) +{ + struct resource *res; + + busdev->gsc = parent; + + /* the IRQs we simulate */ + busdev->busdev_region = alloc_irq_region(32, &busdev_irq_ops, + busdev->name, busdev); + if (!busdev->busdev_region) + return -ENOMEM; + + /* allocate resource region */ + res = request_mem_region(busdev->hpa, 0x100000, busdev->name); + if (res) { + res->flags = IORESOURCE_MEM; /* do not mark it busy ! */ + } + +#if 0 + printk(KERN_WARNING "%s IRQ %d EIM 0x%x", busdev->name, + busdev->parent_irq, busdev->eim); + if (gsc_readl(busdev->hpa + OFFSET_IMR)) + printk(" IMR is non-zero! (0x%x)", + gsc_readl(busdev->hpa + OFFSET_IMR)); + printk("\n"); +#endif + + return 0; +} + +extern struct parisc_driver lasi_driver; +extern struct parisc_driver asp_driver; +extern struct parisc_driver wax_driver; + +void __init gsc_init(void) +{ +#ifdef CONFIG_GSC_LASI + register_parisc_driver(&lasi_driver); + register_parisc_driver(&asp_driver); +#endif +#ifdef CONFIG_GSC_WAX + register_parisc_driver(&wax_driver); +#endif +} diff -Nru a/drivers/parisc/gsc.h b/drivers/parisc/gsc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/gsc.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,45 @@ +/* + * drivers/parisc/gsc.h + * Declarations for functions in gsc.c + * Copyright (c) 2000-2002 Helge Deller, Matthew Wilcox + * + * Distributed under the terms of the GPL, version 2 + */ + +#include +#include + +#define OFFSET_IRR 0x0000 /* Interrupt request register */ +#define OFFSET_IMR 0x0004 /* Interrupt mask register */ +#define OFFSET_IPR 0x0008 /* Interrupt pending register */ +#define OFFSET_ICR 0x000C /* Interrupt control register */ +#define OFFSET_IAR 0x0010 /* Interrupt address register */ + +/* PA I/O Architected devices support at least 5 bits in the EIM register. */ +#define GSC_EIM_WIDTH 5 + +struct gsc_irq { + unsigned long txn_addr; /* IRQ "target" */ + int txn_data; /* HW "IRQ" */ + int irq; /* virtual IRQ */ +}; + +struct busdevice { + struct parisc_device *gsc; + unsigned long hpa; + char *name; + int version; + int type; + int parent_irq; + int eim; + struct irq_region *busdev_region; +}; + +/* short cut to keep the compiler happy */ +#define BUSDEV_DEV(x) ((struct busdevice *) (x)) + +int gsc_common_irqsetup(struct parisc_device *parent, struct busdevice *busdev); +extern int gsc_alloc_irq(struct gsc_irq *dev); /* dev needs an irq */ +extern int gsc_claim_irq(struct gsc_irq *dev, int irq); /* dev needs this irq */ + +void busdev_barked(int busdev_irq, void *dev, struct pt_regs *regs); diff -Nru a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/iosapic.c Mon Nov 4 14:31:01 2002 @@ -0,0 +1,1092 @@ +/* +** I/O Sapic Driver - PCI interrupt line support +** +** (c) Copyright 1999 Grant Grundler +** (c) Copyright 1999 Hewlett-Packard Company +** +** 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. +** +** The I/O sapic driver manages the Interrupt Redirection Table which is +** the control logic to convert PCI line based interrupts into a Message +** Signaled Interrupt (aka Transaction Based Interrupt, TBI). +** +** Acronyms +** -------- +** HPA Hard Physical Address (aka MMIO address) +** IRQ Interrupt ReQuest. Implies Line based interrupt. +** IRT Interrupt Routing Table (provided by PAT firmware) +** IRdT Interrupt Redirection Table. IRQ line to TXN ADDR/DATA +** table which is implemented in I/O SAPIC. +** ISR Interrupt Service Routine. aka Interrupt handler. +** MSI Message Signaled Interrupt. PCI 2.2 functionality. +** aka Transaction Based Interrupt (or TBI). +** PA Precision Architecture. HP's RISC architecture. +** RISC Reduced Instruction Set Computer. +** +** +** What's a Message Signalled Interrupt? +** ------------------------------------- +** MSI is a write transaction which targets a processor and is similar +** to a processor write to memory or MMIO. MSIs can be generated by I/O +** devices as well as processors and require *architecture* to work. +** +** PA only supports MSI. So I/O subsystems must either natively generate +** MSIs (e.g. GSC or HP-PB) or convert line based interrupts into MSIs +** (e.g. PCI and EISA). IA64 supports MSIs via a "local SAPIC" which +** acts on behalf of a processor. +** +** MSI allows any I/O device to interrupt any processor. This makes +** load balancing of the interrupt processing possible on an SMP platform. +** Interrupts are also ordered WRT to DMA data. It's possible on I/O +** coherent systems to completely eliminate PIO reads from the interrupt +** path. The device and driver must be designed and implemented to +** guarantee all DMA has been issued (issues about atomicity here) +** before the MSI is issued. I/O status can then safely be read from +** DMA'd data by the ISR. +** +** +** PA Firmware +** ----------- +** PA-RISC platforms have two fundementally different types of firmware. +** For PCI devices, "Legacy" PDC initializes the "INTERRUPT_LINE" register +** and BARs similar to a traditional PC BIOS. +** The newer "PAT" firmware supports PDC calls which return tables. +** PAT firmware only initializes PCI Console and Boot interface. +** With these tables, the OS can progam all other PCI devices. +** +** One such PAT PDC call returns the "Interrupt Routing Table" (IRT). +** The IRT maps each PCI slot's INTA-D "output" line to an I/O SAPIC +** input line. If the IRT is not available, this driver assumes +** INTERRUPT_LINE register has been programmed by firmware. The latter +** case also means online addition of PCI cards can NOT be supported +** even if HW support is present. +** +** All platforms with PAT firmware to date (Oct 1999) use one Interrupt +** Routing Table for the entire platform. +** +** Where's the iosapic? +** -------------------- +** I/O sapic is part of the "Core Electronics Complex". And on HP platforms +** it's integrated as part of the PCI bus adapter, "lba". So no bus walk +** will discover I/O Sapic. I/O Sapic driver learns about each device +** when lba driver advertises the presence of the I/O sapic by calling +** iosapic_register(). +** +** +** IRQ region notes +** ---------------- +** The data passed to iosapic_interrupt() is per IRQ line. +** Each IRQ line will get one txn_addr/data pair. Thus each IRQ region, +** will have several txn_addr/data pairs (up to 7 for current I/O SAPIC +** implementations). The IRQ region "sysdata" will NOT be directly passed +** to the interrupt handler like GSCtoPCI (dino.c). +** +** iosapic interrupt handler will NOT call do_irq_mask(). +** It doesn't need to read a bit mask to determine which IRQ line was pulled +** since it already knows based on vector_info passed to iosapic_interrupt(). +** +** One IRQ number represents both an IRQ line and a driver ISR. +** The I/O sapic driver can't manage shared IRQ lines because +** additional data besides the IRQ number must be passed via +** irq_region_ops. do_irq() and request_irq() must manage +** a sharing a bit in the mask. +** +** iosapic_interrupt() replaces do_irq_mask() and calls do_irq(). +** Which IRQ line was asserted is already known since each +** line has unique data associated with it. We could omit +** iosapic_interrupt() from the calling path if it did NOT need +** to write EOI. For unshared lines, it really doesn't. +** +** Unfortunately, can't optimize out EOI if IRQ line isn't "shared". +** N-class console "device" and some sort of heartbeat actually share +** one line though only one driver is registered......this was +** true for HP-UX at least. May not be true for parisc-linux. +** +** +** Overview of exported iosapic functions +** -------------------------------------- +** (caveat: code isn't finished yet - this is just the plan) +** +** iosapic_init: +** o initialize globals (lock, etc) +** o try to read IRT. Presence of IRT determines if this is +** a PAT platform or not. +** +** iosapic_register(): +** o create iosapic_info instance data structure +** o allocate vector_info array for this iosapic +** o initialize vector_info - read corresponding IRdT? +** +** iosapic_xlate_pin: (only called by fixup_irq for PAT platform) +** o intr_pin = read cfg (INTERRUPT_PIN); +** o if (device under PCI-PCI bridge) +** translate slot/pin +** +** iosapic_fixup_irq: +** o if PAT platform (IRT present) +** intr_pin = iosapic_xlate_pin(isi,pcidev): +** intr_line = find IRT entry(isi, PCI_SLOT(pcidev), intr_pin) +** save IRT entry into vector_info later +** write cfg INTERRUPT_LINE (with intr_line)? +** else +** intr_line = pcidev->irq +** IRT pointer = NULL +** endif +** o locate vector_info (needs: isi, intr_line) +** o allocate processor "irq" and get txn_addr/data +** o request_irq(processor_irq, iosapic_interrupt, vector_info,...) +** o pcidev->irq = isi->isi_region...base + intr_line; +** +** iosapic_interrupt: +** o call do_irq(vector->isi->irq_region, vector->irq_line, regs) +** o assume level triggered and write EOI +** +** iosapic_enable_irq: +** o clear any pending IRQ on that line +** o enable IRdT - call enable_irq(vector[line]->processor_irq) +** o write EOI in case line is already asserted. +** +** iosapic_disable_irq: +** o disable IRdT - call disable_irq(vector[line]->processor_irq) +** +** FIXME: mask/unmask +*/ + + +/* FIXME: determine which include files are really needed */ +#include +#include +#include +#include /* pci cfg accessor functions */ +#include +#include +#include +#include /* irqaction */ +#include /* irq_region support */ + +#include /* get in-line asm for swab */ +#include +#include +#include +#include +#include /* gsc_read/write functions */ +#ifdef CONFIG_SUPERIO +#include +#endif + +#include +#include "./iosapic_private.h" + +#define MODULE_NAME "iosapic" + +/* "local" compile flags */ +#undef PCI_BRIDGE_FUNCS +#undef DEBUG_IOSAPIC +#undef DEBUG_IOSAPIC_IRT + + +#ifdef DEBUG_IOSAPIC +static char assert_buf[128]; + +static int +assert_failed (char *a, char *f, int l) +{ + sprintf(assert_buf, + "ASSERT(%s) failed!\nline %d in %s\n", + a, /* assertion text */ + l, /* line number */ + f); /* file name */ + panic(assert_buf); + return 0; +} + +#undef ASSERT +#define ASSERT(EX) { if (!(EX)) assert_failed(# EX, __FILE__, __LINE__); } + +#define DBG(x...) printk(x) + +#else /* DEBUG_IOSAPIC */ + +#define DBG(x...) +#undef ASSERT +#define ASSERT(EX) + +#endif /* DEBUG_IOSAPIC */ + +#ifdef DEBUG_IOSAPIC_IRT +#define DBG_IRT(x...) printk(x) +#else +#define DBG_IRT(x...) +#endif + + +#define READ_U8(addr) gsc_readb(addr) +#define READ_U16(addr) le16_to_cpu(gsc_readw((u16 *) (addr))) +#define READ_U32(addr) le32_to_cpu(gsc_readl((u32 *) (addr))) +#define READ_REG16(addr) gsc_readw((u16 *) (addr)) +#define READ_REG32(addr) gsc_readl((u32 *) (addr)) +#define WRITE_U8(value, addr) gsc_writeb(value, addr) +#define WRITE_U16(value, addr) gsc_writew(cpu_to_le16(value), (u16 *) (addr)) +#define WRITE_U32(value, addr) gsc_writel(cpu_to_le32(value), (u32 *) (addr)) +#define WRITE_REG16(value, addr) gsc_writew(value, (u16 *) (addr)) +#define WRITE_REG32(value, addr) gsc_writel(value, (u32 *) (addr)) + + +#define IOSAPIC_REG_SELECT 0 +#define IOSAPIC_REG_WINDOW 0x10 +#define IOSAPIC_REG_EOI 0x40 + +#define IOSAPIC_REG_VERSION 0x1 + +#define IOSAPIC_IRDT_ENTRY(idx) (0x10+(idx)*2) +#define IOSAPIC_IRDT_ENTRY_HI(idx) (0x11+(idx)*2) + +/* +** FIXME: revisit which GFP flags we should really be using. +** GFP_KERNEL includes __GFP_WAIT flag and that may not +** be acceptable. Since this is boot time, we shouldn't have +** to wait ever and this code should (will?) never get called +** from the interrrupt context. +*/ +#define IOSAPIC_KALLOC(a_type, cnt) \ + (a_type *) kmalloc(sizeof(a_type)*(cnt), GFP_KERNEL) +#define IOSAPIC_FREE(addr, f_type, cnt) kfree((void *)addr) + + +#define IOSAPIC_LOCK(lck) spin_lock_irqsave(lck, irqflags) +#define IOSAPIC_UNLOCK(lck) spin_unlock_irqrestore(lck, irqflags) + + +#define IOSAPIC_VERSION_MASK 0x000000ff +#define IOSAPIC_VERSION_SHIFT 0x0 +#define IOSAPIC_VERSION(ver) \ + (int) ((ver & IOSAPIC_VERSION_MASK) >> IOSAPIC_VERSION_SHIFT) + +#define IOSAPIC_MAX_ENTRY_MASK 0x00ff0000 + +#define IOSAPIC_MAX_ENTRY_SHIFT 0x10 +#define IOSAPIC_IRDT_MAX_ENTRY(ver) \ + (int) ((ver&IOSAPIC_MAX_ENTRY_MASK) >> IOSAPIC_MAX_ENTRY_SHIFT) + +/* bits in the "low" I/O Sapic IRdT entry */ +#define IOSAPIC_IRDT_ENABLE 0x10000 +#define IOSAPIC_IRDT_PO_LOW 0x02000 +#define IOSAPIC_IRDT_LEVEL_TRIG 0x08000 +#define IOSAPIC_IRDT_MODE_LPRI 0x00100 + +/* bits in the "high" I/O Sapic IRdT entry */ +#define IOSAPIC_IRDT_ID_EID_SHIFT 0x10 + + + +#define IOSAPIC_EOI(eoi_addr, eoi_data) gsc_writel(eoi_data, eoi_addr) + +static struct iosapic_info *iosapic_list; +static spinlock_t iosapic_lock; +static int iosapic_count; + + +/* +** REVISIT: future platforms may have more than one IRT. +** If so, the following three fields form a structure which +** then be linked into a list. Names are chosen to make searching +** for them easy - not necessarily accurate (eg "cell"). +** +** Alternative: iosapic_info could point to the IRT it's in. +** iosapic_register() could search a list of IRT's. +*/ +static struct irt_entry *irt_cell; +static size_t irt_num_entry; + + + +/* +** iosapic_load_irt +** +** The "Get PCI INT Routing Table Size" option returns the number of +** entries in the PCI interrupt routing table for the cell specified +** in the cell_number argument. The cell number must be for a cell +** within the caller's protection domain. +** +** The "Get PCI INT Routing Table" option returns, for the cell +** specified in the cell_number argument, the PCI interrupt routing +** table in the caller allocated memory pointed to by mem_addr. +** We assume the IRT only contains entries for I/O SAPIC and +** calculate the size based on the size of I/O sapic entries. +** +** The PCI interrupt routing table entry format is derived from the +** IA64 SAL Specification 2.4. The PCI interrupt routing table defines +** the routing of PCI interrupt signals between the PCI device output +** "pins" and the IO SAPICs' input "lines" (including core I/O PCI +** devices). This table does NOT include information for devices/slots +** behind PCI to PCI bridges. See PCI to PCI Bridge Architecture Spec. +** for the architected method of routing of IRQ's behind PPB's. +*/ + + +static int __init /* return number of entries as success/fail flag */ +iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt) +{ + long status; /* PDC return value status */ + struct irt_entry *table; /* start of interrupt routing tbl */ + unsigned long num_entries = 0UL; + + ASSERT(NULL != irt); + + if (is_pdc_pat()) { + + /* Use pat pdc routine to get interrupt routing table size */ + DBG("calling get_irt_size (cell %ld)\n", cell_num); + status = pdc_pat_get_irt_size(&num_entries, cell_num); + DBG("get_irt_size: %ld\n", status); + + ASSERT(status == PDC_OK); + + /* save the number of entries in the table */ + ASSERT(0UL != num_entries); + + /* + ** allocate memory for interrupt routing table + ** This interface isn't really right. We are assuming + ** the contents of the table are exclusively + ** for I/O sapic devices. + */ + table = IOSAPIC_KALLOC(struct irt_entry, num_entries); + if (table == NULL) { + printk(KERN_WARNING MODULE_NAME ": read_irt : can not alloc mem for IRT\n"); + return 0; + } + + /* get PCI INT routing table */ + status = pdc_pat_get_irt(table, cell_num); + DBG("pdc_pat_get_irt: %ld\n", status); + ASSERT(status == PDC_OK); + } else { + /* + ** C3000/J5000 (and similar) platforms with Sprockets PDC + ** will return exactly one IRT for all iosapics. + ** So if we have one, don't need to get it again. + */ + if (NULL != irt_cell) + return 0; + + /* Should be using the Elroy's HPA, but it's ignored anyway */ + status = pdc_pci_irt_size(&num_entries, 0); + DBG("pdc_pci_irt_size: %ld\n", status); + + if (PDC_OK != status) { + /* Not a "legacy" system with I/O SAPIC either */ + return 0; + } + + ASSERT(0UL != num_entries); + + table = IOSAPIC_KALLOC(struct irt_entry, num_entries); + if (table == NULL) { + printk(KERN_WARNING MODULE_NAME ": read_irt : can not alloc mem for IRT\n"); + return 0; + } + + /* HPA ignored by this call too. */ + status = pdc_pci_irt(num_entries, 0, table); + ASSERT(PDC_OK == status); + } + + /* return interrupt table address */ + *irt = table; + +#ifdef DEBUG_IOSAPIC_IRT +{ + struct irt_entry *p = table; + int i; + + printk(KERN_DEBUG MODULE_NAME " Interrupt Routing Table (cell %ld)\n", cell_num); + printk(KERN_DEBUG MODULE_NAME " start = 0x%p num_entries %ld entry_size %d\n", + table, + num_entries, + (int) sizeof(struct irt_entry)); + + for (i = 0 ; i < num_entries ; i++, p++) { + printk(KERN_DEBUG MODULE_NAME " %02x %02x %02x %02x %02x %02x %02x %02x %08x%08x\n", + p->entry_type, p->entry_length, p->interrupt_type, + p->polarity_trigger, p->src_bus_irq_devno, p->src_bus_id, + p->src_seg_id, p->dest_iosapic_intin, + ((u32 *) p)[2], + ((u32 *) p)[3] + ); + } +} +#endif /* DEBUG_IOSAPIC_IRT */ + + return num_entries; +} + + + +void __init +iosapic_init(void) +{ + unsigned long cell = 0; + + /* init global data */ + iosapic_lock = SPIN_LOCK_UNLOCKED; + iosapic_list = (struct iosapic_info *) NULL; + iosapic_count = 0; + + DBG("iosapic_init()\n"); + +#ifdef __LP64__ + if (is_pdc_pat()) { + int status; + struct pdc_pat_cell_num cell_info; + + status = pdc_pat_cell_get_number(&cell_info); + if (status == PDC_OK) { + cell = cell_info.cell_num; + } + } +#endif + + /* + ** get IRT for this cell. + */ + irt_num_entry = iosapic_load_irt(cell, &irt_cell); + if (0 == irt_num_entry) + irt_cell = NULL; /* old PDC w/o iosapic */ +} + + +/* +** Return the IRT entry in case we need to look something else up. +*/ +static struct irt_entry * +irt_find_irqline(struct iosapic_info *isi, u8 slot, u8 intr_pin) +{ + struct irt_entry *i = irt_cell; + int cnt; /* track how many entries we've looked at */ + u8 irq_devno = (slot << IRT_DEV_SHIFT) | (intr_pin-1); + + DBG_IRT("irt_find_irqline() SLOT %d pin %d\n", slot, intr_pin); + + for (cnt=0; cnt < irt_num_entry; cnt++, i++) { + + /* + ** Validate: entry_type, entry_length, interrupt_type + ** + ** Difference between validate vs compare is the former + ** should print debug info and is not expected to "fail" + ** on current platforms. + */ + if (i->entry_type != IRT_IOSAPIC_TYPE) { + DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d type %d\n", i, cnt, i->entry_type); + continue; + } + + if (i->entry_length != IRT_IOSAPIC_LENGTH) { + DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d length %d\n", i, cnt, i->entry_length); + continue; + } + + if (i->interrupt_type != IRT_VECTORED_INTR) { + DBG_IRT(KERN_WARNING MODULE_NAME ":find_irqline(0x%p): skipping entry %d interrupt_type %d\n", i, cnt, i->interrupt_type); + continue; + } + + /* + ** Compare: dest_iosapic_addr, src_bus_irq_devno + */ + if (i->dest_iosapic_addr != (u64) ((long) isi->isi_hpa)) + continue; + + if ((i->src_bus_irq_devno & IRT_IRQ_DEVNO_MASK) != irq_devno) + continue; + + /* + ** Ignore: src_bus_id and rc_seg_id correlate with + ** iosapic_info->isi_hpa on HP platforms. + ** If needed, pass in "PFA" (aka config space addr) + ** instead of slot. + */ + + /* Found it! */ + return i; + } + + printk(KERN_WARNING MODULE_NAME ": 0x%lx : no IRT entry for slot %d, pin %d\n", + isi->isi_hpa, slot, intr_pin); + return NULL; +} + + +/* +** xlate_pin() supports the skewing of IRQ lines done by subsidiary bridges. +** Legacy PDC already does this translation for us and stores it in INTR_LINE. +** +** PAT PDC needs to basically do what legacy PDC does: +** o read PIN +** o adjust PIN in case device is "behind" a PPB +** (eg 4-port 100BT and SCSI/LAN "Combo Card") +** o convert slot/pin to I/O SAPIC input line. +** +** HP platforms only support: +** o one level of skewing for any number of PPBs +** o only support PCI-PCI Bridges. +*/ +static struct irt_entry * +iosapic_xlate_pin(struct iosapic_info *isi, struct pci_dev *pcidev) +{ + u8 intr_pin, intr_slot; + + pci_read_config_byte(pcidev, PCI_INTERRUPT_PIN, &intr_pin); + + DBG_IRT("iosapic_xlate_pin() SLOT %d pin %d\n", + PCI_SLOT(pcidev->devfn), intr_pin); + + if (0 == intr_pin) { + /* The device does NOT support/use IRQ lines. */ + return NULL; + } + + /* Check if pcidev behind a PPB */ + if (NULL != pcidev->bus->self) { + /* Convert pcidev INTR_PIN into something we + ** can lookup in the IRT. + */ +#ifdef PCI_BRIDGE_FUNCS + /* + ** Proposal #1: + ** + ** call implementation specific translation function + ** This is architecturally "cleaner". HP-UX doesn't + ** support other secondary bus types (eg. E/ISA) directly. + ** May be needed for other processor (eg IA64) architectures + ** or by some ambitous soul who wants to watch TV. + */ + if (pci_bridge_funcs->xlate_intr_line) { + intr_pin = pci_bridge_funcs->xlate_intr_line(pcidev); + } +#else /* PCI_BRIDGE_FUNCS */ + struct pci_bus *p = pcidev->bus; + /* + ** Proposal #2: + ** The "pin" is skewed ((pin + dev - 1) % 4). + ** + ** This isn't very clean since I/O SAPIC must assume: + ** - all platforms only have PCI busses. + ** - only PCI-PCI bridge (eg not PCI-EISA, PCI-PCMCIA) + ** - IRQ routing is only skewed once regardless of + ** the number of PPB's between iosapic and device. + ** (Bit3 expansion chassis follows this rule) + ** + ** Advantage is it's really easy to implement. + */ + intr_pin = ((intr_pin-1)+PCI_SLOT(pcidev->devfn)) % 4; + intr_pin++; /* convert back to INTA-D (1-4) */ +#endif /* PCI_BRIDGE_FUNCS */ + + /* + ** Locate the host slot the PPB nearest the Host bus + ** adapter. + */ + while (NULL != p->parent->self) + p = p->parent; + + intr_slot = PCI_SLOT(p->self->devfn); + } else { + intr_slot = PCI_SLOT(pcidev->devfn); + } + DBG_IRT("iosapic_xlate_pin: bus %d slot %d pin %d\n", + pcidev->bus->secondary, intr_slot, intr_pin); + + return irt_find_irqline(isi, intr_slot, intr_pin); +} + + +static void +iosapic_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct vector_info *vi = (struct vector_info *)dev_id; + extern void do_irq(struct irqaction *a, int i, struct pt_regs *p); + int irq_num = vi->vi_ios->isi_region->data.irqbase + vi->vi_irqline; + + DBG("iosapic_interrupt(): irq %d line %d eoi %p\n", + irq, vi->vi_irqline, vi->vi_eoi_addr); + +/* FIXME: Need to mask/unmask? processor IRQ is already masked... */ + do_irq(&vi->vi_ios->isi_region->action[vi->vi_irqline], irq_num, regs); + + /* + ** PCI only supports level triggered in order to share IRQ lines. + ** I/O SAPIC must always issue EOI. + */ + IOSAPIC_EOI(vi->vi_eoi_addr, vi->vi_eoi_data); +} + + +int +iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev) +{ + struct iosapic_info *isi = (struct iosapic_info *)isi_obj; + struct irt_entry *irte = NULL; /* only used if PAT PDC */ + struct vector_info *vi; + int isi_line; /* line used by device */ + int tmp; + int return_irq; +#ifdef CONFIG_SUPERIO + int superio_irq = -1; +#endif + + if (NULL == isi) { + printk(KERN_WARNING MODULE_NAME ": hpa not registered for %s\n", + pcidev->name); + return(-1); + } + +#ifdef CONFIG_SUPERIO + if (is_superio_device(pcidev)) { + superio_irq = superio_fixup_irq(pcidev); + if (superio_irq == -1) + return(-1); + + if (PCI_FUNC(pcidev->devfn) != SUPERIO_USB_FN) { + + /* + * SuperIO USB controller has an irt entry. + * Only let the USB controller hookup the rest + * of the interrupt routing when it comes through. + * Note that interrupts for all three functions + * actually come through the PIC's on function 1! + */ + + pcidev->irq = superio_irq; + return superio_irq; + } + } +#endif /* CONFIG_SUPERIO */ + + /* lookup IRT entry for isi/slot/pin set */ + irte = iosapic_xlate_pin(isi, pcidev); + if (NULL == irte) { + return(-1); + } + DBG_IRT("iosapic_fixup_irq(): irte %p %x %x %x %x %x %x %x %x\n", + irte, + irte->entry_type, + irte->entry_length, + irte->polarity_trigger, + irte->src_bus_irq_devno, + irte->src_bus_id, + irte->src_seg_id, + irte->dest_iosapic_intin, + (u32) irte->dest_iosapic_addr); + isi_line = irte->dest_iosapic_intin; + + /* get vector info for this input line */ + ASSERT(NULL != isi->isi_vector); + vi = &(isi->isi_vector[isi_line]); + DBG_IRT("iosapic_fixup_irq: line %d vi 0x%p\n", isi_line, vi); + vi->vi_irte = irte; + + /* Allocate processor IRQ */ + vi->vi_txn_irq = txn_alloc_irq(); + +/* XXX/FIXME The txn_alloc_irq() code and related code should be moved +** to enable_irq(). That way we only allocate processor IRQ bits +** for devices that actually have drivers claiming them. +** Right now we assign an IRQ to every PCI device present regardless +** of whether it's used or not. +*/ + if (vi->vi_txn_irq < 0) + panic("I/O sapic: couldn't get TXN IRQ\n"); + + /* enable_irq() will use txn_* to program IRdT */ + vi->vi_txn_addr = txn_alloc_addr(vi->vi_txn_irq); + vi->vi_txn_data = txn_alloc_data(vi->vi_txn_irq, 8); + ASSERT(vi->vi_txn_data < 256); /* matches 8 above */ + + tmp = request_irq(vi->vi_txn_irq, iosapic_interrupt, 0, + vi->vi_name, vi); + ASSERT(tmp == 0); + + vi->vi_eoi_addr = (u32 *) (isi->isi_hpa + IOSAPIC_REG_EOI); + vi->vi_eoi_data = cpu_to_le32(vi->vi_irqline); + + ASSERT(NULL != isi->isi_region); + /* pcidev->irq still needs to be virtualized. */ + + return_irq = isi->isi_region->data.irqbase + isi_line; + +#ifdef CONFIG_SUPERIO + if (superio_irq != -1) { + superio_inform_irq(return_irq); + return_irq = superio_irq; + } +#endif + pcidev->irq = return_irq; + + DBG_IRT("iosapic_fixup_irq() %d:%d %x %x line %d irq %d\n", + PCI_SLOT(pcidev->devfn), + PCI_FUNC(pcidev->devfn), pcidev->vendor, pcidev->device, isi_line, return_irq); + + return return_irq; +} + + +static void +iosapic_rd_irt_entry(struct vector_info *vi , u32 *dp0, u32 *dp1) +{ + struct iosapic_info *isp = vi->vi_ios; + u8 idx = vi->vi_irqline; + + /* point the window register to the lower word */ + WRITE_U32(IOSAPIC_IRDT_ENTRY(idx), isp->isi_hpa+IOSAPIC_REG_SELECT); + *dp0 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); + + /* point the window register to the higher word */ + WRITE_U32(IOSAPIC_IRDT_ENTRY_HI(idx), isp->isi_hpa+IOSAPIC_REG_SELECT); + *dp1 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); +} + + +static void +iosapic_wr_irt_entry(struct vector_info *vi, u32 dp0, u32 dp1) +{ + struct iosapic_info *isp = vi->vi_ios; + + ASSERT(NULL != isp); + ASSERT(0 != isp->isi_hpa); + DBG_IRT("iosapic_wr_irt_entry(): irq %d hpa %p WINDOW %p 0x%x 0x%x\n", + vi->vi_irqline, + isp->isi_hpa, isp->isi_hpa+IOSAPIC_REG_WINDOW, + dp0, dp1); + + /* point the window register to the lower word */ + WRITE_U32(IOSAPIC_IRDT_ENTRY(vi->vi_irqline), isp->isi_hpa+IOSAPIC_REG_SELECT); + WRITE_U32( dp0, isp->isi_hpa+IOSAPIC_REG_WINDOW); + + /* Read the window register to flush the writes down to HW */ + dp0 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); + + /* point the window register to the higher word */ + WRITE_U32(IOSAPIC_IRDT_ENTRY_HI(vi->vi_irqline), isp->isi_hpa+IOSAPIC_REG_SELECT); + WRITE_U32( dp1, isp->isi_hpa+IOSAPIC_REG_WINDOW); + + /* Read the window register to flush the writes down to HW */ + dp1 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); +} + + +/* +** set_irt prepares the data (dp0, dp1) according to the vector_info +** and target cpu (id_eid). dp0/dp1 are then used to program I/O SAPIC +** IRdT for the given "vector" (aka IRQ line). +*/ +static void +iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1) +{ + u32 mode = 0; + struct irt_entry *p = vi->vi_irte; + ASSERT(NULL != vi->vi_irte); + + if ((p->polarity_trigger & IRT_PO_MASK) == IRT_ACTIVE_LO) + mode |= IOSAPIC_IRDT_PO_LOW; + + if (((p->polarity_trigger >> IRT_EL_SHIFT) & IRT_EL_MASK) == IRT_LEVEL_TRIG) + mode |= IOSAPIC_IRDT_LEVEL_TRIG; + + /* + ** IA64 REVISIT + ** PA doesn't support EXTINT or LPRIO bits. + */ + + ASSERT(vi->vi_txn_data); + *dp0 = mode | (u32) vi->vi_txn_data; + + /* + ** Extracting id_eid isn't a real clean way of getting it. + ** But the encoding is the same for both PA and IA64 platforms. + */ + if (is_pdc_pat()) { + /* + ** PAT PDC just hands it to us "right". + ** vi_txn_addr comes from cpu_data[x].txn_addr. + */ + *dp1 = (u32) (vi->vi_txn_addr); + } else { + /* + ** eg if base_addr == 0xfffa0000), + ** we want to get 0xa0ff0000. + ** + ** eid 0x0ff00000 -> 0x00ff0000 + ** id 0x000ff000 -> 0xff000000 + */ + *dp1 = (((u32)vi->vi_txn_addr & 0x0ff00000) >> 4) | + (((u32)vi->vi_txn_addr & 0x000ff000) << 12); + } + DBG_IRT("iosapic_set_irt_data(): 0x%x 0x%x\n", *dp0, *dp1); +} + + +static void +iosapic_disable_irq(void *irq_dev, int irq) +{ + ulong irqflags; + struct vector_info *vi = &(((struct vector_info *) irq_dev)[irq]); + u32 d0, d1; + + ASSERT(NULL != vi); + + IOSAPIC_LOCK(&iosapic_lock); + +#ifdef REVISIT_DESIGN_ISSUE +/* +** XXX/FIXME + +disable_irq()/enable_irq(): drawback of using IRQ as a "handle" + +Current disable_irq interface only allows the irq_region support routines +to manage sharing of "irq" objects. The problem is the disable_irq() +interface specifies which IRQ line needs to be disabled but does not +identify the particular ISR which needs to be disabled. IO sapic +(and similar code in Dino) can only support one handler per IRQ +since they don't further encode the meaning of the IRQ number. +irq_region support has to hide it's implementation of "shared IRQ" +behind a function call. + +Encoding the IRQ would be possible by I/O SAPIC but makes life really +complicated for the IRQ handler and not help performance. + +Need more info on how Linux supports shared IRQ lines on a PC. +*/ +#endif /* REVISIT_DESIGN_ISSUE */ + + iosapic_rd_irt_entry(vi, &d0, &d1); + d0 |= IOSAPIC_IRDT_ENABLE; + iosapic_wr_irt_entry(vi, d0, d1); + + IOSAPIC_UNLOCK(&iosapic_lock); + + /* disable ISR for parent */ + disable_irq(vi->vi_txn_irq); +} + + +static void +iosapic_enable_irq(void *dev, int irq) +{ + struct vector_info *vi = &(((struct vector_info *) dev)[irq]); + u32 d0, d1; + + ASSERT(NULL != vi); + ASSERT(NULL != vi->vi_irte); + + /* data is initialized by fixup_irq */ + ASSERT(0 < vi->vi_txn_irq); + ASSERT(0UL != vi->vi_txn_data); + + iosapic_set_irt_data(vi, &d0, &d1); + iosapic_wr_irt_entry(vi, d0, d1); + + +#ifdef DEBUG_IOSAPIC_IRT +{ + u32 *t = (u32 *) ((ulong) vi->vi_eoi_addr & ~0xffUL); + printk("iosapic_enable_irq(): regs %p", vi->vi_eoi_addr); + while (t < vi->vi_eoi_addr) printk(" %x", READ_U32(t++)); + printk("\n"); +} + +printk("iosapic_enable_irq(): sel "); +{ + struct iosapic_info *isp = vi->vi_ios; + + for (d0=0x10; d0<0x1e; d0++) { + /* point the window register to the lower word */ + WRITE_U32(d0, isp->isi_hpa+IOSAPIC_REG_SELECT); + + /* read the word */ + d1 = READ_U32(isp->isi_hpa+IOSAPIC_REG_WINDOW); + printk(" %x", d1); + } +} +printk("\n"); +#endif + + /* + ** KLUGE: IRQ should not be asserted when Drivers enabling their IRQ. + ** PCI supports level triggered in order to share IRQ lines. + ** + ** Issueing I/O SAPIC an EOI causes an interrupt iff IRQ line is + ** asserted. + */ + IOSAPIC_EOI(vi->vi_eoi_addr, vi->vi_eoi_data); +} + + +static void +iosapic_mask_irq(void *dev, int irq) +{ + BUG(); +} + + +static void +iosapic_unmask_irq(void *dev, int irq) +{ + BUG(); +} + + +static struct irq_region_ops iosapic_irq_ops = { + disable_irq: iosapic_disable_irq, + enable_irq: iosapic_enable_irq, + mask_irq: iosapic_mask_irq, + unmask_irq: iosapic_unmask_irq +}; + + +/* +** squirrel away the I/O Sapic Version +*/ +static unsigned int +iosapic_rd_version(struct iosapic_info *isi) +{ + ASSERT(isi); + ASSERT(isi->isi_hpa); + + /* point window to the version register */ + WRITE_U32(IOSAPIC_REG_VERSION, isi->isi_hpa+IOSAPIC_REG_SELECT); + + /* now read the version register */ + return (READ_U32(isi->isi_hpa+IOSAPIC_REG_WINDOW)); +} + + +/* +** iosapic_register() is called by "drivers" with an integrated I/O SAPIC. +** Caller must be certain they have an I/O SAPIC and know its MMIO address. +** +** o allocate iosapic_info and add it to the list +** o read iosapic version and squirrel that away +** o read size of IRdT. +** o allocate and initialize isi_vector[] +** o allocate isi_region (registers region handlers) +*/ +void * +iosapic_register(unsigned long hpa) +{ + struct iosapic_info *isi = NULL; + struct irt_entry *irte = irt_cell; + struct vector_info *vip; + int cnt; /* track how many entries we've looked at */ + + /* + ** Astro based platforms can't support PCI OLARD if they + ** implement the legacy PDC (not PAT). Though Legacy PDC + ** supports an IRT, LBA's with no device under them + ** are *not* listed in the IRT. + ** Search the IRT and ignore iosapic's which aren't + ** in the IRT. + */ + ASSERT(NULL != irte); /* always have built-in devices */ + for (cnt=0; cnt < irt_num_entry; cnt++, irte++) { + ASSERT(IRT_IOSAPIC_TYPE == irte->entry_type); + /* + ** We need sign extension of the hpa on 32-bit kernels. + ** The address in the IRT is *always* 64 bit and really + ** is an unsigned quantity (like all physical addresses). + */ + if (irte->dest_iosapic_addr == (s64) ((long) hpa)) + break; + } + + if (cnt >= irt_num_entry) + return (NULL); + + if ((isi = IOSAPIC_KALLOC(struct iosapic_info, 1)) == NULL) { + BUG(); + return (NULL); + } + + memset(isi, 0, sizeof(struct iosapic_info)); + + isi->isi_hpa = hpa; + isi->isi_version = iosapic_rd_version(isi); + isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1; + + vip = isi->isi_vector = + IOSAPIC_KALLOC(struct vector_info, isi->isi_num_vectors); + + if (vip == NULL) { + IOSAPIC_FREE(isi, struct iosapic_info, 1); + return (NULL); + } + + memset(vip, 0, sizeof(struct vector_info) * isi->isi_num_vectors); + sprintf(isi->isi_name, "IO-SAPIC%02d", iosapic_count++); + + /* + ** Initialize vector array + */ + for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) { + vip->vi_irqline = (unsigned char) cnt; + vip->vi_ios = isi; + sprintf(vip->vi_name, "%s-L%d", isi->isi_name, cnt); + } + + isi->isi_region = alloc_irq_region(isi->isi_num_vectors, + &iosapic_irq_ops, isi->isi_name, + (void *) isi->isi_vector); + + ASSERT(NULL != isi->isi_region); + return ((void *) isi); +} + + +#ifdef DEBUG_IOSAPIC + +static void +iosapic_prt_irt(void *irt, long num_entry) +{ + unsigned int i, *irp = (unsigned int *) irt; + + ASSERT(NULL != irt); + + printk(KERN_DEBUG MODULE_NAME ": Interrupt Routing Table (%lx entries)\n", num_entry); + + for (i=0; ivi_irqline, vi); + printk(KERN_DEBUG "\t\tvi_status: %.4x\n", vi->vi_status); + printk(KERN_DEBUG "\t\tvi_txn_irq: %d\n", vi->vi_txn_irq); + printk(KERN_DEBUG "\t\tvi_txn_addr: %lx\n", vi->vi_txn_addr); + printk(KERN_DEBUG "\t\tvi_txn_data: %lx\n", vi->vi_txn_data); + printk(KERN_DEBUG "\t\tvi_eoi_addr: %p\n", vi->vi_eoi_addr); + printk(KERN_DEBUG "\t\tvi_eoi_data: %x\n", vi->vi_eoi_data); +} + + +static void +iosapic_prt_isi(struct iosapic_info *isi) +{ + ASSERT(NULL != isi); + printk(KERN_DEBUG MODULE_NAME ": io_sapic_info at %p\n", isi); + printk(KERN_DEBUG "\t\tisi_hpa: %lx\n", isi->isi_hpa); + printk(KERN_DEBUG "\t\tisi_status: %x\n", isi->isi_status); + printk(KERN_DEBUG "\t\tisi_version: %x\n", isi->isi_version); + printk(KERN_DEBUG "\t\tisi_vector: %p\n", isi->isi_vector); +} +#endif /* DEBUG_IOSAPIC */ diff -Nru a/drivers/parisc/iosapic_private.h b/drivers/parisc/iosapic_private.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/iosapic_private.h Mon Nov 4 14:31:01 2002 @@ -0,0 +1,168 @@ +/* +** This file is private to iosapic driver. +** If stuff needs to be used by another driver, move it to a common file. +** +** WARNING: fields most data structures here are ordered to make sure +** they pack nicely for 64-bit compilation. (ie sizeof(long) == 8) +*/ + + +/* +** Interrupt Routing Stuff +** ----------------------- +** The interrupt routing table consists of entries derived from +** MP Specification Draft 1.5. There is one interrupt routing +** table per cell. N- and L-class consist of a single cell. +*/ +struct irt_entry { + + /* Entry Type 139 identifies an I/O SAPIC interrupt entry */ + u8 entry_type; + + /* Entry Length 16 indicates entry is 16 bytes long */ + u8 entry_length; + + /* + ** Interrupt Type of 0 indicates a vectored interrupt, + ** all other values are reserved + */ + u8 interrupt_type; + + /* + ** PO and EL + ** Polarity of SAPIC I/O input signals: + ** 00 = Reserved + ** 01 = Active high + ** 10 = Reserved + ** 11 = Active low + ** Trigger mode of SAPIC I/O input signals: + ** 00 = Reserved + ** 01 = Edge-triggered + ** 10 = Reserved + ** 11 = Level-triggered + */ + u8 polarity_trigger; + + /* + ** IRQ and DEVNO + ** irq identifies PCI interrupt signal where + ** 0x0 corresponds to INT_A#, + ** 0x1 corresponds to INT_B#, + ** 0x2 corresponds to INT_C# + ** 0x3 corresponds to INT_D# + ** PCI device number where interrupt originates + */ + u8 src_bus_irq_devno; + + /* Source Bus ID identifies the bus where interrupt signal comes from */ + u8 src_bus_id; + + /* + ** Segment ID is unique across a protection domain and + ** identifies a segment of PCI buses (reserved in + ** MP Specification Draft 1.5) + */ + u8 src_seg_id; + + /* + ** Destination I/O SAPIC INTIN# identifies the INTIN n pin + ** to which the signal is connected + */ + u8 dest_iosapic_intin; + + /* + ** Destination I/O SAPIC Address identifies the I/O SAPIC + ** to which the signal is connected + */ + u64 dest_iosapic_addr; +}; + +#define IRT_IOSAPIC_TYPE 139 +#define IRT_IOSAPIC_LENGTH 16 + +#define IRT_VECTORED_INTR 0 + +#define IRT_PO_MASK 0x3 +#define IRT_ACTIVE_HI 1 +#define IRT_ACTIVE_LO 3 + +#define IRT_EL_MASK 0x3 +#define IRT_EL_SHIFT 2 +#define IRT_EDGE_TRIG 1 +#define IRT_LEVEL_TRIG 3 + +#define IRT_IRQ_MASK 0x3 +#define IRT_DEV_MASK 0x1f +#define IRT_DEV_SHIFT 2 + +#define IRT_IRQ_DEVNO_MASK ((IRT_DEV_MASK << IRT_DEV_SHIFT) | IRT_IRQ_MASK) + +#ifdef SUPPORT_MULTI_CELL +struct iosapic_irt { + struct iosapic_irt *irt_next; /* next routing table */ + struct irt_entry *irt_base; /* intr routing table address */ + size_t irte_count; /* number of entries in the table */ + size_t irte_size; /* size (bytes) of each entry */ +}; +#endif + +struct vector_info { + struct iosapic_info *vi_ios; /* I/O SAPIC this vector is on */ + struct irt_entry *vi_irte; /* IRT entry */ + u32 *vi_eoi_addr; /* precalculate EOI reg address */ + u32 vi_eoi_data; /* IA64: ? PA: swapped txn_data */ + int vi_txn_irq; /* virtual IRQ number for processor */ + ulong vi_txn_addr; /* IA64: id_eid PA: partial HPA */ + ulong vi_txn_data; /* IA64: vector PA: EIR bit */ + u8 vi_status; /* status/flags */ + u8 vi_irqline; /* INTINn(IRQ) */ + char vi_name[32]; /* user visible identity */ +}; + + +struct iosapic_info { + struct iosapic_info *isi_next; /* list of I/O SAPIC */ + unsigned long isi_hpa; /* physical base address */ + struct irq_region *isi_region; /* each I/O SAPIC is one region */ + struct vector_info *isi_vector; /* IRdT (IRQ line) array */ + int isi_num_vectors; /* size of IRdT array */ + int isi_status; /* status/flags */ + unsigned int isi_version; /* DEBUG: data fr version reg */ + /* round up to next cacheline */ + char isi_name[20]; /* identify region for users */ +}; + + + +#ifdef __IA64__ +/* +** PA risc does NOT have any local sapics. IA64 does. +** PIB (Processor Interrupt Block) is handled by Astro or Dew (Stretch CEC). +** +** PA: Get id_eid from IRT and hardcode PIB to 0xfeeNNNN0 +** Emulate the data on PAT platforms. +*/ +struct local_sapic_info { + struct local_sapic_info *lsi_next; /* point to next CPU info */ + int *lsi_cpu_id; /* point to logical CPU id */ + unsigned long *lsi_id_eid; /* point to IA-64 CPU id */ + int *lsi_status; /* point to CPU status */ + void *lsi_private; /* point to special info */ +}; + +/* +** "root" data structure which ties everything together. +** Should always be able to start with sapic_root and locate +** the desired information. +*/ +struct sapic_info { + struct sapic_info *si_next; /* info is per cell */ + int si_cellid; /* cell id */ + unsigned int si_status; /* status */ + char *si_pib_base; /* intr blk base address */ + local_sapic_info_t *si_local_info; + io_sapic_info_t *si_io_info; + extint_info_t *si_extint_info;/* External Intr info */ +}; +#endif + diff -Nru a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/lasi.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,245 @@ +/* + * LASI Device Driver + * + * (c) Copyright 1999 Red Hat Software + * Portions (c) Copyright 1999 The Puffin Group Inc. + * Portions (c) Copyright 1999 Hewlett-Packard + * + * 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. + * + * by Alan Cox and + * Alex deVries + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "gsc.h" + + +#define LASI_VER 0xC008 /* LASI Version */ + +#define LASI_IO_CONF 0x7FFFE /* LASI primary configuration register */ +#define LASI_IO_CONF2 0x7FFFF /* LASI secondary configuration register */ + +static int lasi_choose_irq(struct parisc_device *dev) +{ + int irq; + + /* + ** "irq" bits below are numbered relative to most significant bit. + */ + switch (dev->id.sversion) { + case 0x74: irq = 24; break; /* Centronics */ + case 0x7B: irq = 18; break; /* Audio */ + case 0x81: irq = 17; break; /* Lasi itself */ + case 0x82: irq = 22; break; /* SCSI */ + case 0x83: irq = 11; break; /* Floppy */ + case 0x84: irq = 5; break; /* PS/2 Keyboard */ + case 0x87: irq = 13; break; /* ISDN */ + case 0x8A: irq = 23; break; /* LAN */ + case 0x8C: irq = 26; break; /* RS232 */ + case 0x8D: irq = (dev->hw_path == 13) ? 15 : 14; + break; /* Telephone */ + default: irq = -1; break; /* unknown */ + } + + return irq; +} + +static void __init +lasi_init_irq(struct busdevice *this_lasi) +{ + unsigned long lasi_base = this_lasi->hpa; + + /* Stop LASI barking for a bit */ + gsc_writel(0x00000000, lasi_base+OFFSET_IMR); + + /* clear pending interrupts */ + gsc_readl(lasi_base+OFFSET_IRR); + + /* We're not really convinced we want to reset the onboard + * devices. Firmware does it for us... + */ + + /* Resets */ + /* gsc_writel(0xFFFFFFFF, lasi_base+0x2000);*/ /* Parallel */ + gsc_writel(0xFFFFFFFF, lasi_base+0x4004); /* Audio */ + /* gsc_writel(0xFFFFFFFF, lasi_base+0x5000);*/ /* Serial */ + /* gsc_writel(0xFFFFFFFF, lasi_base+0x6000);*/ /* SCSI */ + gsc_writel(0xFFFFFFFF, lasi_base+0x7000); /* LAN */ + gsc_writel(0xFFFFFFFF, lasi_base+0x8000); /* Keyboard */ + gsc_writel(0xFFFFFFFF, lasi_base+0xA000); /* FDC */ + + /* Ok we hit it on the head with a hammer, our Dog is now + ** comatose and muzzled. Devices will now unmask LASI + ** interrupts as they are registered as irq's in the LASI range. + */ + /* XXX: I thought it was `awks that got `it on the `ead with an + * `ammer. -- willy + */ +} + + +/* + ** lasi_led_init() + ** + ** lasi_led_init() initializes the LED controller on the LASI. + ** + ** Since Mirage and Electra machines use a different LED + ** address register, we need to check for these machines + ** explicitly. + */ + +#ifndef CONFIG_CHASSIS_LCD_LED + +#define lasi_led_init(x) /* nothing */ + +#else + +void __init lasi_led_init(unsigned long lasi_hpa) +{ + unsigned long datareg; + + switch (CPU_HVERSION) { + /* Gecko machines have only one single LED, which can be permanently + turned on by writing a zero into the power control register. */ + case 0x600: /* Gecko (712/60) */ + case 0x601: /* Gecko (712/80) */ + case 0x602: /* Gecko (712/100) */ + case 0x603: /* Anole 64 (743/64) */ + case 0x604: /* Anole 100 (743/100) */ + case 0x605: /* Gecko (712/120) */ + datareg = lasi_hpa + 0x0000C000; + gsc_writeb(0, datareg); + return; /* no need to register the LED interrupt-function */ + + /* Mirage and Electra machines need special offsets */ + case 0x60A: /* Mirage Jr (715/64) */ + case 0x60B: /* Mirage 100 */ + case 0x60C: /* Mirage 100+ */ + case 0x60D: /* Electra 100 */ + case 0x60E: /* Electra 120 */ + datareg = lasi_hpa - 0x00020000; + break; + + default: + datareg = lasi_hpa + 0x0000C000; + break; + } /* switch() */ + + register_led_driver(DISPLAY_MODEL_LASI, LED_CMD_REG_NONE, (char *)datareg); +} +#endif + +/* + * lasi_power_off + * + * Function for lasi to turn off the power. This is accomplished by setting a + * 1 to PWR_ON_L in the Power Control Register + * + */ + +static unsigned long lasi_power_off_hpa; + +static void lasi_power_off(void) +{ + unsigned long datareg; + + /* calculate addr of the Power Control Register */ + datareg = lasi_power_off_hpa + 0x0000C000; + + /* Power down the machine */ + gsc_writel(0x02, datareg); +} + +int __init +lasi_init_chip(struct parisc_device *dev) +{ + struct busdevice *lasi; + struct gsc_irq gsc_irq; + int irq, ret; + + lasi = kmalloc(sizeof(struct busdevice), GFP_KERNEL); + if (!lasi) + return -ENOMEM; + + lasi->name = "Lasi"; + lasi->hpa = dev->hpa; + + /* Check the 4-bit (yes, only 4) version register */ + lasi->version = gsc_readl(lasi->hpa + LASI_VER) & 0xf; + printk(KERN_INFO "%s version %d at 0x%lx found.\n", + lasi->name, lasi->version, lasi->hpa); + + /* initialize the chassis LEDs really early */ + lasi_led_init(lasi->hpa); + + /* Stop LASI barking for a bit */ + lasi_init_irq(lasi); + + /* the IRQ lasi should use */ + irq = gsc_alloc_irq(&gsc_irq); + if (irq < 0) { + printk(KERN_ERR "%s(): cannot get GSC irq\n", + __FUNCTION__); + kfree(lasi); + return -EBUSY; + } + + ret = request_irq(gsc_irq.irq, busdev_barked, 0, "lasi", lasi); + if (ret < 0) { + kfree(lasi); + return ret; + } + + /* Save this for debugging later */ + lasi->parent_irq = gsc_irq.irq; + lasi->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data; + + /* enable IRQ's for devices below LASI */ + gsc_writel(lasi->eim, lasi->hpa + OFFSET_IAR); + + /* Done init'ing, register this driver */ + ret = gsc_common_irqsetup(dev, lasi); + if (ret) { + kfree(lasi); + return ret; + } + + fixup_child_irqs(dev, lasi->busdev_region->data.irqbase, + lasi_choose_irq); + + /* initialize the power off function */ + /* FIXME: Record the LASI HPA for the power off function. This should + * ensure that only the first LASI (the one controlling the power off) + * should set the HPA here */ + lasi_power_off_hpa = lasi->hpa; + pm_power_off = lasi_power_off; + + return ret; +} + +static struct parisc_device_id lasi_tbl[] = { + { HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00081 }, + { 0, } +}; + +struct parisc_driver lasi_driver = { + name: "Lasi", + id_table: lasi_tbl, + probe: lasi_init_chip, +}; diff -Nru a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/lba_pci.c Mon Nov 4 14:31:02 2002 @@ -0,0 +1,1498 @@ +/* +** PCI Lower Bus Adapter (LBA) manager +** +** (c) Copyright 1999,2000 Grant Grundler +** (c) Copyright 1999,2000 Hewlett-Packard Company +** +** 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 module primarily provides access to PCI bus (config/IOport +** spaces) on platforms with an SBA/LBA chipset. A/B/C/J/L/N-class +** with 4 digit model numbers - eg C3000 (and A400...sigh). +** +** LBA driver isn't as simple as the Dino driver because: +** (a) this chip has substantial bug fixes between revisions +** (Only one Dino bug has a software workaround :^( ) +** (b) has more options which we don't (yet) support (DMA hints, OLARD) +** (c) IRQ support lives in the I/O SAPIC driver (not with PCI driver) +** (d) play nicely with both PAT and "Legacy" PA-RISC firmware (PDC). +** (dino only deals with "Legacy" PDC) +** +** LBA driver passes the I/O SAPIC HPA to the I/O SAPIC driver. +** (I/O SAPIC is integratd in the LBA chip). +** +** FIXME: Add support to SBA and LBA drivers for DMA hint sets +** FIXME: Add support for PCI card hot-plug (OLARD). +*/ + +#include +#include +#include +#include +#include /* for __init and __devinit */ +/* #define PCI_DEBUG enable ASSERT */ +#include +#include +#include +#include + +#include +#include /* for struct irq_region support */ +#include +#include +#include +#include + +#include /* for register_parisc_driver() stuff */ +#include /* for iosapic_register() */ +#include /* read/write stuff */ + +#ifndef TRUE +#define TRUE (1 == 1) +#define FALSE (1 == 0) +#endif + +#undef DEBUG_LBA /* general stuff */ +#undef DEBUG_LBA_PORT /* debug I/O Port access */ +#undef DEBUG_LBA_CFG /* debug Config Space Access (ie PCI Bus walk) */ +#undef DEBUG_LBA_PAT /* debug PCI Resource Mgt code - PDC PAT only */ + +#undef FBB_SUPPORT /* Fast Back-Back xfers - NOT READY YET */ + + +#ifdef DEBUG_LBA +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#ifdef DEBUG_LBA_PORT +#define DBG_PORT(x...) printk(x) +#else +#define DBG_PORT(x...) +#endif + +#ifdef DEBUG_LBA_CFG +#define DBG_CFG(x...) printk(x) +#else +#define DBG_CFG(x...) +#endif + +#ifdef DEBUG_LBA_PAT +#define DBG_PAT(x...) printk(x) +#else +#define DBG_PAT(x...) +#endif + +/* +** Config accessor functions only pass in the 8-bit bus number and not +** the 8-bit "PCI Segment" number. Each LBA will be assigned a PCI bus +** number based on what firmware wrote into the scratch register. +** +** The "secondary" bus number is set to this before calling +** pci_register_ops(). If any PPB's are present, the scan will +** discover them and update the "secondary" and "subordinate" +** fields in the pci_bus structure. +** +** Changes in the configuration *may* result in a different +** bus number for each LBA depending on what firmware does. +*/ + +#define MODULE_NAME "lba" + +#define LBA_FUNC_ID 0x0000 /* function id */ +#define LBA_FCLASS 0x0008 /* function class, bist, header, rev... */ +#define LBA_CAPABLE 0x0030 /* capabilities register */ + +#define LBA_PCI_CFG_ADDR 0x0040 /* poke CFG address here */ +#define LBA_PCI_CFG_DATA 0x0048 /* read or write data here */ + +#define LBA_PMC_MTLT 0x0050 /* Firmware sets this - read only. */ +#define LBA_FW_SCRATCH 0x0058 /* Firmware writes the PCI bus number here. */ +#define LBA_ERROR_ADDR 0x0070 /* On error, address gets logged here */ + +#define LBA_ARB_MASK 0x0080 /* bit 0 enable arbitration. PAT/PDC enables */ +#define LBA_ARB_PRI 0x0088 /* firmware sets this. */ +#define LBA_ARB_MODE 0x0090 /* firmware sets this. */ +#define LBA_ARB_MTLT 0x0098 /* firmware sets this. */ + +#define LBA_MOD_ID 0x0100 /* Module ID. PDC_PAT_CELL reports 4 */ + +#define LBA_STAT_CTL 0x0108 /* Status & Control */ +#define LBA_BUS_RESET 0x01 /* Deassert PCI Bus Reset Signal */ +#define CLEAR_ERRLOG 0x10 /* "Clear Error Log" cmd */ +#define CLEAR_ERRLOG_ENABLE 0x20 /* "Clear Error Log" Enable */ +#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */ + +#define LBA_LMMIO_BASE 0x0200 /* < 4GB I/O address range */ +#define LBA_LMMIO_MASK 0x0208 + +#define LBA_GMMIO_BASE 0x0210 /* > 4GB I/O address range */ +#define LBA_GMMIO_MASK 0x0218 + +#define LBA_WLMMIO_BASE 0x0220 /* All < 4GB ranges under the same *SBA* */ +#define LBA_WLMMIO_MASK 0x0228 + +#define LBA_WGMMIO_BASE 0x0230 /* All > 4GB ranges under the same *SBA* */ +#define LBA_WGMMIO_MASK 0x0238 + +#define LBA_IOS_BASE 0x0240 /* I/O port space for this LBA */ +#define LBA_IOS_MASK 0x0248 + +#define LBA_ELMMIO_BASE 0x0250 /* Extra LMMIO range */ +#define LBA_ELMMIO_MASK 0x0258 + +#define LBA_EIOS_BASE 0x0260 /* Extra I/O port space */ +#define LBA_EIOS_MASK 0x0268 + +#define LBA_DMA_CTL 0x0278 /* firmware sets this */ + +#define LBA_IBASE 0x0300 /* SBA DMA support */ +#define LBA_IMASK 0x0308 + +/* FIXME: ignore DMA Hint stuff until we can measure performance */ +#define LBA_HINT_CFG 0x0310 +#define LBA_HINT_BASE 0x0380 /* 14 registers at every 8 bytes. */ + +/* ERROR regs are needed for config cycle kluges */ +#define LBA_ERROR_CONFIG 0x0680 +#define LBA_SMART_MODE 0x20 +#define LBA_ERROR_STATUS 0x0688 +#define LBA_ROPE_CTL 0x06A0 + +#define LBA_IOSAPIC_BASE 0x800 /* Offset of IRQ logic */ + +/* non-postable I/O port space, densely packed */ +#ifdef __LP64__ +#define LBA_ASTRO_PORT_BASE (0xfffffffffee00000UL) +#else +#define LBA_ASTRO_PORT_BASE (0xfee00000UL) +#endif + + +/* +** lba_device: Per instance Elroy data structure +*/ +struct lba_device { + struct pci_hba_data hba; + + spinlock_t lba_lock; + void *iosapic_obj; + +#ifdef __LP64__ + unsigned long lmmio_base; /* PA_VIEW - fixup MEM addresses */ + unsigned long gmmio_base; /* PA_VIEW - Not used (yet) */ + unsigned long iop_base; /* PA_VIEW - for IO port accessor funcs */ +#endif + + int flags; /* state/functionality enabled */ + int hw_rev; /* HW revision of chip */ +}; + + +static u32 lba_t32; + +/* +** lba "flags" +*/ +#define LBA_FLAG_NO_DMA_DURING_CFG 0x01 +#define LBA_FLAG_SKIP_PROBE 0x10 + +/* Tape Release 4 == hw_rev 5 */ +#define LBA_TR4PLUS(d) ((d)->hw_rev > 0x4) +#define LBA_DMA_DURING_CFG_DISABLED(d) ((d)->flags & LBA_FLAG_NO_DMA_DURING_CFG) +#define LBA_SKIP_PROBE(d) ((d)->flags & LBA_FLAG_SKIP_PROBE) + + +/* Looks nice and keeps the compiler happy */ +#define LBA_DEV(d) ((struct lba_device *) (d)) + + +/* +** Only allow 8 subsidiary busses per LBA +** Problem is the PCI bus numbering is globally shared. +*/ +#define LBA_MAX_NUM_BUSES 8 + +/************************************ + * LBA register read and write support + * + * BE WARNED: register writes are posted. + * (ie follow writes which must reach HW with a read) + */ +#define READ_U8(addr) __raw_readb(addr) +#define READ_U16(addr) __raw_readw(addr) +#define READ_U32(addr) __raw_readl(addr) +#define WRITE_U8(value, addr) __raw_writeb(value, addr) +#define WRITE_U16(value, addr) __raw_writew(value, addr) +#define WRITE_U32(value, addr) __raw_writel(value, addr) + +#define READ_REG8(addr) readb(addr) +#define READ_REG16(addr) readw(addr) +#define READ_REG32(addr) readl(addr) +#define READ_REG64(addr) readq(addr) +#define WRITE_REG8(value, addr) writeb(value, addr) +#define WRITE_REG16(value, addr) writew(value, addr) +#define WRITE_REG32(value, addr) writel(value, addr) + + +#define LBA_CFG_TOK(bus,dfn) ((u32) ((bus)<<16 | (dfn)<<8)) +#define LBA_CFG_BUS(tok) ((u8) ((tok)>>16)) +#define LBA_CFG_DEV(tok) ((u8) ((tok)>>11) & 0x1f) +#define LBA_CFG_FUNC(tok) ((u8) ((tok)>>8 ) & 0x7) + + +/* +** Extract LBA (Rope) number from HPA +** REVISIT: 16 ropes for Stretch/Ike? +*/ +#define ROPES_PER_SBA 8 +#define LBA_NUM(x) ((((unsigned long) x) >> 13) & (ROPES_PER_SBA-1)) + + +static void +lba_dump_res(struct resource *r, int d) +{ + int i; + + if (NULL == r) + return; + + printk(KERN_DEBUG "(%p)", r->parent); + for (i = d; i ; --i) printk(" "); + printk(KERN_DEBUG "%p [%lx,%lx]/%x\n", r, r->start, r->end, (int) r->flags); + lba_dump_res(r->child, d+2); + lba_dump_res(r->sibling, d); +} + + +/* +** LBA rev 2.0, 2.1, 2.2, and 3.0 bus walks require a complex +** workaround for cfg cycles: +** -- preserve LBA state +** -- LBA_FLAG_NO_DMA_DURING_CFG workaround +** -- turn on smart mode +** -- probe with config writes before doing config reads +** -- check ERROR_STATUS +** -- clear ERROR_STATUS +** -- restore LBA state +** +** The workaround is only used for device discovery. +*/ + +static int +lba_device_present( u8 bus, u8 dfn, struct lba_device *d) +{ + u8 first_bus = d->hba.hba_bus->secondary; + u8 last_sub_bus = d->hba.hba_bus->subordinate; +#if 0 +/* FIXME - see below in this function */ + u8 dev = PCI_SLOT(dfn); + u8 func = PCI_FUNC(dfn); +#endif + + ASSERT(bus >= first_bus); + ASSERT(bus <= last_sub_bus); + ASSERT((bus - first_bus) < LBA_MAX_NUM_BUSES); + + if ((bus < first_bus) || + (bus > last_sub_bus) || + ((bus - first_bus) >= LBA_MAX_NUM_BUSES)) + { + /* devices that fall into any of these cases won't get claimed */ + return(FALSE); + } + +#if 0 +/* +** FIXME: Need to implement code to fill the devices bitmap based +** on contents of the local pci_bus tree "data base". +** pci_register_ops() walks the bus for us and builds the tree. +** For now, always do the config cycle. +*/ + bus -= first_bus; + + return (((d->devices[bus][dev]) >> func) & 0x1); +#else + return TRUE; +#endif +} + + + +#define LBA_CFG_SETUP(d, tok) { \ + /* Save contents of error config register. */ \ + error_config = READ_REG32(d->hba.base_addr + LBA_ERROR_CONFIG); \ +\ + /* Save contents of status control register. */ \ + status_control = READ_REG32(d->hba.base_addr + LBA_STAT_CTL); \ +\ + /* For LBA rev 2.0, 2.1, 2.2, and 3.0, we must disable DMA \ + ** arbitration for full bus walks. \ + */ \ + if (LBA_DMA_DURING_CFG_DISABLED(d)) { \ + /* Save contents of arb mask register. */ \ + arb_mask = READ_REG32(d->hba.base_addr + LBA_ARB_MASK); \ +\ + /* \ + * Turn off all device arbitration bits (i.e. everything \ + * except arbitration enable bit). \ + */ \ + WRITE_REG32(0x1, d->hba.base_addr + LBA_ARB_MASK); \ + } \ +\ + /* \ + * Set the smart mode bit so that master aborts don't cause \ + * LBA to go into PCI fatal mode (required). \ + */ \ + WRITE_REG32(error_config | LBA_SMART_MODE, d->hba.base_addr + LBA_ERROR_CONFIG); \ +} + + +#define LBA_CFG_PROBE(d, tok) { \ + /* \ + * Setup Vendor ID write and read back the address register \ + * to make sure that LBA is the bus master. \ + */ \ + WRITE_REG32(tok | PCI_VENDOR_ID, (d)->hba.base_addr + LBA_PCI_CFG_ADDR);\ + /* \ + * Read address register to ensure that LBA is the bus master, \ + * which implies that DMA traffic has stopped when DMA arb is off. \ + */ \ + lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ + /* \ + * Generate a cfg write cycle (will have no affect on \ + * Vendor ID register since read-only). \ + */ \ + WRITE_REG32(~0, (d)->hba.base_addr + LBA_PCI_CFG_DATA); \ + /* \ + * Make sure write has completed before proceeding further, \ + * i.e. before setting clear enable. \ + */ \ + lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ +} + + +/* + * HPREVISIT: + * -- Can't tell if config cycle got the error. + * + * OV bit is broken until rev 4.0, so can't use OV bit and + * LBA_ERROR_LOG_ADDR to tell if error belongs to config cycle. + * + * As of rev 4.0, no longer need the error check. + * + * -- Even if we could tell, we still want to return -1 + * for **ANY** error (not just master abort). + * + * -- Only clear non-fatal errors (we don't want to bring + * LBA out of pci-fatal mode). + * + * Actually, there is still a race in which + * we could be clearing a fatal error. We will + * live with this during our initial bus walk + * until rev 4.0 (no driver activity during + * initial bus walk). The initial bus walk + * has race conditions concerning the use of + * smart mode as well. + */ + +#define LBA_MASTER_ABORT_ERROR 0xc +#define LBA_FATAL_ERROR 0x10 + +#define LBA_CFG_MASTER_ABORT_CHECK(d, base, tok, error) { \ + u32 error_status = 0; \ + /* \ + * Set clear enable (CE) bit. Unset by HW when new \ + * errors are logged -- LBA HW ERS section 14.3.3). \ + */ \ + WRITE_REG32(status_control | CLEAR_ERRLOG_ENABLE, base + LBA_STAT_CTL); \ + error_status = READ_REG32(base + LBA_ERROR_STATUS); \ + if ((error_status & 0x1f) != 0) { \ + /* \ + * Fail the config read request. \ + */ \ + error = 1; \ + if ((error_status & LBA_FATAL_ERROR) == 0) { \ + /* \ + * Clear error status (if fatal bit not set) by setting \ + * clear error log bit (CL). \ + */ \ + WRITE_REG32(status_control | CLEAR_ERRLOG, base + LBA_STAT_CTL); \ + } \ + } \ +} + +#define LBA_CFG_TR4_ADDR_SETUP(d, addr) \ + WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR) + +#define LBA_CFG_ADDR_SETUP(d, addr) { \ + WRITE_REG32(((addr) & ~3), (d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ + /* \ + * HPREVISIT: \ + * -- Potentially could skip this once DMA bug fixed. \ + * \ + * Read address register to ensure that LBA is the bus master, \ + * which implies that DMA traffic has stopped when DMA arb is off. \ + */ \ + lba_t32 = READ_REG32((d)->hba.base_addr + LBA_PCI_CFG_ADDR); \ +} + + +#define LBA_CFG_RESTORE(d, base) { \ + /* \ + * Restore status control register (turn off clear enable). \ + */ \ + WRITE_REG32(status_control, base + LBA_STAT_CTL); \ + /* \ + * Restore error config register (turn off smart mode). \ + */ \ + WRITE_REG32(error_config, base + LBA_ERROR_CONFIG); \ + if (LBA_DMA_DURING_CFG_DISABLED(d)) { \ + /* \ + * Restore arb mask register (reenables DMA arbitration). \ + */ \ + WRITE_REG32(arb_mask, base + LBA_ARB_MASK); \ + } \ +} + + + +static unsigned int +lba_rd_cfg(struct lba_device *d, u32 tok, u8 reg, u32 size) +{ + u32 data = ~0; + int error = 0; + u32 arb_mask = 0; /* used by LBA_CFG_SETUP/RESTORE */ + u32 error_config = 0; /* used by LBA_CFG_SETUP/RESTORE */ + u32 status_control = 0; /* used by LBA_CFG_SETUP/RESTORE */ + + ASSERT((size == sizeof(u8)) || + (size == sizeof(u16)) || + (size == sizeof(u32))); + + if ((size != sizeof(u8)) && + (size != sizeof(u16)) && + (size != sizeof(u32))) { + return(data); + } + + LBA_CFG_SETUP(d, tok); + LBA_CFG_PROBE(d, tok); + LBA_CFG_MASTER_ABORT_CHECK(d, d->hba.base_addr, tok, error); + if (!error) { + LBA_CFG_ADDR_SETUP(d, tok | reg); + switch (size) { + case sizeof(u8): + data = (u32) READ_REG8(d->hba.base_addr + LBA_PCI_CFG_DATA + (reg & 3)); + break; + case sizeof(u16): + data = (u32) READ_REG16(d->hba.base_addr + LBA_PCI_CFG_DATA + (reg & 2)); + break; + case sizeof(u32): + data = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_DATA); + break; + default: + break; /* leave data as -1 */ + } + } + LBA_CFG_RESTORE(d, d->hba.base_addr); + return(data); +} + + +static int lba_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 *data) +{ + struct lba_device *d = LBA_DEV(bus->sysdata); + u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary; + u32 tok = LBA_CFG_TOK(local_bus, devfn); + +/* FIXME: B2K/C3600 workaround is always use old method... */ + /* if (!LBA_TR4PLUS(d) && !LBA_SKIP_PROBE(d)) */ { + /* original - Generate config cycle on broken elroy + with risk we will miss PCI bus errors. */ + *data = lba_rd_cfg(d, tok, pos, size); + DBG_CFG("%s(%x+%2x) -> 0x%x (a)\n", __FUNCTION__, tok, pos, *data); + return(*data == ~0UL); + } + + if (LBA_SKIP_PROBE(d) && (!lba_device_present(bus->secondary, devfn, d))) + { + DBG_CFG("%s(%x+%2x) -> -1 (b)\n", __FUNCTION__, tok, pos); + /* either don't want to look or know device isn't present. */ + *data = ~0U; + return(0); + } + + /* Basic Algorithm + ** Should only get here on fully working LBA rev. + ** This is how simple the code should have been. + */ + LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); + switch(size) { + case 1: *(u8 *) data = READ_REG8(d->hba.base_addr + LBA_PCI_CFG_DATA); + break; + case 2: *(u16 *) data = READ_REG16(d->hba.base_addr + LBA_PCI_CFG_DATA); + break; + case 4: *(u32 *) data = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_DATA); + break; + } + DBG_CFG("%s(%x+%2x) -> 0x%x (c)\n", __FUNCTION__, tok, pos, *data); + return(*data == ~0U); +} + + +static void +lba_wr_cfg( struct lba_device *d, u32 tok, u8 reg, u32 data, u32 size) +{ + int error = 0; + u32 arb_mask = 0; + u32 error_config = 0; + u32 status_control = 0; + + ASSERT((size == sizeof(u8)) || + (size == sizeof(u16)) || + (size == sizeof(u32))); + + if ((size != sizeof(u8)) && + (size != sizeof(u16)) && + (size != sizeof(u32))) { + return; + } + + LBA_CFG_SETUP(d, tok); + LBA_CFG_ADDR_SETUP(d, tok | reg); + switch (size) { + case sizeof(u8): + WRITE_REG8((u8) data, d->hba.base_addr + LBA_PCI_CFG_DATA + (reg&3)); + break; + case sizeof(u16): + WRITE_REG16((u8) data, d->hba.base_addr + LBA_PCI_CFG_DATA +(reg&2)); + break; + case sizeof(u32): + WRITE_REG32(data, d->hba.base_addr + LBA_PCI_CFG_DATA); + break; + default: + break; + } + LBA_CFG_MASTER_ABORT_CHECK(d, d->hba.base_addr, tok, error); + LBA_CFG_RESTORE(d, d->hba.base_addr); +} + + +/* + * LBA 4.0 config write code implements non-postable semantics + * by doing a read of CONFIG ADDR after the write. + */ + +static int lba_cfg_write(struct pci_bus *bus, unsigned int devfn, int pos, int size, u32 data) +{ + struct lba_device *d = LBA_DEV(bus->sysdata); + u32 local_bus = (bus->parent == NULL) ? 0 : bus->secondary; + u32 tok = LBA_CFG_TOK(local_bus,devfn); + + ASSERT((tok & 0xff) == 0); + ASSERT(pos < 0x100); + + if (!LBA_TR4PLUS(d) && !LBA_SKIP_PROBE(d)) { + /* Original Workaround */ + lba_wr_cfg(d, tok, pos, (u32) data, size); + DBG_CFG("%s(%x+%2x) = 0x%x (a)\n", __FUNCTION__, tok, pos,data); + return 0; + } + + if (LBA_SKIP_PROBE(d) && (!lba_device_present(bus->secondary, devfn, d))) { + DBG_CFG("%s(%x+%2x) = 0x%x (b)\n", __FUNCTION__, tok, pos,data); + return 1; /* New Workaround */ + } + + DBG_CFG("%s(%x+%2x) = 0x%x (c)\n", __FUNCTION__, tok, pos, data); + /* Basic Algorithm */ + LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); + switch(size) { + case 1: WRITE_REG8 (data, d->hba.base_addr + LBA_PCI_CFG_DATA); + break; + case 2: WRITE_REG16(data, d->hba.base_addr + LBA_PCI_CFG_DATA); + break; + case 4: WRITE_REG32(data, d->hba.base_addr + LBA_PCI_CFG_DATA); + break; + } + lba_t32 = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_ADDR); + return 0; +} + + +static struct pci_ops lba_cfg_ops = { + read: lba_cfg_read, + write: lba_cfg_write, +}; + + +static void +lba_bios_init(void) +{ + DBG(MODULE_NAME ": lba_bios_init\n"); +} + + +#ifdef __LP64__ + +/* +** Determine if a device is already configured. +** If so, reserve it resources. +** +** Read PCI cfg command register and see if I/O or MMIO is enabled. +** PAT has to enable the devices it's using. +** +** Note: resources are fixed up before we try to claim them. +*/ +static void +lba_claim_dev_resources(struct pci_dev *dev) +{ + u16 cmd; + int i, srch_flags; + + (void) pci_read_config_word(dev, PCI_COMMAND, &cmd); + + srch_flags = (cmd & PCI_COMMAND_IO) ? IORESOURCE_IO : 0; + if (cmd & PCI_COMMAND_MEMORY) + srch_flags |= IORESOURCE_MEM; + + if (!srch_flags) + return; + + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { + if (dev->resource[i].flags & srch_flags) { + pci_claim_resource(dev, i); + DBG(" claimed %s %d [%lx,%lx]/%x\n", + dev->slot_name, i, + dev->resource[i].start, + dev->resource[i].end, + (int) dev->resource[i].flags + ); + } + } +} +#endif + + +/* +** The algorithm is generic code. +** But it needs to access local data structures to get the IRQ base. +** Could make this a "pci_fixup_irq(bus, region)" but not sure +** it's worth it. +** +** Called by do_pci_scan_bus() immediately after each PCI bus is walked. +** Resources aren't allocated until recursive buswalk below HBA is completed. +*/ +static void +lba_fixup_bus(struct pci_bus *bus) +{ + struct list_head *ln; +#ifdef FBB_SUPPORT + u16 fbb_enable = PCI_STATUS_FAST_BACK; + u16 status; +#endif + struct lba_device *ldev = LBA_DEV(bus->sysdata); + int lba_portbase = HBA_PORT_BASE(ldev->hba.hba_num); + + DBG("lba_fixup_bus(0x%p) bus %d sysdata 0x%p\n", + bus, bus->secondary, bus->sysdata); + + /* + ** Properly Setup MMIO resources for this bus. + ** pci_alloc_primary_bus() mangles this. + */ + if (NULL == bus->self) { + int err; + + DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n", + ldev->hba.io_space.name, + ldev->hba.io_space.start, ldev->hba.io_space.end, + (int) ldev->hba.io_space.flags); + DBG("lba_fixup_bus() %s [%lx/%lx]/%x\n", + ldev->hba.lmmio_space.name, + ldev->hba.lmmio_space.start, ldev->hba.lmmio_space.end, + (int) ldev->hba.lmmio_space.flags); + + err = request_resource(&ioport_resource, &(ldev->hba.io_space)); + if (err < 0) { + BUG(); + lba_dump_res(&ioport_resource, 2); + } + err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space)); + if (err < 0) { + BUG(); + lba_dump_res(&iomem_resource, 2); + } + + bus->resource[0] = &(ldev->hba.io_space); + bus->resource[1] = &(ldev->hba.lmmio_space); + } else { + /* KLUGE ALERT! + ** PCI-PCI Bridge resource munging. + ** This hack should go away in the near future. + ** It's based on the Alpha port. + */ + int i; + u16 cmd; + + for (i = 0; i < 4; i++) { + bus->resource[i] = + &bus->self->resource[PCI_BRIDGE_RESOURCES+i]; + bus->resource[i]->name = bus->name; + } +#if 0 + bus->resource[0]->flags |= pci_bridge_check_io(bus->self); +#else + bus->resource[0]->flags |= IORESOURCE_IO; +#endif + bus->resource[1]->flags |= IORESOURCE_MEM; + bus->resource[2]->flags = 0; /* Don't support prefetchable */ + bus->resource[3]->flags = 0; /* not used */ + + /* + ** If the PPB is enabled (ie already configured) then + ** just read those values. + */ + (void) pci_read_config_word(bus->self, PCI_COMMAND, &cmd); + if (cmd & (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)) { + pci_read_bridge_bases(bus); + } else { + /* Not configured. + ** For now, propogate HBA limits to the bus; + ** PCI will adjust them later. + */ + bus->resource[0]->end = ldev->hba.io_space.end; + bus->resource[1]->end = ldev->hba.lmmio_space.end; + } + + /* Turn off downstream PF memory address range by default */ + bus->resource[2]->start = 1024*1024; + bus->resource[2]->end = bus->resource[2]->start - 1; + } + + + list_for_each(ln, &bus->devices) { + int i; + struct pci_dev *dev = pci_dev_b(ln); + + DBG("lba_fixup_bus() %s\n", dev->name); + + /* Virtualize Device/Bridge Resources. */ + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *res = &dev->resource[i]; + + /* If resource not allocated - skip it */ + if (!res->start) + continue; + + if (res->flags & IORESOURCE_IO) { + DBG("lba_fixup_bus() I/O Ports [%lx/%lx] -> ", + res->start, res->end); + res->start |= lba_portbase; + res->end |= lba_portbase; + DBG("[%lx/%lx]\n", res->start, res->end); + } else if (res->flags & IORESOURCE_MEM) { + /* + ** Convert PCI (IO_VIEW) addresses to + ** processor (PA_VIEW) addresses + */ + DBG("lba_fixup_bus() MMIO [%lx/%lx] -> ", + res->start, res->end); + res->start = PCI_HOST_ADDR(HBA_DATA(ldev), res->start); + res->end = PCI_HOST_ADDR(HBA_DATA(ldev), res->end); + DBG("[%lx/%lx]\n", res->start, res->end); + } + } + +#ifdef FBB_SUPPORT + /* + ** If one device does not support FBB transfers, + ** No one on the bus can be allowed to use them. + */ + (void) pci_read_config_word(dev, PCI_STATUS, &status); + fbb_enable &= status; +#endif + +#ifdef __LP64__ + if (is_pdc_pat()) { + /* Claim resources for PDC's devices */ + lba_claim_dev_resources(dev); + } +#endif + + /* + ** P2PB's have no IRQs. ignore them. + */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) + continue; + + /* Adjust INTERRUPT_LINE for this dev */ + iosapic_fixup_irq(ldev->iosapic_obj, dev); + } + +#ifdef FBB_SUPPORT +/* FIXME/REVISIT - finish figuring out to set FBB on both +** pci_setup_bridge() clobbers PCI_BRIDGE_CONTROL. +** Can't fixup here anyway....garr... +*/ + if (fbb_enable) { + if (bus->self) { + u8 control; + /* enable on PPB */ + (void) pci_read_config_byte(bus->self, PCI_BRIDGE_CONTROL, &control); + (void) pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, control | PCI_STATUS_FAST_BACK); + + } else { + /* enable on LBA */ + } + fbb_enable = PCI_COMMAND_FAST_BACK; + } + + /* Lastly enable FBB/PERR/SERR on all devices too */ + list_for_each(ln, &bus->devices) { + (void) pci_read_config_word(dev, PCI_COMMAND, &status); + status |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR | fbb_enable; + (void) pci_write_config_word(dev, PCI_COMMAND, status); + } +#endif +} + + +struct pci_bios_ops lba_bios_ops = { + init: lba_bios_init, + fixup_bus: lba_fixup_bus, +}; + + + + +/******************************************************* +** +** LBA Sprockets "I/O Port" Space Accessor Functions +** +** This set of accessor functions is intended for use with +** "legacy firmware" (ie Sprockets on Allegro/Forte boxes). +** +** Many PCI devices don't require use of I/O port space (eg Tulip, +** NCR720) since they export the same registers to both MMIO and +** I/O port space. In general I/O port space is slower than +** MMIO since drivers are designed so PIO writes can be posted. +** +********************************************************/ + +#define LBA_PORT_IN(size, mask) \ +static u##size lba_astro_in##size (struct pci_hba_data *d, u16 addr) \ +{ \ + u##size t; \ + t = READ_REG##size(LBA_ASTRO_PORT_BASE + addr); \ + DBG_PORT(" 0x%x\n", t); \ + return (t); \ +} + +LBA_PORT_IN( 8, 3) +LBA_PORT_IN(16, 2) +LBA_PORT_IN(32, 0) + + + +/* +** BUG X4107: Ordering broken - DMA RD return can bypass PIO WR +** +** Fixed in Elroy 2.2. The READ_U32(..., LBA_FUNC_ID) below is +** guarantee non-postable completion semantics - not avoid X4107. +** The READ_U32 only guarantees the write data gets to elroy but +** out to the PCI bus. We can't read stuff from I/O port space +** since we don't know what has side-effects. Attempting to read +** from configuration space would be suicidal given the number of +** bugs in that elroy functionality. +** +** Description: +** DMA read results can improperly pass PIO writes (X4107). The +** result of this bug is that if a processor modifies a location in +** memory after having issued PIO writes, the PIO writes are not +** guaranteed to be completed before a PCI device is allowed to see +** the modified data in a DMA read. +** +** Note that IKE bug X3719 in TR1 IKEs will result in the same +** symptom. +** +** Workaround: +** The workaround for this bug is to always follow a PIO write with +** a PIO read to the same bus before starting DMA on that PCI bus. +** +*/ +#define LBA_PORT_OUT(size, mask) \ +static void lba_astro_out##size (struct pci_hba_data *d, u16 addr, u##size val) \ +{ \ + ASSERT(d != NULL); \ + DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, d, addr, val); \ + WRITE_REG##size(val, LBA_ASTRO_PORT_BASE + addr); \ + if (LBA_DEV(d)->hw_rev < 3) \ + lba_t32 = READ_U32(d->base_addr + LBA_FUNC_ID); \ +} + +LBA_PORT_OUT( 8, 3) +LBA_PORT_OUT(16, 2) +LBA_PORT_OUT(32, 0) + + +static struct pci_port_ops lba_astro_port_ops = { + inb: lba_astro_in8, + inw: lba_astro_in16, + inl: lba_astro_in32, + outb: lba_astro_out8, + outw: lba_astro_out16, + outl: lba_astro_out32 +}; + + +#ifdef __LP64__ +#define PIOP_TO_GMMIO(lba, addr) \ + ((lba)->iop_base + (((addr)&0xFFFC)<<10) + ((addr)&3)) + +/******************************************************* +** +** LBA PAT "I/O Port" Space Accessor Functions +** +** This set of accessor functions is intended for use with +** "PAT PDC" firmware (ie Prelude/Rhapsody/Piranha boxes). +** +** This uses the PIOP space located in the first 64MB of GMMIO. +** Each rope gets a full 64*KB* (ie 4 bytes per page) this way. +** bits 1:0 stay the same. bits 15:2 become 25:12. +** Then add the base and we can generate an I/O Port cycle. +********************************************************/ +#undef LBA_PORT_IN +#define LBA_PORT_IN(size, mask) \ +static u##size lba_pat_in##size (struct pci_hba_data *l, u16 addr) \ +{ \ + u##size t; \ + ASSERT(bus != NULL); \ + DBG_PORT("%s(0x%p, 0x%x) ->", __FUNCTION__, l, addr); \ + t = READ_REG##size(PIOP_TO_GMMIO(LBA_DEV(l), addr)); \ + DBG_PORT(" 0x%x\n", t); \ + return (t); \ +} + +LBA_PORT_IN( 8, 3) +LBA_PORT_IN(16, 2) +LBA_PORT_IN(32, 0) + + +#undef LBA_PORT_OUT +#define LBA_PORT_OUT(size, mask) \ +static void lba_pat_out##size (struct pci_hba_data *l, u16 addr, u##size val) \ +{ \ + void *where = (void *) PIOP_TO_GMMIO(LBA_DEV(l), addr); \ + ASSERT(bus != NULL); \ + DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, l, addr, val); \ + WRITE_REG##size(val, where); \ + /* flush the I/O down to the elroy at least */ \ + lba_t32 = READ_U32(l->base_addr + LBA_FUNC_ID); \ +} + +LBA_PORT_OUT( 8, 3) +LBA_PORT_OUT(16, 2) +LBA_PORT_OUT(32, 0) + + +static struct pci_port_ops lba_pat_port_ops = { + inb: lba_pat_in8, + inw: lba_pat_in16, + inl: lba_pat_in32, + outb: lba_pat_out8, + outw: lba_pat_out16, + outl: lba_pat_out32 +}; + + + +/* +** make range information from PDC available to PCI subsystem. +** We make the PDC call here in order to get the PCI bus range +** numbers. The rest will get forwarded in pcibios_fixup_bus(). +** We don't have a struct pci_bus assigned to us yet. +*/ +static void +lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) +{ + unsigned long bytecnt; + pdc_pat_cell_mod_maddr_block_t pa_pdc_cell; /* PA_VIEW */ + pdc_pat_cell_mod_maddr_block_t io_pdc_cell; /* IO_VIEW */ + long io_count; + long status; /* PDC return status */ + long pa_count; + int i; + + /* return cell module (IO view) */ + status = pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index, + PA_VIEW, & pa_pdc_cell); + pa_count = pa_pdc_cell.mod[1]; + + status |= pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index, + IO_VIEW, &io_pdc_cell); + io_count = io_pdc_cell.mod[1]; + + /* We've already done this once for device discovery...*/ + if (status != PDC_OK) { + panic("pdc_pat_cell_module() call failed for LBA!\n"); + } + + if (PAT_GET_ENTITY(pa_pdc_cell.mod_info) != PAT_ENTITY_LBA) { + panic("pdc_pat_cell_module() entity returned != PAT_ENTITY_LBA!\n"); + } + + /* + ** Inspect the resources PAT tells us about + */ + for (i = 0; i < pa_count; i++) { + struct { + unsigned long type; + unsigned long start; + unsigned long end; /* aka finish */ + } *p, *io; + struct resource *r; + + p = (void *) &(pa_pdc_cell.mod[2+i*3]); + io = (void *) &(io_pdc_cell.mod[2+i*3]); + + /* Convert the PAT range data to PCI "struct resource" */ + switch(p->type & 0xff) { + case PAT_PBNUM: + lba_dev->hba.bus_num.start = p->start; + lba_dev->hba.bus_num.end = p->end; + break; + case PAT_LMMIO: + /* used to fix up pre-initialized MEM BARs */ + lba_dev->hba.lmmio_space_offset = p->start - io->start; + + r = &(lba_dev->hba.lmmio_space); + r->name = "LBA LMMIO"; + r->start = p->start; + r->end = p->end; + r->flags = IORESOURCE_MEM; + r->parent = r->sibling = r->child = NULL; + break; + case PAT_GMMIO: + printk(KERN_WARNING MODULE_NAME + " range[%d] : ignoring GMMIO (0x%lx)\n", + i, p->start); + lba_dev->gmmio_base = p->start; + break; + case PAT_NPIOP: + printk(KERN_WARNING MODULE_NAME + " range[%d] : ignoring NPIOP (0x%lx)\n", + i, p->start); + break; + case PAT_PIOP: + /* + ** Postable I/O port space is per PCI host adapter. + */ + + /* save base of 64MB PIOP region */ + lba_dev->iop_base = p->start; + + r = &(lba_dev->hba.io_space); + r->name = "LBA I/O Port"; + r->start = HBA_PORT_BASE(lba_dev->hba.hba_num); + r->end = r->start + HBA_PORT_SPACE_SIZE - 1; + r->flags = IORESOURCE_IO; + r->parent = r->sibling = r->child = NULL; + break; + default: + printk(KERN_WARNING MODULE_NAME + " range[%d] : unknown pat range type (0x%lx)\n", + i, p->type & 0xff); + break; + } + } +} +#endif /* __LP64__ */ + + +static void +lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) +{ + struct resource *r; + unsigned long rsize; + int lba_num; + +#ifdef __LP64__ + /* + ** Sign extend all BAR values on "legacy" platforms. + ** "Sprockets" PDC (Forte/Allegro) initializes everything + ** for "legacy" 32-bit OS (HPUX 10.20). + ** Upper 32-bits of 64-bit BAR will be zero too. + */ + lba_dev->hba.lmmio_space_offset = 0xffffffff00000000UL; +#else + lba_dev->hba.lmmio_space_offset = 0UL; +#endif + + /* + ** With "legacy" firmware, the lowest byte of FW_SCRATCH + ** represents bus->secondary and the second byte represents + ** bus->subsidiary (i.e. highest PPB programmed by firmware). + ** PCI bus walk *should* end up with the same result. + ** FIXME: But we don't have sanity checks in PCI or LBA. + */ + lba_num = READ_REG32(pa_dev->hpa + LBA_FW_SCRATCH); + r = &(lba_dev->hba.bus_num); + r->name = "LBA PCI Busses"; + r->start = lba_num & 0xff; + r->end = (lba_num>>8) & 0xff; + + /* Set up local PCI Bus resources - we don't really need + ** them for Legacy boxes but it's nice to see in /proc. + */ + r = &(lba_dev->hba.lmmio_space); + r->name = "LBA PCI LMMIO"; + r->flags = IORESOURCE_MEM; + /* Ignore "Range Enable" bit in the BASE register */ + r->start = PCI_HOST_ADDR(HBA_DATA(lba_dev), + ((long) READ_REG32(pa_dev->hpa + LBA_LMMIO_BASE)) & ~1UL); + rsize = ~READ_REG32(pa_dev->hpa + LBA_LMMIO_MASK) + 1; + + /* + ** Each rope only gets part of the distributed range. + ** Adjust "window" for this rope + */ + rsize /= ROPES_PER_SBA; + r->start += rsize * LBA_NUM(pa_dev->hpa); + r->end = r->start + rsize - 1 ; + + /* + ** XXX FIXME - ignore LBA_ELMMIO_BASE for now + ** "Directed" ranges are used when the "distributed range" isn't + ** sufficient for all devices below a given LBA. Typically devices + ** like graphics cards or X25 may need a directed range when the + ** bus has multiple slots (ie multiple devices) or the device + ** needs more than the typical 4 or 8MB a distributed range offers. + ** + ** The main reason for ignoring it now frigging complications. + ** Directed ranges may overlap (and have precedence) over + ** distributed ranges. Ie a distributed range assigned to a unused + ** rope may be used by a directed range on a different rope. + ** Support for graphics devices may require fixing this + ** since they may be assigned a directed range which overlaps + ** an existing (but unused portion of) distributed range. + */ + r = &(lba_dev->hba.elmmio_space); + r->name = "extra LBA PCI LMMIO"; + r->flags = IORESOURCE_MEM; + r->start = READ_REG32(pa_dev->hpa + LBA_ELMMIO_BASE); + r->end = 0; + + /* check Range Enable bit */ + if (r->start & 1) { + /* First baby step to getting Direct Ranges listed in /proc. + ** AFAIK, only Sprockets PDC will setup a directed Range. + */ + + r->start &= ~1; + r->end = r->start; + r->end += ~READ_REG32(pa_dev->hpa + LBA_ELMMIO_MASK); + printk(KERN_DEBUG "WARNING: Ignoring enabled ELMMIO BASE 0x%0lx SIZE 0x%lx\n", + r->start, + r->end + 1); + + } + + r = &(lba_dev->hba.io_space); + r->name = "LBA PCI I/O Ports"; + r->flags = IORESOURCE_IO; + r->start = READ_REG32(pa_dev->hpa + LBA_IOS_BASE) & ~1L; + r->end = r->start + (READ_REG32(pa_dev->hpa + LBA_IOS_MASK) ^ (HBA_PORT_SPACE_SIZE - 1)); + + /* Virtualize the I/O Port space ranges */ + lba_num = HBA_PORT_BASE(lba_dev->hba.hba_num); + r->start |= lba_num; + r->end |= lba_num; +} + + +/************************************************************************** +** +** LBA initialization code (HW and SW) +** +** o identify LBA chip itself +** o initialize LBA chip modes (HardFail) +** o FIXME: initialize DMA hints for reasonable defaults +** o enable configuration functions +** o call pci_register_ops() to discover devs (fixup/fixup_bus get invoked) +** +**************************************************************************/ + +static int __init +lba_hw_init(struct lba_device *d) +{ + u32 stat; + u32 bus_reset; /* PDC_PAT_BUG */ + +#if 0 + printk(KERN_DEBUG "LBA %lx STAT_CTL %Lx ERROR_CFG %Lx STATUS %Lx DMA_CTL %Lx\n", + d->hba.base_addr, + READ_REG64(d->hba.base_addr + LBA_STAT_CTL), + READ_REG64(d->hba.base_addr + LBA_ERROR_CONFIG), + READ_REG64(d->hba.base_addr + LBA_ERROR_STATUS), + READ_REG64(d->hba.base_addr + LBA_DMA_CTL) ); + printk(KERN_DEBUG " ARB mask %Lx pri %Lx mode %Lx mtlt %Lx\n", + READ_REG64(d->hba.base_addr + LBA_ARB_MASK), + READ_REG64(d->hba.base_addr + LBA_ARB_PRI), + READ_REG64(d->hba.base_addr + LBA_ARB_MODE), + READ_REG64(d->hba.base_addr + LBA_ARB_MTLT) ); + printk(KERN_DEBUG " HINT cfg 0x%Lx\n", + READ_REG64(d->hba.base_addr + LBA_HINT_CFG)); + printk(KERN_DEBUG " HINT reg "); + { int i; + for (i=LBA_HINT_BASE; i< (14*8 + LBA_HINT_BASE); i+=8) + printk(" %Lx", READ_REG64(d->hba.base_addr + i)); + } + printk("\n"); +#endif /* DEBUG_LBA_PAT */ + +#ifdef __LP64__ +#warning FIXME add support for PDC_PAT_IO "Get slot status" - OLAR support +#endif + + /* PDC_PAT_BUG: exhibited in rev 40.48 on L2000 */ + bus_reset = READ_REG32(d->hba.base_addr + LBA_STAT_CTL + 4) & 1; + if (bus_reset) { + printk(KERN_DEBUG "NOTICE: PCI bus reset still asserted! (clearing)\n"); + } + + stat = READ_REG32(d->hba.base_addr + LBA_ERROR_CONFIG); + if (stat & LBA_SMART_MODE) { + printk(KERN_DEBUG "NOTICE: LBA in SMART mode! (cleared)\n"); + stat &= ~LBA_SMART_MODE; + WRITE_REG32(stat, d->hba.base_addr + LBA_ERROR_CONFIG); + } + + /* Set HF mode as the default (vs. -1 mode). */ + stat = READ_REG32(d->hba.base_addr + LBA_STAT_CTL); + WRITE_REG32(stat | HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL); + + /* + ** Writing a zero to STAT_CTL.rf (bit 0) will clear reset signal + ** if it's not already set. If we just cleared the PCI Bus Reset + ** signal, wait a bit for the PCI devices to recover and setup. + */ + if (bus_reset) + mdelay(pci_post_reset_delay); + + if (0 == READ_REG32(d->hba.base_addr + LBA_ARB_MASK)) { + /* + ** PDC_PAT_BUG: PDC rev 40.48 on L2000. + ** B2000/C3600/J6000 also have this problem? + ** + ** Elroys with hot pluggable slots don't get configured + ** correctly if the slot is empty. ARB_MASK is set to 0 + ** and we can't master transactions on the bus if it's + ** not at least one. 0x3 enables elroy and first slot. + */ + printk(KERN_DEBUG "NOTICE: Enabling PCI Arbitration\n"); + WRITE_REG32(0x3, d->hba.base_addr + LBA_ARB_MASK); + } + + /* + ** FIXME: Hint registers are programmed with default hint + ** values by firmware. Hints should be sane even if we + ** can't reprogram them the way drivers want. + */ + return 0; +} + + + +static void __init +lba_common_init(struct lba_device *lba_dev) +{ + pci_bios = &lba_bios_ops; + pcibios_register_hba(HBA_DATA(lba_dev)); + lba_dev->lba_lock = SPIN_LOCK_UNLOCKED; + + /* + ** Set flags which depend on hw_rev + */ + if (!LBA_TR4PLUS(lba_dev)) { + lba_dev->flags |= LBA_FLAG_NO_DMA_DURING_CFG; + } +} + + + +/* +** Determine if lba should claim this chip (return 0) or not (return 1). +** If so, initialize the chip and tell other partners in crime they +** have work to do. +*/ +static int __init +lba_driver_callback(struct parisc_device *dev) +{ + struct lba_device *lba_dev; + struct pci_bus *lba_bus; + u32 func_class; + void *tmp_obj; + char *version; + + /* Read HW Rev First */ + func_class = READ_REG32(dev->hpa + LBA_FCLASS); + func_class &= 0xf; + + switch (func_class) { + case 0: version = "TR1.0"; break; + case 1: version = "TR2.0"; break; + case 2: version = "TR2.1"; break; + case 3: version = "TR2.2"; break; + case 4: version = "TR3.0"; break; + case 5: version = "TR4.0"; break; + default: version = "TR4+"; + } + + printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n", + MODULE_NAME, version, func_class & 0xf, dev->hpa); + + /* Just in case we find some prototypes... */ + if (func_class < 2) { + printk(KERN_WARNING "Can't support LBA older than TR2.1 " + "- continuing under adversity.\n"); + } + + /* + ** Tell I/O SAPIC driver we have a IRQ handler/region. + */ + tmp_obj = iosapic_register(dev->hpa + LBA_IOSAPIC_BASE); + + /* NOTE: PCI devices (e.g. 103c:1005 graphics card) which don't + ** have an IRT entry will get NULL back from iosapic code. + */ + + lba_dev = kmalloc(sizeof(struct lba_device), GFP_KERNEL); + if (NULL == lba_dev) + { + printk(KERN_ERR "lba_init_chip - couldn't alloc lba_device\n"); + return(1); + } + + memset(lba_dev, 0, sizeof(struct lba_device)); + + + /* ---------- First : initialize data we already have --------- */ + + /* + ** Need hw_rev to adjust configuration space behavior. + ** LBA_TR4PLUS macro uses hw_rev field. + */ + lba_dev->hw_rev = func_class; + + lba_dev->hba.base_addr = dev->hpa; /* faster access */ + lba_dev->hba.dev = dev; + lba_dev->iosapic_obj = tmp_obj; /* save interrupt handle */ + lba_dev->hba.iommu = sba_get_iommu(dev); /* get iommu data */ + + /* ------------ Second : initialize common stuff ---------- */ + lba_common_init(lba_dev); + + if (lba_hw_init(lba_dev)) + return(1); + + /* ---------- Third : setup I/O Port and MMIO resources --------- */ + +#ifdef __LP64__ + if (is_pdc_pat()) { + /* PDC PAT firmware uses PIOP region of GMMIO space. */ + pci_port = &lba_pat_port_ops; + + /* Go ask PDC PAT what resources this LBA has */ + lba_pat_resources(dev, lba_dev); + } else +#endif + { + /* Sprockets PDC uses NPIOP region */ + pci_port = &lba_astro_port_ops; + + /* Poke the chip a bit for /proc output */ + lba_legacy_resources(dev, lba_dev); + } + + /* + ** Tell PCI support another PCI bus was found. + ** Walks PCI bus for us too. + */ + lba_bus = lba_dev->hba.hba_bus = + pci_scan_bus(lba_dev->hba.bus_num.start, &lba_cfg_ops, (void *) lba_dev); + +#ifdef __LP64__ + if (is_pdc_pat()) { + /* assign resources to un-initialized devices */ + DBG_PAT("LBA pcibios_assign_unassigned_resources()\n"); + pcibios_assign_unassigned_resources(lba_bus); + +#ifdef DEBUG_LBA_PAT + DBG_PAT("\nLBA PIOP resource tree\n"); + lba_dump_res(&lba_dev->hba.io_space, 2); + DBG_PAT("\nLBA LMMIO resource tree\n"); + lba_dump_res(&lba_dev->hba.lmmio_space, 2); +#endif + } +#endif + + /* + ** Once PCI register ops has walked the bus, access to config + ** space is restricted. Avoids master aborts on config cycles. + ** Early LBA revs go fatal on *any* master abort. + */ + if (!LBA_TR4PLUS(lba_dev)) { + lba_dev->flags |= LBA_FLAG_SKIP_PROBE; + } + + /* Whew! Finally done! Tell services we got this one covered. */ + return 0; +} + +static struct parisc_device_id lba_tbl[] = { + { HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x782, 0xa }, + { 0, } +}; + +static struct parisc_driver lba_driver = { + name: MODULE_NAME, + id_table: lba_tbl, + probe: lba_driver_callback +}; + +/* +** One time initialization to let the world know the LBA was found. +** Must be called exactly once before pci_init(). +*/ +void __init lba_init(void) +{ + register_parisc_driver(&lba_driver); +} + +/* +** Initialize the IBASE/IMASK registers for LBA (Elroy). +** Only called from sba_iommu.c in order to route ranges (MMIO vs DMA). +** sba_iommu is responsible for locking (none needed at init time). +*/ +void +lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask) +{ + unsigned long base_addr = lba->hpa; + + imask <<= 2; /* adjust for hints - 2 more bits */ + + ASSERT((ibase & 0x003fffff) == 0); + ASSERT((imask & 0x003fffff) == 0); + + DBG("%s() ibase 0x%x imask 0x%x\n", __FUNCTION__, ibase, imask); + WRITE_REG32( imask, base_addr + LBA_IMASK); + WRITE_REG32( ibase, base_addr + LBA_IBASE); +} + diff -Nru a/drivers/parisc/led.c b/drivers/parisc/led.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/led.c Mon Nov 4 14:31:01 2002 @@ -0,0 +1,775 @@ +/* + * Chassis LCD/LED driver for HP-PARISC workstations + * + * (c) Copyright 2000 Red Hat Software + * (c) Copyright 2000 Helge Deller + * (c) Copyright 2001-2002 Helge Deller + * (c) Copyright 2001 Randolph Chung + * + * 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. + * + * TODO: + * - speed-up calculations with inlined assembler + * - interface to write to second row of LCD from /proc + */ + +#include +#include +#include /* for offsetof() */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* HZ */ +#include +#include +#include + +/* The control of the LEDs and LCDs on PARISC-machines have to be done + completely in software. The necessary calculations are done in a tasklet + which is scheduled at every timer interrupt and since the calculations + may consume relatively much CPU-time some of the calculations can be + turned off with the following variables (controlled via procfs) */ + +static int led_type = -1; +static int led_heartbeat = 1; +static int led_diskio = 1; +static int led_lanrxtx = 1; +static char lcd_text[32]; + +#if 0 +#define DPRINTK(x) printk x +#else +#define DPRINTK(x) +#endif + + +#define CALC_ADD(val, comp, add) \ + (val<=(comp/8) ? add/16 : val<=(comp/4) ? add/8 : val<=(comp/2) ? add/4 : add) + + +struct lcd_block { + unsigned char command; /* stores the command byte */ + unsigned char on; /* value for turning LED on */ + unsigned char off; /* value for turning LED off */ +}; + +/* Structure returned by PDC_RETURN_CHASSIS_INFO */ +/* NOTE: we use unsigned long:16 two times, since the following member + lcd_cmd_reg_addr needs to be 64bit aligned on 64bit PA2.0-machines */ +struct pdc_chassis_lcd_info_ret_block { + unsigned long model:16; /* DISPLAY_MODEL_XXXX */ + unsigned long lcd_width:16; /* width of the LCD in chars (DISPLAY_MODEL_LCD only) */ + char *lcd_cmd_reg_addr; /* ptr to LCD cmd-register & data ptr for LED */ + char *lcd_data_reg_addr; /* ptr to LCD data-register (LCD only) */ + unsigned int min_cmd_delay; /* delay in uS after cmd-write (LCD only) */ + unsigned char reset_cmd1; /* command #1 for writing LCD string (LCD only) */ + unsigned char reset_cmd2; /* command #2 for writing LCD string (LCD only) */ + unsigned char act_enable; /* 0 = no activity (LCD only) */ + struct lcd_block heartbeat; + struct lcd_block disk_io; + struct lcd_block lan_rcv; + struct lcd_block lan_tx; + char _pad; +}; + + +/* LCD_CMD and LCD_DATA for KittyHawk machines */ +#define KITTYHAWK_LCD_CMD (0xfffffffff0190000UL) /* 64bit-ready */ +#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD+1) + +/* lcd_info is pre-initialized to the values needed to program KittyHawk LCD's + * HP seems to have used Sharp/Hitachi HD44780 LCDs most of the time. */ +static struct pdc_chassis_lcd_info_ret_block +lcd_info __attribute__((aligned(8))) = +{ + model: DISPLAY_MODEL_LCD, + lcd_width: 16, + lcd_cmd_reg_addr: (char *) KITTYHAWK_LCD_CMD, + lcd_data_reg_addr:(char *) KITTYHAWK_LCD_DATA, + min_cmd_delay: 40, + reset_cmd1: 0x80, + reset_cmd2: 0xc0, +}; + + +/* direct access to some of the lcd_info variables */ +#define LCD_CMD_REG lcd_info.lcd_cmd_reg_addr +#define LCD_DATA_REG lcd_info.lcd_data_reg_addr +#define LED_DATA_REG lcd_info.lcd_cmd_reg_addr /* LASI & ASP only */ + + +/* ptr to LCD/LED-specific function */ +static void (*led_func_ptr) (unsigned char); + +#define LED_HASLCD 1 +#define LED_NOLCD 0 +#ifdef CONFIG_PROC_FS +static int led_proc_read(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + char *out = page; + int len; + + switch ((long)data) + { + case LED_NOLCD: + out += sprintf(out, "Heartbeat: %d\n", led_heartbeat); + out += sprintf(out, "Disk IO: %d\n", led_diskio); + out += sprintf(out, "LAN Rx/Tx: %d\n", led_lanrxtx); + break; + case LED_HASLCD: + out += sprintf(out, "%s\n", lcd_text); + break; + default: + *eof = 1; + return 0; + } + + len = out - page - off; + if (len < count) { + *eof = 1; + if (len <= 0) return 0; + } else { + len = count; + } + *start = page + off; + return len; +} + +static int led_proc_write(struct file *file, const char *buf, + unsigned long count, void *data) +{ + char *cur, lbuf[count]; + int d; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + memset(lbuf, 0, count); + + copy_from_user(lbuf, buf, count); + cur = lbuf; + + /* skip initial spaces */ + while (*cur && isspace(*cur)) + { + cur++; + } + + switch ((long)data) + { + case LED_NOLCD: + d = *cur++ - '0'; + if (d != 0 && d != 1) goto parse_error; + led_heartbeat = d; + + if (*cur++ != ' ') goto parse_error; + + d = *cur++ - '0'; + if (d != 0 && d != 1) goto parse_error; + led_diskio = d; + + if (*cur++ != ' ') goto parse_error; + + d = *cur++ - '0'; + if (d != 0 && d != 1) goto parse_error; + led_lanrxtx = d; + + break; + case LED_HASLCD: + if (*cur == 0) + { + /* reset to default */ + lcd_print("Linux " UTS_RELEASE); + } + else + { + /* chop off trailing \n.. if the user gives multiple + * \n then it's all their fault.. */ + if (*cur && cur[strlen(cur)-1] == '\n') + cur[strlen(cur)-1] = 0; + lcd_print(cur); + } + break; + default: + return 0; + } + + return count; + +parse_error: + if ((long)data == LED_NOLCD) + printk(KERN_CRIT "Parse error: expect \"n n n\" (n == 0 or 1) for heartbeat,\ndisk io and lan tx/rx indicators\n"); + return -EINVAL; +} + +static int __init led_create_procfs(void) +{ + struct proc_dir_entry *proc_pdc_root = NULL; + struct proc_dir_entry *ent; + + if (led_type == -1) return -1; + + proc_pdc_root = proc_mkdir("pdc", 0); + if (!proc_pdc_root) return -1; + proc_pdc_root->owner = THIS_MODULE; + ent = create_proc_entry("led", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root); + if (!ent) return -1; + ent->nlink = 1; + ent->data = (void *)LED_NOLCD; /* LED */ + ent->read_proc = led_proc_read; + ent->write_proc = led_proc_write; + ent->owner = THIS_MODULE; + + if (led_type == LED_HASLCD) + { + ent = create_proc_entry("lcd", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root); + if (!ent) return -1; + ent->nlink = 1; + ent->data = (void *)LED_HASLCD; /* LCD */ + ent->read_proc = led_proc_read; + ent->write_proc = led_proc_write; + ent->owner = THIS_MODULE; + } + + return 0; +} +#endif + +/* + ** + ** led_ASP_driver() + ** + */ +#define LED_DATA 0x01 /* data to shift (0:on 1:off) */ +#define LED_STROBE 0x02 /* strobe to clock data */ +static void led_ASP_driver(unsigned char leds) +{ + int i; + + leds = ~leds; + for (i = 0; i < 8; i++) { + unsigned char value; + value = (leds & 0x80) >> 7; + gsc_writeb( value, LED_DATA_REG ); + gsc_writeb( value | LED_STROBE, LED_DATA_REG ); + leds <<= 1; + } +} + + +/* + ** + ** led_LASI_driver() + ** + */ +static void led_LASI_driver(unsigned char leds) +{ + leds = ~leds; + gsc_writeb( leds, LED_DATA_REG ); +} + + +/* + ** + ** led_LCD_driver() + ** + ** The logic of the LCD driver is, that we write at every scheduled call + ** only to one of LCD_CMD_REG _or_ LCD_DATA_REG - registers. + ** That way we don't need to let this tasklet busywait for min_cmd_delay + ** milliseconds. + ** + ** TODO: check the value of "min_cmd_delay" against the value of HZ. + ** + */ +static void led_LCD_driver(unsigned char leds) +{ + static int last_index; /* 0:heartbeat, 1:disk, 2:lan_in, 3:lan_out */ + static int last_was_cmd;/* 0: CMD was written last, 1: DATA was last */ + struct lcd_block *block_ptr; + int value; + + switch (last_index) { + case 0: block_ptr = &lcd_info.heartbeat; + value = leds & LED_HEARTBEAT; + break; + case 1: block_ptr = &lcd_info.disk_io; + value = leds & LED_DISK_IO; + break; + case 2: block_ptr = &lcd_info.lan_rcv; + value = leds & LED_LAN_RCV; + break; + case 3: block_ptr = &lcd_info.lan_tx; + value = leds & LED_LAN_TX; + break; + default: /* should never happen: */ + return; + } + + if (last_was_cmd) { + /* write the value to the LCD data port */ + gsc_writeb( value ? block_ptr->on : block_ptr->off, LCD_DATA_REG ); + } else { + /* write the command-byte to the LCD command register */ + gsc_writeb( block_ptr->command, LCD_CMD_REG ); + } + + /* now update the vars for the next interrupt iteration */ + if (++last_was_cmd == 2) { /* switch between cmd & data */ + last_was_cmd = 0; + if (++last_index == 4) + last_index = 0; /* switch back to heartbeat index */ + } +} + + +/* + ** + ** led_get_net_stats() + ** + ** calculate the TX- & RX-troughput on the network interfaces in + ** the system for usage in the LED code + ** + ** (analog to dev_get_info() from net/core/dev.c) + ** + */ +static unsigned long led_net_rx_counter, led_net_tx_counter; + +static void led_get_net_stats(int addvalue) +{ +#ifdef CONFIG_NET + static unsigned long rx_total_last, tx_total_last; + unsigned long rx_total, tx_total; + struct net_device *dev; + struct net_device_stats *stats; + + rx_total = tx_total = 0; + + /* we are running as a tasklet, so locking dev_base + * for reading should be OK */ + read_lock(&dev_base_lock); + for (dev = dev_base; dev != NULL; dev = dev->next) { + if (dev->get_stats) { + stats = dev->get_stats(dev); + rx_total += stats->rx_packets; + tx_total += stats->tx_packets; + } + } + read_unlock(&dev_base_lock); + + rx_total -= rx_total_last; + tx_total -= tx_total_last; + + if (rx_total) + led_net_rx_counter += CALC_ADD(rx_total, tx_total, addvalue); + + if (tx_total) + led_net_tx_counter += CALC_ADD(tx_total, rx_total, addvalue); + + rx_total_last += rx_total; + tx_total_last += tx_total; +#endif +} + + +/* + ** + ** led_get_diskio_stats() + ** + ** calculate the disk-io througput in the system + ** (analog to linux/fs/proc/proc_misc.c) + ** + */ +static unsigned long led_diskio_counter; + +static void led_get_diskio_stats(int addvalue) +{ + static unsigned int diskio_total_last, diskio_max; + int major, disk, total; + + total = 0; + for (major = 0; major < DK_MAX_MAJOR; major++) { + for (disk = 0; disk < DK_MAX_DISK; disk++) + total += kstat.dk_drive[major][disk]; + } + total -= diskio_total_last; + + if (total) { + if (total >= diskio_max) { + led_diskio_counter += addvalue; + diskio_max = total; /* new maximum value found */ + } else + led_diskio_counter += CALC_ADD(total, diskio_max, addvalue); + } + + diskio_total_last += total; +} + + + +/* + ** led_tasklet_func() + ** + ** is scheduled at every timer interrupt from time.c and + ** updates the chassis LCD/LED + + TODO: + - display load average (older machines like 715/64 have 4 "free" LED's for that) + - optimizations + */ + +static unsigned char currentleds; /* stores current value of the LEDs */ + +#define HEARTBEAT_LEN (HZ*6/100) +#define HEARTBEAT_2ND_RANGE_START (HZ*22/100) +#define HEARTBEAT_2ND_RANGE_END (HEARTBEAT_2ND_RANGE_START + HEARTBEAT_LEN) + +static void led_tasklet_func(unsigned long unused) +{ + static unsigned int count, count_HZ; + static unsigned char lastleds; + + /* exit if not initialized */ + if (!led_func_ptr) + return; + + /* increment the local counters */ + ++count; + if (++count_HZ == HZ) + count_HZ = 0; + + if (led_heartbeat) + { + /* flash heartbeat-LED like a real heart (2 x short then a long delay) */ + if (count_HZ=HEARTBEAT_2ND_RANGE_START && count_HZ + * All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * + * + * + * HINT: + * Support of the soft power switch button may be enabled or disabled at + * runtime through the "/proc/sys/kernel/power" procfs entry. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#ifdef DEBUG +# define DPRINTK(x) printk x +#else +# define DPRINTK(x) do { } while (0) +#endif + + +/* filename in /proc which can be used to enable/disable the power switch */ +#define SYSCTL_FILENAME "sys/kernel/power" + + +#define DIAG_CODE(code) (0x14000000 + ((code)<<5)) + +/* this will go to processor.h or any other place... */ +/* taken from PCXL ERS page 82 */ +#define MFCPU_X(rDiagReg, t_ch, t_th, code) \ + (DIAG_CODE(code) + ((rDiagReg)<<21) + ((t_ch)<<16) + ((t_th)<<0) ) + +#define MTCPU(dr, gr) MFCPU_X(dr, gr, 0, 0x12) /* move value of gr to dr[dr] */ +#define MFCPU_C(dr, gr) MFCPU_X(dr, gr, 0, 0x30) /* for dr0 and dr8 only ! */ +#define MFCPU_T(dr, gr) MFCPU_X(dr, 0, gr, 0xa0) /* all dr except dr0 and dr8 */ + +#define __getDIAG(dr) ( { \ + register unsigned long __res asm("r28");\ + __asm__ __volatile__ ( \ + ".word %1\n nop\n" : "=&r" (__res) : "i" (MFCPU_T(dr,28)) \ + ); \ + __res; \ +} ) + + +static void deferred_poweroff(void *dummy) +{ + extern int cad_pid; /* from kernel/sys.c */ + if (kill_proc(cad_pid, SIGINT, 1)) { + /* just in case killing init process failed */ + machine_power_off(); + } +} + +/* + * This function gets called from interrupt context. + * As it's called within an interrupt, it wouldn't sync if we don't + * use schedule_work(). + */ + +static DECLARE_WORK(poweroff_work, deferred_poweroff, NULL); + +static void poweroff(void) +{ + static int powering_off; + + if (powering_off) + return; + + powering_off++; + schedule_work(&poweroff_work); +} + + +/* local time-counter for shutdown */ +static int shutdown_timer; + +/* check, give feedback and start shutdown after one second */ +static void process_shutdown(void) +{ + if (shutdown_timer == 0) + DPRINTK((KERN_INFO "Shutdown requested...\n")); + + shutdown_timer++; + + /* wait until the button was pressed for 1 second */ + if (shutdown_timer == HZ) { + static char msg[] = "Shutting down..."; + DPRINTK((KERN_INFO "%s\n", msg)); +#ifdef CONFIG_CHASSIS_LCD_LED + lcd_print(msg); +#endif + poweroff(); + } +} + + +/* main power switch tasklet struct (scheduled from time.c) */ +DECLARE_TASKLET_DISABLED(power_tasklet, NULL, 0); + +/* soft power switch enabled/disabled */ +#ifdef CONFIG_PROC_FS +static int pwrsw_enabled = 1; +#else +#define pwrsw_enabled (1) +#endif + +/* + * On gecko style machines (e.g. 712/xx and 715/xx) + * the power switch status is stored in Bit 0 ("the highest bit") + * of CPU diagnose register 25. + * + */ +static void gecko_tasklet_func(unsigned long unused) +{ + if (!pwrsw_enabled) + return; + + if (__getDIAG(25) & 0x80000000) { + /* power switch button not pressed or released again */ + /* Warning: Some machines do never reset this DIAG flag! */ + shutdown_timer = 0; + } else { + process_shutdown(); + } +} + + + +/* + * Check the power switch status which is read from the + * real I/O location at soft_power_reg. + * Bit 31 ("the lowest bit) is the status of the power switch. + */ + +static void polling_tasklet_func(unsigned long soft_power_reg) +{ + unsigned long current_status; + + if (!pwrsw_enabled) + return; + + current_status = gsc_readl(soft_power_reg); + if (current_status & 0x1) { + /* power switch button not pressed */ + shutdown_timer = 0; + } else { + process_shutdown(); + } +} + + +/* + * powerfail interruption handler (irq IRQ_FROM_REGION(CPU_IRQ_REGION)+2) + */ +#if 0 +static void powerfail_interrupt(int code, void *x, struct pt_regs *regs) +{ + printk(KERN_CRIT "POWERFAIL INTERRUPTION !\n"); + poweroff(); +} +#endif + + + + +/* + * /proc filesystem support + */ + +#ifdef CONFIG_SYSCTL +static int power_proc_read(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + char *out = page; + int len; + + out += sprintf(out, "Software power switch support: "); + out += sprintf(out, pwrsw_enabled ? "enabled (1)" : "disabled (0)" ); + out += sprintf(out, "\n"); + + len = out - page - off; + if (len < count) { + *eof = 1; + if (len <= 0) return 0; + } else { + len = count; + } + *start = page + off; + return len; +} + +static int power_proc_write(struct file *file, const char *buf, + unsigned long count, void *data) +{ + char *cur, lbuf[count]; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + memset(lbuf, 0, count); + + copy_from_user(lbuf, buf, count); + cur = lbuf; + + /* skip initial spaces */ + while (*cur && isspace(*cur)) + cur++; + + switch (*cur) { + case '0': pwrsw_enabled = 0; + break; + case '1': pwrsw_enabled = 1; + break; + default: printk(KERN_CRIT "/proc/" SYSCTL_FILENAME + ": Parse error: only '0' or '1' allowed!\n"); + return -EINVAL; + } /* switch() */ + + return count; +} + +static struct proc_dir_entry *ent; + +static void __init power_create_procfs(void) +{ + if (!power_tasklet.func) + return; + + ent = create_proc_entry(SYSCTL_FILENAME, S_IFREG|S_IRUGO|S_IWUSR, 0); + if (!ent) return; + + ent->nlink = 1; + ent->read_proc = power_proc_read; + ent->write_proc = power_proc_write; + ent->owner = THIS_MODULE; +} + +static void __exit power_remove_procfs(void) +{ + remove_proc_entry(SYSCTL_FILENAME, NULL); +} + +#else +#define power_create_procfs() do { } while (0) +#define power_remove_procfs() do { } while (0) +#endif /* CONFIG_SYSCTL */ + + + +/* parisc_panic_event() is called by the panic handler. + * As soon as a panic occurs, our tasklets above will not be + * executed any longer. This function then re-enables the + * soft-power switch and allows the user to switch off the system + */ +static int parisc_panic_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + /* re-enable the soft-power switch */ + pdc_soft_power_button(0); + return NOTIFY_DONE; +} + +static struct notifier_block parisc_panic_block = { + notifier_call: parisc_panic_event, + priority: INT_MAX, +}; + + +static int __init power_init(void) +{ + unsigned long ret; + unsigned long soft_power_reg = 0; + +#if 0 + request_irq( IRQ_FROM_REGION(CPU_IRQ_REGION)+2, &powerfail_interrupt, + 0, "powerfail", NULL); +#endif + + /* enable the soft power switch if possible */ + ret = pdc_soft_power_info(&soft_power_reg); + if (ret == PDC_OK) + ret = pdc_soft_power_button(1); + if (ret != PDC_OK) + soft_power_reg = -1UL; + + switch (soft_power_reg) { + case 0: printk(KERN_INFO "Gecko-style soft power switch enabled.\n"); + power_tasklet.func = gecko_tasklet_func; + break; + + case -1UL: printk(KERN_INFO "Soft power switch support not available.\n"); + return -ENODEV; + + default: printk(KERN_INFO "Soft power switch enabled, polling @ 0x%08lx.\n", + soft_power_reg); + power_tasklet.data = soft_power_reg; + power_tasklet.func = polling_tasklet_func; + } + + /* Register a call for panic conditions. */ + notifier_chain_register(&panic_notifier_list, &parisc_panic_block); + + power_create_procfs(); + tasklet_enable(&power_tasklet); + + return 0; +} + +static void __exit power_exit(void) +{ + if (!power_tasklet.func) + return; + + tasklet_disable(&power_tasklet); + notifier_chain_unregister(&panic_notifier_list, &parisc_panic_block); + power_remove_procfs(); + power_tasklet.func = NULL; + pdc_soft_power_button(0); +} + +module_init(power_init); +module_exit(power_exit); + + +MODULE_AUTHOR("Helge Deller"); +MODULE_DESCRIPTION("Soft power switch driver"); +MODULE_LICENSE("Dual BSD/GPL"); + + +EXPORT_NO_SYMBOLS; + diff -Nru a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/sba_iommu.c Mon Nov 4 14:31:02 2002 @@ -0,0 +1,2052 @@ +/* +** System Bus Adapter (SBA) I/O MMU manager +** +** (c) Copyright 2000 Grant Grundler +** (c) Copyright 2000 Hewlett-Packard Company +** +** Portions (c) 1999 Dave S. Miller (from sparc64 I/O MMU code) +** +** 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 module initializes the IOC (I/O Controller) found on B1000/C3000/ +** J5000/J7000/N-class/L-class machines and their successors. +** +** FIXME: add DMA hint support programming in both sba and lba modules. +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#undef PCI_DEBUG /* for ASSERT */ +#include +#undef PCI_DEBUG + +#include +#include +#include /* for DMA_CHUNK_SIZE */ + +#include /* for register_parisc_driver() stuff */ + +#include +#include /* for proc_runway_root */ +#include /* for PDC_MODEL_* */ + +#define MODULE_NAME "SBA" + +/* +** The number of debug flags is a clue - this code is fragile. +** Don't even think about messing with it unless you have +** plenty of 710's to sacrifice to the computer gods. :^) +*/ +#undef DEBUG_SBA_INIT +#undef DEBUG_SBA_RUN +#undef DEBUG_SBA_RUN_SG +#undef DEBUG_SBA_RESOURCE +#undef ASSERT_PDIR_SANITY +#undef DEBUG_LARGE_SG_ENTRIES +#undef DEBUG_DMB_TRAP + +#define SBA_INLINE __inline__ + +#ifdef DEBUG_SBA_INIT +#define DBG_INIT(x...) printk(x) +#else +#define DBG_INIT(x...) +#endif + +#ifdef DEBUG_SBA_RUN +#define DBG_RUN(x...) printk(x) +#else +#define DBG_RUN(x...) +#endif + +#ifdef DEBUG_SBA_RUN_SG +#define DBG_RUN_SG(x...) printk(x) +#else +#define DBG_RUN_SG(x...) +#endif + + +#ifdef DEBUG_SBA_RESOURCE +#define DBG_RES(x...) printk(x) +#else +#define DBG_RES(x...) +#endif + +/* +** The number of pdir entries to "free" before issueing +** a read to PCOM register to flush out PCOM writes. +** Interacts with allocation granularity (ie 4 or 8 entries +** allocated and free'd/purged at a time might make this +** less interesting). +*/ +#define DELAYED_RESOURCE_CNT 16 + +#define DEFAULT_DMA_HINT_REG 0 + +#define ASTRO_RUNWAY_PORT 0x582 +#define ASTRO_ROPES_PORT 0x780 + +#define IKE_MERCED_PORT 0x803 +#define IKE_ROPES_PORT 0x781 + +#define REO_MERCED_PORT 0x804 +#define REO_ROPES_PORT 0x782 + +#define REOG_MERCED_PORT 0x805 +#define REOG_ROPES_PORT 0x783 + +#define SBA_FUNC_ID 0x0000 /* function id */ +#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */ + +#define IS_ASTRO(id) \ +(((id)->hversion == ASTRO_RUNWAY_PORT) || ((id)->hversion == ASTRO_ROPES_PORT)) + +#define IS_IKE(id) \ +(((id)->hversion == IKE_MERCED_PORT) || ((id)->hversion == IKE_ROPES_PORT)) + +#define SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */ + +#define ASTRO_IOC_OFFSET 0x20000 +/* Ike's IOC's occupy functions 2 and 3 (not 0 and 1) */ +#define IKE_IOC_OFFSET(p) ((p+2)*SBA_FUNC_SIZE) + +#define IOC_CTRL 0x8 /* IOC_CTRL offset */ +#define IOC_CTRL_TC (1 << 0) /* TOC Enable */ +#define IOC_CTRL_CE (1 << 1) /* Coalesce Enable */ +#define IOC_CTRL_DE (1 << 2) /* Dillon Enable */ +#define IOC_CTRL_RM (1 << 8) /* Real Mode */ +#define IOC_CTRL_NC (1 << 9) /* Non Coherent Mode */ + +#define MAX_IOC 2 /* per Ike. Astro only has 1 */ + + +/* +** Offsets into MBIB (Function 0 on Ike and hopefully Astro) +** Firmware programs this stuff. Don't touch it. +*/ +#define IOS_DIST_BASE 0x390 +#define IOS_DIST_MASK 0x398 +#define IOS_DIST_ROUTE 0x3A0 + +#define IOS_DIRECT_BASE 0x3C0 +#define IOS_DIRECT_MASK 0x3C8 +#define IOS_DIRECT_ROUTE 0x3D0 + +/* +** Offsets into I/O TLB (Function 2 and 3 on Ike) +*/ +#define ROPE0_CTL 0x200 /* "regbus pci0" */ +#define ROPE1_CTL 0x208 +#define ROPE2_CTL 0x210 +#define ROPE3_CTL 0x218 +#define ROPE4_CTL 0x220 +#define ROPE5_CTL 0x228 +#define ROPE6_CTL 0x230 +#define ROPE7_CTL 0x238 + +#define HF_ENABLE 0x40 + + +#define IOC_IBASE 0x300 /* IO TLB */ +#define IOC_IMASK 0x308 +#define IOC_PCOM 0x310 +#define IOC_TCNFG 0x318 +#define IOC_PDIR_BASE 0x320 + +#define IOC_IOVA_SPACE_BASE 0 /* IOVA ranges start at 0 */ + +/* +** IOC supports 4/8/16/64KB page sizes (see TCNFG register) +** It's safer (avoid memory corruption) to keep DMA page mappings +** equivalently sized to VM PAGE_SIZE. +** +** We really can't avoid generating a new mapping for each +** page since the Virtual Coherence Index has to be generated +** and updated for each page. +** +** IOVP_SIZE could only be greater than PAGE_SIZE if we are +** confident the drivers really only touch the next physical +** page iff that driver instance owns it. +*/ +#define IOVP_SIZE PAGE_SIZE +#define IOVP_SHIFT PAGE_SHIFT +#define IOVP_MASK PAGE_MASK + +#define SBA_PERF_CFG 0x708 /* Performance Counter stuff */ +#define SBA_PERF_MASK1 0x718 +#define SBA_PERF_MASK2 0x730 + + +/* +** Offsets into PCI Performance Counters (functions 12 and 13) +** Controlled by PERF registers in function 2 & 3 respectively. +*/ +#define SBA_PERF_CNT1 0x200 +#define SBA_PERF_CNT2 0x208 +#define SBA_PERF_CNT3 0x210 + + +struct ioc { + unsigned long ioc_hpa; /* I/O MMU base address */ + char *res_map; /* resource map, bit == pdir entry */ + u64 *pdir_base; /* physical base address */ + + unsigned long *res_hint; /* next avail IOVP - circular search */ + spinlock_t res_lock; + unsigned long hint_mask_pdir; /* bits used for DMA hints */ + unsigned int res_bitshift; /* from the LEFT! */ + unsigned int res_size; /* size of resource map in bytes */ + unsigned int hint_shift_pdir; +#if DELAYED_RESOURCE_CNT > 0 + int saved_cnt; + struct sba_dma_pair { + dma_addr_t iova; + size_t size; + } saved[DELAYED_RESOURCE_CNT]; +#endif + +#ifdef CONFIG_PROC_FS +#define SBA_SEARCH_SAMPLE 0x100 + unsigned long avg_search[SBA_SEARCH_SAMPLE]; + unsigned long avg_idx; /* current index into avg_search */ + unsigned long used_pages; + unsigned long msingle_calls; + unsigned long msingle_pages; + unsigned long msg_calls; + unsigned long msg_pages; + unsigned long usingle_calls; + unsigned long usingle_pages; + unsigned long usg_calls; + unsigned long usg_pages; +#endif + + /* STUFF We don't need in performance path */ + unsigned int pdir_size; /* in bytes, determined by IOV Space size */ + unsigned long ibase; /* pdir IOV Space base - shared w/lba_pci */ + unsigned long imask; /* pdir IOV Space mask - shared w/lba_pci */ +}; + +struct sba_device { + struct sba_device *next; /* list of SBA's in system */ + struct parisc_device *dev; /* dev found in bus walk */ + struct parisc_device_id *iodc; /* data about dev from firmware */ + const char *name; + unsigned long sba_hpa; /* base address */ + spinlock_t sba_lock; + unsigned int flags; /* state/functionality enabled */ + unsigned int hw_rev; /* HW revision of chip */ + + unsigned int num_ioc; /* number of on-board IOC's */ + struct ioc ioc[MAX_IOC]; +}; + + +static struct sba_device *sba_list; + +static unsigned long ioc_needs_fdc = 0; + +/* Ratio of Host MEM to IOV Space size */ +static unsigned long sba_mem_ratio = 8; + +/* global count of IOMMUs in the system */ +static unsigned int global_ioc_cnt = 0; + +/* PA8700 (Piranha 2.2) bug workaround */ +static unsigned long piranha_bad_128k = 0; + +/* Looks nice and keeps the compiler happy */ +#define SBA_DEV(d) ((struct sba_device *) (d)) + + +#define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1)) + + +/************************************ +** SBA register read and write support +** +** BE WARNED: register writes are posted. +** (ie follow writes which must reach HW with a read) +** +** Superdome (in particular, REO) allows only 64-bit CSR accesses. +*/ +#define READ_REG32(addr) le32_to_cpu(__raw_readl(addr)) +#define READ_REG64(addr) le64_to_cpu(__raw_readq(addr)) +#define WRITE_REG32(val, addr) __raw_writel(cpu_to_le32(val), addr) +#define WRITE_REG64(val, addr) __raw_writeq(cpu_to_le64(val), addr) + +#ifdef __LP64__ +#define READ_REG(addr) READ_REG64(addr) +#define WRITE_REG(value, addr) WRITE_REG64(value, addr) +#else +#define READ_REG(addr) READ_REG32(addr) +#define WRITE_REG(value, addr) WRITE_REG32(value, addr) +#endif + +#ifdef DEBUG_SBA_INIT + +/* NOTE: When __LP64__ isn't defined, READ_REG64() is two 32-bit reads */ + +/** + * sba_dump_ranges - debugging only - print ranges assigned to this IOA + * @hpa: base address of the sba + * + * Print the MMIO and IO Port address ranges forwarded by an Astro/Ike/RIO + * IO Adapter (aka Bus Converter). + */ +static void +sba_dump_ranges(unsigned long hpa) +{ + DBG_INIT("SBA at 0x%lx\n", hpa); + DBG_INIT("IOS_DIST_BASE : %Lx\n", READ_REG64(hpa+IOS_DIST_BASE)); + DBG_INIT("IOS_DIST_MASK : %Lx\n", READ_REG64(hpa+IOS_DIST_MASK)); + DBG_INIT("IOS_DIST_ROUTE : %Lx\n", READ_REG64(hpa+IOS_DIST_ROUTE)); + DBG_INIT("\n"); + DBG_INIT("IOS_DIRECT_BASE : %Lx\n", READ_REG64(hpa+IOS_DIRECT_BASE)); + DBG_INIT("IOS_DIRECT_MASK : %Lx\n", READ_REG64(hpa+IOS_DIRECT_MASK)); + DBG_INIT("IOS_DIRECT_ROUTE: %Lx\n", READ_REG64(hpa+IOS_DIRECT_ROUTE)); +} + +/** + * sba_dump_tlb - debugging only - print IOMMU operating parameters + * @hpa: base address of the IOMMU + * + * Print the size/location of the IO MMU PDIR. + */ +static void +sba_dump_tlb(unsigned long hpa) +{ + DBG_INIT("IO TLB at 0x%lx\n", hpa); + DBG_INIT("IOC_IBASE : %Lx\n", READ_REG64(hpa+IOC_IBASE)); + DBG_INIT("IOC_IMASK : %Lx\n", READ_REG64(hpa+IOC_IMASK)); + DBG_INIT("IOC_TCNFG : %Lx\n", READ_REG64(hpa+IOC_TCNFG)); + DBG_INIT("IOC_PDIR_BASE: %Lx\n", READ_REG64(hpa+IOC_PDIR_BASE)); + DBG_INIT("\n"); +} +#endif + + +#ifdef ASSERT_PDIR_SANITY + +/** + * sba_dump_pdir_entry - debugging only - print one IOMMU PDIR entry + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @msg: text to print ont the output line. + * @pide: pdir index. + * + * Print one entry of the IO MMU PDIR in human readable form. + */ +static void +sba_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide) +{ + /* start printing from lowest pde in rval */ + u64 *ptr = &(ioc->pdir_base[pide & (~0U * BITS_PER_LONG)]); + unsigned long *rptr = (unsigned long *) &(ioc->res_map[(pide >>3) & ~(sizeof(unsigned long) - 1)]); + uint rcnt; + + printk(KERN_DEBUG "SBA: %s rp %p bit %d rval 0x%lx\n", + msg, + rptr, pide & (BITS_PER_LONG - 1), *rptr); + + rcnt = 0; + while (rcnt < BITS_PER_LONG) { + printk(KERN_DEBUG "%s %2d %p %016Lx\n", + (rcnt == (pide & (BITS_PER_LONG - 1))) + ? " -->" : " ", + rcnt, ptr, *ptr ); + rcnt++; + ptr++; + } + printk(KERN_DEBUG "%s", msg); +} + + +/** + * sba_check_pdir - debugging only - consistency checker + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @msg: text to print ont the output line. + * + * Verify the resource map and pdir state is consistent + */ +static int +sba_check_pdir(struct ioc *ioc, char *msg) +{ + u32 *rptr_end = (u32 *) &(ioc->res_map[ioc->res_size]); + u32 *rptr = (u32 *) ioc->res_map; /* resource map ptr */ + u64 *pptr = ioc->pdir_base; /* pdir ptr */ + uint pide = 0; + + while (rptr < rptr_end) { + u32 rval = *rptr; + int rcnt = 32; /* number of bits we might check */ + + while (rcnt) { + /* Get last byte and highest bit from that */ + u32 pde = ((u32) (((char *)pptr)[7])) << 24; + if ((rval ^ pde) & 0x80000000) + { + /* + ** BUMMER! -- res_map != pdir -- + ** Dump rval and matching pdir entries + */ + sba_dump_pdir_entry(ioc, msg, pide); + return(1); + } + rcnt--; + rval <<= 1; /* try the next bit */ + pptr++; + pide++; + } + rptr++; /* look at next word of res_map */ + } + /* It'd be nice if we always got here :^) */ + return 0; +} + + +/** + * sba_dump_sg - debugging only - print Scatter-Gather list + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @startsg: head of the SG list + * @nents: number of entries in SG list + * + * print the SG list so we can verify it's correct by hand. + */ +static void +sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents) +{ + while (nents-- > 0) { + printk(KERN_DEBUG " %d : %08lx/%05x %p/%05x\n", + nents, + (unsigned long) sg_dma_address(startsg), + sg_dma_len(startsg), + sg_virt_addr(startsg), startsg->length); + startsg++; + } +} + +#endif /* ASSERT_PDIR_SANITY */ + + + + +/************************************************************** +* +* I/O Pdir Resource Management +* +* Bits set in the resource map are in use. +* Each bit can represent a number of pages. +* LSbs represent lower addresses (IOVA's). +* +***************************************************************/ +#define PAGES_PER_RANGE 1 /* could increase this to 4 or 8 if needed */ + +/* Convert from IOVP to IOVA and vice versa. */ +#define SBA_IOVA(ioc,iovp,offset,hint_reg) ((iovp) | (offset) | ((hint_reg)<<(ioc->hint_shift_pdir))) +#define SBA_IOVP(ioc,iova) ((iova) & ioc->hint_mask_pdir) + +/* FIXME : review these macros to verify correctness and usage */ +#define PDIR_INDEX(iovp) ((iovp)>>IOVP_SHIFT) +#define MKIOVP(dma_hint,pide) (dma_addr_t)((long)(dma_hint) | ((long)(pide) << IOVP_SHIFT)) +#define MKIOVA(iovp,offset) (dma_addr_t)((long)iovp | (long)offset) + +#define RESMAP_MASK(n) (~0UL << (BITS_PER_LONG - (n))) +#define RESMAP_IDX_MASK (sizeof(unsigned long) - 1) + + +/** + * sba_search_bitmap - find free space in IO PDIR resource bitmap + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @bits_wanted: number of entries we need. + * + * Find consecutive free bits in resource bitmap. + * Each bit represents one entry in the IO Pdir. + * Cool perf optimization: search for log2(size) bits at a time. + */ +static SBA_INLINE unsigned long +sba_search_bitmap(struct ioc *ioc, unsigned long bits_wanted) +{ + unsigned long *res_ptr = ioc->res_hint; + unsigned long *res_end = (unsigned long *) &(ioc->res_map[ioc->res_size]); + unsigned long pide = ~0UL; + + ASSERT(((unsigned long) ioc->res_hint & (sizeof(unsigned long) - 1UL)) == 0); + ASSERT(res_ptr < res_end); + if (bits_wanted > (BITS_PER_LONG/2)) { + /* Search word at a time - no mask needed */ + for(; res_ptr < res_end; ++res_ptr) { + if (*res_ptr == 0) { + *res_ptr = RESMAP_MASK(bits_wanted); + pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); + pide <<= 3; /* convert to bit address */ + break; + } + } + /* point to the next word on next pass */ + res_ptr++; + ioc->res_bitshift = 0; + } else { + /* + ** Search the resource bit map on well-aligned values. + ** "o" is the alignment. + ** We need the alignment to invalidate I/O TLB using + ** SBA HW features in the unmap path. + */ + unsigned long o = 1 << get_order(bits_wanted << PAGE_SHIFT); + uint bitshiftcnt = ROUNDUP(ioc->res_bitshift, o); + unsigned long mask; + + if (bitshiftcnt >= BITS_PER_LONG) { + bitshiftcnt = 0; + res_ptr++; + } + mask = RESMAP_MASK(bits_wanted) >> bitshiftcnt; + + DBG_RES("%s() o %ld %p", __FUNCTION__, o, res_ptr); + while(res_ptr < res_end) + { + DBG_RES(" %p %lx %lx\n", res_ptr, mask, *res_ptr); + ASSERT(0 != mask); + if(0 == ((*res_ptr) & mask)) { + *res_ptr |= mask; /* mark resources busy! */ + pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map); + pide <<= 3; /* convert to bit address */ + pide += bitshiftcnt; + break; + } + mask >>= o; + bitshiftcnt += o; + if (0 == mask) { + mask = RESMAP_MASK(bits_wanted); + bitshiftcnt=0; + res_ptr++; + } + } + /* look in the same word on the next pass */ + ioc->res_bitshift = bitshiftcnt + bits_wanted; + } + + /* wrapped ? */ + if (res_end <= res_ptr) { + ioc->res_hint = (unsigned long *) ioc->res_map; + ioc->res_bitshift = 0; + } else { + ioc->res_hint = res_ptr; + } + return (pide); +} + + +/** + * sba_alloc_range - find free bits and mark them in IO PDIR resource bitmap + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @size: number of bytes to create a mapping for + * + * Given a size, find consecutive unmarked and then mark those bits in the + * resource bit map. + */ +static int +sba_alloc_range(struct ioc *ioc, size_t size) +{ + unsigned int pages_needed = size >> IOVP_SHIFT; +#ifdef CONFIG_PROC_FS + unsigned long cr_start = mfctl(16); +#endif + unsigned long pide; + + ASSERT(pages_needed); + ASSERT((pages_needed * IOVP_SIZE) <= DMA_CHUNK_SIZE); + ASSERT(pages_needed <= BITS_PER_LONG); + ASSERT(0 == (size & ~IOVP_MASK)); + + /* + ** "seek and ye shall find"...praying never hurts either... + ** ggg sacrifices another 710 to the computer gods. + */ + + pide = sba_search_bitmap(ioc, pages_needed); + if (pide >= (ioc->res_size << 3)) { + pide = sba_search_bitmap(ioc, pages_needed); + if (pide >= (ioc->res_size << 3)) + panic(__FILE__ ": I/O MMU @ %lx is out of mapping resources\n", ioc->ioc_hpa); + } + +#ifdef ASSERT_PDIR_SANITY + /* verify the first enable bit is clear */ + if(0x00 != ((u8 *) ioc->pdir_base)[pide*sizeof(u64) + 7]) { + sba_dump_pdir_entry(ioc, "sba_search_bitmap() botched it?", pide); + } +#endif + + DBG_RES("%s(%x) %d -> %lx hint %x/%x\n", + __FUNCTION__, size, pages_needed, pide, + (uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map), + ioc->res_bitshift ); + +#ifdef CONFIG_PROC_FS + { + unsigned long cr_end = mfctl(16); + unsigned long tmp = cr_end - cr_start; + /* check for roll over */ + cr_start = (cr_end < cr_start) ? -(tmp) : (tmp); + } + ioc->avg_search[ioc->avg_idx++] = cr_start; + ioc->avg_idx &= SBA_SEARCH_SAMPLE - 1; + + ioc->used_pages += pages_needed; +#endif + + return (pide); +} + + +/** + * sba_free_range - unmark bits in IO PDIR resource bitmap + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @iova: IO virtual address which was previously allocated. + * @size: number of bytes to create a mapping for + * + * clear bits in the ioc's resource map + */ +static SBA_INLINE void +sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size) +{ + unsigned long iovp = SBA_IOVP(ioc, iova); + unsigned int pide = PDIR_INDEX(iovp); + unsigned int ridx = pide >> 3; /* convert bit to byte address */ + unsigned long *res_ptr = (unsigned long *) &((ioc)->res_map[ridx & ~RESMAP_IDX_MASK]); + + int bits_not_wanted = size >> IOVP_SHIFT; + + /* 3-bits "bit" address plus 2 (or 3) bits for "byte" == bit in word */ + unsigned long m = RESMAP_MASK(bits_not_wanted) >> (pide & (BITS_PER_LONG - 1)); + + DBG_RES("%s( ,%x,%x) %x/%lx %x %p %lx\n", + __FUNCTION__, (uint) iova, size, + bits_not_wanted, m, pide, res_ptr, *res_ptr); + +#ifdef CONFIG_PROC_FS + ioc->used_pages -= bits_not_wanted; +#endif + + ASSERT(m != 0); + ASSERT(bits_not_wanted); + ASSERT((bits_not_wanted * IOVP_SIZE) <= DMA_CHUNK_SIZE); + ASSERT(bits_not_wanted <= BITS_PER_LONG); + ASSERT((*res_ptr & m) == m); /* verify same bits are set */ + *res_ptr &= ~m; +} + + +/************************************************************** +* +* "Dynamic DMA Mapping" support (aka "Coherent I/O") +* +***************************************************************/ + +#define SBA_DMA_HINT(ioc, val) ((val) << (ioc)->hint_shift_pdir) + + +typedef unsigned long space_t; +#define KERNEL_SPACE 0 + +/** + * sba_io_pdir_entry - fill in one IO PDIR entry + * @pdir_ptr: pointer to IO PDIR entry + * @sid: process Space ID + * @vba: Virtual CPU address of buffer to map + * + * SBA Mapping Routine + * + * Given a virtual address (vba, arg2) and space id, (sid, arg1) + * sba_io_pdir_entry() loads the I/O PDIR entry pointed to by + * pdir_ptr (arg0). Each IO Pdir entry consists of 8 bytes as + * shown below (MSB == bit 0): + * + * 0 19 51 55 63 + * +-+---------------------+----------------------------------+----+--------+ + * |V| U | PPN[43:12] | U | VI | + * +-+---------------------+----------------------------------+----+--------+ + * + * V == Valid Bit + * U == Unused + * PPN == Physical Page Number + * VI == Virtual Index (aka Coherent Index) + * + * The physical address fields are filled with the results of the LPA + * instruction. The virtual index field is filled with the results of + * of the LCI (Load Coherence Index) instruction. The 8 bits used for + * the virtual index are bits 12:19 of the value returned by LCI. + * + * We need to pre-swap the bytes since PCX-W is Big Endian. + */ + + +void SBA_INLINE +sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba) +{ + u64 pa; /* physical address */ + register unsigned ci; /* coherent index */ + + /* We currently only support kernel addresses. + * fdc instr below will need to reload sr1 with KERNEL_SPACE + * once we try to support direct DMA to user space. + */ + ASSERT(sid == KERNEL_SPACE); + + pa = virt_to_phys(vba); + pa &= ~4095ULL; /* clear out offset bits */ + + mtsp(sid,1); + asm("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba)); + pa |= (ci >> 12) & 0xff; /* move CI (8 bits) into lowest byte */ + + pa |= 0x8000000000000000ULL; /* set "valid" bit */ + *pdir_ptr = cpu_to_le64(pa); /* swap and store into I/O Pdir */ + + /* + * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit set + * (bit #61, big endian), we have to flush and sync every time + * IO-PDIR is changed in Ike/Astro. + */ + if (ioc_needs_fdc) { + asm volatile("fdc 0(%%sr1,%0)\n\tsync" : : "r" (pdir_ptr)); + } +} + + +/** + * sba_mark_invalid - invalidate one or more IO PDIR entries + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @iova: IO Virtual Address mapped earlier + * @byte_cnt: number of bytes this mapping covers. + * + * Marking the IO PDIR entry(ies) as Invalid and invalidate + * corresponding IO TLB entry. The Ike PCOM (Purge Command Register) + * is to purge stale entries in the IO TLB when unmapping entries. + * + * The PCOM register supports purging of multiple pages, with a minium + * of 1 page and a maximum of 2GB. Hardware requires the address be + * aligned to the size of the range being purged. The size of the range + * must be a power of 2. The "Cool perf optimization" in the + * allocation routine helps keep that true. + */ +static SBA_INLINE void +sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) +{ + u32 iovp = (u32) SBA_IOVP(ioc,iova); + + /* Even though this is a big-endian machine, the entries + ** in the iopdir are little endian. That's why we clear the byte + ** at +7 instead of at +0. + */ + int off = PDIR_INDEX(iovp)*sizeof(u64)+7; + + /* Must be non-zero and rounded up */ + ASSERT(byte_cnt > 0); + ASSERT(0 == (byte_cnt & ~IOVP_MASK)); + +#ifdef ASSERT_PDIR_SANITY + /* Assert first pdir entry is set */ + if (0x80 != (((u8 *) ioc->pdir_base)[off])) { + sba_dump_pdir_entry(ioc,"sba_mark_invalid()", PDIR_INDEX(iovp)); + } +#endif + + if (byte_cnt <= IOVP_SIZE) + { + ASSERT( off < ioc->pdir_size); + + iovp |= IOVP_SHIFT; /* set "size" field for PCOM */ + + /* + ** clear I/O PDIR entry "valid" bit + ** Do NOT clear the rest - save it for debugging. + ** We should only clear bits that have previously + ** been enabled. + */ + ((u8 *)(ioc->pdir_base))[off] = 0; + } else { + u32 t = get_order(byte_cnt) + PAGE_SHIFT; + + iovp |= t; + ASSERT(t <= 31); /* 2GB! Max value of "size" field */ + + do { + /* verify this pdir entry is enabled */ + ASSERT(0x80 == (((u8 *) ioc->pdir_base)[off] & 0x80)); + /* clear I/O Pdir entry "valid" bit first */ + ((u8 *)(ioc->pdir_base))[off] = 0; + off += sizeof(u64); + byte_cnt -= IOVP_SIZE; + } while (byte_cnt > 0); + } + + WRITE_REG(iovp, ioc->ioc_hpa+IOC_PCOM); +} + +/** + * sba_dma_supported - PCI driver can query DMA support + * @dev: instance of PCI owned by the driver that's asking + * @mask: number of address bits this PCI device can handle + * + * See Documentation/DMA-mapping.txt + */ +static int +sba_dma_supported( struct pci_dev *dev, u64 mask) +{ + if (dev == NULL) { + printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n"); + BUG(); + return(0); + } + + dev->dma_mask = mask; /* save it */ + + /* only support 32-bit PCI devices - no DAC support (yet) */ + return((int) (mask == 0xffffffff)); +} + + +/** + * sba_map_single - map one buffer and return IOVA for DMA + * @dev: instance of PCI owned by the driver that's asking. + * @addr: driver buffer to map. + * @size: number of bytes to map in driver buffer. + * @direction: R/W or both. + * + * See Documentation/DMA-mapping.txt + */ +static dma_addr_t +sba_map_single(struct pci_dev *dev, void *addr, size_t size, int direction) +{ + struct ioc *ioc; + unsigned long flags; + dma_addr_t iovp; + dma_addr_t offset; + u64 *pdir_start; + int pide; + + ASSERT(size > 0); + ASSERT(size <= DMA_CHUNK_SIZE); + + ASSERT(dev->sysdata); + ioc = GET_IOC(dev); + ASSERT(ioc); + + /* save offset bits */ + offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK; + + /* round up to nearest IOVP_SIZE */ + size = (size + offset + ~IOVP_MASK) & IOVP_MASK; + + spin_lock_irqsave(&ioc->res_lock, flags); +#ifdef ASSERT_PDIR_SANITY + sba_check_pdir(ioc,"Check before sba_map_single()"); +#endif + +#ifdef CONFIG_PROC_FS + ioc->msingle_calls++; + ioc->msingle_pages += size >> IOVP_SHIFT; +#endif + pide = sba_alloc_range(ioc, size); + iovp = (dma_addr_t) pide << IOVP_SHIFT; + + DBG_RUN("%s() 0x%p -> 0x%lx", + __FUNCTION__, addr, (long) iovp | offset); + + pdir_start = &(ioc->pdir_base[pide]); + + while (size > 0) { + ASSERT(((u8 *)pdir_start)[7] == 0); /* verify availability */ + sba_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long) addr); + + DBG_RUN(" pdir 0x%p %02x%02x%02x%02x%02x%02x%02x%02x\n", + pdir_start, + (u8) (((u8 *) pdir_start)[7]), + (u8) (((u8 *) pdir_start)[6]), + (u8) (((u8 *) pdir_start)[5]), + (u8) (((u8 *) pdir_start)[4]), + (u8) (((u8 *) pdir_start)[3]), + (u8) (((u8 *) pdir_start)[2]), + (u8) (((u8 *) pdir_start)[1]), + (u8) (((u8 *) pdir_start)[0]) + ); + + addr += IOVP_SIZE; + size -= IOVP_SIZE; + pdir_start++; + } + /* form complete address */ +#ifdef ASSERT_PDIR_SANITY + sba_check_pdir(ioc,"Check after sba_map_single()"); +#endif + spin_unlock_irqrestore(&ioc->res_lock, flags); + return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG); +} + + +/** + * sba_unmap_single - unmap one IOVA and free resources + * @dev: instance of PCI owned by the driver that's asking. + * @iova: IOVA of driver buffer previously mapped. + * @size: number of bytes mapped in driver buffer. + * @direction: R/W or both. + * + * See Documentation/DMA-mapping.txt + */ +static void +sba_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, int direction) +{ + struct ioc *ioc; +#if DELAYED_RESOURCE_CNT > 0 + struct sba_dma_pair *d; +#endif + unsigned long flags; + dma_addr_t offset; + + ASSERT(dev->sysdata); + ioc = GET_IOC(dev); + ASSERT(ioc); + + offset = iova & ~IOVP_MASK; + + DBG_RUN("%s() iovp 0x%lx/%x\n", + __FUNCTION__, (long) iova, size); + + iova ^= offset; /* clear offset bits */ + size += offset; + size = ROUNDUP(size, IOVP_SIZE); + + spin_lock_irqsave(&ioc->res_lock, flags); + +#ifdef CONFIG_PROC_FS + ioc->usingle_calls++; + ioc->usingle_pages += size >> IOVP_SHIFT; +#endif + +#if DELAYED_RESOURCE_CNT > 0 + d = &(ioc->saved[ioc->saved_cnt]); + d->iova = iova; + d->size = size; + if (++(ioc->saved_cnt) >= DELAYED_RESOURCE_CNT) { + int cnt = ioc->saved_cnt; + while (cnt--) { + sba_mark_invalid(ioc, d->iova, d->size); + sba_free_range(ioc, d->iova, d->size); + d--; + } + ioc->saved_cnt = 0; + READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ + } +#else /* DELAYED_RESOURCE_CNT == 0 */ + sba_mark_invalid(ioc, iova, size); + sba_free_range(ioc, iova, size); + READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ +#endif /* DELAYED_RESOURCE_CNT == 0 */ + spin_unlock_irqrestore(&ioc->res_lock, flags); + + /* XXX REVISIT for 2.5 Linux - need syncdma for zero-copy support. + ** For Astro based systems this isn't a big deal WRT performance. + ** As long as 2.4 kernels copyin/copyout data from/to userspace, + ** we don't need the syncdma. The issue here is I/O MMU cachelines + ** are *not* coherent in all cases. May be hwrev dependent. + ** Need to investigate more. + asm volatile("syncdma"); + */ +} + + +/** + * sba_alloc_consistent - allocate/map shared mem for DMA + * @hwdev: instance of PCI owned by the driver that's asking. + * @size: number of bytes mapped in driver buffer. + * @dma_handle: IOVA of new buffer. + * + * See Documentation/DMA-mapping.txt + */ +static void * +sba_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) +{ + void *ret; + + if (!hwdev) { + /* only support PCI */ + *dma_handle = 0; + return 0; + } + + ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size)); + + if (ret) { + memset(ret, 0, size); + *dma_handle = sba_map_single(hwdev, ret, size, 0); + } + + return ret; +} + + +/** + * sba_free_consistent - free/unmap shared mem for DMA + * @hwdev: instance of PCI owned by the driver that's asking. + * @size: number of bytes mapped in driver buffer. + * @vaddr: virtual address IOVA of "consistent" buffer. + * @dma_handler: IO virtual address of "consistent" buffer. + * + * See Documentation/DMA-mapping.txt + */ +static void +sba_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) +{ + sba_unmap_single(hwdev, dma_handle, size, 0); + free_pages((unsigned long) vaddr, get_order(size)); +} + + +/* +** Since 0 is a valid pdir_base index value, can't use that +** to determine if a value is valid or not. Use a flag to indicate +** the SG list entry contains a valid pdir index. +*/ +#define PIDE_FLAG 0x80000000UL + +#ifdef DEBUG_LARGE_SG_ENTRIES +int dump_run_sg = 0; +#endif + + +/** + * sba_fill_pdir - write allocated SG entries into IO PDIR + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @startsg: list of IOVA/size pairs + * @nents: number of entries in startsg list + * + * Take preprocessed SG list and write corresponding entries + * in the IO PDIR. + */ + +static SBA_INLINE int +sba_fill_pdir( + struct ioc *ioc, + struct scatterlist *startsg, + int nents) +{ + struct scatterlist *dma_sg = startsg; /* pointer to current DMA */ + int n_mappings = 0; + u64 *pdirp = 0; + unsigned long dma_offset = 0; + + dma_sg--; + while (nents-- > 0) { + int cnt = sg_dma_len(startsg); + sg_dma_len(startsg) = 0; + +#ifdef DEBUG_LARGE_SG_ENTRIES + if (dump_run_sg) + printk(KERN_DEBUG " %2d : %08lx/%05x %p/%05x\n", + nents, + (unsigned long) sg_dma_address(startsg), cnt, + sg_virt_address(startsg), startsg->length + ); +#else + DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n", + nents, + (unsigned long) sg_dma_address(startsg), cnt, + sg_virt_addr(startsg), startsg->length + ); +#endif + /* + ** Look for the start of a new DMA stream + */ + if (sg_dma_address(startsg) & PIDE_FLAG) { + u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG; + dma_offset = (unsigned long) pide & ~IOVP_MASK; + sg_dma_address(startsg) = 0; + dma_sg++; + sg_dma_address(dma_sg) = pide; + pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]); + n_mappings++; + } + + /* + ** Look for a VCONTIG chunk + */ + if (cnt) { + unsigned long vaddr = (unsigned long) sg_virt_addr(startsg); + ASSERT(pdirp); + + /* Since multiple Vcontig blocks could make up + ** one DMA stream, *add* cnt to dma_len. + */ + sg_dma_len(dma_sg) += cnt; + cnt += dma_offset; + dma_offset=0; /* only want offset on first chunk */ + cnt = ROUNDUP(cnt, IOVP_SIZE); +#ifdef CONFIG_PROC_FS + ioc->msg_pages += cnt >> IOVP_SHIFT; +#endif + do { + sba_io_pdir_entry(pdirp, KERNEL_SPACE, vaddr); + vaddr += IOVP_SIZE; + cnt -= IOVP_SIZE; + pdirp++; + } while (cnt > 0); + } + startsg++; + } +#ifdef DEBUG_LARGE_SG_ENTRIES + dump_run_sg = 0; +#endif + return(n_mappings); +} + + +/* +** Two address ranges are DMA contiguous *iff* "end of prev" and +** "start of next" are both on a page boundry. +** +** (shift left is a quick trick to mask off upper bits) +*/ +#define DMA_CONTIG(__X, __Y) \ + (((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL) + + +/** + * sba_coalesce_chunks - preprocess the SG list + * @ioc: IO MMU structure which owns the pdir we are interested in. + * @startsg: list of IOVA/size pairs + * @nents: number of entries in startsg list + * + * First pass is to walk the SG list and determine where the breaks are + * in the DMA stream. Allocates PDIR entries but does not fill them. + * Returns the number of DMA chunks. + * + * Doing the fill seperate from the coalescing/allocation keeps the + * code simpler. Future enhancement could make one pass through + * the sglist do both. + */ +static SBA_INLINE int +sba_coalesce_chunks( struct ioc *ioc, + struct scatterlist *startsg, + int nents) +{ + struct scatterlist *vcontig_sg; /* VCONTIG chunk head */ + unsigned long vcontig_len; /* len of VCONTIG chunk */ + unsigned long vcontig_end; + struct scatterlist *dma_sg; /* next DMA stream head */ + unsigned long dma_offset, dma_len; /* start/len of DMA stream */ + int n_mappings = 0; + + while (nents > 0) { + unsigned long vaddr = (unsigned long) sg_virt_addr(startsg); + + /* + ** Prepare for first/next DMA stream + */ + dma_sg = vcontig_sg = startsg; + dma_len = vcontig_len = vcontig_end = startsg->length; + vcontig_end += vaddr; + dma_offset = vaddr & ~IOVP_MASK; + + /* PARANOID: clear entries */ + sg_dma_address(startsg) = 0; + sg_dma_len(startsg) = 0; + + /* + ** This loop terminates one iteration "early" since + ** it's always looking one "ahead". + */ + while (--nents > 0) { + unsigned long vaddr; /* tmp */ + + startsg++; + + /* PARANOID: clear entries */ + sg_dma_address(startsg) = 0; + sg_dma_len(startsg) = 0; + + /* catch brokenness in SCSI layer */ + ASSERT(startsg->length <= DMA_CHUNK_SIZE); + + /* + ** First make sure current dma stream won't + ** exceed DMA_CHUNK_SIZE if we coalesce the + ** next entry. + */ + if (((dma_len + dma_offset + startsg->length + ~IOVP_MASK) & IOVP_MASK) > DMA_CHUNK_SIZE) + break; + + /* + ** Then look for virtually contiguous blocks. + ** PARISC needs to associate a virtual address + ** with each IO address mapped. The CPU cache is + ** virtually tagged and the IOMMU uses part + ** of the virtual address to participate in + ** CPU cache coherency. + ** + ** append the next transaction? + */ + vaddr = (unsigned long) sg_virt_addr(startsg); + if (vcontig_end == vaddr) + { + vcontig_len += startsg->length; + vcontig_end += startsg->length; + dma_len += startsg->length; + continue; + } + +#ifdef DEBUG_LARGE_SG_ENTRIES + dump_run_sg = (vcontig_len > IOVP_SIZE); +#endif + + /* + ** Not virtually contigous. + ** Terminate prev chunk. + ** Start a new chunk. + ** + ** Once we start a new VCONTIG chunk, dma_offset + ** can't change. And we need the offset from the first + ** chunk - not the last one. Ergo Successive chunks + ** must start on page boundaries and dove tail + ** with it's predecessor. + */ + sg_dma_len(vcontig_sg) = vcontig_len; + + vcontig_sg = startsg; + vcontig_len = startsg->length; + + /* + ** 3) do the entries end/start on page boundaries? + ** Don't update vcontig_end until we've checked. + */ + if (DMA_CONTIG(vcontig_end, vaddr)) + { + vcontig_end = vcontig_len + vaddr; + dma_len += vcontig_len; + continue; + } else { + break; + } + } + + /* + ** End of DMA Stream + ** Terminate last VCONTIG block. + ** Allocate space for DMA stream. + */ + sg_dma_len(vcontig_sg) = vcontig_len; + dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK; + ASSERT(dma_len <= DMA_CHUNK_SIZE); + sg_dma_address(dma_sg) = + PIDE_FLAG + | (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT) + | dma_offset; + n_mappings++; + } + + return n_mappings; +} + + +/** + * sba_map_sg - map Scatter/Gather list + * @dev: instance of PCI owned by the driver that's asking. + * @sglist: array of buffer/length pairs + * @nents: number of entries in list + * @direction: R/W or both. + * + * See Documentation/DMA-mapping.txt + */ +static int +sba_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +{ + struct ioc *ioc; + int coalesced, filled = 0; + unsigned long flags; + + DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents); + + ASSERT(dev->sysdata); + ioc = GET_IOC(dev); + ASSERT(ioc); + + /* Fast path single entry scatterlists. */ + if (nents == 1) { + sg_dma_address(sglist) = sba_map_single(dev, + (void *)sg_virt_addr(sglist), + sglist->length, direction); + sg_dma_len(sglist) = sglist->length; + return 1; + } + + spin_lock_irqsave(&ioc->res_lock, flags); + +#ifdef ASSERT_PDIR_SANITY + if (sba_check_pdir(ioc,"Check before sba_map_sg()")) + { + sba_dump_sg(ioc, sglist, nents); + panic("Check before sba_map_sg()"); + } +#endif + +#ifdef CONFIG_PROC_FS + ioc->msg_calls++; +#endif + + /* + ** First coalesce the chunks and allocate I/O pdir space + ** + ** If this is one DMA stream, we can properly map using the + ** correct virtual address associated with each DMA page. + ** w/o this association, we wouldn't have coherent DMA! + ** Access to the virtual address is what forces a two pass algorithm. + */ + coalesced = sba_coalesce_chunks(ioc, sglist, nents); + + /* + ** Program the I/O Pdir + ** + ** map the virtual addresses to the I/O Pdir + ** o dma_address will contain the pdir index + ** o dma_len will contain the number of bytes to map + ** o address contains the virtual address. + */ + filled = sba_fill_pdir(ioc, sglist, nents); + +#ifdef ASSERT_PDIR_SANITY + if (sba_check_pdir(ioc,"Check after sba_map_sg()")) + { + sba_dump_sg(ioc, sglist, nents); + panic("Check after sba_map_sg()\n"); + } +#endif + + spin_unlock_irqrestore(&ioc->res_lock, flags); + + ASSERT(coalesced == filled); + DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled); + + return filled; +} + + +/** + * sba_unmap_sg - unmap Scatter/Gather list + * @dev: instance of PCI owned by the driver that's asking. + * @sglist: array of buffer/length pairs + * @nents: number of entries in list + * @direction: R/W or both. + * + * See Documentation/DMA-mapping.txt + */ +static void +sba_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +{ + struct ioc *ioc; +#ifdef ASSERT_PDIR_SANITY + unsigned long flags; +#endif + + DBG_RUN_SG("%s() START %d entries, %p,%x\n", + __FUNCTION__, nents, sg_virt_addr(sglist), sglist->length); + + ASSERT(dev->sysdata); + ioc = GET_IOC(dev); + ASSERT(ioc); + +#ifdef CONFIG_PROC_FS + ioc->usg_calls++; +#endif + +#ifdef ASSERT_PDIR_SANITY + spin_lock_irqsave(&ioc->res_lock, flags); + sba_check_pdir(ioc,"Check before sba_unmap_sg()"); + spin_unlock_irqrestore(&ioc->res_lock, flags); +#endif + + while (sg_dma_len(sglist) && nents--) { + + sba_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction); +#ifdef CONFIG_PROC_FS + ioc->usg_pages += ((sg_dma_address(sglist) & ~IOVP_MASK) + sg_dma_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT; + ioc->usingle_calls--; /* kluge since call is unmap_sg() */ +#endif + ++sglist; + } + + DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__, nents); + +#ifdef ASSERT_PDIR_SANITY + spin_lock_irqsave(&ioc->res_lock, flags); + sba_check_pdir(ioc,"Check after sba_unmap_sg()"); + spin_unlock_irqrestore(&ioc->res_lock, flags); +#endif + +} + +static struct pci_dma_ops sba_ops = { + sba_dma_supported, + sba_alloc_consistent, /* allocate cacheable host mem */ + sba_free_consistent, /* release cacheable host mem */ + sba_map_single, + sba_unmap_single, + sba_map_sg, + sba_unmap_sg, + NULL, /* dma_sync_single */ + NULL /* dma_sync_sg */ +}; + + +/************************************************************************** +** +** SBA PAT PDC support +** +** o call pdc_pat_cell_module() +** o store ranges in PCI "resource" structures +** +**************************************************************************/ + +static void +sba_get_pat_resources(struct sba_device *sba_dev) +{ +#if 0 +/* +** TODO/REVISIT/FIXME: support for directed ranges requires calls to +** PAT PDC to program the SBA/LBA directed range registers...this +** burden may fall on the LBA code since it directly supports the +** PCI subsystem. It's not clear yet. - ggg +*/ +PAT_MOD(mod)->mod_info.mod_pages = PAT_GET_MOD_PAGES(temp); + FIXME : ??? +PAT_MOD(mod)->mod_info.dvi = PAT_GET_DVI(temp); + Tells where the dvi bits are located in the address. +PAT_MOD(mod)->mod_info.ioc = PAT_GET_IOC(temp); + FIXME : ??? +#endif +} + + +/************************************************************** +* +* Initialization and claim +* +***************************************************************/ +#define PIRANHA_ADDR_MASK 0x00160000UL /* bit 17,18,20 */ +#define PIRANHA_ADDR_VAL 0x00060000UL /* bit 17,18 on */ +static void * +sba_alloc_pdir(unsigned int pdir_size) +{ + unsigned long pdir_base; + unsigned long pdir_order = get_order(pdir_size); + + pdir_base = __get_free_pages(GFP_KERNEL, pdir_order); + if (NULL == (void *) pdir_base) + panic("sba_ioc_init() could not allocate I/O Page Table\n"); + + /* If this is not PA8700 (PCX-W2) + ** OR newer than ver 2.2 + ** OR in a system that doesn't need VINDEX bits from SBA, + ** + ** then we aren't exposed to the HW bug. + */ + if ( ((boot_cpu_data.pdc.cpuid >> 5) & 0x7f) != 0x13 + || (boot_cpu_data.pdc.versions > 0x202) + || (boot_cpu_data.pdc.capabilities & 0x08L) ) + return (void *) pdir_base; + + /* + * PA8700 (PCX-W2, aka piranha) silent data corruption fix + * + * An interaction between PA8700 CPU (Ver 2.2 or older) and + * Ike/Astro can cause silent data corruption. This is only + * a problem if the I/O PDIR is located in memory such that + * (little-endian) bits 17 and 18 are on and bit 20 is off. + * + * Since the max IO Pdir size is 2MB, by cleverly allocating the + * right physical address, we can either avoid (IOPDIR <= 1MB) + * or minimize (2MB IO Pdir) the problem if we restrict the + * IO Pdir to a maximum size of 2MB-128K (1902K). + * + * Because we always allocate 2^N sized IO pdirs, either of the + * "bad" regions will be the last 128K if at all. That's easy + * to test for. + * + */ + if (pdir_order <= (19-12)) { + if (((virt_to_phys(pdir_base)+pdir_size-1) & PIRANHA_ADDR_MASK) == PIRANHA_ADDR_VAL) { + /* allocate a new one on 512k alignment */ + unsigned long new_pdir = __get_free_pages(GFP_KERNEL, (19-12)); + /* release original */ + free_pages(pdir_base, pdir_order); + + pdir_base = new_pdir; + + /* release excess */ + while (pdir_order < (19-12)) { + new_pdir += pdir_size; + free_pages(new_pdir, pdir_order); + pdir_order +=1; + pdir_size <<=1; + } + } + } else { + /* + ** 1MB or 2MB Pdir + ** Needs to be aligned on an "odd" 1MB boundary. + */ + unsigned long new_pdir = __get_free_pages(GFP_KERNEL, pdir_order+1); /* 2 or 4MB */ + + /* release original */ + free_pages( pdir_base, pdir_order); + + /* release first 1MB */ + free_pages(new_pdir, 20-12); + + pdir_base = new_pdir + 1024*1024; + + if (pdir_order > (20-12)) { + /* + ** 2MB Pdir. + ** + ** Flag tells init_bitmap() to mark bad 128k as used + ** and to reduce the size by 128k. + */ + piranha_bad_128k = 1; + + new_pdir += 3*1024*1024; + /* release last 1MB */ + free_pages(new_pdir, 20-12); + + /* release unusable 128KB */ + free_pages(new_pdir - 128*1024 , 17-12); + + pdir_size -= 128*1024; + } + } + + memset((void *) pdir_base, 0, pdir_size); + return (void *) pdir_base; +} + + +static void +sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num) +{ + /* lba_set_iregs() is in arch/parisc/kernel/lba_pci.c */ + extern void lba_set_iregs(struct parisc_device *, u32, u32); + + u32 iova_space_size, iova_space_mask; + int pdir_size, iov_order; + unsigned long physmem; + struct parisc_device *lba; + + /* + ** Determine IOVA Space size from memory size. + ** + ** Ideally, PCI drivers would register the maximum number + ** of DMA they can have outstanding for each device they + ** own. Next best thing would be to guess how much DMA + ** can be outstanding based on PCI Class/sub-class. Both + ** methods still require some "extra" to support PCI + ** Hot-Plug/Removal of PCI cards. (aka PCI OLARD). + ** + ** While we have 32-bits "IOVA" space, top two 2 bits are used + ** for DMA hints - ergo only 30 bits max. + */ + + physmem = num_physpages << PAGE_SHIFT; + iova_space_size = (u32) (physmem/(sba_mem_ratio*global_ioc_cnt)); + + /* limit IOVA space size to 1MB-1GB */ + if (iova_space_size < 1024*1024) { + iova_space_size = 1024*1024; + } +#ifdef __LP64__ + else if (iova_space_size > 512*1024*1024) { + iova_space_size = 512*1024*1024; + } +#endif + + /* + ** iova space must be log2() in size. + ** thus, pdir/res_map will also be log2(). + ** PIRANHA BUG: Exception is when IO Pdir is 2MB (gets reduced) + */ + iov_order = get_order(iova_space_size >> (IOVP_SHIFT-PAGE_SHIFT)); + ASSERT(iov_order <= (30 - IOVP_SHIFT)); /* iova_space_size <= 1GB */ + ASSERT(iov_order >= (20 - IOVP_SHIFT)); /* iova_space_size >= 1MB */ + iova_space_size = 1 << (iov_order + IOVP_SHIFT); + + ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64); + + ASSERT(pdir_size < 4*1024*1024); /* max pdir size == 2MB */ + + /* Verify it's a power of two */ + ASSERT((1 << get_order(pdir_size)) == (pdir_size >> PAGE_SHIFT)); + + DBG_INIT("%s() hpa 0x%lx mem %dMB IOV %dMB (%d bits) PDIR size 0x%0x\n", + __FUNCTION__, ioc->ioc_hpa, (int) (physmem>>20), + iova_space_size>>20, iov_order + PAGE_SHIFT, pdir_size); + + /* FIXME : DMA HINTs not used */ + ioc->hint_shift_pdir = iov_order + PAGE_SHIFT; + ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT)); + + ioc->pdir_base = sba_alloc_pdir(pdir_size); + + DBG_INIT("%s() pdir %p size %x hint_shift_pdir %x hint_mask_pdir %lx\n", + __FUNCTION__, ioc->pdir_base, pdir_size, + ioc->hint_shift_pdir, ioc->hint_mask_pdir); + + ASSERT((((unsigned long) ioc->pdir_base) & PAGE_MASK) == (unsigned long) ioc->pdir_base); + WRITE_REG64(virt_to_phys(ioc->pdir_base), ioc->ioc_hpa + IOC_PDIR_BASE); + + /* build IMASK for IOC and Elroy */ + iova_space_mask = 0xffffffff; + iova_space_mask <<= (iov_order + PAGE_SHIFT); + + /* + ** On C3000 w/512MB mem, HP-UX 10.20 reports: + ** ibase=0, imask=0xFE000000, size=0x2000000. + */ + ioc->ibase = IOC_IOVA_SPACE_BASE | 1; /* bit 0 == enable bit */ + ioc->imask = iova_space_mask; /* save it */ + + DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n", + __FUNCTION__, ioc->ibase, ioc->imask); + + /* + ** FIXME: Hint registers are programmed with default hint + ** values during boot, so hints should be sane even if we + ** can't reprogram them the way drivers want. + */ + + /* + ** setup Elroy IBASE/IMASK registers as well. + */ + for (lba = sba->child; lba; lba = lba->sibling) { + int rope_num = (lba->hpa >> 13) & 0xf; + if (rope_num >> 3 == ioc_num) + lba_set_iregs(lba, ioc->ibase, ioc->imask); + } + + /* + ** Program the IOC's ibase and enable IOVA translation + */ + WRITE_REG(ioc->ibase, ioc->ioc_hpa+IOC_IBASE); + WRITE_REG(ioc->imask, ioc->ioc_hpa+IOC_IMASK); + + /* Set I/O PDIR Page size to 4K */ + WRITE_REG(0, ioc->ioc_hpa+IOC_TCNFG); + + /* + ** Clear I/O TLB of any possible entries. + ** (Yes. This is a bit paranoid...but so what) + */ + WRITE_REG(0 | 31, ioc->ioc_hpa+IOC_PCOM); + + DBG_INIT("%s() DONE\n", __FUNCTION__); +} + + + +/************************************************************************** +** +** SBA initialization code (HW and SW) +** +** o identify SBA chip itself +** o initialize SBA chip modes (HardFail) +** o initialize SBA chip modes (HardFail) +** o FIXME: initialize DMA hints for reasonable defaults +** +**************************************************************************/ + +static void +sba_hw_init(struct sba_device *sba_dev) +{ + int i; + int num_ioc; + u64 ioc_ctl; + + ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL); + DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->", + __FUNCTION__, sba_dev->sba_hpa, ioc_ctl); + ioc_ctl &= ~(IOC_CTRL_RM | IOC_CTRL_NC | IOC_CTRL_CE); + ioc_ctl |= IOC_CTRL_TC; /* Astro: firmware enables this */ + + WRITE_REG(ioc_ctl, sba_dev->sba_hpa+IOC_CTRL); + +#ifdef DEBUG_SBA_INIT + ioc_ctl = READ_REG64(sba_dev->sba_hpa+IOC_CTRL); + DBG_INIT(" 0x%Lx\n", ioc_ctl); +#endif + + if (IS_ASTRO(sba_dev->iodc)) { + /* PAT_PDC (L-class) also reports the same goofy base */ + sba_dev->ioc[0].ioc_hpa = ASTRO_IOC_OFFSET; + num_ioc = 1; + } else { + sba_dev->ioc[0].ioc_hpa = sba_dev->ioc[1].ioc_hpa = 0; + num_ioc = 2; + } + + sba_dev->num_ioc = num_ioc; + for (i = 0; i < num_ioc; i++) { + sba_dev->ioc[i].ioc_hpa += sba_dev->sba_hpa + IKE_IOC_OFFSET(i); + + /* + ** Make sure the box crashes if we get any errors on a rope. + */ + WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE0_CTL); + WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE1_CTL); + WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE2_CTL); + WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE3_CTL); + WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE4_CTL); + WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE5_CTL); + WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE6_CTL); + WRITE_REG(HF_ENABLE, sba_dev->ioc[i].ioc_hpa + ROPE7_CTL); + + /* flush out the writes */ + READ_REG(sba_dev->ioc[i].ioc_hpa + ROPE7_CTL); + + sba_ioc_init(sba_dev->dev, &(sba_dev->ioc[i]), i); + } +} + +static void +sba_common_init(struct sba_device *sba_dev) +{ + int i; + + /* add this one to the head of the list (order doesn't matter) + ** This will be useful for debugging - especially if we get coredumps + */ + sba_dev->next = sba_list; + sba_list = sba_dev; + + for(i=0; i< sba_dev->num_ioc; i++) { + int res_size; +#ifdef DEBUG_DMB_TRAP + extern void iterate_pages(unsigned long , unsigned long , + void (*)(pte_t * , unsigned long), + unsigned long ); + void set_data_memory_break(pte_t * , unsigned long); +#endif + /* resource map size dictated by pdir_size */ + res_size = sba_dev->ioc[i].pdir_size/sizeof(u64); /* entries */ + + /* Second part of PIRANHA BUG */ + if (piranha_bad_128k) { + res_size -= (128*1024)/sizeof(u64); + } + + res_size >>= 3; /* convert bit count to byte count */ + DBG_INIT("%s() res_size 0x%x\n", + __FUNCTION__, res_size); + + sba_dev->ioc[i].res_size = res_size; + sba_dev->ioc[i].res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size)); + +#ifdef DEBUG_DMB_TRAP + iterate_pages( sba_dev->ioc[i].res_map, res_size, + set_data_memory_break, 0); +#endif + + if (NULL == sba_dev->ioc[i].res_map) + { + panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__ ); + } + + memset(sba_dev->ioc[i].res_map, 0, res_size); + /* next available IOVP - circular search */ + sba_dev->ioc[i].res_hint = (unsigned long *) + &(sba_dev->ioc[i].res_map[L1_CACHE_BYTES]); + +#ifdef ASSERT_PDIR_SANITY + /* Mark first bit busy - ie no IOVA 0 */ + sba_dev->ioc[i].res_map[0] = 0x80; + sba_dev->ioc[i].pdir_base[0] = 0xeeffc0addbba0080ULL; +#endif + + /* Third (and last) part of PIRANHA BUG */ + if (piranha_bad_128k) { + /* region from +1408K to +1536 is un-usable. */ + + int idx_start = (1408*1024/sizeof(u64)) >> 3; + int idx_end = (1536*1024/sizeof(u64)) >> 3; + long *p_start = (long *) &(sba_dev->ioc[i].res_map[idx_start]); + long *p_end = (long *) &(sba_dev->ioc[i].res_map[idx_end]); + + /* mark that part of the io pdir busy */ + while (p_start < p_end) + *p_start++ = -1; + + } + +#ifdef DEBUG_DMB_TRAP + iterate_pages( sba_dev->ioc[i].res_map, res_size, + set_data_memory_break, 0); + iterate_pages( sba_dev->ioc[i].pdir_base, sba_dev->ioc[i].pdir_size, + set_data_memory_break, 0); +#endif + + DBG_INIT("%s() %d res_map %x %p\n", + __FUNCTION__, i, res_size, sba_dev->ioc[i].res_map); + } + + sba_dev->sba_lock = SPIN_LOCK_UNLOCKED; + ioc_needs_fdc = boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC; + +#ifdef DEBUG_SBA_INIT + /* + * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit set + * (bit #61, big endian), we have to flush and sync every time + * IO-PDIR is changed in Ike/Astro. + */ + if (boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC) { + printk(KERN_INFO MODULE_NAME " FDC/SYNC required.\n"); + } else { + printk(KERN_INFO MODULE_NAME " IOC has cache coherent PDIR.\n"); + } +#endif +} + +#ifdef CONFIG_PROC_FS +static int sba_proc_info(char *buf, char **start, off_t offset, int len) +{ + struct sba_device *sba_dev = sba_list; + struct ioc *ioc = &sba_dev->ioc[0]; /* FIXME: Multi-IOC support! */ + int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */ + unsigned long i = 0, avg = 0, min, max; + + sprintf(buf, "%s rev %d.%d\n", + sba_dev->name, + (sba_dev->hw_rev & 0x7) + 1, + (sba_dev->hw_rev & 0x18) >> 3 + ); + sprintf(buf, "%sIO PDIR size : %d bytes (%d entries)\n", + buf, + (int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */ + total_pages); + + sprintf(buf, "%sIO PDIR entries : %ld free %ld used (%d%%)\n", buf, + total_pages - ioc->used_pages, ioc->used_pages, + (int) (ioc->used_pages * 100 / total_pages)); + + sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", + buf, ioc->res_size, ioc->res_size << 3); /* 8 bits per byte */ + + min = max = ioc->avg_search[0]; + for (i = 0; i < SBA_SEARCH_SAMPLE; i++) { + avg += ioc->avg_search[i]; + if (ioc->avg_search[i] > max) max = ioc->avg_search[i]; + if (ioc->avg_search[i] < min) min = ioc->avg_search[i]; + } + avg /= SBA_SEARCH_SAMPLE; + sprintf(buf, "%s Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n", + buf, min, avg, max); + + sprintf(buf, "%spci_map_single(): %12ld calls %12ld pages (avg %d/1000)\n", + buf, ioc->msingle_calls, ioc->msingle_pages, + (int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls)); + + /* KLUGE - unmap_sg calls unmap_single for each mapped page */ + min = ioc->usingle_calls; + max = ioc->usingle_pages - ioc->usg_pages; + sprintf(buf, "%spci_unmap_single: %12ld calls %12ld pages (avg %d/1000)\n", + buf, min, max, + (int) ((max * 1000)/min)); + + sprintf(buf, "%spci_map_sg() : %12ld calls %12ld pages (avg %d/1000)\n", + buf, ioc->msg_calls, ioc->msg_pages, + (int) ((ioc->msg_pages * 1000)/ioc->msg_calls)); + + sprintf(buf, "%spci_unmap_sg() : %12ld calls %12ld pages (avg %d/1000)\n", + buf, ioc->usg_calls, ioc->usg_pages, + (int) ((ioc->usg_pages * 1000)/ioc->usg_calls)); + + return strlen(buf); +} + +#if 0 +/* XXX too much output - exceeds 4k limit and needs to be re-written */ +static int +sba_resource_map(char *buf, char **start, off_t offset, int len) +{ + struct sba_device *sba_dev = sba_list; + struct ioc *ioc = &sba_dev->ioc[0]; /* FIXME: Mutli-IOC suppoer! */ + unsigned int *res_ptr = (unsigned int *)ioc->res_map; + int i; + + buf[0] = '\0'; + for(i = 0; i < (ioc->res_size / sizeof(unsigned int)); ++i, ++res_ptr) { + if ((i & 7) == 0) + strcat(buf,"\n "); + sprintf(buf, "%s %08x", buf, *res_ptr); + } + strcat(buf, "\n"); + + return strlen(buf); +} +#endif /* 0 */ +#endif /* CONFIG_PROC_FS */ + +static struct parisc_device_id sba_tbl[] = { + { HPHW_IOA, HVERSION_REV_ANY_ID, ASTRO_RUNWAY_PORT, 0xb }, + { HPHW_BCPORT, HVERSION_REV_ANY_ID, IKE_MERCED_PORT, 0xc }, + { HPHW_BCPORT, HVERSION_REV_ANY_ID, REO_MERCED_PORT, 0xc }, + { HPHW_BCPORT, HVERSION_REV_ANY_ID, REOG_MERCED_PORT, 0xc }, +/* These two entries commented out because we don't find them in a + * buswalk yet. If/when we do, they would cause us to think we had + * many more SBAs then we really do. + * { HPHW_BCPORT, HVERSION_REV_ANY_ID, ASTRO_ROPES_PORT, 0xc }, + * { HPHW_BCPORT, HVERSION_REV_ANY_ID, IKE_ROPES_PORT, 0xc }, + */ + { 0, } +}; + +int sba_driver_callback(struct parisc_device *); + +static struct parisc_driver sba_driver = { + name: MODULE_NAME, + id_table: sba_tbl, + probe: sba_driver_callback, +}; + +/* +** Determine if lba should claim this chip (return 0) or not (return 1). +** If so, initialize the chip and tell other partners in crime they +** have work to do. +*/ +int +sba_driver_callback(struct parisc_device *dev) +{ + struct sba_device *sba_dev; + u32 func_class; + int i; + char *version; + +#ifdef DEBUG_SBA_INIT + sba_dump_ranges(dev->hpa); +#endif + + /* Read HW Rev First */ + func_class = READ_REG(dev->hpa + SBA_FCLASS); + + if (IS_ASTRO(&dev->id)) { + unsigned long fclass; + static char astro_rev[]="Astro ?.?"; + + /* Astro is broken...Read HW Rev First */ + fclass = READ_REG(dev->hpa); + + astro_rev[6] = '1' + (char) (fclass & 0x7); + astro_rev[8] = '0' + (char) ((fclass & 0x18) >> 3); + version = astro_rev; + + } else if (IS_IKE(&dev->id)) { + static char ike_rev[]="Ike rev ?"; + + ike_rev[8] = '0' + (char) (func_class & 0xff); + version = ike_rev; + } else { + static char reo_rev[]="REO rev ?"; + + reo_rev[8] = '0' + (char) (func_class & 0xff); + version = reo_rev; + } + + if (!global_ioc_cnt) { + global_ioc_cnt = count_parisc_driver(&sba_driver); + + /* Only Astro has one IOC per SBA */ + if (!IS_ASTRO(&dev->id)) + global_ioc_cnt *= 2; + } + + printk(KERN_INFO "%s found %s at 0x%lx\n", + MODULE_NAME, version, dev->hpa); + +#ifdef DEBUG_SBA_INIT + sba_dump_tlb(dev->hpa); +#endif + + sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL); + if (NULL == sba_dev) { + printk(KERN_ERR MODULE_NAME " - couldn't alloc sba_device\n"); + return(1); + } + + dev->sysdata = (void *) sba_dev; + memset(sba_dev, 0, sizeof(struct sba_device)); + + for(i=0; iioc[i].res_lock)); + + sba_dev->dev = dev; + sba_dev->hw_rev = func_class; + sba_dev->iodc = &dev->id; + sba_dev->name = dev->name; + sba_dev->sba_hpa = dev->hpa; /* faster access */ + + sba_get_pat_resources(sba_dev); + sba_hw_init(sba_dev); + sba_common_init(sba_dev); + + hppa_dma_ops = &sba_ops; + +#ifdef CONFIG_PROC_FS + if (IS_ASTRO(&dev->id)) { + create_proc_info_entry("Astro", 0, proc_runway_root, sba_proc_info); + } else if (IS_IKE(&dev->id)) { + create_proc_info_entry("Ike", 0, proc_runway_root, sba_proc_info); + } else { + create_proc_info_entry("Reo", 0, proc_runway_root, sba_proc_info); + } +#if 0 + create_proc_info_entry("bitmap", 0, proc_runway_root, sba_resource_map); +#endif +#endif + return 0; +} + +/* +** One time initialization to let the world know the SBA was found. +** This is the only routine which is NOT static. +** Must be called exactly once before pci_init(). +*/ +void __init sba_init(void) +{ + register_parisc_driver(&sba_driver); +} + + +/** + * sba_get_iommu - Assign the iommu pointer for the pci bus controller. + * @dev: The parisc device. + * + * This function searches through the registerd IOMMU's and returns the + * appropriate IOMMU data for the given parisc PCI controller. + */ +void * sba_get_iommu(struct parisc_device *pci_hba) +{ + struct sba_device *sba = (struct sba_device *) pci_hba->parent->sysdata; + char t = pci_hba->parent->id.hw_type; + int iocnum = (pci_hba->hw_path >> 3); /* rope # */ + + if ((t!=HPHW_IOA) && (t!=HPHW_BCPORT)) + BUG(); + + return &(sba->ioc[iocnum]); +} diff -Nru a/drivers/parisc/superio.c b/drivers/parisc/superio.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/superio.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,542 @@ +/* National Semiconductor NS87560UBD Super I/O controller used in + * HP [BCJ]x000 workstations. + * + * This chip is a horrid piece of engineering, and National + * denies any knowledge of its existence. Thus no datasheet is + * available off www.national.com. + * + * (C) Copyright 2000 Linuxcare, Inc. + * (C) Copyright 2000 Linuxcare Canada, Inc. + * (C) Copyright 2000 Martin K. Petersen + * (C) Copyright 2000 Alex deVries + * (C) Copyright 2001 John Marvin + * + * 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. + * + * The initial version of this is by Martin Peterson. Alex deVries + * has spent a bit of time trying to coax it into working. + * + * Major changes to get basic interrupt infrastructure working to + * hopefully be able to support all SuperIO devices. Currently + * works with serial. -- John Marvin + */ + + +/* NOTES: + * + * Function 0 is an IDE controller. It is identical to a PC87415 IDE + * controller (and identifies itself as such). + * + * Function 1 is a "Legacy I/O" controller. Under this function is a + * whole mess of legacy I/O peripherals. Of course, HP hasn't enabled + * all the functionality in hardware, but the following is available: + * + * Two 16550A compatible serial controllers + * An IEEE 1284 compatible parallel port + * A floppy disk controller + * + * Function 2 is a USB controller. + * + * We must be incredibly careful during initialization. Since all + * interrupts are routed through function 1 (which is not allowed by + * the PCI spec), we need to program the PICs on the legacy I/O port + * *before* we attempt to set up IDE and USB. @#$!& + * + * According to HP, devices are only enabled by firmware if they have + * a physical device connected. + * + * Configuration register bits: + * 0x5A: FDC, SP1, IDE1, SP2, IDE2, PAR, Reserved, P92 + * 0x5B: RTC, 8259, 8254, DMA1, DMA2, KBC, P61, APM + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct superio_device sio_dev = { + iosapic_irq: -1 +}; + + +#undef DEBUG_INIT + +void +superio_inform_irq(int irq) +{ + if (sio_dev.iosapic_irq != -1) { + printk(KERN_ERR "SuperIO: superio_inform_irq called twice! (more than one SuperIO?)\n"); + BUG(); + return; + } + + sio_dev.iosapic_irq = irq; +} + +static void +superio_interrupt(int irq, void *devp, struct pt_regs *regs) +{ + struct superio_device *sio = (struct superio_device *)devp; + u8 results; + u8 local_irq; + + /* Poll the 8259 to see if there's an interrupt. */ + outb (OCW3_POLL,IC_PIC1+0); + + results = inb(IC_PIC1+0); + + if ((results & 0x80) == 0) { +#ifndef CONFIG_SMP + /* HACK: need to investigate why this happens if SMP enabled */ + BUG(); /* This shouldn't happen */ +#endif + return; + } + + /* Check to see which device is interrupting */ + + local_irq = results & 0x0f; + + if (local_irq == 2 || local_irq > 7) { + printk(KERN_ERR "SuperIO: slave interrupted!\n"); + BUG(); + return; + } + + if (local_irq == 7) { + + /* Could be spurious. Check in service bits */ + + outb(OCW3_ISR,IC_PIC1+0); + results = inb(IC_PIC1+0); + if ((results & 0x80) == 0) { /* if ISR7 not set: spurious */ + printk(KERN_WARNING "SuperIO: spurious interrupt!\n"); + return; + } + } + + /* Call the appropriate device's interrupt */ + + do_irq(&sio->irq_region->action[local_irq], + sio->irq_region->data.irqbase + local_irq, + regs); + + /* set EOI */ + + outb((OCW2_SEOI|local_irq),IC_PIC1 + 0); + return; +} + +/* Initialize Super I/O device */ + +static void __devinit +superio_init(struct superio_device *sio) +{ + struct pci_dev *pdev = sio->lio_pdev; + u16 word; + u8 i; + + if (!pdev || sio->iosapic_irq == -1) { + printk(KERN_ERR "All SuperIO functions not found!\n"); + BUG(); + return; + } + + printk (KERN_INFO "SuperIO: Found NS87560 Legacy I/O device at %s (IRQ %i) \n", + pdev->slot_name,sio->iosapic_irq); + + /* Find our I/O devices */ + pci_read_config_word (pdev, SIO_SP1BAR, &sio->sp1_base); + sio->sp1_base &= ~1; + printk (KERN_INFO "SuperIO: Serial port 1 at 0x%x\n", sio->sp1_base); + + pci_read_config_word (pdev, SIO_SP2BAR, &sio->sp2_base); + sio->sp2_base &= ~1; + printk (KERN_INFO "SuperIO: Serial port 2 at 0x%x\n", sio->sp2_base); + + pci_read_config_word (pdev, SIO_PPBAR, &sio->pp_base); + sio->pp_base &= ~1; + printk (KERN_INFO "SuperIO: Parallel port at 0x%x\n", sio->pp_base); + + pci_read_config_word (pdev, SIO_FDCBAR, &sio->fdc_base); + sio->fdc_base &= ~1; + printk (KERN_INFO "SuperIO: Floppy controller at 0x%x\n", sio->fdc_base); + pci_read_config_word (pdev, SIO_ACPIBAR, &sio->acpi_base); + sio->acpi_base &= ~1; + printk (KERN_INFO "SuperIO: ACPI at 0x%x\n", sio->acpi_base); + + request_region (IC_PIC1, 0x1f, "pic1"); + request_region (IC_PIC2, 0x1f, "pic2"); + request_region (sio->acpi_base, 0x1f, "acpi"); + + /* Enable the legacy I/O function */ + pci_read_config_word (pdev, PCI_COMMAND, &word); + word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO; + pci_write_config_word (pdev, PCI_COMMAND, word); + pci_set_master (pdev); + + /* Next project is programming the onboard interrupt + * controllers. PDC hasn't done this for us, since it's using + * polled I/O. + */ + + /* Set PIC interrupts to edge triggered */ + pci_write_config_byte (pdev, TRIGGER_1, 0x0); + pci_write_config_byte (pdev, TRIGGER_2, 0x0); + + /* Disable all interrupt routing */ + for (i = IR_LOW ; i < IR_HIGH ; i++) + pci_write_config_byte (pdev, i, 0x0); + + /* PIC1 Initialization Command Word register programming */ + outb (0x11,IC_PIC1+0); /* ICW1: ICW4 write req | ICW1 */ + outb (0x00,IC_PIC1+1); /* ICW2: N/A */ + outb (0x04,IC_PIC1+1); /* ICW3: Cascade */ + outb (0x01,IC_PIC1+1); /* ICW4: x86 mode */ + + /* PIC1 Program Operational Control Words */ + outb (0xff,IC_PIC1+1); /* OCW1: Mask all interrupts */ + outb (0xc2,IC_PIC1+0); /* OCW2: priority (3-7,0-2) */ + + /* PIC2 Initialization Command Word register programming */ + outb (0x11,IC_PIC2+0); /* ICW1: ICW4 write req | ICW1 */ + outb (0x00,IC_PIC2+1); /* ICW2: N/A */ + outb (0x02,IC_PIC2+1); /* ICW3: Slave ID code */ + outb (0x01,IC_PIC2+1); /* ICW4: x86 mode */ + + /* Program Operational Control Words */ + outb (0xff,IC_PIC1+1); /* OCW1: Mask all interrupts */ + outb (0x68,IC_PIC1+0); /* OCW3: OCW3 select | ESMM | SMM */ + + /* Write master mask reg */ + + outb (0xff,IC_PIC1+1); + + /* Set up interrupt routing */ + + pci_write_config_byte (pdev, IR_USB, 0x10); /* USB on IRQ1 */ + pci_write_config_byte (pdev, IR_SER, 0x43); /* SP1 on IRQ3, SP2 on IRQ4 */ + pci_write_config_byte (pdev, IR_PFD, 0x65); /* PAR on IRQ5, FDC on IRQ6 */ + pci_write_config_byte (pdev, IR_IDE, 0x07); /* IDE1 on IRQ7 */ + + /* Set USB and IDE to level triggered interrupts, rest to edge */ + pci_write_config_byte (pdev, TRIGGER_1, 0x82); /* IRQ 1 and 7 */ + + /* Setup USB power regulation */ + outb(1, sio->acpi_base + USB_REG_CR); + if (inb(sio->acpi_base + USB_REG_CR) & 1) + printk(KERN_INFO "SuperIO: USB regulator enabled\n"); + else + printk(KERN_ERR "USB regulator not initialized!\n"); + + pci_enable_device(pdev); + + if (request_irq(sio->iosapic_irq,superio_interrupt,SA_INTERRUPT, + "SuperIO",(void *)sio)) { + + printk(KERN_ERR "SuperIO: could not get irq\n"); + BUG(); + return; + } + + sio->iosapic_irq_enabled = 1; + +} + +static void +superio_disable_irq(void *dev, int local_irq) +{ + u8 r8; + + if ((local_irq < 1) || (local_irq == 2) || (local_irq > 7)) { + printk(KERN_ERR "SuperIO: Illegal irq number.\n"); + BUG(); + return; + } + + /* Mask interrupt */ + + r8 = inb(IC_PIC1+1); + r8 |= (1 << local_irq); + outb (r8,IC_PIC1+1); +} + +static void +superio_enable_irq(void *dev, int local_irq) +{ + struct superio_device *sio = (struct superio_device *)dev; + u8 r8; + + if ((local_irq < 1) || (local_irq == 2) || (local_irq > 7)) { + printk(KERN_ERR "SuperIO: Illegal irq number.\n"); + BUG(); + return; + } + + /* + * It's possible that we haven't initialized the legacy IO + * function yet. If not, do it now. + */ + + if (!sio->iosapic_irq_enabled) + superio_init(sio); + + /* Unmask interrupt */ + + r8 = inb(IC_PIC1+1); + r8 &= ~(1 << local_irq); + outb (r8,IC_PIC1+1); +} + +static void +superio_mask_irq(void *dev, int local_irq) +{ + BUG(); +} + +static void +superio_unmask_irq(void *dev, int local_irq) +{ + BUG(); +} + +static struct irq_region_ops superio_irq_ops = { + disable_irq: superio_disable_irq, + enable_irq: superio_enable_irq, + mask_irq: superio_mask_irq, + unmask_irq: superio_unmask_irq +}; + +#ifdef DEBUG_INIT +static unsigned short expected_device[3] = { + PCI_DEVICE_ID_NS_87415, + PCI_DEVICE_ID_NS_87560_LIO, + PCI_DEVICE_ID_NS_87560_USB +}; +#endif + +int superio_fixup_irq(struct pci_dev *pcidev) +{ + int local_irq; + +#ifdef DEBUG_INIT + int fn; + fn = PCI_FUNC(pcidev->devfn); + + /* Verify the function number matches the expected device id. */ + if (expected_device[fn] != pcidev->device) { + BUG(); + return -1; + } + printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %p\n", + pcidev->slot_name, + pcidev->vendor, pcidev->device, + __builtin_return_address(0)); +#endif + + if (!sio_dev.irq_region) { + /* Allocate an irq region for SuperIO devices */ + sio_dev.irq_region = alloc_irq_region(SUPERIO_NIRQS, + &superio_irq_ops, + "SuperIO", (void *) &sio_dev); + if (!sio_dev.irq_region) { + printk(KERN_WARNING "SuperIO: alloc_irq_region failed\n"); + return -1; + } + } + + /* + * We don't allocate a SuperIO irq for the legacy IO function, + * since it is a "bridge". Instead, we will allocate irq's for + * each legacy device as they are initialized. + */ + + switch(pcidev->device) { + case PCI_DEVICE_ID_NS_87415: /* Function 0 */ + local_irq = IDE_IRQ; + break; + case PCI_DEVICE_ID_NS_87560_LIO: /* Function 1 */ + sio_dev.lio_pdev = pcidev; /* save for later initialization */ + return -1; + case PCI_DEVICE_ID_NS_87560_USB: /* Function 2 */ + local_irq = USB_IRQ; + break; + default: + local_irq = -1; + BUG(); + break; + } + + return(sio_dev.irq_region->data.irqbase + local_irq); +} + +void __devinit +superio_serial_init(void) +{ +#ifdef CONFIG_SERIAL + struct serial_struct *serial; + int retval; + + if (!sio_dev.irq_region) + return; /* superio not present */ + + if (!sio_dev.iosapic_irq_enabled) + superio_init(&sio_dev); + + serial = kmalloc(2 * sizeof (struct serial_struct), GFP_KERNEL); + + if (!serial) { + printk(KERN_WARNING "SuperIO: Could not get memory for serial struct.\n"); + return; + } + + memset(serial, 0, 2 * sizeof (struct serial_struct)); + + serial->type = PORT_16550A; + serial->line = 0; + serial->port = sio_dev.sp1_base; + serial->port_high = 0; + serial->irq = sio_dev.irq_region->data.irqbase + SP1_IRQ; + serial->io_type = SERIAL_IO_PORT; + serial->flags = 0; + serial->xmit_fifo_size = 16; + serial->custom_divisor = 0; + serial->baud_base = 115200; + + retval = register_serial(serial); + if (retval < 0) { + printk(KERN_WARNING "SuperIO: Register Serial #0 failed.\n"); + kfree (serial); + return; + } + + serial++; + + serial->type = PORT_16550A; + serial->line = 1; + serial->port = sio_dev.sp2_base; + serial->port_high = 0; + serial->irq = sio_dev.irq_region->data.irqbase + SP2_IRQ; + serial->io_type = SERIAL_IO_PORT; + serial->flags = 0; + serial->xmit_fifo_size = 16; + serial->custom_divisor = 0; + serial->baud_base = 115200; + + retval = register_serial(serial); + if (retval < 0) + printk(KERN_WARNING "SuperIO: Register Serial #1 failed.\n"); +#endif /* CONFIG_SERIAL */ +} + +EXPORT_SYMBOL(superio_serial_init); + + +#ifdef CONFIG_PARPORT_PC +void __devinit +superio_parport_init(void) +{ + if (!sio_dev.irq_region) + return; /* superio not present */ + + if (!sio_dev.iosapic_irq_enabled) + superio_init(&sio_dev); + + if (!parport_pc_probe_port(sio_dev.pp_base, + 0 /*base_hi*/, + sio_dev.irq_region->data.irqbase + PAR_IRQ, + PARPORT_DMA_NONE /* dma */, + NULL /*struct pci_dev* */)) + + printk(KERN_WARNING "SuperIO: Probing parallel port failed.\n"); +} + +EXPORT_SYMBOL(superio_parport_init); +#endif /* CONFIG_PARPORT_PC */ + + +int +superio_get_ide_irq(void) +{ + if (sio_dev.irq_region) + return sio_dev.irq_region->data.irqbase + IDE_IRQ; + else + return 0; +} + +EXPORT_SYMBOL(superio_get_ide_irq); + +static int __devinit superio_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ +#ifdef DEBUG_INIT + printk("superio_probe(%s) ven 0x%x dev 0x%x sv 0x%x sd 0x%x class 0x%x\n", + dev->slot_name, + dev->vendor, dev->device, + dev->subsystem_vendor, dev->subsystem_device, + dev->class); +/* +** superio_probe(00:0e.0) ven 0x100b dev 0x2 sv 0x0 sd 0x0 class 0x1018a +** superio_probe(00:0e.1) ven 0x100b dev 0xe sv 0x0 sd 0x0 class 0x68000 +** superio_probe(00:0e.2) ven 0x100b dev 0x12 sv 0x0 sd 0x0 class 0xc0310 +*/ +#endif + + /* superio_fixup_irq(dev); */ + + if (dev->device == PCI_DEVICE_ID_NS_87560_LIO) { +#ifdef CONFIG_PARPORT_PC + superio_parport_init(); +#endif +#ifdef CONFIG_SERIAL + superio_serial_init(); +#endif + /* REVISIT : superio_fdc_init() ? */ + return 0; + } else { + /* don't claim this device; let whatever either driver + * do it + */ + return -1; + } +} + +static struct pci_device_id superio_tbl[] __devinitdata = { + { PCI_VENDOR_ID_NS, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, } +}; + +static struct pci_driver superio_driver = { + name: "SuperIO", + id_table: superio_tbl, + probe: superio_probe, +}; + +static int __init superio_modinit(void) +{ + return pci_module_init(&superio_driver); +} + +static void __exit superio_exit(void) +{ + pci_unregister_driver(&superio_driver); +} + +module_init(superio_modinit); +module_exit(superio_exit); diff -Nru a/drivers/parisc/wax.c b/drivers/parisc/wax.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/wax.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,141 @@ +/* + * WAX Device Driver + * + * (c) Copyright 2000 The Puffin Group Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * by Helge Deller + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "gsc.h" + +#define WAX_GSC_IRQ 7 /* Hardcoded Interrupt for GSC */ +#define WAX_GSC_NMI_IRQ 29 + +static int wax_choose_irq(struct parisc_device *dev) +{ + int irq = -1; + + switch (dev->id.sversion) { + case 0x73: irq = 30; break; /* HIL */ + case 0x8c: irq = 25; break; /* RS232 */ + case 0x90: irq = 21; break; /* WAX EISA BA */ + } + + return irq; +} + +static void __init +wax_init_irq(struct busdevice *wax) +{ + unsigned long base = wax->hpa; + + /* Stop WAX barking for a bit */ + gsc_writel(0x00000000, base+OFFSET_IMR); + + /* clear pending interrupts */ + (volatile u32) gsc_readl(base+OFFSET_IRR); + + /* We're not really convinced we want to reset the onboard + * devices. Firmware does it for us... + */ + + /* Resets */ +// gsc_writel(0xFFFFFFFF, base+0x1000); /* HIL */ +// gsc_writel(0xFFFFFFFF, base+0x2000); /* RS232-B on Wax */ + + /* Ok we hit it on the head with a hammer, our Dog is now + ** comatose and muzzled. Devices will now unmask WAX + ** interrupts as they are registered as irq's in the WAX range. + */ +} + +int __init +wax_init_chip(struct parisc_device *dev) +{ + struct busdevice *wax; + struct gsc_irq gsc_irq; + int irq, ret; + + wax = kmalloc(sizeof(struct busdevice), GFP_KERNEL); + if (!wax) + return -ENOMEM; + + wax->name = "Wax"; + wax->hpa = dev->hpa; + + wax->version = 0; /* gsc_readb(wax->hpa+WAX_VER); */ + printk(KERN_INFO "%s at 0x%lx found.\n", wax->name, wax->hpa); + + /* Stop wax hissing for a bit */ + wax_init_irq(wax); + + /* the IRQ wax should use */ + irq = gsc_claim_irq(&gsc_irq, WAX_GSC_IRQ); + if (irq < 0) { + printk(KERN_ERR "%s(): cannot get GSC irq\n", + __FUNCTION__); + kfree(wax); + return -EBUSY; + } + + ret = request_irq(gsc_irq.irq, busdev_barked, 0, "wax", wax); + if (ret < 0) { + kfree(wax); + return ret; + } + + /* Save this for debugging later */ + wax->parent_irq = gsc_irq.irq; + wax->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data; + + /* enable IRQ's for devices below WAX */ + gsc_writel(wax->eim, wax->hpa + OFFSET_IAR); + + /* Done init'ing, register this driver */ + ret = gsc_common_irqsetup(dev, wax); + if (ret) { + kfree(wax); + return ret; + } + + fixup_child_irqs(dev, wax->busdev_region->data.irqbase, + wax_choose_irq); + /* On 715-class machines, Wax EISA is a sibling of Wax, not a child. */ + if (dev->parent->id.hw_type != HPHW_IOA) { + fixup_child_irqs(dev->parent, wax->busdev_region->data.irqbase, + wax_choose_irq); + } + + return ret; +} + +static struct parisc_device_id wax_tbl[] = { + { HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008e }, + { 0, } +}; + +MODULE_DEVICE_TABLE(parisc, wax_tbl); + +struct parisc_driver wax_driver = { + name: "Wax", + id_table: wax_tbl, + probe: wax_init_chip, +}; diff -Nru a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c --- a/drivers/parport/parport_gsc.c Mon Nov 4 14:31:02 2002 +++ b/drivers/parport/parport_gsc.c Mon Nov 4 14:31:02 2002 @@ -7,7 +7,7 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * by Helge Deller + * (C) 1999-2001 by Helge Deller * * * based on parport_pc.c by @@ -36,9 +36,9 @@ #include #include #include +#include #include -#include #include #include #include @@ -47,6 +47,7 @@ MODULE_AUTHOR("Helge Deller "); MODULE_DESCRIPTION("HP-PARISC PC-style parallel port driver"); MODULE_SUPPORTED_DEVICE("integrated PC-style parallel port"); +MODULE_LICENSE("GPL"); /* @@ -347,13 +348,6 @@ struct parport tmp; struct parport *p = &tmp; -#if 1 -#warning Take this out when region handling works again, -#else - if (check_region(base, 3)) - return NULL; -#endif - priv = kmalloc (sizeof (struct parport_gsc_private), GFP_KERNEL); if (!priv) { printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base); @@ -430,12 +424,6 @@ printk("]\n"); parport_proc_register(p); - request_region (p->base, 3, p->name); - if (p->size > 3) - request_region (p->base + 3, p->size - 3, p->name); - if (p->modes & PARPORT_MODE_ECP) - request_region (p->base_hi, 3, p->name); - if (p->irq != PARPORT_IRQ_NONE) { if (request_irq (p->irq, parport_gsc_interrupt, 0, p->name, p)) { @@ -465,62 +453,56 @@ static int __initdata parport_count; -static int __init parport_init_chip(struct hp_device *d, struct pa_iodc_driver *dri) +static int __devinit parport_init_chip(struct parisc_device *dev) { unsigned long port; - int irq; - - irq = busdevice_alloc_irq(d); - if (!irq) { - printk(KERN_DEBUG "IRQ not found for parallel device at 0x%p\n", d->hpa); - return -ENODEV; + if (!dev->irq) { + printk("IRQ not found for parallel device at 0x%lx\n", dev->hpa); + return -ENODEV; } - port = ((unsigned long) d->hpa) + PARPORT_GSC_OFFSET; + port = dev->hpa + PARPORT_GSC_OFFSET; - /* - some older machines with ASP-chip don't support the enhanced parport modes - */ - if (!pdc_add_valid( (void *)(port+4))) { - /* Initialize bidirectional-mode (0x10) & data-tranfer-mode #1 (0x20) */ - printk(KERN_DEBUG "%s: initialize bidirectional-mode.\n", __FUNCTION__); - parport_writeb ( (0x10 + 0x20), port + 4); + /* some older machines with ASP-chip don't support + * the enhanced parport modes. + */ + if (boot_cpu_data.cpu_type > pcxt && !pdc_add_valid(port+4)) { + + /* Initialize bidirectional-mode (0x10) & data-tranfer-mode #1 (0x20) */ + printk("%s: initialize bidirectional-mode.\n", __FUNCTION__); + parport_writeb ( (0x10 + 0x20), port + 4); + } else { - printk(KERN_DEBUG "%s: enhanced parport-modes not supported.\n", __FUNCTION__); + printk("%s: enhanced parport-modes not supported.\n", __FUNCTION__); } - if (parport_gsc_probe_port(port, 0, - irq, /* PARPORT_IRQ_NONE */ - PARPORT_DMA_NONE, NULL)) - parport_count++; + if (parport_gsc_probe_port(port, 0, dev->irq, + /* PARPORT_IRQ_NONE */ PARPORT_DMA_NONE, NULL)) + parport_count++; return 0; } -static struct pa_iodc_driver parport_drivers_for[] __initdata = { - {HPHW_FIO, 0x0, 0x0, 0x74, 0x0, 0, /* 715/64 */ - DRIVER_CHECK_SVERSION + DRIVER_CHECK_HWTYPE, - "parallel device", "HP 7xx - Series", (void *) parport_init_chip}, - { 0 } +static struct parisc_device_id parport_tbl[] = { + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x74 }, + { 0, } }; -int __init parport_gsc_init(void) -{ - parport_count = 0; - - register_driver(parport_drivers_for); - - return 0; -} +MODULE_DEVICE_TABLE(parisc, parport_tbl); +static struct parisc_driver parport_driver = { + name: "Parallel", + id_table: parport_tbl, + probe: parport_init_chip, +}; -static int __init parport_gsc_init_module(void) -{ - return !parport_gsc_init(); +int __devinit parport_gsc_init(void) +{ + return register_parisc_driver(&parport_driver); } -static void __exit parport_gsc_exit_module(void) +static void __devexit parport_gsc_exit(void) { struct parport *p = parport_enumerate(), *tmp; while (p) { @@ -532,11 +514,6 @@ free_dma(p->dma); if (p->irq != PARPORT_IRQ_NONE) free_irq(p->irq, p); - release_region(p->base, 3); - if (p->size > 3) - release_region(p->base + 3, p->size - 3); - if (p->modes & PARPORT_MODE_ECP) - release_region(p->base_hi, 3); parport_proc_unregister(p); if (priv->dma_buf) pci_free_consistent(priv->dev, PAGE_SIZE, @@ -548,7 +525,8 @@ } p = tmp; } + unregister_parisc_driver(&parport_driver); } -module_init(parport_gsc_init_module); -module_exit(parport_gsc_exit_module); +module_init(parport_gsc_init); +module_exit(parport_gsc_exit); diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c --- a/drivers/pci/pci.c Mon Nov 4 14:31:01 2002 +++ b/drivers/pci/pci.c Mon Nov 4 14:31:01 2002 @@ -642,6 +642,11 @@ __setup("pci=", pci_setup); +#if defined(CONFIG_ISA) || defined(CONFIG_EISA) +struct pci_dev *isa_bridge; +EXPORT_SYMBOL(isa_bridge); +#endif + EXPORT_SYMBOL(pci_enable_device); EXPORT_SYMBOL(pci_disable_device); EXPORT_SYMBOL(pci_find_capability); diff -Nru a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c --- a/drivers/pnp/isapnp/core.c Mon Nov 4 14:31:02 2002 +++ b/drivers/pnp/isapnp/core.c Mon Nov 4 14:31:02 2002 @@ -43,6 +43,7 @@ #include #include #include +#include LIST_HEAD(isapnp_cards); LIST_HEAD(isapnp_devices); diff -Nru a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c --- a/drivers/s390/net/lcs.c Mon Nov 4 14:31:00 2002 +++ b/drivers/s390/net/lcs.c Mon Nov 4 14:31:00 2002 @@ -126,7 +126,6 @@ #include #include #include -#include #include #include #include diff -Nru a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c --- a/drivers/sbus/char/aurora.c Mon Nov 4 14:31:01 2002 +++ b/drivers/sbus/char/aurora.c Mon Nov 4 14:31:01 2002 @@ -59,7 +59,6 @@ #include #include #include -#include #include #include diff -Nru a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c --- a/drivers/scsi/3w-xxxx.c Mon Nov 4 14:31:02 2002 +++ b/drivers/scsi/3w-xxxx.c Mon Nov 4 14:31:02 2002 @@ -153,6 +153,17 @@ Cleanup some AEN severity levels. 1.02.00.027 - Add drive not supported AEN code for SATA controllers. Remove spurious unknown ioctl error message. + 1.02.00.028 - Fix bug where multiple controllers with no units were the + same card number. + Fix bug where cards were being shut down more than once. + 1.02.00.029 - Add missing pci_free_consistent() in tw_allocate_memory(). + Replace pci_map_single() with pci_map_page() for highmem. + Check for tw_setfeature() failure. + 1.02.00.030 - Make driver 64-bit clean. + 1.02.00.031 - Cleanup polling timeouts/routines in several places. + Add support for mode sense opcode. + Add support for cache mode page. + Add support for synchronize cache opcode. */ #include @@ -205,7 +216,7 @@ }; /* Globals */ -char *tw_driver_version="1.02.00.027"; +char *tw_driver_version="1.02.00.031"; TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; int tw_device_extension_count = 0; @@ -281,11 +292,10 @@ { TW_Command *command_packet; TW_Param *param; - int tries = 0; int request_id = 0; - u32 command_que_value = 0, command_que_addr; - u32 status_reg_value = 0, status_reg_addr; - u32 param_value; + u32 command_que_addr; + unsigned long command_que_value; + unsigned long param_value; TW_Response_Queue response_queue; u32 response_que_addr; unsigned short aen; @@ -293,13 +303,11 @@ int finished = 0; int first_reset = 0; int queue = 0; - int imax, i; int found = 0, table_max = 0; dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue()\n"); command_que_addr = tw_dev->registers.command_que_addr; - status_reg_addr = tw_dev->registers.status_reg_addr; response_que_addr = tw_dev->registers.response_que_addr; if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT | TW_STATUS_MICROCONTROLLER_READY, 30)) { @@ -351,114 +359,96 @@ command_packet->byte8.param.sgl[0].address = param_value; command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector); - imax = TW_POLL_MAX_RETRIES; - /* Now drain the controller's aen queue */ do { /* Post command packet */ outl(command_que_value, command_que_addr); /* Now poll for completion */ - for (i=0;istatus != 0) { + if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) { + /* Bad response */ + tw_decode_sense(tw_dev, request_id, 0); return 1; + } else { + /* We know this is a 3w-1x00, and doesn't support aen's */ + return 0; } - - if (command_packet->status != 0) { - if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) { - /* Bad response */ - tw_decode_sense(tw_dev, request_id, 0); + } + + /* Now check the aen */ + aen = *(unsigned short *)(param->data); + aen_code = (aen & 0x0ff); + queue = 0; + switch (aen_code) { + case TW_AEN_QUEUE_EMPTY: + dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]); + if (first_reset != 1) { return 1; } else { - /* We know this is a 3w-1x00, and doesn't support aen's */ - return 0; + finished = 1; } - } - - /* Now check the aen */ - aen = *(unsigned short *)(param->data); - aen_code = (aen & 0x0ff); - queue = 0; - switch (aen_code) { - case TW_AEN_QUEUE_EMPTY: - dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]); - if (first_reset != 1) { - continue; - } else { - finished = 1; - } - break; - case TW_AEN_SOFT_RESET: - if (first_reset == 0) { - first_reset = 1; - } else { - printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]); - tw_dev->aen_count++; - queue = 1; - } - break; - default: - if (aen == 0x0ff) { - printk(KERN_WARNING "3w-xxxx: AEN: INFO: AEN queue overflow.\n"); - } else { - table_max = sizeof(tw_aen_string)/sizeof(char *); - if ((aen & 0x0ff) < table_max) { - if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') { - printk(KERN_WARNING "3w-xxxx: AEN: %s%d.\n", tw_aen_string[aen & 0xff], aen >> 8); - } else { - printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]); - } - } else - printk(KERN_WARNING "3w-xxxx: Received AEN %d.\n", aen); - } + break; + case TW_AEN_SOFT_RESET: + if (first_reset == 0) { + first_reset = 1; + } else { + printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]); tw_dev->aen_count++; queue = 1; - } - - /* Now put the aen on the aen_queue */ - if (queue == 1) { - tw_dev->aen_queue[tw_dev->aen_tail] = aen; - if (tw_dev->aen_tail == TW_Q_LENGTH - 1) { - tw_dev->aen_tail = TW_Q_START; + } + break; + default: + if (aen == 0x0ff) { + printk(KERN_WARNING "3w-xxxx: AEN: INFO: AEN queue overflow.\n"); } else { - tw_dev->aen_tail = tw_dev->aen_tail + 1; + table_max = sizeof(tw_aen_string)/sizeof(char *); + if ((aen & 0x0ff) < table_max) { + if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') { + printk(KERN_WARNING "3w-xxxx: AEN: %s%d.\n", tw_aen_string[aen & 0xff], aen >> 8); + } else { + printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]); + } + } else + printk(KERN_WARNING "3w-xxxx: Received AEN %d.\n", aen); } - if (tw_dev->aen_head == tw_dev->aen_tail) { - if (tw_dev->aen_head == TW_Q_LENGTH - 1) { - tw_dev->aen_head = TW_Q_START; - } else { - tw_dev->aen_head = tw_dev->aen_head + 1; - } + tw_dev->aen_count++; + queue = 1; + } + + /* Now put the aen on the aen_queue */ + if (queue == 1) { + tw_dev->aen_queue[tw_dev->aen_tail] = aen; + if (tw_dev->aen_tail == TW_Q_LENGTH - 1) { + tw_dev->aen_tail = TW_Q_START; + } else { + tw_dev->aen_tail = tw_dev->aen_tail + 1; + } + if (tw_dev->aen_head == tw_dev->aen_tail) { + if (tw_dev->aen_head == TW_Q_LENGTH - 1) { + tw_dev->aen_head = TW_Q_START; + } else { + tw_dev->aen_head = tw_dev->aen_head + 1; } } - found = 1; - break; } + found = 1; } if (found == 0) { printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Response never received.\n"); return 1; } - tries++; - } while ((tries < TW_MAX_AEN_TRIES) && (finished == 0)); - - if (tries >=TW_MAX_AEN_TRIES) { - printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Aen queue error.\n"); - return 1; - } + } while (finished == 0); return 0; } /* End tw_aen_drain_queue() */ @@ -468,9 +458,10 @@ { TW_Command *command_packet; TW_Param *param; - u32 command_que_value = 0, command_que_addr; + u32 command_que_addr; + unsigned long command_que_value; u32 status_reg_value = 0, status_reg_addr; - u32 param_value = 0; + unsigned long param_value = 0; dprintk(KERN_NOTICE "3w-xxxx: tw_aen_read_queue()\n"); command_que_addr = tw_dev->registers.command_que_addr; @@ -539,7 +530,7 @@ { int i; dma_addr_t dma_handle; - u32 *cpu_addr = NULL; + unsigned long *cpu_addr = NULL; dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n"); @@ -550,8 +541,9 @@ return 1; } - if ((u32)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) { + if ((unsigned long)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) { printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n"); + pci_free_consistent(tw_dev->tw_pci_dev, size, cpu_addr, dma_handle); return 1; } @@ -816,13 +808,14 @@ struct pci_dev *tw_pci_dev = NULL; u32 status_reg_value; unsigned char c = 1; - int i; + int i, j = -1; u16 device[TW_NUMDEVICES] = { TW_DEVICE_ID, TW_DEVICE_ID2 }; dprintk(KERN_NOTICE "3w-xxxx: tw_findcards()\n"); for (i=0;i= TW_MAX_RESET_TRIES) { - printk(KERN_WARNING "3w-xxxx: Controller errors, card not responding, check all cabling for card %d.\n", numcards); + printk(KERN_WARNING "3w-xxxx: Controller errors, card not responding, check all cabling for card %d.\n", j); tw_free_device_extension(tw_dev); kfree(tw_dev); continue; @@ -908,7 +901,7 @@ printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", (tw_dev->tw_pci_dev->resource[0].start), (tw_dev->tw_pci_dev->resource[0].start) + - TW_IO_ADDRESS_RANGE, numcards); + TW_IO_ADDRESS_RANGE, j); tw_free_device_extension(tw_dev); kfree(tw_dev); continue; @@ -918,7 +911,7 @@ request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME); error = tw_initialize_units(tw_dev); if (error) { - printk(KERN_WARNING "3w-xxxx: No valid units for for card %d.\n", numcards); + printk(KERN_WARNING "3w-xxxx: No valid units for for card %d.\n", j); release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); tw_free_device_extension(tw_dev); kfree(tw_dev); @@ -927,13 +920,16 @@ error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS); if (error) { - printk(KERN_WARNING "3w-xxxx: Connection initialization failed for card %d.\n", numcards); + printk(KERN_WARNING "3w-xxxx: Connection initialization failed for card %d.\n", j); release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); tw_free_device_extension(tw_dev); kfree(tw_dev); continue; } + /* Set card status as online */ + tw_dev->online = 1; + /* Calculate max cmds per lun, and setup queues */ if (tw_dev->num_units > 0) { /* Use SHT cmd_per_lun here */ @@ -945,7 +941,7 @@ /* Register the card with the kernel SCSI layer */ host = scsi_register(tw_host, sizeof(TW_Device_Extension)); if (host == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards); + printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", j); release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); tw_free_device_extension(tw_dev); kfree(tw_dev); @@ -982,7 +978,7 @@ tw_device_extension_count = numcards; tw_dev2->host = host; } else { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards); + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", j); scsi_unregister(host); release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); tw_free_device_extension(tw_dev); @@ -991,12 +987,21 @@ } /* Tell the firmware we support shutdown notification*/ - tw_setfeature(tw_dev2, 2, 1, &c); + error = tw_setfeature(tw_dev2, 2, 1, &c); + if (error) { + printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Error setting features for card %d.\n", j); + scsi_unregister(host); + release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); + tw_free_device_extension(tw_dev); + kfree(tw_dev); + numcards--; + continue; + } /* Now setup the interrupt handler */ error = tw_setup_irq(tw_dev2); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", numcards-1); + printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", j); scsi_unregister(host); release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE); @@ -1045,8 +1050,11 @@ int i; for (i=0;ionline == 1) { + printk(KERN_NOTICE "3w-xxxx: Shutting down card %d.\n", i); + tw_shutdown_device(tw_device_extension_list[i]); + tw_device_extension_list[i]->online = 0; + } } unregister_reboot_notifier(&tw_notifier); @@ -1056,18 +1064,15 @@ /* This function will send an initconnection command to controller */ int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits) { - u32 command_que_addr, command_que_value; - u32 status_reg_addr, status_reg_value; + unsigned long command_que_value; + u32 command_que_addr; u32 response_que_addr; TW_Command *command_packet; TW_Response_Queue response_queue; int request_id = 0; - int i = 0; - int imax = 0; dprintk(KERN_NOTICE "3w-xxxx: tw_initconnection()\n"); command_que_addr = tw_dev->registers.command_que_addr; - status_reg_addr = tw_dev->registers.status_reg_addr; response_que_addr = tw_dev->registers.response_que_addr; /* Initialize InitConnection command packet */ @@ -1099,29 +1104,18 @@ outl(command_que_value, command_que_addr); /* Poll for completion */ - imax = TW_POLL_MAX_RETRIES; - for (i=0;istatus != 0) { - /* bad response */ - tw_decode_sense(tw_dev, request_id, 0); - return 1; - } - break; /* Response was okay, so we exit */ + if (command_packet->status != 0) { + /* bad response */ + tw_decode_sense(tw_dev, request_id, 0); + return 1; } } return 0; @@ -1168,16 +1162,15 @@ TW_Command *command_packet; TW_Param *param; int i, imax, num_units = 0; - u32 status_reg_addr, status_reg_value; - u32 command_que_addr, command_que_value; + unsigned long command_que_value; + u32 command_que_addr; u32 response_que_addr; TW_Response_Queue response_queue; - u32 param_value; + unsigned long param_value; unsigned char *is_unit_present; dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units()\n"); - status_reg_addr = tw_dev->registers.status_reg_addr; command_que_addr = tw_dev->registers.command_que_addr; response_que_addr = tw_dev->registers.response_que_addr; @@ -1226,31 +1219,20 @@ outl(command_que_value, command_que_addr); /* Poll for completion */ - imax = TW_POLL_MAX_RETRIES; - for(i=0; istatus != 0) { - /* bad response */ - tw_decode_sense(tw_dev, request_id, 0); - return 1; - } - found = 1; - break; + if (command_packet->status != 0) { + /* bad response */ + tw_decode_sense(tw_dev, request_id, 0); + return 1; } + found = 1; } if (found == 0) { /* response never received */ @@ -1432,6 +1414,13 @@ dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_CAPACITY\n"); error = tw_scsiop_read_capacity_complete(tw_dev, request_id); break; + case MODE_SENSE: + dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught MODE_SENSE\n"); + error = tw_scsiop_mode_sense_complete(tw_dev, request_id); + break; + case SYNCHRONIZE_CACHE: + dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught SYNCHRONIZE_CACHE\n"); + break; case TW_IOCTL: dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TW_IOCTL\n"); error = tw_ioctl_complete(tw_dev, request_id); @@ -1490,11 +1479,11 @@ int bufflen, error = 0; TW_Param *param; TW_Command *command_packet, *command_save; - u32 param_value; + unsigned long param_value; TW_Ioctl *ioctl = NULL; TW_Passthru *passthru = NULL; int tw_aen_code, i, use_sg; - char *data_ptr; + unsigned long *data_ptr; int total_bytes = 0, posted = 0; dma_addr_t dma_handle; struct timeval before, timeout; @@ -1601,7 +1590,7 @@ passthru = (TW_Passthru *)tw_dev->command_packet_virtual_address[request_id]; passthru->sg_list[0].length = passthru->sector_count*512; if (passthru->sg_list[0].length > TW_MAX_PASSTHRU_BYTES) { - printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%ld) too big.\n", passthru->sg_list[0].length); + printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Passthru size (%d) too big.\n", passthru->sg_list[0].length); return 1; } passthru->sg_list[0].address = tw_dev->alignment_physical_address[request_id]; @@ -1639,15 +1628,15 @@ tw_dev->ioctl_data[request_id] = pci_alloc_consistent(tw_dev->tw_pci_dev, total_bytes, &dma_handle); if (!tw_dev->ioctl_data[request_id]) { - printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): kmalloc failed for request_id %d.\n", tw_dev->host->host_no, request_id); + printk(KERN_WARNING "3w-xxxx: scsi%d: tw_ioctl(): pci_alloc_consistent() failed for request_id %d.\n", tw_dev->host->host_no, request_id); return 1; } /* Copy param sglist into the kernel */ data_ptr = tw_dev->ioctl_data[request_id]; for (i=0;ibyte8.param.sgl[i].address != NULL) { - error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.param.sgl[i].address, command_packet->byte8.param.sgl[i].length); + if (command_packet->byte8.param.sgl[i].address != 0) { + error = copy_from_user(data_ptr, (void *)(unsigned long)command_packet->byte8.param.sgl[i].address, command_packet->byte8.param.sgl[i].length); if (error) { dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist from userspace.\n", tw_dev->host->host_no); goto tw_ioctl_bail; @@ -1677,8 +1666,8 @@ /* Copy io sglist into the kernel */ data_ptr = tw_dev->ioctl_data[request_id]; for (i=0;ibyte8.io.sgl[i].address != NULL) { - error = copy_from_user(data_ptr, (u32 *)command_packet->byte8.io.sgl[i].address, command_packet->byte8.io.sgl[i].length); + if (command_packet->byte8.io.sgl[i].address != 0) { + error = copy_from_user(data_ptr, (void *)(unsigned long)command_packet->byte8.io.sgl[i].address, command_packet->byte8.io.sgl[i].length); if (error) { dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist from userspace.\n", tw_dev->host->host_no); goto tw_ioctl_bail; @@ -1732,10 +1721,10 @@ /* Now copy up the param or io sglist to userspace */ if (command_packet->byte0.sgl_offset == 2) { use_sg = command_save->size - 3; - data_ptr = phys_to_virt(command_packet->byte8.param.sgl[0].address); + data_ptr = tw_dev->ioctl_data[request_id]; for (i=0;ibyte8.param.sgl[i].address != NULL) { - error = copy_to_user((u32 *)command_save->byte8.param.sgl[i].address, data_ptr, command_save->byte8.param.sgl[i].length); + if (command_save->byte8.param.sgl[i].address != 0) { + error = copy_to_user((void *)(unsigned long)command_save->byte8.param.sgl[i].address, data_ptr, command_save->byte8.param.sgl[i].length); if (error) { dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying param sglist to userspace.\n", tw_dev->host->host_no); goto tw_ioctl_bail; @@ -1752,10 +1741,10 @@ if (command_packet->byte0.sgl_offset == 3) { use_sg = command_save->size - 4; if (command_packet->byte0.opcode == TW_OP_READ) { - data_ptr = phys_to_virt(command_packet->byte8.io.sgl[0].address); + data_ptr = tw_dev->ioctl_data[request_id]; for(i=0;ibyte8.io.sgl[i].address != NULL) { - error = copy_to_user((u32 *)command_save->byte8.io.sgl[i].address, data_ptr, command_save->byte8.io.sgl[i].length); + if (command_save->byte8.io.sgl[i].address != 0) { + error = copy_to_user((void *)(unsigned long)command_save->byte8.io.sgl[i].address, data_ptr, command_save->byte8.io.sgl[i].length); if (error) { dprintk(KERN_WARNING "3w-xxxx: scsi%d: Error copying io sglist to userspace.\n", tw_dev->host->host_no); goto tw_ioctl_bail; @@ -1885,6 +1874,12 @@ return 0; use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + + if (use_sg == 0) { + printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n"); + return 0; + } + cmd->SCp.phase = 2; cmd->SCp.have_data_in = use_sg; @@ -1901,8 +1896,14 @@ if (cmd->request_bufflen == 0) return 0; - mapping = pci_map_single(pdev, cmd->request_buffer, cmd->request_bufflen, dma_dir); - cmd->SCp.phase = 2; + mapping = pci_map_page(pdev, virt_to_page(cmd->request_buffer), ((unsigned long)cmd->request_buffer & ~PAGE_MASK), cmd->request_bufflen, dma_dir); + + if (mapping == 0) { + printk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data(): pci_map_page() failed.\n"); + return 0; + } + + cmd->SCp.phase = 1; cmd->SCp.have_data_in = mapping; return mapping; @@ -1951,11 +1952,45 @@ return 0; } /* End tw_poll_status() */ +/* This function will poll the status register for disappearance of a flag */ +int tw_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds) +{ + u32 status_reg_addr, status_reg_value; + struct timeval before, timeout; + + status_reg_addr = tw_dev->registers.status_reg_addr; + do_gettimeofday(&before); + status_reg_value = inl(status_reg_addr); + + if (tw_check_bits(status_reg_value)) { + dprintk(KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Unexpected bits.\n"); + tw_decode_bits(tw_dev, status_reg_value, 0); + } + + while ((status_reg_value & flag) != 0) { + status_reg_value = inl(status_reg_addr); + + if (tw_check_bits(status_reg_value)) { + dprintk(KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Unexpected bits.\n"); + tw_decode_bits(tw_dev, status_reg_value, 0); + } + + do_gettimeofday(&timeout); + if (before.tv_sec + seconds < timeout.tv_sec) { + dprintk(KERN_WARNING "3w-xxxx: tw_poll_status_gone(): Flag 0x%x never disappeared.\n", flag); + return 1; + } + mdelay(5); + } + return 0; +} /* End tw_poll_status_gone() */ + /* This function will attempt to post a command packet to the board */ int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id) { u32 status_reg_addr, status_reg_value; - u32 command_que_addr, command_que_value; + unsigned long command_que_value; + u32 command_que_addr; dprintk(KERN_NOTICE "3w-xxxx: tw_post_command_packet()\n"); command_que_addr = tw_dev->registers.command_que_addr; @@ -2164,14 +2199,14 @@ for (i=0;isrb[i] == SCpnt) { if (tw_dev->state[i] == TW_S_STARTED) { - printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (0x%x) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, (u32)SCpnt); + printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, SCpnt); tw_dev->state[i] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, i); spin_unlock(&tw_dev->tw_lock); return (SUCCESS); } if (tw_dev->state[i] == TW_S_PENDING) { - printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (0x%x) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, (u32)SCpnt); + printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, SCpnt); if (tw_dev->pending_head == TW_Q_LENGTH-1) { tw_dev->pending_head = TW_Q_START; } else { @@ -2185,7 +2220,7 @@ } if (tw_dev->state[i] == TW_S_POSTED) { /* If the command has already been posted, we have to reset the card */ - printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, (u32)SCpnt); + printk(KERN_WARNING "3w-xxxx: scsi%d: Unit #%d: Command (%p) timed out, resetting card.\n", tw_dev->host->host_no, tw_dev->srb[i]==0 ? 0 : tw_dev->srb[i]->target, SCpnt); /* We have to let AEN requests through before the reset */ spin_unlock(&tw_dev->tw_lock); spin_unlock_irq(tw_dev->host->host_lock); @@ -2278,9 +2313,9 @@ printk(KERN_INFO "3w-xxxx: Request_id: %d\n", j); printk(KERN_INFO "Opcode: 0x%x\n", command->byte0.opcode); printk(KERN_INFO "Block_count: 0x%x\n", command->byte6.block_count); - printk(KERN_INFO "LBA: 0x%x\n", (u32)command->byte8.io.lba); - printk(KERN_INFO "Physical command packet addr: 0x%x\n", tw_dev->command_packet_physical_address[j]); - printk(KERN_INFO "Scsi_Cmnd: 0x%x\n", (u32)tw_dev->srb[j]); + printk(KERN_INFO "LBA: 0x%x\n", command->byte8.io.lba); + printk(KERN_INFO "Physical command packet addr: 0x%lx\n", tw_dev->command_packet_physical_address[j]); + printk(KERN_INFO "Scsi_Cmnd: %p\n", tw_dev->srb[j]); } } printk(KERN_INFO "3w-xxxx: Free_head: %3d\n", tw_dev->free_head); @@ -2373,6 +2408,14 @@ dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught REQUEST_SENSE.\n"); error = tw_scsiop_request_sense(tw_dev, request_id); break; + case MODE_SENSE: + dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught MODE_SENSE.\n"); + error = tw_scsiop_mode_sense(tw_dev, request_id); + break; + case SYNCHRONIZE_CACHE: + dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught SYNCHRONIZE_CACHE.\n"); + error = tw_scsiop_synchronize_cache(tw_dev, request_id); + break; case TW_IOCTL: dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TW_SCSI_IOCTL.\n"); error = tw_ioctl(tw_dev, request_id); @@ -2428,8 +2471,9 @@ { TW_Param *param; TW_Command *command_packet; - u32 command_que_value, command_que_addr; - u32 param_value; + unsigned long command_que_value; + u32 command_que_addr; + unsigned long param_value; dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry()\n"); @@ -2527,13 +2571,115 @@ return 0; } /* End tw_scsiop_inquiry_complete() */ +/* This function handles scsi mode_sense commands */ +int tw_scsiop_mode_sense(TW_Device_Extension *tw_dev, int request_id) +{ + TW_Param *param; + TW_Command *command_packet; + unsigned long command_que_value; + unsigned long param_value; + + dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense()\n"); + + /* Only page control = 0, page code = 0x8 (cache page) supported */ + if (tw_dev->srb[request_id]->cmnd[2] != 0x8) { + tw_dev->state[request_id] = TW_S_COMPLETED; + tw_state_request_finish(tw_dev, request_id); + tw_dev->srb[request_id]->result = (DID_OK << 16); + tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); + return 0; + } + + /* Now read firmware cache setting for this unit */ + command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; + if (command_packet == NULL) { + printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet virtual address.\n"); + return 1; + } + + /* Setup the command packet */ + memset(command_packet, 0, sizeof(TW_Sector)); + command_packet->byte0.opcode = TW_OP_GET_PARAM; + command_packet->byte0.sgl_offset = 2; + command_packet->size = 4; + command_packet->request_id = request_id; + command_packet->byte3.unit = 0; + command_packet->byte3.host_id = 0; + command_packet->status = 0; + command_packet->flags = 0; + command_packet->byte6.parameter_count = 1; + + /* Setup the param */ + if (tw_dev->alignment_virtual_address[request_id] == NULL) { + printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment virtual address.\n"); + return 1; + } + + param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; + memset(param, 0, sizeof(TW_Sector)); + param->table_id = TW_UNIT_INFORMATION_TABLE_BASE + tw_dev->srb[request_id]->target; + param->parameter_id = 7; /* unit flags */ + param->parameter_size_bytes = 1; + param_value = tw_dev->alignment_physical_address[request_id]; + if (param_value == 0) { + printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment physical address.\n"); + return 1; + } + + command_packet->byte8.param.sgl[0].address = param_value; + command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector); + command_que_value = tw_dev->command_packet_physical_address[request_id]; + if (command_que_value == 0) { + printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet physical address.\n"); + return 1; + } + + /* Now try to post the command packet */ + tw_post_command_packet(tw_dev, request_id); + + return 0; +} /* End tw_scsiop_mode_sense() */ + +/* This function is called by the isr to complete a mode sense command */ +int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int request_id) +{ + TW_Param *param; + unsigned char *flags; + unsigned char *request_buffer; + + dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense_complete()\n"); + + param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; + if (param == NULL) { + printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense_complete(): Bad alignment virtual address.\n"); + return 1; + } + flags = (char *)&(param->data[0]); + request_buffer = tw_dev->srb[request_id]->buffer; + memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen); + + request_buffer[0] = 0xf; /* mode data length */ + request_buffer[1] = 0; /* default medium type */ + request_buffer[2] = 0x10; /* dpo/fua support on */ + request_buffer[3] = 0; /* no block descriptors */ + request_buffer[4] = 0x8; /* caching page */ + request_buffer[5] = 0xa; /* page length */ + if (*flags & 0x1) + request_buffer[6] = 0x4; /* WCE on */ + else + request_buffer[6] = 0x0; /* WCE off */ + + return 0; +} /* End tw_scsiop_mode_sense_complete() */ + /* This function handles scsi read_capacity commands */ int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id) { TW_Param *param; TW_Command *command_packet; - u32 command_que_addr, command_que_value; - u32 param_value; + unsigned long command_que_value; + u32 command_que_addr; + unsigned long param_value; dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity()\n"); @@ -2637,7 +2783,8 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id) { TW_Command *command_packet; - u32 command_que_addr, command_que_value = 0; + unsigned long command_que_value; + u32 command_que_addr = 0x0; u32 lba = 0x0, num_sectors = 0x0, buffaddr = 0x0; int i, use_sg; Scsi_Cmnd *srb; @@ -2700,6 +2847,9 @@ if (tw_dev->srb[request_id]->use_sg == 0) { dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n"); buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]); + if (buffaddr == 0) + return 1; + command_packet->byte8.io.sgl[0].address = buffaddr; command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen; command_packet->size+=2; @@ -2707,7 +2857,10 @@ /* Do this if we have multiple sg list entries */ if (tw_dev->srb[request_id]->use_sg > 0) { - use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);; + use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]); + if (use_sg == 0) + return 1; + for (i=0;ibyte8.io.sgl[i].address = sg_dma_address(&sglist[i]); command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]); @@ -2749,6 +2902,44 @@ return 0; } /* End tw_scsiop_request_sense() */ +/* This function will handle synchronize cache scsi command */ +int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id) +{ + TW_Command *command_packet; + unsigned long command_que_value; + + dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_synchronize_cache()\n"); + + /* Send firmware flush command for this unit */ + command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; + if (command_packet == NULL) { + printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet virtual address.\n"); + return 1; + } + + /* Setup the command packet */ + memset(command_packet, 0, sizeof(TW_Sector)); + command_packet->byte0.opcode = TW_OP_FLUSH_CACHE; + command_packet->byte0.sgl_offset = 0; + command_packet->size = 2; + command_packet->request_id = request_id; + command_packet->byte3.unit = tw_dev->srb[request_id]->target; + command_packet->byte3.host_id = 0; + command_packet->status = 0; + command_packet->flags = 0; + command_packet->byte6.parameter_count = 1; + command_que_value = tw_dev->command_packet_physical_address[request_id]; + if (command_que_value == 0) { + printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet physical address.\n"); + return 1; + } + + /* Now try to post the command packet */ + tw_post_command_packet(tw_dev, request_id); + + return 0; +} /* End tw_scsiop_synchronize_cache() */ + /* This function will handle test unit ready scsi command */ int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id) { @@ -2771,11 +2962,10 @@ TW_Command *command_packet; TW_Response_Queue response_queue; int request_id = 0; - u32 command_que_value, command_que_addr; - u32 status_reg_addr, status_reg_value; + unsigned long command_que_value; + u32 command_que_addr; u32 response_que_addr; - u32 param_value; - int imax, i; + unsigned long param_value; /* Initialize SetParam command packet */ if (tw_dev->command_packet_virtual_address[request_id] == NULL) { @@ -2814,40 +3004,28 @@ return 1; } command_que_addr = tw_dev->registers.command_que_addr; - status_reg_addr = tw_dev->registers.status_reg_addr; response_que_addr = tw_dev->registers.response_que_addr; /* Send command packet to the board */ outl(command_que_value, command_que_addr); /* Poll for completion */ - imax = TW_POLL_MAX_RETRIES; - for (i=0;istatus != 0) { - /* bad response */ - tw_decode_sense(tw_dev, request_id, 0); - return 1; - } - break; /* Response was okay, so we exit */ + if (command_packet->status != 0) { + /* bad response */ + tw_decode_sense(tw_dev, request_id, 0); + return 1; } } - return 0; + return 0; } /* End tw_setfeature() */ /* This function will setup the interrupt handler */ @@ -2957,10 +3135,13 @@ dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n"); - if (cmd->use_sg) { - pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir); - } else { - pci_unmap_single(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, dma_dir); + switch(cmd->SCp.phase) { + case 1: + pci_unmap_page(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, dma_dir); + break; + case 2: + pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir); + break; } } /* End tw_unmap_scsi_data() */ diff -Nru a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h --- a/drivers/scsi/3w-xxxx.h Mon Nov 4 14:31:01 2002 +++ b/drivers/scsi/3w-xxxx.h Mon Nov 4 14:31:01 2002 @@ -164,7 +164,7 @@ #define TW_RESPONSE_ID_MASK 0x00000FF0 /* PCI related defines */ -#define TW_IO_ADDRESS_RANGE 0xD +#define TW_IO_ADDRESS_RANGE 0x10 #define TW_DEVICE_NAME "3ware Storage Controller" #define TW_VENDOR_ID (0x13C1) /* 3ware */ #define TW_DEVICE_ID (0x1000) /* Storage Controller */ @@ -183,6 +183,7 @@ #define TW_OP_SET_PARAM 0x13 #define TW_OP_SECTOR_INFO 0x1a #define TW_OP_AEN_LISTEN 0x1c +#define TW_OP_FLUSH_CACHE 0x0e #define TW_CMD_PACKET 0x1d #define TW_ATA_PASSTHRU 0x1e #define TW_CMD_PACKET_WITH_DATA 0x1f @@ -221,7 +222,6 @@ #define TW_MAX_CMDS_PER_LUN 255 #define TW_BLOCK_SIZE 0x200 /* 512-byte blocks */ #define TW_IOCTL 0x80 -#define TW_MAX_AEN_TRIES 100 #define TW_UNIT_ONLINE 1 #define TW_IN_INTR 1 #define TW_IN_IOCTL 2 @@ -248,8 +248,8 @@ /* Scatter Gather List Entry */ typedef struct TAG_TW_SG_Entry { - unsigned long address; - unsigned long length; + u32 address; + u32 length; } TW_SG_Entry; typedef unsigned char TW_Sector[512]; @@ -277,17 +277,17 @@ } byte6; union { struct { - unsigned long lba; + u32 lba; TW_SG_Entry sgl[TW_MAX_SGL_LENGTH]; - unsigned long padding; /* pad to 512 bytes */ + u32 padding; /* pad to 512 bytes */ } io; struct { TW_SG_Entry sgl[TW_MAX_SGL_LENGTH]; - unsigned long padding[2]; + u32 padding[2]; } param; struct { - unsigned long response_queue_pointer; - unsigned long padding[125]; + u32 response_queue_pointer; + u32 padding[125]; } init_connection; struct { char version[504]; @@ -376,12 +376,12 @@ typedef struct TAG_TW_Device_Extension { TW_Registers registers; - u32 *alignment_virtual_address[TW_Q_LENGTH]; - u32 alignment_physical_address[TW_Q_LENGTH]; + unsigned long *alignment_virtual_address[TW_Q_LENGTH]; + unsigned long alignment_physical_address[TW_Q_LENGTH]; int is_unit_present[TW_MAX_UNITS]; int num_units; - u32 *command_packet_virtual_address[TW_Q_LENGTH]; - u32 command_packet_physical_address[TW_Q_LENGTH]; + unsigned long *command_packet_virtual_address[TW_Q_LENGTH]; + unsigned long command_packet_physical_address[TW_Q_LENGTH]; struct pci_dev *tw_pci_dev; Scsi_Cmnd *srb[TW_Q_LENGTH]; unsigned char free_queue[TW_Q_LENGTH]; @@ -411,8 +411,9 @@ unsigned char aen_head; unsigned char aen_tail; volatile long flags; /* long req'd for set_bit --RR */ - char *ioctl_data[TW_Q_LENGTH]; + unsigned long *ioctl_data[TW_Q_LENGTH]; int reset_print; + char online; } TW_Device_Extension; /* Function prototypes */ @@ -440,10 +441,11 @@ int tw_ioctl_complete(TW_Device_Extension *tw_dev, int request_id); void tw_mask_command_interrupt(TW_Device_Extension *tw_dev); int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds); +int tw_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds); int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id); int tw_reset_device_extension(TW_Device_Extension *tw_dev); int tw_reset_sequence(TW_Device_Extension *tw_dev); -int tw_scsi_biosparam(struct scsi_device *sdev, struct block_device *bev, +int tw_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]); int tw_scsi_detect(Scsi_Host_Template *tw_host); int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt); @@ -453,10 +455,13 @@ int tw_scsi_release(struct Scsi_Host *tw_host); int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id); int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id); +int tw_scsiop_mode_sense(TW_Device_Extension *tw_dev, int request_id); +int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int request_id); int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id); int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int request_id); int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id); int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id); +int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id); int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id); int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, unsigned char *val); @@ -485,6 +490,7 @@ present : 0, \ unchecked_isa_dma : 0, \ use_clustering : ENABLE_CLUSTERING, \ - emulated : 1 \ + emulated : 1, \ + highmem_io : 1 \ } #endif /* _3W_XXXX_H */ diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile --- a/drivers/scsi/Makefile Mon Nov 4 14:31:02 2002 +++ b/drivers/scsi/Makefile Mon Nov 4 14:31:02 2002 @@ -42,7 +42,7 @@ obj-$(CONFIG_ATARI_SCSI) += atari_scsi.o obj-$(CONFIG_MAC_SCSI) += mac_scsi.o obj-$(CONFIG_SCSI_MAC_ESP) += mac_esp.o NCR53C9x.o -obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o +obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o obj-$(CONFIG_MVME16x_SCSI) += mvme16x.o 53c7xx.o obj-$(CONFIG_BVME6000_SCSI) += bvme6000.o 53c7xx.o obj-$(CONFIG_SCSI_SIM710) += sim710.o diff -Nru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c --- a/drivers/scsi/aacraid/aachba.c Mon Nov 4 14:31:01 2002 +++ b/drivers/scsi/aacraid/aachba.c Mon Nov 4 14:31:01 2002 @@ -220,7 +220,6 @@ static struct fsa_scsi_hba *fsa_dev[MAXIMUM_NUM_ADAPTERS]; /* SCSI Device Instance Pointers */ static struct sense_data sense_data[MAXIMUM_NUM_CONTAINERS]; -static void get_sd_devname(int disknum, char *buffer); static unsigned long aac_build_sg(Scsi_Cmnd* scsicmd, struct sgmap* sgmap); static unsigned long aac_build_sg64(Scsi_Cmnd* scsicmd, struct sgmap64* psg); static int aac_send_srb_fib(Scsi_Cmnd* scsicmd); @@ -1061,8 +1060,10 @@ */ spin_unlock_irq(scsicmd->host->host_lock); - fsa_dev_ptr->devno[cid] = - DEVICE_NR(scsicmd->request->rq_dev); + if (scsicmd->request->rq_disk) + memcpy(fsa_dev_ptr->devname[cid], + scsicmd->request->rq_disk->disk_name, + 8); ret = aac_read(scsicmd, cid); spin_lock_irq(scsicmd->host->host_lock); return ret; @@ -1112,40 +1113,18 @@ qd.locked = fsa_dev_ptr->locked[qd.cnum]; qd.deleted = fsa_dev_ptr->deleted[qd.cnum]; - if (fsa_dev_ptr->devno[qd.cnum] == -1) + if (fsa_dev_ptr->devno[qd.cnum][0] == '\0') qd.unmapped = 1; else qd.unmapped = 0; - get_sd_devname(fsa_dev_ptr->devno[qd.cnum], qd.name); + strncpy(dq.name, fsa_dev_ptr->devname[qd.cnum], 8); if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk))) return -EFAULT; return 0; } -static void get_sd_devname(int disknum, char *buffer) -{ - if (disknum < 0) { - sprintf(buffer, "%s", ""); - return; - } - - if (disknum < 26) - sprintf(buffer, "sd%c", 'a' + disknum); - else { - unsigned int min1; - unsigned int min2; - /* - * For larger numbers of disks, we need to go to a new - * naming scheme. - */ - min1 = disknum / 26; - min2 = disknum % 26; - sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2); - } -} - static int force_delete_disk(struct aac_dev *dev, void *arg) { struct aac_delete_disk dd; @@ -1191,7 +1170,7 @@ * Mark the container as no longer being valid. */ fsa_dev_ptr->valid[dd.cnum] = 0; - fsa_dev_ptr->devno[dd.cnum] = -1; + fsa_dev_ptr->devno[dd.cnum][0] = '\0'; return 0; } } diff -Nru a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h --- a/drivers/scsi/aacraid/aacraid.h Mon Nov 4 14:31:01 2002 +++ b/drivers/scsi/aacraid/aacraid.h Mon Nov 4 14:31:01 2002 @@ -639,7 +639,7 @@ u8 ro[MAXIMUM_NUM_CONTAINERS]; u8 locked[MAXIMUM_NUM_CONTAINERS]; u8 deleted[MAXIMUM_NUM_CONTAINERS]; - u32 devno[MAXIMUM_NUM_CONTAINERS]; + char devname[MAXIMUM_NUM_CONTAINERS][8]; }; struct fib { diff -Nru a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c --- a/drivers/scsi/aacraid/linit.c Mon Nov 4 14:31:01 2002 +++ b/drivers/scsi/aacraid/linit.c Mon Nov 4 14:31:01 2002 @@ -237,7 +237,7 @@ /* Initialize the ordinal number of the device to -1 */ fsa_dev_ptr = &(aac->fsa_dev); for( container = 0; container < MAXIMUM_NUM_CONTAINERS; container++ ) - fsa_dev_ptr->devno[container] = -1; + fsa_dev_ptr->devname[container][0] = '\0'; dprintk((KERN_DEBUG "Initializing Hardware...\n")); if((*aac_drivers[index].init)(aac , host_ptr->unique_id) != 0) diff -Nru a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c --- a/drivers/scsi/aha1542.c Mon Nov 4 14:31:02 2002 +++ b/drivers/scsi/aha1542.c Mon Nov 4 14:31:02 2002 @@ -1635,14 +1635,18 @@ if (HOSTDATA(SCpnt->host)->SCint[i]) { if (HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) { printk(KERN_ERR "Timed out command pending for %s\n", - kdevname(SCpnt->request->rq_dev)); + SCpnt->request->rq_disk ? + SCpnt->request->rq_disk->disk_name : "?" + ); if (HOSTDATA(SCpnt->host)->mb[i].status) { printk(KERN_ERR "OGMB still full - restarting\n"); aha1542_out(SCpnt->host->io_port, &ahacmd, 1); }; } else printk(KERN_ERR "Other pending command %s\n", - kdevname(SCpnt->request->rq_dev)); + SCpnt->request->rq_disk ? + SCpnt->request->rq_disk->disk_name : "?" + ); } #endif diff -Nru a/drivers/scsi/aic7xxx/Makefile b/drivers/scsi/aic7xxx/Makefile --- a/drivers/scsi/aic7xxx/Makefile Mon Nov 4 14:31:03 2002 +++ b/drivers/scsi/aic7xxx/Makefile Mon Nov 4 14:31:03 2002 @@ -1,6 +1,8 @@ # # Makefile for the Linux aic7xxx SCSI driver. # +# Let kbuild descend into aicasm when cleaning +subdir- += aicasm obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx.o @@ -23,11 +25,6 @@ # Files generated that shall be removed upon make clean clean-files := aic7xxx_seq.h aic7xxx_reg.h -# Command to be executed upon make clean -clean-rule := $(MAKE) -C $(src)/aicasm clean - -include $(TOPDIR)/Rules.make - # Dependencies for generated files need to be listed explicitly $(obj)/aic7xxx_core.o: $(obj)/aic7xxx_seq.h @@ -41,7 +38,7 @@ $(obj)/aicasm/aicasm -I$(obj) -r $(obj)/aic7xxx_reg.h \ -o $(obj)/aic7xxx_seq.h $(src)/aic7xxx.seq -$(obj)/aic7xxx_reg.h: $(obj)/aix7xxx_seq.h +$(obj)/aic7xxx_reg.h: $(obj)/aic7xxx_seq.h $(obj)/aicasm/aicasm: $(src)/aicasm/*.[chyl] $(MAKE) -C $(src)/aicasm diff -Nru a/drivers/scsi/aic7xxx/aicasm/Makefile b/drivers/scsi/aic7xxx/aicasm/Makefile --- a/drivers/scsi/aic7xxx/aicasm/Makefile Mon Nov 4 14:31:02 2002 +++ b/drivers/scsi/aic7xxx/aicasm/Makefile Mon Nov 4 14:31:02 2002 @@ -7,7 +7,9 @@ GENHDRS= y.tab.h aicdb.h SRCS= ${GENSRCS} ${CSRCS} -CLEANFILES= ${GENSRCS} ${GENHDRS} y.output + +# Cleaned up by make clean +clean-files := $(GENSRCS) $(GENHDRS) y.output $(PROG) # Override default kernel CFLAGS. This is a userland app. AICASM_CFLAGS:= -I/usr/include -I. -ldb YFLAGS= -d @@ -41,9 +43,6 @@ else \ echo "*** Install db development libraries"; \ fi - -clean: - @rm -f $(CLEANFILES) $(PROG) y.tab.h aicasm_gram.c: aicasm_gram.y $(YACC) $(YFLAGS) aicasm_gram.y diff -Nru a/drivers/scsi/constants.c b/drivers/scsi/constants.c --- a/drivers/scsi/constants.c Mon Nov 4 14:31:02 2002 +++ b/drivers/scsi/constants.c Mon Nov 4 14:31:02 2002 @@ -905,12 +905,13 @@ static void print_sense_internal(const char * devclass, const unsigned char * sense_buffer, - kdev_t dev) + struct request *req) { int s, sense_class, valid, code, info; const char * error = NULL; unsigned char asc, ascq; const char *sense_txt; + char *name = req->rq_disk ? req->rq_disk->disk_name : "?"; sense_class = (sense_buffer[0] >> 4) & 0x07; code = sense_buffer[0] & 0xf; @@ -954,10 +955,10 @@ sense_txt = scsi_sense_key_string(sense_buffer[2]); if (sense_txt) printk("%s%s: sense key %s\n", - devclass, kdevname(dev), sense_txt); + devclass, name, sense_txt); else printk("%s%s: sense = %2x %2x\n", - devclass, kdevname(dev), + devclass, name, sense_buffer[0], sense_buffer[2]); asc = ascq = 0; @@ -981,10 +982,10 @@ sense_txt = scsi_sense_key_string(sense_buffer[0]); if (sense_txt) printk("%s%s: old sense key %s\n", - devclass, kdevname(dev), sense_txt); + devclass, name, sense_txt); else printk("%s%s: sense = %2x %2x\n", - devclass, kdevname(dev), + devclass, name, sense_buffer[0], sense_buffer[2]); printk("Non-extended sense class %d code 0x%0x\n", @@ -1006,13 +1007,13 @@ void print_sense(const char * devclass, Scsi_Cmnd * SCpnt) { print_sense_internal(devclass, SCpnt->sense_buffer, - SCpnt->request->rq_dev); + SCpnt->request); } void print_req_sense(const char * devclass, Scsi_Request * SRpnt) { print_sense_internal(devclass, SRpnt->sr_sense_buffer, - SRpnt->sr_request->rq_dev); + SRpnt->sr_request); } #if (CONSTANTS & CONST_MSG) diff -Nru a/drivers/scsi/eata.c b/drivers/scsi/eata.c --- a/drivers/scsi/eata.c Mon Nov 4 14:31:02 2002 +++ b/drivers/scsi/eata.c Mon Nov 4 14:31:02 2002 @@ -1,6 +1,17 @@ /* * eata.c - Low-level driver for EATA/DMA SCSI host adapters. * + * 28 Oct 2002 Rev. 8.00 for linux 2.5.44-ac4 + * + Use new tcq and adjust_queue_depth api. + * + New command line option (tm:[0-2]) to choose the type of tags: + * 0 -> disable tagging ; 1 -> simple tags ; 2 -> ordered tags. + * Default is tm:0 (tagged commands disabled). + * For compatibility the "tc:" option is an alias of the "tm:" + * option; tc:n is equivalent to tm:0 and tc:y is equivalent to + * tm:1. + * + The tagged_comm module parameter has been removed, use tag_mode + * instead, equivalent to the "tm:" boot option. + * * 10 Oct 2002 Rev. 7.70 for linux 2.5.42 * + Foreport from revision 6.70. * @@ -362,24 +373,21 @@ * rs:n use BIOS order while detecting PCI boards; * lc:y enables linked commands; * lc:n disables linked commands; - * tc:y enables tagged commands; - * tc:n disables tagged commands; - * tm:0 use head/simple/ordered queue tag sequences; - * tm:1 use only simple queue tags; - * tm:2 use only head of queue tags; - * tm:3 use only ordered queue tags; + * tm:0 disables tagged commands (same as tc:n); + * tm:1 use simple queue tags (same as tc:y); + * tm:2 use ordered queue tags (same as tc:2); * mq:xx set the max queue depth to the value xx (2 <= xx <= 32). * - * The default value is: "eata=lc:n,tc:n,mq:16,tm:0,et:n,rs:n". + * The default value is: "eata=lc:n,mq:16,tm:0,et:n,rs:n". * An example using the list of detection probes could be: - * "eata=0x7410,0x230,lc:y,tc:n,mq:4,et:n". + * "eata=0x7410,0x230,lc:y,tm:2,mq:4,et:n". * * When loading as a module, parameters can be specified as well. * The above example would be (use 1 in place of y and 0 in place of n): * - * modprobe eata io_port=0x7410,0x230 linked_comm=1 tagged_comm=0 \ - * max_queue_depth=4 tag_mode=0 \ - * ext_tran=0 rev_scan=1 + * modprobe eata io_port=0x7410,0x230 linked_comm=1 \ + * max_queue_depth=4 ext_tran=0 tag_mode=2 \ + * rev_scan=1 * * ---------------------------------------------------------------------------- * In this implementation, linked commands are designed to work with any DISK @@ -447,15 +455,11 @@ MODULE_PARM(boot_options, "s"); MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i"); MODULE_PARM(linked_comm, "i"); -MODULE_PARM(tagged_comm, "i"); MODULE_PARM(link_statistics, "i"); MODULE_PARM(max_queue_depth, "i"); MODULE_PARM(tag_mode, "i"); MODULE_PARM(ext_tran, "i"); MODULE_PARM(rev_scan, "i"); -MODULE_PARM(isa_probe, "i"); -MODULE_PARM(eisa_probe, "i"); -MODULE_PARM(pci_probe, "i"); MODULE_AUTHOR("Dario Ballabio"); #endif @@ -472,6 +476,7 @@ #include #include "scsi.h" #include "hosts.h" +#include "sd.h" #include #include #include "eata.h" @@ -481,6 +486,7 @@ #include #include #include +#include #if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD) #error "Adjust your defines" @@ -528,10 +534,9 @@ #define ABORTING 6 #define NO_DMA 0xff #define MAXLOOP 10000 -#define TAG_MIXED 0 +#define TAG_DISABLED 0 #define TAG_SIMPLE 1 -#define TAG_HEAD 2 -#define TAG_ORDERED 3 +#define TAG_ORDERED 2 #define REG_CMD 7 #define REG_STATUS 7 @@ -543,7 +548,7 @@ #define REG_LM 3 #define REG_MID 4 #define REG_MSB 5 -#define REGION_SIZE 9UL +#define REGION_SIZE 9 #define MAX_ISA_ADDR 0x03ff #define MIN_EISA_ADDR 0x1c88 #define MAX_EISA_ADDR 0xfc88 @@ -567,7 +572,7 @@ #define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM) /* "EATA", in Big Endian format */ -#define EATA_SIG_BE 0x45415441 +#define EATA_SIGNATURE 0x41544145 /* Number of valid bytes in the board config structure for EATA 2.0x */ #define EATA_2_0A_SIZE 28 @@ -578,12 +583,6 @@ struct eata_info { u_int32_t data_len; /* Number of valid bytes after this field */ u_int32_t sign; /* ASCII "EATA" signature */ - -#if defined(__BIG_ENDIAN_BITFIELD) - unchar version:4, :4; - unchar haaval:1, ata:1, drqvld:1, dmasup:1, morsup:1, trnxfr:1, tarsup:1, - ocsena:1; -#else unchar :4, /* unused low nibble */ version:4; /* EATA version, should be 0x1 */ unchar ocsena:1, /* Overlap Command Support Enabled */ @@ -594,8 +593,6 @@ drqvld:1, /* DRQ Index (DRQX) is valid */ ata:1, /* This is an ATA device */ haaval:1; /* Host Adapter Address Valid */ -#endif - ushort cp_pad_len; /* Number of pad bytes after cp_len */ unchar host_addr[4]; /* Host Adapter SCSI ID for channels 3, 2, 1, 0 */ u_int32_t cp_len; /* Number of valid bytes in cp */ @@ -603,15 +600,6 @@ ushort queue_size; /* Max number of cp that can be queued */ ushort unused; ushort scatt_size; /* Max number of entries in scatter/gather table */ - -#if defined(__BIG_ENDIAN_BITFIELD) - unchar drqx:2, second:1, irq_tr:1, irq:4; - unchar sync; - unchar :4, res1:1, large_sg:1, forcaddr:1, isaena:1; - unchar max_chan:3, max_id:5; - unchar max_lun; - unchar eisa:1, pci:1, idquest:1, m1:1, :4; -#else unchar irq:4, /* Interrupt Request assigned to this controller */ irq_tr:1, /* 0 for edge triggered, 1 for level triggered */ second:1, /* 1 if this is a secondary (not primary) controller */ @@ -634,8 +622,6 @@ idquest:1, /* RAIDNUM returned is questionable */ pci:1, /* This board is PCI */ eisa:1; /* This board is EISA */ -#endif - unchar raidnum; /* Uniquely identifies this HBA in a system */ unchar notused; @@ -645,30 +631,18 @@ /* Board config structure */ struct eata_config { ushort len; /* Number of bytes following this field */ - -#if defined(__BIG_ENDIAN_BITFIELD) - unchar :4, tarena:1, mdpena:1, ocena:1, edis:1; -#else unchar edis:1, /* Disable EATA interface after config command */ ocena:1, /* Overlapped Commands Enabled */ mdpena:1, /* Transfer all Modified Data Pointer Messages */ tarena:1, /* Target Mode Enabled for this controller */ :4; -#endif - unchar cpad[511]; }; /* Returned status packet structure */ struct mssp { - -#if defined(__BIG_ENDIAN_BITFIELD) - unchar eoc:1, adapter_status:7; -#else unchar adapter_status:7, /* State related to current command */ eoc:1; /* End Of Command (1 = command completed) */ -#endif - unchar target_status; /* SCSI status received after data transfer */ unchar unused[2]; u_int32_t inv_res_len; /* Number of bytes not transferred */ @@ -683,16 +657,6 @@ /* MailBox SCSI Command Packet */ struct mscp { - -#if defined(__BIG_ENDIAN_BITFIELD) - unchar din:1, dout:1, interp:1, :1, sg:1, reqsen:1, init:1, sreset:1; - unchar sense_len; - unchar unused[3]; - unchar :7, fwnest:1; - unchar :5, hbaci:1, iat:1, phsunit:1; - unchar channel:3, target:5; - unchar one:1, dispri:1, luntar:1, lun:5; -#else unchar sreset:1, /* SCSI Bus Reset Signal should be asserted */ init:1, /* Re-initialize controller and self test */ reqsen:1, /* Transfer Request Sense Data to addr using DMA */ @@ -715,8 +679,6 @@ luntar:1, /* This cp is for Target (not LUN) */ dispri:1, /* Disconnect Privilege granted */ one:1; /* 1 */ -#endif - unchar mess[3]; /* Massage to/from Target */ unchar cdb[12]; /* Command Descriptor Block */ u_int32_t data_len; /* If sg=0 Data Length, if sg=1 sglist length */ @@ -793,28 +755,22 @@ #define BN(board) (HD(board)->board_name) /* Device is Big Endian */ -#define H2DEV(x) cpu_to_be32(x) -#define DEV2H(x) be32_to_cpu(x) -#define H2DEV16(x) cpu_to_be16(x) -#define DEV2H16(x) be16_to_cpu(x) - -/* But transfer orientation from the 16 bit data register is Little Endian */ -#define REG2H(x) le16_to_cpu(x) +#define H2DEV(x) cpu_to_be32(x) +#define DEV2H(x) be32_to_cpu(x) static void do_interrupt_handler(int, void *, struct pt_regs *); static void flush_dev(Scsi_Device *, unsigned long, unsigned int, unsigned int); static int do_trace = FALSE; static int setup_done = FALSE; static int link_statistics; -static int tag_mode = TAG_MIXED; static int ext_tran = FALSE; static int rev_scan = TRUE; static char *boot_options; #if defined(CONFIG_SCSI_EATA_TAGGED_QUEUE) -static int tagged_comm = TRUE; +static int tag_mode = TAG_SIMPLE; #else -static int tagged_comm = FALSE; +static int tag_mode = TAG_DISABLED; #endif #if defined(CONFIG_SCSI_EATA_LINKED_COMMANDS) @@ -846,38 +802,57 @@ #else static int pci_probe = FALSE; #endif - + static int eata2x_slave_attach(Scsi_Device *dev) { int j, tqd, utqd; - char *link_suffix = ""; + char *tag_suffix, *link_suffix; struct Scsi_Host *host = dev->host; j = ((struct hostdata *) host->hostdata)->board_number; utqd = MAX_CMD_PER_LUN; - tqd = (host->can_queue - utqd); + tqd = max_queue_depth; - if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm)) { - if(!dev->tagged_supported) - scsi_adjust_queue_depth(dev, 0, tqd); - else + if (TLDEV(dev->type) && dev->tagged_supported) + + if (tag_mode == TAG_SIMPLE) { scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, tqd); - } else { + tag_suffix = ", simple tags"; + } + else if (tag_mode == TAG_ORDERED) { + scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, tqd); + tag_suffix = ", ordered tags"; + } + else { + scsi_adjust_queue_depth(dev, 0, tqd); + tag_suffix = ", no tags"; + } + + else if (TLDEV(dev->type) && linked_comm) { + scsi_adjust_queue_depth(dev, 0, tqd); + tag_suffix = ", untagged"; + } + + else { scsi_adjust_queue_depth(dev, 0, utqd); - } + tag_suffix = ""; + } - if (!dev->simple_tags && dev->new_queue_depth > 2) + if (TLDEV(dev->type) && linked_comm && dev->new_queue_depth > 2) link_suffix = ", sorted"; - else if (dev->simple_tags) + else if (TLDEV(dev->type)) link_suffix = ", unsorted"; + else + link_suffix = ""; - printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s.\n", + printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n", BN(j), host->host_no, dev->channel, dev->id, dev->lun, - dev->new_queue_depth, link_suffix); - return 0; + dev->new_queue_depth, link_suffix, tag_suffix); + + return FALSE; } -static inline int wait_on_busy(unsigned long iobase, unsigned int loop) { +static int wait_on_busy(unsigned long iobase, unsigned int loop) { while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED) { udelay(1L); @@ -887,7 +862,7 @@ return FALSE; } -static inline int do_dma(unsigned long iobase, unsigned long addr, unchar cmd) { +static int do_dma(unsigned long iobase, unsigned long addr, unchar cmd) { unsigned char *byaddr; unsigned long devaddr; @@ -906,7 +881,7 @@ return FALSE; } -static inline int read_pio(unsigned long iobase, ushort *start, ushort *end) { +static int read_pio(unsigned long iobase, ushort *start, ushort *end) { unsigned int loop = MAXLOOP; ushort *p; @@ -918,13 +893,13 @@ } loop = MAXLOOP; - *p = REG2H(inw(iobase)); + *p = inw(iobase); } return FALSE; } -static inline struct pci_dev *get_pci_dev(unsigned long port_base) { +static struct pci_dev *get_pci_dev(unsigned long port_base) { #if defined(CONFIG_PCI) @@ -972,12 +947,12 @@ #endif /* end CONFIG_PCI */ } -static inline int port_detect \ +static int port_detect \ (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt) { unsigned char irq, dma_channel, subversion, i, is_pci = FALSE; unsigned char protocol_rev; struct eata_info info; - char *bus_type, dma_name[16], tag_type; + char *bus_type, dma_name[16]; struct pci_dev *pdev; /* Allowed DMA channels for ISA (0 indicates reserved) */ @@ -995,48 +970,31 @@ } if (do_dma(port_base, 0, READ_CONFIG_PIO)) { -#if defined(DEBUG_DETECT) - printk("%s: detect, do_dma failed at 0x%03lx.\n", name, port_base); -#endif release_region(port_base, REGION_SIZE); return FALSE; } /* Read the info structure */ if (read_pio(port_base, (ushort *)&info, (ushort *)&info.ipad[0])) { -#if defined(DEBUG_DETECT) - printk("%s: detect, read_pio failed at 0x%03lx.\n", name, port_base); -#endif release_region(port_base, REGION_SIZE); return FALSE; } - info.data_len = DEV2H(info.data_len); - info.sign = DEV2H(info.sign); - info.cp_pad_len = DEV2H16(info.cp_pad_len); - info.cp_len = DEV2H(info.cp_len); - info.sp_len = DEV2H(info.sp_len); - info.scatt_size = DEV2H16(info.scatt_size); - info.queue_size = DEV2H16(info.queue_size); - /* Check the controller "EATA" signature */ - if (info.sign != EATA_SIG_BE) { -#if defined(DEBUG_DETECT) - printk("%s: signature 0x%04x discarded.\n", name, info.sign); -#endif + if (info.sign != EATA_SIGNATURE) { release_region(port_base, REGION_SIZE); return FALSE; } - if (info.data_len < EATA_2_0A_SIZE) { + if (DEV2H(info.data_len) < EATA_2_0A_SIZE) { printk("%s: config structure size (%d bytes) too short, detaching.\n", - name, info.data_len); + name, DEV2H(info.data_len)); release_region(port_base, REGION_SIZE); return FALSE; } - else if (info.data_len == EATA_2_0A_SIZE) + else if (DEV2H(info.data_len) == EATA_2_0A_SIZE) protocol_rev = 'A'; - else if (info.data_len == EATA_2_0B_SIZE) + else if (DEV2H(info.data_len) == EATA_2_0B_SIZE) protocol_rev = 'B'; else protocol_rev = 'C'; @@ -1148,7 +1106,7 @@ /* Set board configuration */ memset((char *)cf, 0, sizeof(struct eata_config)); - cf->len = (ushort) H2DEV16((ushort)510); + cf->len = (ushort) cpu_to_be16((ushort)510); cf->ocena = TRUE; if (do_dma(port_base, cf_dma_addr, SET_CONFIG_DMA)) { @@ -1179,9 +1137,9 @@ sh[j]->n_io_port = REGION_SIZE; sh[j]->dma_channel = dma_channel; sh[j]->irq = irq; - sh[j]->sg_tablesize = (ushort) info.scatt_size; + sh[j]->sg_tablesize = (ushort) be16_to_cpu(info.scatt_size); sh[j]->this_id = (ushort) info.host_addr[3]; - sh[j]->can_queue = (ushort) info.queue_size; + sh[j]->can_queue = (ushort) be16_to_cpu(info.queue_size); sh[j]->cmd_per_lun = MAX_CMD_PER_LUN; memset(HD(j), 0, sizeof(struct hostdata)); HD(j)->subversion = subversion; @@ -1268,18 +1226,13 @@ if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN; - if (tagged_comm) { - if (tag_mode == TAG_SIMPLE) tag_type = '1'; - else if (tag_mode == TAG_HEAD) tag_type = '2'; - else if (tag_mode == TAG_ORDERED) tag_type = '3'; - else tag_type = 'y'; - } - else tag_type = 'n'; + if (tag_mode != TAG_DISABLED && tag_mode != TAG_SIMPLE) + tag_mode = TAG_ORDERED; if (j == 0) { printk("EATA/DMA 2.0x: Copyright (C) 1994-2002 Dario Ballabio.\n"); - printk("%s config options -> tc:%c, lc:%c, mq:%d, rs:%c, et:%c, "\ - "ip:%c, ep:%c, pp:%c.\n", driver_name, tag_type, + printk("%s config options -> tm:%d, lc:%c, mq:%d, rs:%c, et:%c, "\ + "ip:%c, ep:%c, pp:%c.\n", driver_name, tag_mode, YESNO(linked_comm), max_queue_depth, YESNO(rev_scan), YESNO(ext_tran), YESNO(isa_probe), YESNO(eisa_probe), YESNO(pci_probe)); @@ -1301,8 +1254,8 @@ printk("%s: Vers. 0x%x, ocs %u, tar %u, trnxfr %u, more %u, SYNC 0x%x, "\ "sec. %u, infol %d, cpl %d spl %d.\n", name, info.version, info.ocsena, info.tarsup, info.trnxfr, info.morsup, info.sync, - info.second, info.data_len, info.cp_len, - info.sp_len); + info.second, DEV2H(info.data_len), DEV2H(info.cp_len), + DEV2H(info.sp_len)); if (protocol_rev == 'B' || protocol_rev == 'C') printk("%s: isaena %u, forcaddr %u, max_id %u, max_chan %u, "\ @@ -1346,15 +1299,12 @@ else val = (int) simple_strtoul(pc, NULL, 0); if (!strncmp(cur, "lc:", 3)) linked_comm = val; - else if (!strncmp(cur, "tc:", 3)) tagged_comm = val; else if (!strncmp(cur, "tm:", 3)) tag_mode = val; + else if (!strncmp(cur, "tc:", 3)) tag_mode = val; else if (!strncmp(cur, "mq:", 3)) max_queue_depth = val; else if (!strncmp(cur, "ls:", 3)) link_statistics = val; else if (!strncmp(cur, "et:", 3)) ext_tran = val; else if (!strncmp(cur, "rs:", 3)) rev_scan = val; - else if (!strncmp(cur, "ip:", 3)) isa_probe = val; - else if (!strncmp(cur, "ep:", 3)) eisa_probe = val; - else if (!strncmp(cur, "pp:", 3)) pci_probe = val; if ((cur = strchr(cur, ','))) ++cur; } @@ -1419,7 +1369,7 @@ return; } -int eata2x_detect(Scsi_Host_Template *tpnt) { +static int eata2x_detect(Scsi_Host_Template *tpnt) { unsigned int j = 0, k; unsigned long spin_flags; @@ -1439,19 +1389,7 @@ for (k = 0; k < MAX_BOARDS + 1; k++) sh[k] = NULL; - for (k = MAX_INT_PARAM; io_port[k]; k++) - if (io_port[k] == SKIP) continue; - else if (io_port[k] <= MAX_ISA_ADDR) { - if (!isa_probe) io_port[k] = SKIP; - } - else if (io_port[k] >= MIN_EISA_ADDR && io_port[k] <= MAX_EISA_ADDR) { - if (!eisa_probe) io_port[k] = SKIP; - } - - if (pci_probe) { - if (!setup_done) add_pci_ports(); - else enable_pci_ports(); - } + if (!setup_done) add_pci_ports(); for (k = 0; io_port[k]; k++) { @@ -1465,7 +1403,7 @@ return j; } -static inline void map_dma(unsigned int i, unsigned int j) { +static void map_dma(unsigned int i, unsigned int j) { unsigned int k, count, pci_dir; struct scatterlist *sgpnt; struct mscp *cpp; @@ -1552,7 +1490,7 @@ DEV2H(cpp->data_len), pci_dir); } -static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) { +static void scsi_to_dev_dir(unsigned int i, unsigned int j) { unsigned int k; static const unsigned char data_out_cmds[] = { @@ -1606,7 +1544,7 @@ } -static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { +static int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { unsigned int i, j, k; struct mscp *cpp; @@ -1670,25 +1608,8 @@ /* Map DMA buffers and SG list */ map_dma(i, j); - if (SCpnt->device->simple_tags) { - - if (HD(j)->target_redo[SCpnt->target][SCpnt->channel] || - HD(j)->target_to[SCpnt->target][SCpnt->channel]) - cpp->mess[0] = ORDERED_QUEUE_TAG; - else if (tag_mode == TAG_SIMPLE) cpp->mess[0] = SIMPLE_QUEUE_TAG; - else if (tag_mode == TAG_HEAD) cpp->mess[0] = HEAD_OF_QUEUE_TAG; - else if (tag_mode == TAG_ORDERED) cpp->mess[0] = ORDERED_QUEUE_TAG; - else if (SCpnt->device->current_tag == 0) - cpp->mess[0] = ORDERED_QUEUE_TAG; - else if (SCpnt->device->current_tag == 1) - cpp->mess[0] = HEAD_OF_QUEUE_TAG; - else - cpp->mess[0] = SIMPLE_QUEUE_TAG; - - cpp->mess[1] = SCpnt->device->current_tag++; - } - - if (SCpnt->device->new_queue_depth > 2 && !SCpnt->device->simple_tags) { + if (linked_comm && SCpnt->device->new_queue_depth > 2 + && TLDEV(SCpnt->device->type)) { HD(j)->cp_stat[i] = READY; flush_dev(SCpnt->device, SCpnt->request->sector, j, FALSE); return 0; @@ -1707,14 +1628,7 @@ return 0; } -int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { - int rtn; - - rtn = do_qcomm(SCpnt, done); - return rtn; -} - -static inline int do_abort(Scsi_Cmnd *SCarg) { +static int eata2x_eh_abort(Scsi_Cmnd *SCarg) { unsigned int i, j; j = ((struct hostdata *) SCarg->host->hostdata)->board_number; @@ -1788,12 +1702,7 @@ panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i); } -int eata2x_abort(Scsi_Cmnd *SCarg) { - - return do_abort(SCarg); -} - -static inline int do_reset(Scsi_Cmnd *SCarg) { +static int eata2x_eh_host_reset(Scsi_Cmnd *SCarg) { unsigned int i, j, time, k, c, limit = 0; int arg_done = FALSE; Scsi_Cmnd *SCpnt; @@ -1925,23 +1834,18 @@ return SUCCESS; } -int eata2x_reset(Scsi_Cmnd *SCarg) { - - return do_reset(SCarg); -} - -int eata2x_biosparam(struct scsi_device *sdev, struct block_device *bdev, +int eata2x_bios_param(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *dkinfo) { int size = capacity; - if (ext_tran || (scsicam_bios_param(bdev, capacity, dkinfo) < 0)) { + if (ext_tran || (scsicam_bios_param(disk, bdev, dkinfo) < 0)) { dkinfo[0] = 255; dkinfo[1] = 63; dkinfo[2] = size / (dkinfo[0] * dkinfo[1]); } #if defined (DEBUG_GEOMETRY) - printk ("%s: biosparam, head=%d, sec=%d, cyl=%d.\n", driver_name, + printk ("%s: bios_param, head=%d, sec=%d, cyl=%d.\n", driver_name, dkinfo[0], dkinfo[1], dkinfo[2]); #endif @@ -1973,7 +1877,7 @@ return; } -static inline int reorder(unsigned int j, unsigned long cursec, +static int reorder(unsigned int j, unsigned long cursec, unsigned int ihdlr, unsigned int il[], unsigned int n_ready) { Scsi_Cmnd *SCpnt; struct mscp *cpp; @@ -2108,7 +2012,7 @@ } -static inline void ihdlr(int irq, unsigned int j) { +static void ihdlr(int irq, unsigned int j) { Scsi_Cmnd *SCpnt; unsigned int i, k, c, status, tstatus, reg; struct mssp *spp; @@ -2351,7 +2255,7 @@ spin_unlock_irqrestore(sh[j]->host_lock, spin_flags); } -int eata2x_release(struct Scsi_Host *shpnt) { +static int eata2x_release(struct Scsi_Host *shpnt) { unsigned int i, j; for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++); diff -Nru a/drivers/scsi/eata.h b/drivers/scsi/eata.h --- a/drivers/scsi/eata.h Mon Nov 4 14:31:01 2002 +++ b/drivers/scsi/eata.h Mon Nov 4 14:31:01 2002 @@ -1,34 +1,32 @@ /* * eata.h - used by the low-level driver for EATA/DMA SCSI host adapters. */ -#ifndef _EATA_H -#define _EATA_H -#include - -int eata2x_detect(Scsi_Host_Template *); -int eata2x_release(struct Scsi_Host *); -int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -int eata2x_abort(Scsi_Cmnd *); -int eata2x_reset(Scsi_Cmnd *); -int eata2x_biosparam(struct scsi_device *, struct block_device *, +static int eata2x_detect(Scsi_Host_Template *); +static int eata2x_release(struct Scsi_Host *); +static int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +static int eata2x_eh_abort(Scsi_Cmnd *); +static int eata2x_eh_host_reset(Scsi_Cmnd *); +static int eata2x_biosparam(struct scsi_device *, struct block_device *, sector_t, int *); static int eata2x_slave_attach(Scsi_Device *); -#define EATA_VERSION "7.70.00" +#define EATA_VERSION "8.00.00" #define EATA { \ name: "EATA/DMA 2.0x rev. " EATA_VERSION " ", \ detect: eata2x_detect, \ release: eata2x_release, \ queuecommand: eata2x_queuecommand, \ - eh_abort_handler: eata2x_abort, \ - eh_host_reset_handler: eata2x_reset, \ - bios_param: eata2x_biosparam, \ + abort: NULL, \ + reset: NULL, \ + eh_abort_handler: eata2x_eh_abort, \ + eh_device_reset_handler: NULL, \ + eh_bus_reset_handler: NULL, \ + eh_host_reset_handler: eata2x_eh_host_reset, \ + bios_param: eata2x_bios_param, \ slave_attach: eata2x_slave_attach, \ this_id: 7, \ unchecked_isa_dma: 1, \ - use_clustering: ENABLE_CLUSTERING, \ + use_clustering: ENABLE_CLUSTERING \ } - -#endif diff -Nru a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h --- a/drivers/scsi/hosts.h Mon Nov 4 14:31:01 2002 +++ b/drivers/scsi/hosts.h Mon Nov 4 14:31:01 2002 @@ -191,6 +191,13 @@ int (*eh_host_reset_handler)(Scsi_Cmnd *); /* + * Old EH handlers, no longer used. Make them warn the user of old + * drivers by using a wrogn type + */ + int (*abort)(int); + int (*reset)(int,int); + + /* * Once the device has responded to an INQUIRY and we know the device * is online, call into the low level driver with the Scsi_Device * * (so that the low level driver may save it off in a safe location @@ -560,9 +567,6 @@ const char * tag; struct module * module; /* Used for loadable modules */ unsigned char scsi_type; - unsigned int major; - unsigned int min_major; /* Minimum major in range. */ - unsigned int max_major; /* Maximum major in range. */ unsigned int nr_dev; /* Number currently attached */ unsigned int dev_noticed; /* Number of devices detected. */ unsigned int dev_max; /* Current size of arrays */ diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c --- a/drivers/scsi/ide-scsi.c Mon Nov 4 14:31:02 2002 +++ b/drivers/scsi/ide-scsi.c Mon Nov 4 14:31:02 2002 @@ -489,7 +489,7 @@ static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, sector_t block) { #if IDESCSI_DEBUG_LOG - printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors); + printk (KERN_INFO "rq_status: %d, dev: %s, cmd: %d, errors: %d\n",rq->rq_status, rq->rq_disk->disk_name,rq->cmd,rq->errors); printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors); #endif /* IDESCSI_DEBUG_LOG */ @@ -760,9 +760,13 @@ static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd) { idescsi_scsi_t *scsi = drive->driver_data; + struct gendisk *disk = cmd->request->rq_disk; - if (major(cmd->request->rq_dev) == SCSI_GENERIC_MAJOR) - return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); + if (disk) { + struct Scsi_Device_Template **p = disk->private_data; + if (strcmp((*p)->tag, "sg") == 0) + return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); + } return test_bit(IDESCSI_TRANSFORM, &scsi->transform); } diff -Nru a/drivers/scsi/inia100.h b/drivers/scsi/inia100.h --- a/drivers/scsi/inia100.h Mon Nov 4 14:31:00 2002 +++ b/drivers/scsi/inia100.h Mon Nov 4 14:31:00 2002 @@ -92,6 +92,8 @@ detect: inia100_detect, \ release: inia100_release, \ queuecommand: inia100_queue, \ + abort: inia100_abort, \ + reset: inia100_reset, \ can_queue: 1, \ this_id: 1, \ sg_tablesize: SG_ALL, \ diff -Nru a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h --- a/drivers/scsi/ncr53c8xx.h Mon Nov 4 14:31:01 2002 +++ b/drivers/scsi/ncr53c8xx.h Mon Nov 4 14:31:01 2002 @@ -76,6 +76,8 @@ info: ncr53c8xx_info, \ queuecommand: ncr53c8xx_queue_command,\ slave_attach: ncr53c8xx_slave_attach, \ + abort: ncr53c8xx_abort, \ + reset: ncr53c8xx_reset, \ can_queue: SCSI_NCR_CAN_QUEUE, \ this_id: 7, \ sg_tablesize: SCSI_NCR_SG_TABLESIZE, \ diff -Nru a/drivers/scsi/osst.c b/drivers/scsi/osst.c --- a/drivers/scsi/osst.c Mon Nov 4 14:31:01 2002 +++ b/drivers/scsi/osst.c Mon Nov 4 14:31:01 2002 @@ -162,7 +162,6 @@ name: "OnStream tape", tag: "osst", scsi_type: TYPE_TAPE, - major: OSST_MAJOR, detect: osst_detect, init: osst_init, attach: osst_attach, @@ -179,13 +178,18 @@ static int osst_write_error_recovery(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int pending); +static inline char *tape_name(OS_Scsi_Tape *tape) +{ + return tape->disk->disk_name; +} + /* Routines that handle the interaction with mid-layer SCSI routines */ /* Convert the result to success code */ static int osst_chk_result(OS_Scsi_Tape * STp, Scsi_Request * SRpnt) { - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); int result = SRpnt->sr_result; unsigned char * sense = SRpnt->sr_sense_buffer, scode; #if DEBUG @@ -205,8 +209,8 @@ #if DEBUG if (debugging) { - printk(OSST_DEB_MSG "osst%d:D: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n", - dev, result, + printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n", + name, result, SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2], SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5], SRpnt->sr_bufflen); @@ -225,22 +229,22 @@ SRpnt->sr_cmnd[0] != MODE_SENSE && SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ if (driver_byte(result) & DRIVER_SENSE) { - printk(KERN_WARNING "osst%d:W: Command with sense data: ", dev); + printk(KERN_WARNING "%s:W: Command with sense data: ", name); print_req_sense("osst:", SRpnt); } else { static int notyetprinted = 1; printk(KERN_WARNING - "osst%d:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", - dev, result, suggestion(result), driver_byte(result) & DRIVER_MASK, + "%s:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", + name, result, suggestion(result), driver_byte(result) & DRIVER_MASK, host_byte(result)); if (notyetprinted) { notyetprinted = 0; printk(KERN_INFO - "osst%d:I: This warning may be caused by your scsi controller,\n", dev); + "%s:I: This warning may be caused by your scsi controller,\n", name); printk(KERN_INFO - "osst%d:I: it has been reported with some Buslogic cards.\n", dev); + "%s:I: it has been reported with some Buslogic cards.\n", name); } } } @@ -256,8 +260,8 @@ stp = "write"; else stp = "ioctl"; - printk(OSST_DEB_MSG "osst%d:D: Recovered %s error (%d).\n", dev, stp, - os_scsi_tapes[dev]->recover_count); + printk(OSST_DEB_MSG "%s:D: Recovered %s error (%d).\n", name, stp, + STp->recover_count); } #endif if ((sense[2] & 0xe0) == 0) @@ -270,33 +274,27 @@ /* Wakeup from interrupt */ static void osst_sleep_done (Scsi_Cmnd * SCpnt) { - unsigned int dev = TAPE_NR(SCpnt->request->rq_dev); - OS_Scsi_Tape * STp; + OS_Scsi_Tape * STp = container_of(SCpnt->request->rq_disk->private_data, + OS_Scsi_Tape, driver); - if (os_scsi_tapes && (STp = os_scsi_tapes[dev])) { - if ((STp->buffer)->writing && - (SCpnt->sense_buffer[0] & 0x70) == 0x70 && - (SCpnt->sense_buffer[2] & 0x40)) { - /* EOM at write-behind, has all been written? */ - if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW) - (STp->buffer)->midlevel_result = SCpnt->result; /* Error */ - else - (STp->buffer)->midlevel_result = INT_MAX; /* OK */ - } + if ((STp->buffer)->writing && + (SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x40)) { + /* EOM at write-behind, has all been written? */ + if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW) + (STp->buffer)->midlevel_result = SCpnt->result; /* Error */ else - (STp->buffer)->midlevel_result = SCpnt->result; - SCpnt->request->rq_status = RQ_SCSI_DONE; - (STp->buffer)->last_SRpnt = SCpnt->sc_request; - -#if DEBUG - STp->write_pending = 0; -#endif - complete(SCpnt->request->waiting); + (STp->buffer)->midlevel_result = INT_MAX; /* OK */ } + else + (STp->buffer)->midlevel_result = SCpnt->result; + SCpnt->request->rq_status = RQ_SCSI_DONE; + (STp->buffer)->last_SRpnt = SCpnt->sc_request; + #if DEBUG - else if (debugging) - printk(OSST_DEB_MSG "osst?:D: Illegal interrupt device %x\n", dev); + STp->write_pending = 0; #endif + complete(SCpnt->request->waiting); } @@ -313,7 +311,7 @@ #endif if (SRpnt == NULL) { if ((SRpnt = scsi_allocate_request(STp->device)) == NULL) { - printk(KERN_ERR "osst%d:E: Can't get SCSI request->\n", TAPE_NR(STp->devt)); + printk(KERN_ERR "%s:E: Can't get SCSI request->\n", tape_name(STp)); if (signal_pending(current)) (STp->buffer)->syscall_result = (-EINTR); else @@ -336,7 +334,7 @@ SRpnt->sr_cmd_len = 0; SRpnt->sr_request->waiting = &(STp->wait); SRpnt->sr_request->rq_status = RQ_SCSI_BUSY; - SRpnt->sr_request->rq_dev = STp->devt; + SRpnt->sr_request->rq_disk = STp->disk; scsi_do_req(SRpnt, (void *)cmd, bp, bytes, osst_sleep_done, timeout, retries); @@ -352,7 +350,7 @@ (STp->first_frame_position == 240 /* or STp->read_error_frame to fail again on the block calculated above */ && ++repeat < 3))) { - printk(OSST_DEB_MSG "osst%d:D: Injecting read error\n", TAPE_NR(STp->devt)); + printk(OSST_DEB_MSG "%s:D: Injecting read error\n", tape_name(STp)); STp->buffer->last_result_fatal = 1; } #endif @@ -466,10 +464,10 @@ */ static int osst_verify_frame(OS_Scsi_Tape * STp, int frame_seq_number, int quiet) { + char *name = tape_name(STp); os_aux_t * aux = STp->buffer->aux; os_partition_t * par = &(aux->partition); ST_partstat * STps = &(STp->ps[STp->partition]); - int dev = TAPE_NR(STp->devt); int blk_cnt, blk_sz, i; if (STp->raw) { @@ -484,42 +482,42 @@ } if (STp->buffer->syscall_result) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Skipping frame, read error\n", dev); + printk(OSST_DEB_MSG "%s:D: Skipping frame, read error\n", name); #endif return 0; } if (ntohl(aux->format_id) != 0) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Skipping frame, format_id %u\n", dev, ntohl(aux->format_id)); + printk(OSST_DEB_MSG "%s:D: Skipping frame, format_id %u\n", name, ntohl(aux->format_id)); #endif goto err_out; } if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 && (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Skipping frame, incorrect application signature\n", dev); + printk(OSST_DEB_MSG "%s:D: Skipping frame, incorrect application signature\n", name); #endif goto err_out; } if (par->partition_num != OS_DATA_PARTITION) { if (!STp->linux_media || STp->linux_media_version != 2) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Skipping frame, partition num %d\n", - dev, par->partition_num); + printk(OSST_DEB_MSG "%s:D: Skipping frame, partition num %d\n", + name, par->partition_num); #endif goto err_out; } } if (par->par_desc_ver != OS_PARTITION_VERSION) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Skipping frame, partition version %d\n", dev, par->par_desc_ver); + printk(OSST_DEB_MSG "%s:D: Skipping frame, partition version %d\n", name, par->par_desc_ver); #endif goto err_out; } if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n", - dev, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr); + printk(OSST_DEB_MSG "%s:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n", + name, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr); #endif goto err_out; } @@ -528,13 +526,13 @@ aux->frame_type != OS_FRAME_TYPE_MARKER) { if (!quiet) #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Skipping frame, frame type %x\n", dev, aux->frame_type); + printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type); #endif goto err_out; } if (aux->frame_type == OS_FRAME_TYPE_EOD && STp->first_frame_position < STp->eod_frame_ppos) { - printk(KERN_INFO "osst%d:I: Skipping premature EOD frame %d\n", dev, + printk(KERN_INFO "%s:I: Skipping premature EOD frame %d\n", name, STp->first_frame_position); goto err_out; } @@ -543,8 +541,8 @@ if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) { if (!quiet) #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Skipping frame, sequence number %u (expected %d)\n", - dev, ntohl(aux->frame_seq_num), frame_seq_number); + printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n", + name, ntohl(aux->frame_seq_num), frame_seq_number); #endif goto err_out; } @@ -555,7 +553,7 @@ if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt || STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: %s filemark %d at frame pos %d\n", dev, + printk(OSST_DEB_MSG "%s:D: %s filemark %d at frame pos %d\n", name, STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected", i, STp->first_frame_position - 1); #endif @@ -576,8 +574,8 @@ /* See what block size was used to write file */ if (STp->block_size != blk_sz && blk_sz > 0) { printk(KERN_INFO - "osst%d:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n", - dev, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k', + "%s:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n", + name, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k', STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k'); STp->block_size = blk_sz; @@ -605,9 +603,9 @@ long startwait = jiffies; #if DEBUG int dbg = debugging; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); - printk(OSST_DEB_MSG "osst%d:D: Reached onstream wait ready\n", dev); + printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name); #endif memset(cmd, 0, MAX_COMMAND_SIZE); @@ -624,8 +622,8 @@ SRpnt->sr_sense_buffer[13] == 0 ) )) { #if DEBUG if (debugging) { - printk(OSST_DEB_MSG "osst%d:D: Sleeping in onstream wait ready\n", dev); - printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev); + printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait ready\n", name); + printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); debugging = 0; } #endif @@ -644,15 +642,15 @@ if ( STp->buffer->syscall_result && osst_write_error_recovery(STp, aSRpnt, 0) ) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Abnormal exit from onstream wait ready\n", dev); - printk(OSST_DEB_MSG "osst%d:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", dev, + printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait ready\n", name); + printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name, STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]); #endif return (-EIO); } #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Normal exit from onstream wait ready\n", dev); + printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait ready\n", name); #endif return 0; } @@ -667,9 +665,9 @@ long startwait = jiffies; #if DEBUG int dbg = debugging; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); - printk(OSST_DEB_MSG "osst%d:D: Reached onstream wait for medium\n", dev); + printk(OSST_DEB_MSG "%s:D: Reached onstream wait for medium\n", name); #endif memset(cmd, 0, MAX_COMMAND_SIZE); @@ -684,8 +682,8 @@ SRpnt->sr_sense_buffer[13] == 0 ) { #if DEBUG if (debugging) { - printk(OSST_DEB_MSG "osst%d:D: Sleeping in onstream wait medium\n", dev); - printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev); + printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait medium\n", name); + printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); debugging = 0; } #endif @@ -704,15 +702,15 @@ if ( STp->buffer->syscall_result && SRpnt->sr_sense_buffer[2] != 2 && SRpnt->sr_sense_buffer[12] != 4 && SRpnt->sr_sense_buffer[13] == 1) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Abnormal exit from onstream wait medium\n", dev); - printk(OSST_DEB_MSG "osst%d:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", dev, + printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait medium\n", name); + printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name, STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]); #endif return 0; } #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Normal exit from onstream wait medium\n", dev); + printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait medium\n", name); #endif return 1; } @@ -738,9 +736,9 @@ int result = 0; #if DEBUG - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); - printk(OSST_DEB_MSG "osst%d:D: Reached onstream flush drive buffer (write filemark)\n", dev); + printk(OSST_DEB_MSG "%s:D: Reached onstream flush drive buffer (write filemark)\n", name); #endif memset(cmd, 0, MAX_COMMAND_SIZE); @@ -763,12 +761,12 @@ static int osst_wait_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int curr, int minlast, int to) { long startwait = jiffies; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); #if DEBUG char notyetprinted = 1; #endif if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING) - printk(KERN_ERR "osst%i:A: Waiting for frame without having initialized read!\n", dev); + printk(KERN_ERR "%s:A: Waiting for frame without having initialized read!\n", name); while (time_before (jiffies, startwait + to*HZ)) { @@ -787,8 +785,8 @@ #if DEBUG if (debugging || jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC) printk (OSST_DEB_MSG - "osst%d:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n", - dev, curr, curr+minlast, STp->first_frame_position, + "%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n", + name, curr, curr+minlast, STp->first_frame_position, STp->last_frame_position, STp->cur_frames, result, (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ); @@ -798,8 +796,8 @@ #if DEBUG if (jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC && notyetprinted) { - printk (OSST_DEB_MSG "osst%d:D: Wait for frame %i (>%i): %i-%i %i (%i)\n", - dev, curr, curr+minlast, STp->first_frame_position, + printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n", + name, curr, curr+minlast, STp->first_frame_position, STp->last_frame_position, STp->cur_frames, result); notyetprinted--; } @@ -808,8 +806,8 @@ schedule_timeout (HZ / OSST_POLL_PER_SEC); } #if DEBUG - printk (OSST_DEB_MSG "osst%d:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n", - dev, curr, curr+minlast, STp->first_frame_position, + printk (OSST_DEB_MSG "%s:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n", + name, curr, curr+minlast, STp->first_frame_position, STp->last_frame_position, STp->cur_frames, (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ); #endif @@ -826,7 +824,7 @@ int retval = 0; #if DEBUG os_aux_t * aux = STp->buffer->aux; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); #endif /* TODO: Error handling */ @@ -843,7 +841,7 @@ #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Reading frame from OnStream tape\n", dev); + printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name); #endif SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_READ, STp->timeout, MAX_RETRIES, TRUE); @@ -856,13 +854,13 @@ if (STp->read_error_frame == 0) { STp->read_error_frame = STp->first_frame_position; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Recording read error at %d\n", dev, STp->read_error_frame); + printk(OSST_DEB_MSG "%s:D: Recording read error at %d\n", name, STp->read_error_frame); #endif } #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", - dev, + printk(OSST_DEB_MSG "%s:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", + name, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[1], SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[3], SRpnt->sr_sense_buffer[4], SRpnt->sr_sense_buffer[5], @@ -874,7 +872,7 @@ #if DEBUG if (debugging) { printk(OSST_DEB_MSG - "osst%d:D: AUX: %c%c%c%c UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", dev, + "%s:D: AUX: %c%c%c%c UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", name, aux->application_sig[0], aux->application_sig[1], aux->application_sig[2], aux->application_sig[3], ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr), @@ -883,9 +881,9 @@ ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num), ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) ); if (aux->frame_type==2) - printk(OSST_DEB_MSG "osst%d:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", dev, + printk(OSST_DEB_MSG "%s:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", name, ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn)); - printk(OSST_DEB_MSG "osst%d:D: Exit read frame from OnStream tape with code %d\n", dev, retval); + printk(OSST_DEB_MSG "%s:D: Exit read frame from OnStream tape with code %d\n", name, retval); } #endif return (retval); @@ -898,7 +896,7 @@ unsigned char cmd[MAX_COMMAND_SIZE]; int retval = 0; #if DEBUG - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); #endif if (STps->rw != ST_READING) { /* Initialize read operation */ @@ -918,7 +916,7 @@ cmd[1] = 1; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Start Read Ahead on OnStream tape\n", dev); + printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name); #endif SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_RETRIES, TRUE); *aSRpnt = SRpnt; @@ -931,7 +929,7 @@ static int osst_get_logical_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int frame_seq_number, int quiet) { ST_partstat * STps = &(STp->ps[STp->partition]); - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); int cnt = 0, bad = 0, past = 0, @@ -943,13 +941,13 @@ */ while (1) { if (cnt++ > 400) { - printk(KERN_ERR "osst%d:E: Couldn't find logical frame %d, aborting\n", - dev, frame_seq_number); + printk(KERN_ERR "%s:E: Couldn't find logical frame %d, aborting\n", + name, frame_seq_number); if (STp->read_error_frame) { osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0); #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Repositioning tape to bad frame %d\n", - dev, STp->read_error_frame); + printk(OSST_DEB_MSG "%s:D: Repositioning tape to bad frame %d\n", + name, STp->read_error_frame); #endif STp->read_error_frame = 0; } @@ -957,8 +955,8 @@ } #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Looking for frame %d, attempt %d\n", - dev, frame_seq_number, cnt); + printk(OSST_DEB_MSG "%s:D: Looking for frame %d, attempt %d\n", + name, frame_seq_number, cnt); #endif if ( osst_initiate_read(STp, aSRpnt) || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) { @@ -975,8 +973,8 @@ cnt += 20; } #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Bad frame detected, positioning tape to block %d\n", - dev, position); + printk(OSST_DEB_MSG "%s:D: Bad frame detected, positioning tape to block %d\n", + name, position); #endif osst_set_frame_position(STp, aSRpnt, position, 0); continue; @@ -987,8 +985,8 @@ x = ntohl(STp->buffer->aux->frame_seq_num); if (STp->fast_open) { printk(KERN_WARNING - "osst%d:W: Found logical frame %d instead of %d after fast open\n", - dev, x, frame_seq_number); + "%s:W: Found logical frame %d instead of %d after fast open\n", + name, x, frame_seq_number); STp->header_ok = 0; STp->read_error_frame = 0; return (-EIO); @@ -1007,8 +1005,8 @@ } #if DEBUG printk(OSST_DEB_MSG - "osst%d:D: Found logical frame %d while looking for %d: back up %d\n", - dev, x, frame_seq_number, + "%s:D: Found logical frame %d while looking for %d: back up %d\n", + name, x, frame_seq_number, STp->first_frame_position - position); #endif osst_set_frame_position(STp, aSRpnt, position, 0); @@ -1019,7 +1017,7 @@ } if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Skipping config partition\n", dev); + printk(OSST_DEB_MSG "%s:D: Skipping config partition\n", name); #endif osst_set_frame_position(STp, aSRpnt, 0xbb8, 0); cnt--; @@ -1029,16 +1027,16 @@ if (cnt > 1) { STp->recover_count++; STp->recover_erreg++; - printk(KERN_WARNING "osst%d:I: Don't worry, Read error at position %d recovered\n", - dev, STp->read_error_frame); + printk(KERN_WARNING "%s:I: Don't worry, Read error at position %d recovered\n", + name, STp->read_error_frame); } STp->read_count++; #if DEBUG if (debugging || STps->eof) printk(OSST_DEB_MSG - "osst%d:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n", - dev, frame_seq_number, STp->frame_seq_number, STps->eof); + "%s:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n", + name, frame_seq_number, STp->frame_seq_number, STps->eof); #endif STp->fast_open = FALSE; STp->read_error_frame = 0; @@ -1048,14 +1046,14 @@ static int osst_seek_logical_blk(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int logical_blk_num) { ST_partstat * STps = &(STp->ps[STp->partition]); - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); int retries = 0; int frame_seq_estimate, ppos_estimate, move; if (logical_blk_num < 0) logical_blk_num = 0; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Seeking logical block %d (now at %d, size %d%c)\n", - dev, logical_blk_num, STp->logical_blk_num, + printk(OSST_DEB_MSG "%s:D: Seeking logical block %d (now at %d, size %d%c)\n", + name, logical_blk_num, STp->logical_blk_num, STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k'); #endif @@ -1093,8 +1091,8 @@ } #if DEBUG printk(OSST_DEB_MSG - "osst%d:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n", - dev, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, + "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n", + name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, STp->logical_blk_num, logical_blk_num, move); #endif frame_seq_estimate += move; @@ -1106,8 +1104,8 @@ STp->logical_blk_num = logical_blk_num; #if DEBUG printk(OSST_DEB_MSG - "osst%d:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n", - dev, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer, + "%s:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n", + name, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer, STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size, STp->block_size); #endif @@ -1129,8 +1127,8 @@ goto error; /* we are not yet at the estimated frame, adjust our estimate of its physical position */ #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n", - dev, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, + printk(OSST_DEB_MSG "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n", + name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, STp->logical_blk_num, logical_blk_num); #endif if (frame_seq_estimate != STp->frame_seq_number) @@ -1139,8 +1137,8 @@ break; } error: - printk(KERN_ERR "osst%d:E: Couldn't seek to logical block %d (at %d), %d retries\n", - dev, logical_blk_num, STp->logical_blk_num, retries); + printk(KERN_ERR "%s:E: Couldn't seek to logical block %d (at %d), %d retries\n", + name, logical_blk_num, STp->logical_blk_num, retries); return (-EIO); } @@ -1157,11 +1155,11 @@ { int sector; #if DEBUG - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); printk(OSST_DEB_MSG - "osst%d:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n", - dev, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num, + "%s:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n", + name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num, STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block, STp->ps[STp->partition].rw == ST_WRITING?'w':'r', STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes: @@ -1190,10 +1188,10 @@ offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT, r; #if DEBUG - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); - printk(OSST_DEB_MSG "osst%d:D: Seeking sector %d in frame %d at offset %d\n", - dev, sector, frame, offset); + printk(OSST_DEB_MSG "%s:D: Seeking sector %d in frame %d at offset %d\n", + name, sector, frame, offset); #endif if (frame < 0 || frame >= STp->capacity) return (-ENXIO); @@ -1232,8 +1230,8 @@ STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF; #if DEBUG printk(OSST_DEB_MSG - "osst%d:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n", - dev, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num, + "%s:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n", + name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof); #endif return 0; @@ -1259,7 +1257,7 @@ - (nframes + pending - 1); int logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num) - (nframes + pending - 1) * blks_per_frame; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); long startwait = jiffies; #if DEBUG int dbg = debugging; @@ -1268,14 +1266,14 @@ if ((buffer = (unsigned char *)vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL) return (-EIO); - printk(KERN_INFO "osst%d:I: Reading back %d frames from drive buffer%s\n", - dev, nframes, pending?" and one that was pending":""); + printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n", + name, nframes, pending?" and one that was pending":""); osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE])); #if DEBUG if (pending && debugging) - printk(OSST_DEB_MSG "osst%d:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n", - dev, frame_seq_number + nframes, + printk(OSST_DEB_MSG "%s:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n", + name, frame_seq_number + nframes, logical_blk_num + nframes * blks_per_frame, p[0], p[1], p[2], p[3]); #endif @@ -1291,7 +1289,7 @@ STp->timeout, MAX_RETRIES, TRUE); if ((STp->buffer)->syscall_result || !SRpnt) { - printk(KERN_ERR "osst%d:E: Failed to read frame back from OnStream buffer\n", dev); + printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name); vfree((void *)buffer); *aSRpnt = SRpnt; return (-EIO); @@ -1299,15 +1297,15 @@ osst_copy_from_buffer(STp->buffer, p); #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Read back logical frame %d, data %02x %02x %02x %02x\n", - dev, frame_seq_number + i, p[0], p[1], p[2], p[3]); + printk(OSST_DEB_MSG "%s:D: Read back logical frame %d, data %02x %02x %02x %02x\n", + name, frame_seq_number + i, p[0], p[1], p[2], p[3]); #endif } *aSRpnt = SRpnt; osst_get_frame_position(STp, aSRpnt); #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Frames left in buffer: %d\n", dev, STp->cur_frames); + printk(OSST_DEB_MSG "%s:D: Frames left in buffer: %d\n", name, STp->cur_frames); #endif /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */ /* In the header we don't actually re-write the frames that fail, just the ones after them */ @@ -1324,8 +1322,8 @@ else new_frame += skip; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Position to frame %d, write fseq %d\n", - dev, new_frame+i, frame_seq_number+i); + printk(OSST_DEB_MSG "%s:D: Position to frame %d, write fseq %d\n", + name, new_frame+i, frame_seq_number+i); #endif osst_set_frame_position(STp, aSRpnt, new_frame + i, 0); osst_wait_ready(STp, aSRpnt, 60); @@ -1333,7 +1331,7 @@ SRpnt = * aSRpnt; if (new_frame > frame + 1000) { - printk(KERN_ERR "osst%d:E: Failed to find writable tape media\n", dev); + printk(KERN_ERR "%s:E: Failed to find writable tape media\n", name); vfree((void *)buffer); return (-EIO); } @@ -1355,8 +1353,8 @@ #if DEBUG if (debugging) printk(OSST_DEB_MSG - "osst%d:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n", - dev, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame, + "%s:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n", + name, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame, p[0], p[1], p[2], p[3]); #endif SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE, @@ -1370,7 +1368,7 @@ /* if we just sent the last frame, wait till all successfully written */ if ( i == nframes + pending ) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Check re-write successful\n", dev); + printk(OSST_DEB_MSG "%s:D: Check re-write successful\n", name); #endif memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = WRITE_FILEMARKS; @@ -1379,8 +1377,8 @@ STp->timeout, MAX_WRITE_RETRIES, TRUE); #if DEBUG if (debugging) { - printk(OSST_DEB_MSG "osst%d:D: Sleeping in re-write wait ready\n", dev); - printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev); + printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name); + printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); debugging = 0; } #endif @@ -1405,7 +1403,7 @@ } #if DEBUG debugging = dbg; - printk(OSST_DEB_MSG "osst%d:D: Wait re-write finished\n", dev); + printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name); #endif } } @@ -1414,7 +1412,7 @@ if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) == 13 && SRpnt->sr_sense_buffer[12] == 0 && SRpnt->sr_sense_buffer[13] == 2) { - printk(KERN_ERR "osst%d:E: Volume overflow in write error recovery\n", dev); + printk(KERN_ERR "%s:E: Volume overflow in write error recovery\n", name); vfree((void *)buffer); return (-EIO); /* hit end of tape = fail */ } @@ -1424,12 +1422,12 @@ SRpnt->sr_sense_buffer[6] ) - new_frame; p = &buffer[i * OS_DATA_SIZE]; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Additional write error at %d\n", dev, new_frame+i); + printk(OSST_DEB_MSG "%s:D: Additional write error at %d\n", name, new_frame+i); #endif osst_get_frame_position(STp, aSRpnt); #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: reported frame positions: host = %d, tape = %d\n", - dev, STp->first_frame_position, STp->last_frame_position); + printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n", + name, STp->first_frame_position, STp->last_frame_position); #endif } } @@ -1444,7 +1442,7 @@ { unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request * SRpnt; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); int expected = 0; int attempts = 1000 / skip; int flag = 1; @@ -1462,8 +1460,8 @@ frame = 3000-skip; expected = frame+skip+STp->cur_frames+pending; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Position to fppos %d, re-write from fseq %d\n", - dev, frame+skip, STp->frame_seq_number-STp->cur_frames-pending); + printk(OSST_DEB_MSG "%s:D: Position to fppos %d, re-write from fseq %d\n", + name, frame+skip, STp->frame_seq_number-STp->cur_frames-pending); #endif osst_set_frame_position(STp, aSRpnt, frame + skip, 1); flag = 0; @@ -1471,8 +1469,8 @@ } if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */ #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Addl error, host %d, tape %d, buffer %d\n", - dev, STp->first_frame_position, + printk(OSST_DEB_MSG "%s:D: Addl error, host %d, tape %d, buffer %d\n", + name, STp->first_frame_position, STp->last_frame_position, STp->cur_frames); #endif frame = STp->last_frame_position; @@ -1486,8 +1484,8 @@ cmd[1] = 1; cmd[4] = 1; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: About to write pending fseq %d at fppos %d\n", - dev, STp->frame_seq_number-1, STp->first_frame_position); + printk(OSST_DEB_MSG "%s:D: About to write pending fseq %d at fppos %d\n", + name, STp->frame_seq_number-1, STp->first_frame_position); #endif SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_WRITE, STp->timeout, MAX_WRITE_RETRIES, TRUE); @@ -1498,8 +1496,8 @@ SRpnt->sr_sense_buffer[12] == 0 && SRpnt->sr_sense_buffer[13] == 2) { printk(KERN_ERR - "osst%d:E: Volume overflow in write error recovery\n", - dev); + "%s:E: Volume overflow in write error recovery\n", + name); break; /* hit end of tape = fail */ } flag = 1; @@ -1512,25 +1510,25 @@ if (STp->cur_frames == 0) { #if DEBUG debugging = dbg; - printk(OSST_DEB_MSG "osst%d:D: Wait re-write finished\n", dev); + printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name); #endif if (STp->first_frame_position != expected) { - printk(KERN_ERR "osst%d:A: Actual position %d - expected %d\n", - dev, STp->first_frame_position, expected); + printk(KERN_ERR "%s:A: Actual position %d - expected %d\n", + name, STp->first_frame_position, expected); return (-EIO); } return 0; } #if DEBUG if (debugging) { - printk(OSST_DEB_MSG "osst%d:D: Sleeping in re-write wait ready\n", dev); - printk(OSST_DEB_MSG "osst%d:D: Turning off debugging for a while\n", dev); + printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name); + printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); debugging = 0; } #endif schedule_timeout(HZ / 10); } - printk(KERN_ERR "osst%d:E: Failed to find valid tape media\n", dev); + printk(KERN_ERR "%s:E: Failed to find valid tape media\n", name); #if DEBUG debugging = dbg; #endif @@ -1545,7 +1543,7 @@ { Scsi_Request * SRpnt = * aSRpnt; ST_partstat * STps = & STp->ps[STp->partition]; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); int retval = 0; int rw_state; unsigned int frame, skip; @@ -1556,7 +1554,7 @@ || SRpnt->sr_sense_buffer[12] != 12 || SRpnt->sr_sense_buffer[13] != 0) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Write error recovery cannot handle %02x:%02x:%02x\n", dev, + printk(OSST_DEB_MSG "%s:D: Write error recovery cannot handle %02x:%02x:%02x\n", name, SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]); #endif return (-EIO); @@ -1568,47 +1566,47 @@ skip = SRpnt->sr_sense_buffer[9]; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Detected physical bad frame at %u, advised to skip %d\n", dev, frame, skip); + printk(OSST_DEB_MSG "%s:D: Detected physical bad frame at %u, advised to skip %d\n", name, frame, skip); #endif osst_get_frame_position(STp, aSRpnt); #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: reported frame positions: host = %d, tape = %d\n", - dev, STp->first_frame_position, STp->last_frame_position); + printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n", + name, STp->first_frame_position, STp->last_frame_position); #endif switch (STp->write_type) { case OS_WRITE_DATA: case OS_WRITE_EOD: case OS_WRITE_NEW_MARK: printk(KERN_WARNING - "osst%d:I: Relocating %d buffered logical frames from position %u to %u\n", - dev, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip); + "%s:I: Relocating %d buffered logical frames from position %u to %u\n", + name, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip); if (STp->os_fw_rev >= 10600) retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending); else retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending); - printk(KERN_WARNING "osst%d:%s: %sWrite error%srecovered\n", dev, + printk(KERN_WARNING "%s:%s: %sWrite error%srecovered\n", name, retval?"E" :"I", retval?"" :"Don't worry, ", retval?" not ":" "); break; case OS_WRITE_LAST_MARK: - printk(KERN_ERR "osst%d:E: Bad frame in update last marker, fatal\n", dev); + printk(KERN_ERR "%s:E: Bad frame in update last marker, fatal\n", name); osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0); retval = -EIO; break; case OS_WRITE_HEADER: - printk(KERN_WARNING "osst%d:I: Bad frame in header partition, skipped\n", dev); + printk(KERN_WARNING "%s:I: Bad frame in header partition, skipped\n", name); retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending); break; default: - printk(KERN_INFO "osst%d:I: Bad frame in filler, ignored\n", dev); + printk(KERN_INFO "%s:I: Bad frame in filler, ignored\n", name); osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0); } osst_get_frame_position(STp, aSRpnt); #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n", - dev, STp->cur_frames, STp->first_frame_position, STp->last_frame_position); - printk(OSST_DEB_MSG "osst%d:D: next logical frame to write: %d\n", dev, STp->logical_blk_num); + printk(OSST_DEB_MSG "%s:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n", + name, STp->cur_frames, STp->first_frame_position, STp->last_frame_position); + printk(OSST_DEB_MSG "%s:D: next logical frame to write: %d\n", name, STp->logical_blk_num); #endif if (retval == 0) { STp->recover_count++; @@ -1621,16 +1619,16 @@ static int osst_space_over_filemarks_backward(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int mt_op, int mt_count) { - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); int cnt; int last_mark_ppos = -1; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Reached space_over_filemarks_backwards %d %d\n", dev, mt_op, mt_count); + printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_backwards %d %d\n", name, mt_op, mt_count); #endif if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks_bwd\n", dev); + printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_bwd\n", name); #endif return -EIO; } @@ -1649,11 +1647,11 @@ last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]); #if DEBUG if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX) - printk(OSST_DEB_MSG "osst%d:D: Filemark lookup fail due to %s\n", dev, + printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name, STp->header_cache == NULL?"lack of header cache":"count out of range"); else - printk(OSST_DEB_MSG "osst%d:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n", - dev, cnt, + printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n", + name, cnt, ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) || (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos))?"match":"error", @@ -1664,13 +1662,13 @@ if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG printk(OSST_DEB_MSG - "osst%d:D: Couldn't get logical blk num in space_filemarks\n", dev); + "%s:D: Couldn't get logical blk num in space_filemarks\n", name); #endif return (-EIO); } if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "osst%d:W: Expected to find marker at ppos %d, not found\n", - dev, last_mark_ppos); + printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", + name, last_mark_ppos); return (-EIO); } if (mt_op == MTBSFM) { @@ -1681,7 +1679,7 @@ return 0; } #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Reverting to scan filemark backwards\n", dev); + printk(OSST_DEB_MSG "%s:D: Reverting to scan filemark backwards\n", name); #endif } cnt = 0; @@ -1690,19 +1688,19 @@ if (last_mark_ppos == -1) return (-EIO); #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Positioning to last mark at %d\n", dev, last_mark_ppos); + printk(OSST_DEB_MSG "%s:D: Positioning to last mark at %d\n", name, last_mark_ppos); #endif osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos); cnt++; if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n", dev); + printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name); #endif return (-EIO); } if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "osst%d:W: Expected to find marker at ppos %d, not found\n", - dev, last_mark_ppos); + printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", + name, last_mark_ppos); return (-EIO); } } @@ -1724,20 +1722,20 @@ { int cnt = 0; #if DEBUG - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); - printk(OSST_DEB_MSG "osst%d:D: Reached space_over_filemarks_forward_slow %d %d\n", dev, mt_op, mt_count); + printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_slow %d %d\n", name, mt_op, mt_count); #endif if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks_fwd\n", dev); + printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name); #endif return (-EIO); } while (1) { if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n", dev); + printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name); #endif return (-EIO); } @@ -1745,12 +1743,12 @@ cnt++; if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: space_fwd: EOD reached\n", dev); + printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name); #endif if (STp->first_frame_position > STp->eod_frame_ppos+1) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: EOD position corrected (%d=>%d)\n", - dev, STp->eod_frame_ppos, STp->first_frame_position-1); + printk(OSST_DEB_MSG "%s:D: EOD position corrected (%d=>%d)\n", + name, STp->eod_frame_ppos, STp->first_frame_position-1); #endif STp->eod_frame_ppos = STp->first_frame_position-1; } @@ -1774,16 +1772,16 @@ static int osst_space_over_filemarks_forward_fast(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int mt_op, int mt_count) { - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); int cnt = 0, next_mark_ppos = -1; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Reached space_over_filemarks_forward_fast %d %d\n", dev, mt_op, mt_count); + printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_fast %d %d\n", name, mt_op, mt_count); #endif if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks_fwd\n", dev); + printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name); #endif return (-EIO); } @@ -1803,11 +1801,11 @@ next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]); #if DEBUG if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX) - printk(OSST_DEB_MSG "osst%d:D: Filemark lookup fail due to %s\n", dev, + printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name, STp->header_cache == NULL?"lack of header cache":"count out of range"); else - printk(OSST_DEB_MSG "osst%d:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n", - dev, cnt, + printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n", + name, cnt, ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) || (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos))?"match":"error", @@ -1815,26 +1813,26 @@ #endif if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Reverting to slow filemark space\n", dev); + printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name); #endif return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count); } else { osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos); if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n", - dev); + printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", + name); #endif return (-EIO); } if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "osst%d:W: Expected to find marker at ppos %d, not found\n", - dev, next_mark_ppos); + printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", + name, next_mark_ppos); return (-EIO); } if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) { - printk(KERN_WARNING "osst%d:W: Expected to find marker %d at ppos %d, not %d\n", - dev, cnt+mt_count, next_mark_ppos, + printk(KERN_WARNING "%s:W: Expected to find marker %d at ppos %d, not %d\n", + name, cnt+mt_count, next_mark_ppos, ntohl(STp->buffer->aux->filemark_cnt)); return (-EIO); } @@ -1848,14 +1846,14 @@ break; if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: space_fwd: EOD reached\n", dev); + printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name); #endif return (-EIO); } if (ntohl(STp->buffer->aux->filemark_cnt) == 0) { if (STp->first_mark_ppos == -1) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Reverting to slow filemark space\n", dev); + printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name); #endif return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count); } @@ -1863,14 +1861,14 @@ if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG printk(OSST_DEB_MSG - "osst%d:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n", - dev); + "%s:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n", + name); #endif return (-EIO); } if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "osst%d:W: Expected to find filemark at %d\n", - dev, STp->first_mark_ppos); + printk(KERN_WARNING "%s:W: Expected to find filemark at %d\n", + name, STp->first_mark_ppos); return (-EIO); } } else { @@ -1884,25 +1882,25 @@ next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos); if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Reverting to slow filemark space\n", dev); + printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name); #endif return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt); } #if DEBUG - else printk(OSST_DEB_MSG "osst%d:D: Positioning to next mark at %d\n", dev, next_mark_ppos); + else printk(OSST_DEB_MSG "%s:D: Positioning to next mark at %d\n", name, next_mark_ppos); #endif osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos); cnt++; if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in space_filemarks\n", - dev); + printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", + name); #endif return (-EIO); } if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "osst%d:W: Expected to find marker at ppos %d, not found\n", - dev, next_mark_ppos); + printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", + name, next_mark_ppos); return (-EIO); } } @@ -1924,7 +1922,7 @@ { unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request * SRpnt = * aSRpnt; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = MODE_SELECT; @@ -1941,13 +1939,13 @@ (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries; if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Setting number of retries on OnStream tape to %d\n", dev, retries); + printk(OSST_DEB_MSG "%s:D: Setting number of retries on OnStream tape to %d\n", name, retries); SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE); *aSRpnt = SRpnt; if ((STp->buffer)->syscall_result) - printk (KERN_ERR "osst%d:D: Couldn't set retries to %d\n", dev, retries); + printk (KERN_ERR "%s:D: Couldn't set retries to %d\n", name, retries); } #endif @@ -1958,15 +1956,15 @@ int this_mark_ppos = STp->first_frame_position; int this_mark_lbn = STp->logical_blk_num; #if DEBUG - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); #endif if (STp->raw) return 0; STp->write_type = OS_WRITE_NEW_MARK; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n", - dev, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn); + printk(OSST_DEB_MSG "%s:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n", + name, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn); #endif STp->dirty = 1; result = osst_flush_write_buffer(STp, aSRpnt); @@ -1984,7 +1982,7 @@ { int result; #if DEBUG - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); #endif if (STp->raw) return 0; @@ -1992,7 +1990,7 @@ STp->write_type = OS_WRITE_EOD; STp->eod_frame_ppos = STp->first_frame_position; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", dev, + printk(OSST_DEB_MSG "%s:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", name, STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num); #endif STp->dirty = 1; @@ -2005,10 +2003,10 @@ static int osst_write_filler(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int where, int count) { - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Reached onstream write filler group %d\n", dev, where); + printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where); #endif osst_wait_ready(STp, aSRpnt, 60 * 5); osst_set_frame_position(STp, aSRpnt, where, 0); @@ -2018,23 +2016,23 @@ STp->buffer->buffer_bytes = 6; STp->dirty = 1; if (osst_flush_write_buffer(STp, aSRpnt)) { - printk(KERN_INFO "osst%i:I: Couldn't write filler frame\n", dev); + printk(KERN_INFO "%s:I: Couldn't write filler frame\n", name); return (-EIO); } } #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Exiting onstream write filler group\n", dev); + printk(OSST_DEB_MSG "%s:D: Exiting onstream write filler group\n", name); #endif return osst_flush_drive_buffer(STp, aSRpnt); } static int __osst_write_header(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int where, int count) { - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); int result; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Reached onstream write header group %d\n", dev, where); + printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where); #endif osst_wait_ready(STp, aSRpnt, 60 * 5); osst_set_frame_position(STp, aSRpnt, where, 0); @@ -2044,13 +2042,13 @@ STp->buffer->buffer_bytes = sizeof(os_header_t); STp->dirty = 1; if (osst_flush_write_buffer(STp, aSRpnt)) { - printk(KERN_INFO "osst%i:I: Couldn't write header frame\n", dev); + printk(KERN_INFO "%s:I: Couldn't write header frame\n", name); return (-EIO); } } result = osst_flush_drive_buffer(STp, aSRpnt); #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Write onstream header group %s\n", dev, result?"failed":"done"); + printk(OSST_DEB_MSG "%s:D: Write onstream header group %s\n", name, result?"failed":"done"); #endif return result; } @@ -2059,21 +2057,21 @@ { os_header_t * header; int result; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Writing tape header\n", dev); + printk(OSST_DEB_MSG "%s:D: Writing tape header\n", name); #endif if (STp->raw) return 0; if (STp->header_cache == NULL) { if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) { - printk(KERN_ERR "osst%i:E: Failed to allocate header cache\n", dev); + printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name); return (-ENOMEM); } memset(STp->header_cache, 0, sizeof(os_header_t)); #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Allocated and cleared memory for header cache\n", dev); + printk(OSST_DEB_MSG "%s:D: Allocated and cleared memory for header cache\n", name); #endif } if (STp->header_ok) STp->update_frame_cntr++; @@ -2114,12 +2112,12 @@ if (locate_eod) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Locating back to eod frame addr %d\n", dev, STp->eod_frame_ppos); + printk(OSST_DEB_MSG "%s:D: Locating back to eod frame addr %d\n", name, STp->eod_frame_ppos); #endif osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0); } if (result) - printk(KERN_ERR "osst%i:E: Write header failed\n", dev); + printk(KERN_ERR "%s:E: Write header failed\n", name); else { memcpy(STp->application_sig, "LIN4", 4); STp->linux_media = 1; @@ -2144,7 +2142,7 @@ static int __osst_analyze_headers(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int ppos) { - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); os_header_t * header; os_aux_t * aux; char id_string[8]; @@ -2156,15 +2154,15 @@ if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) { if (osst_set_frame_position(STp, aSRpnt, ppos, 0)) - printk(KERN_WARNING "osst%i:W: Couldn't position tape\n", dev); + printk(KERN_WARNING "%s:W: Couldn't position tape\n", name); if (osst_initiate_read (STp, aSRpnt)) { - printk(KERN_WARNING "osst%i:W: Couldn't initiate read\n", dev); + printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name); return 0; } } if (osst_read_frame(STp, aSRpnt, 180)) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Couldn't read header frame\n", dev); + printk(OSST_DEB_MSG "%s:D: Couldn't read header frame\n", name); #endif return 0; } @@ -2172,7 +2170,7 @@ aux = STp->buffer->aux; if (aux->frame_type != OS_FRAME_TYPE_HEADER) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Skipping non-header frame (%d)\n", dev, ppos); + printk(OSST_DEB_MSG "%s:D: Skipping non-header frame (%d)\n", name, ppos); #endif return 0; } @@ -2182,7 +2180,7 @@ ntohl(aux->partition.first_frame_ppos) != 0 || ntohl(aux->partition.last_frame_ppos) != 0xbb7 ) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Invalid header frame (%d,%d,%d,%d,%d)\n", dev, + printk(OSST_DEB_MSG "%s:D: Invalid header frame (%d,%d,%d,%d,%d)\n", name, ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num), aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos), ntohl(aux->partition.last_frame_ppos)); @@ -2194,22 +2192,22 @@ strncpy(id_string, header->ident_str, 7); id_string[7] = 0; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Invalid header identification string %s\n", dev, id_string); + printk(OSST_DEB_MSG "%s:D: Invalid header identification string %s\n", name, id_string); #endif return 0; } update_frame_cntr = ntohl(aux->update_frame_cntr); if (update_frame_cntr < STp->update_frame_cntr) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Skipping frame %d with update_frame_counter %d<%d\n", - dev, ppos, update_frame_cntr, STp->update_frame_cntr); + printk(OSST_DEB_MSG "%s:D: Skipping frame %d with update_frame_counter %d<%d\n", + name, ppos, update_frame_cntr, STp->update_frame_cntr); #endif return 0; } if (header->major_rev != 1 || header->minor_rev != 4 ) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: %s revision %d.%d detected (1.4 supported)\n", - dev, (header->major_rev != 1 || header->minor_rev < 2 || + printk(OSST_DEB_MSG "%s:D: %s revision %d.%d detected (1.4 supported)\n", + name, (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4 )? "Invalid" : "Warning:", header->major_rev, header->minor_rev); #endif @@ -2218,8 +2216,8 @@ } #if DEBUG if (header->pt_par_num != 1) - printk(KERN_INFO "osst%i:W: %d partitions defined, only one supported\n", - dev, header->pt_par_num); + printk(KERN_INFO "%s:W: %d partitions defined, only one supported\n", + name, header->pt_par_num); #endif memcpy(id_string, aux->application_sig, 4); id_string[4] = 0; @@ -2227,23 +2225,23 @@ STp->linux_media = 1; linux_media_version = id_string[3] - '0'; if (linux_media_version != 4) - printk(KERN_INFO "osst%i:I: Linux media version %d detected (current 4)\n", - dev, linux_media_version); + printk(KERN_INFO "%s:I: Linux media version %d detected (current 4)\n", + name, linux_media_version); } else { - printk(KERN_WARNING "osst%i:W: Non Linux media detected (%s)\n", dev, id_string); + printk(KERN_WARNING "%s:W: Non Linux media detected (%s)\n", name, id_string); return 0; } if (linux_media_version < STp->linux_media_version) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Skipping frame %d with linux_media_version %d\n", - dev, ppos, linux_media_version); + printk(OSST_DEB_MSG "%s:D: Skipping frame %d with linux_media_version %d\n", + name, ppos, linux_media_version); #endif return 0; } if (linux_media_version > STp->linux_media_version) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Frame %d sets linux_media_version to %d\n", - dev, ppos, linux_media_version); + printk(OSST_DEB_MSG "%s:D: Frame %d sets linux_media_version to %d\n", + name, ppos, linux_media_version); #endif memcpy(STp->application_sig, id_string, 5); STp->linux_media_version = linux_media_version; @@ -2251,16 +2249,16 @@ } if (update_frame_cntr > STp->update_frame_cntr) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Frame %d sets update_frame_counter to %d\n", - dev, ppos, update_frame_cntr); + printk(OSST_DEB_MSG "%s:D: Frame %d sets update_frame_counter to %d\n", + name, ppos, update_frame_cntr); #endif if (STp->header_cache == NULL) { if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) { - printk(KERN_ERR "osst%i:E: Failed to allocate header cache\n", dev); + printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name); return 0; } #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Allocated memory for header cache\n", dev); + printk(OSST_DEB_MSG "%s:D: Allocated memory for header cache\n", name); #endif } osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache); @@ -2276,18 +2274,18 @@ STp->last_mark_lbn = ntohl(aux->last_mark_lbn); STp->update_frame_cntr = update_frame_cntr; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Detected write pass %d, update frame counter %d, filemark counter %d\n", - dev, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt); - printk(OSST_DEB_MSG "osst%d:D: first data frame on tape = %d, last = %d, eod frame = %d\n", dev, + printk(OSST_DEB_MSG "%s:D: Detected write pass %d, update frame counter %d, filemark counter %d\n", + name, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt); + printk(OSST_DEB_MSG "%s:D: first data frame on tape = %d, last = %d, eod frame = %d\n", name, STp->first_data_ppos, ntohl(header->partition[0].last_frame_ppos), ntohl(header->partition[0].eod_frame_ppos)); - printk(OSST_DEB_MSG "osst%d:D: first mark on tape = %d, last = %d, eod frame = %d\n", - dev, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos); + printk(OSST_DEB_MSG "%s:D: first mark on tape = %d, last = %d, eod frame = %d\n", + name, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos); #endif if (header->minor_rev < 4 && STp->linux_media_version == 4) { #if DEBUG - printk(OSST_DEB_MSG "osst%i:D: Moving filemark list to ADR 1.4 location\n", dev); + printk(OSST_DEB_MSG "%s:D: Moving filemark list to ADR 1.4 location\n", name); #endif memcpy((void *)header->dat_fm_tab.fm_tab_ent, (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent)); @@ -2312,7 +2310,7 @@ header->dat_fm_tab.fm_tab_ent_sz != 4 || header->dat_fm_tab.fm_tab_ent_cnt != htons(STp->filemark_cntfilemark_cnt:OS_FM_TAB_MAX))) - printk(KERN_WARNING "osst%i:W: Failed consistency check ADR 1.4 format\n", dev); + printk(KERN_WARNING "%s:W: Failed consistency check ADR 1.4 format\n", name); } @@ -2324,7 +2322,7 @@ int position, ppos; int first, last; int valid = 0; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); position = osst_get_frame_position(STp, aSRpnt); @@ -2338,7 +2336,7 @@ STp->eod_frame_ppos = STp->first_data_ppos = -1; STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Reading header\n", dev); + printk(OSST_DEB_MSG "%s:D: Reading header\n", name); #endif /* optimization for speed - if we are positioned at ppos 10, read second group first */ @@ -2359,7 +2357,7 @@ valid = 1; if (!valid) { - printk(KERN_ERR "osst%i:E: Failed to find valid ADRL header, new media?\n", dev); + printk(KERN_ERR "%s:E: Failed to find valid ADRL header, new media?\n", name); STp->eod_frame_ppos = STp->first_data_ppos = 0; osst_set_frame_position(STp, aSRpnt, 10, 0); return 0; @@ -2384,14 +2382,14 @@ int prev_mark_ppos = -1; int actual_mark_ppos, i, n; #if DEBUG - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); - printk(OSST_DEB_MSG "osst%d:D: Verify that the tape is really the one we think before writing\n", dev); + printk(OSST_DEB_MSG "%s:D: Verify that the tape is really the one we think before writing\n", name); #endif osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0); if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Couldn't get logical blk num in verify_position\n", dev); + printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in verify_position\n", name); #endif return (-EIO); } @@ -2407,7 +2405,7 @@ frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) || prev_mark_ppos != actual_mark_ppos ) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", dev, + printk(OSST_DEB_MSG "%s:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", name, STp->first_frame_position, frame_position, STp->frame_seq_number + (halfway_frame?0:1), frame_seq_numbr, actual_mark_ppos, prev_mark_ppos); @@ -2453,7 +2451,7 @@ static int osst_configure_onstream(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt) { unsigned char cmd[MAX_COMMAND_SIZE]; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); Scsi_Request * SRpnt = * aSRpnt; osst_mode_parameter_header_t * header; osst_block_size_page_t * bs; @@ -2463,14 +2461,14 @@ if (STp->ready != ST_READY) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Not Ready\n", dev); + printk(OSST_DEB_MSG "%s:D: Not Ready\n", name); #endif return (-EIO); } if (STp->os_fw_rev < 10600) { - printk(KERN_INFO "osst%i:I: Old OnStream firmware revision detected (%s),\n", dev, STp->device->rev); - printk(KERN_INFO "osst%d:I: an upgrade to version 1.06 or above is recommended\n", dev); + printk(KERN_INFO "%s:I: Old OnStream firmware revision detected (%s),\n", name, STp->device->rev); + printk(KERN_INFO "%s:I: an upgrade to version 1.06 or above is recommended\n", name); } /* @@ -2492,7 +2490,7 @@ } *aSRpnt = SRpnt; if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "osst%i:E: Can't get tape block size mode page\n", dev); + printk (KERN_ERR "%s:E: Can't get tape block size mode page\n", name); return (-EIO); } @@ -2500,10 +2498,10 @@ bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl); #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: 32KB play back: %s\n", dev, bs->play32 ? "Yes" : "No"); - printk(OSST_DEB_MSG "osst%d:D: 32.5KB play back: %s\n", dev, bs->play32_5 ? "Yes" : "No"); - printk(OSST_DEB_MSG "osst%d:D: 32KB record: %s\n", dev, bs->record32 ? "Yes" : "No"); - printk(OSST_DEB_MSG "osst%d:D: 32.5KB record: %s\n", dev, bs->record32_5 ? "Yes" : "No"); + printk(OSST_DEB_MSG "%s:D: 32KB play back: %s\n", name, bs->play32 ? "Yes" : "No"); + printk(OSST_DEB_MSG "%s:D: 32.5KB play back: %s\n", name, bs->play32_5 ? "Yes" : "No"); + printk(OSST_DEB_MSG "%s:D: 32KB record: %s\n", name, bs->record32 ? "Yes" : "No"); + printk(OSST_DEB_MSG "%s:D: 32.5KB record: %s\n", name, bs->record32_5 ? "Yes" : "No"); #endif /* @@ -2523,12 +2521,12 @@ SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE); *aSRpnt = SRpnt; if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "osst%i:E: Couldn't set tape block size mode page\n", dev); + printk (KERN_ERR "%s:E: Couldn't set tape block size mode page\n", name); return (-EIO); } #if DEBUG - printk(KERN_INFO "osst%d:D: Drive Block Size changed to 32.5K\n", dev); + printk(KERN_INFO "%s:D: Drive Block Size changed to 32.5K\n", name); /* * In debug mode, we want to see as many errors as possible * to test the error recovery mechanism. @@ -2564,7 +2562,7 @@ *aSRpnt = SRpnt; if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "osst%i:E: Couldn't set vendor name to %s\n", dev, + printk (KERN_ERR "%s:E: Couldn't set vendor name to %s\n", name, (char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2)); return (-EIO); } @@ -2579,7 +2577,7 @@ *aSRpnt = SRpnt; if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "osst%i:E: Can't get capabilities page\n", dev); + printk (KERN_ERR "%s:E: Can't get capabilities page\n", name); return (-EIO); } @@ -2599,7 +2597,7 @@ *aSRpnt = SRpnt; if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "osst%i:E: Can't get tape parameter page\n", dev); + printk (KERN_ERR "%s:E: Can't get tape parameter page\n", name); return (-EIO); } @@ -2610,8 +2608,8 @@ STp->density = prm->density; STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks); #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n", - dev, STp->density, STp->capacity / 32, drive_buffer_size); + printk(OSST_DEB_MSG "%s:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n", + name, STp->density, STp->capacity / 32, drive_buffer_size); #endif return 0; @@ -2624,12 +2622,12 @@ static int cross_eof(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, int forward) { int result; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Stepping over filemark %s.\n", - dev, forward ? "forward" : "backward"); + printk(OSST_DEB_MSG "%s:D: Stepping over filemark %s.\n", + name, forward ? "forward" : "backward"); #endif if (forward) { @@ -2641,8 +2639,8 @@ result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1); if (result < 0) - printk(KERN_WARNING "osst%d:W: Stepping over filemark %s failed.\n", - dev, forward ? "forward" : "backward"); + printk(KERN_WARNING "%s:W: Stepping over filemark %s failed.\n", + name, forward ? "forward" : "backward"); return result; } @@ -2661,7 +2659,7 @@ char mybuf[24]; char * olddata = STp->buffer->b_data; int oldsize = STp->buffer->buffer_size; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); if (STp->ready != ST_READY) return (-EIO); @@ -2681,7 +2679,7 @@ result = ((SRpnt->sr_sense_buffer[2] & 0x0f) == 3) ? -EIO : -EINVAL; if (result == -EINVAL) - printk(KERN_ERR "osst%d:E: Can't read tape position.\n", dev); + printk(KERN_ERR "%s:E: Can't read tape position.\n", name); else { if (result == -EIO) { /* re-read position */ @@ -2706,7 +2704,7 @@ STp->cur_frames = (STp->buffer)->b_data[15]; #if DEBUG if (debugging) { - printk(OSST_DEB_MSG "osst%d:D: Drive Positions: host %d, tape %d%s, buffer %d\n", dev, + printk(OSST_DEB_MSG "%s:D: Drive Positions: host %d, tape %d%s, buffer %d\n", name, STp->first_frame_position, STp->last_frame_position, ((STp->buffer)->b_data[0]&0x80)?" (BOP)": ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"", @@ -2715,7 +2713,7 @@ #endif if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) { #if DEBUG - printk(KERN_WARNING "osst%d:D: Correcting read position %d, %d, %d\n", dev, + printk(KERN_WARNING "%s:D: Correcting read position %d, %d, %d\n", name, STp->first_frame_position, STp->last_frame_position, STp->cur_frames); #endif STp->first_frame_position = STp->last_frame_position; @@ -2735,14 +2733,14 @@ ST_partstat * STps; int result = 0; int pp = (ppos == 3000 && !skip)? 0 : ppos; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); if (STp->ready != ST_READY) return (-EIO); STps = &(STp->ps[STp->partition]); if (ppos < 0 || ppos > STp->capacity) { - printk(KERN_WARNING "osst%d:W: Reposition request %d out of range\n", dev, ppos); + printk(KERN_WARNING "%s:W: Reposition request %d out of range\n", name, ppos); pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1); result = (-EINVAL); } @@ -2750,7 +2748,7 @@ do { #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Setting ppos to %d.\n", dev, pp); + printk(OSST_DEB_MSG "%s:D: Setting ppos to %d.\n", name, pp); #endif memset (scmd, 0, MAX_COMMAND_SIZE); scmd[0] = SEEK_10; @@ -2770,8 +2768,8 @@ if ((STp->buffer)->syscall_result != 0) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: SEEK command from %d to %d failed.\n", - dev, STp->first_frame_position, pp); + printk(OSST_DEB_MSG "%s:D: SEEK command from %d to %d failed.\n", + name, STp->first_frame_position, pp); #endif result = (-EIO); } @@ -2798,26 +2796,26 @@ unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request * SRpnt = *aSRpnt; ST_partstat * STps; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); if ((STp->buffer)->writing) { if (SRpnt == (STp->buffer)->last_SRpnt) #if DEBUG { printk(OSST_DEB_MSG - "osst%d:D: aSRpnt points to Scsi_Request that write_behind_check will release -- cleared\n", dev); + "%s:D: aSRpnt points to Scsi_Request that write_behind_check will release -- cleared\n", name); #endif *aSRpnt = SRpnt = NULL; #if DEBUG } else if (SRpnt) printk(OSST_DEB_MSG - "osst%d:D: aSRpnt does not point to Scsi_Request that write_behind_check will release -- strange\n", dev); + "%s:D: aSRpnt does not point to Scsi_Request that write_behind_check will release -- strange\n", name); #endif osst_write_behind_check(STp); if ((STp->buffer)->syscall_result) { #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Async write error (flush) %x.\n", - dev, (STp->buffer)->midlevel_result); + printk(OSST_DEB_MSG "%s:D: Async write error (flush) %x.\n", + name, (STp->buffer)->midlevel_result); #endif if ((STp->buffer)->midlevel_result == INT_MAX) return (-ENOSPC); @@ -2851,8 +2849,8 @@ case OS_WRITE_DATA: #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Writing %d blocks to frame %d, lblks %d-%d\n", - dev, blks, STp->frame_seq_number, + printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", + name, blks, STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1); #endif osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++, @@ -2874,8 +2872,8 @@ } #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Flushing %d bytes, Transfering %d bytes in %d lblocks.\n", - dev, offset, transfer, blks); + printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transfering %d bytes in %d lblocks.\n", + name, offset, transfer, blks); #endif SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, SCSI_DATA_WRITE, @@ -2887,8 +2885,8 @@ if ((STp->buffer)->syscall_result != 0) { #if DEBUG printk(OSST_DEB_MSG - "osst%d:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n", - dev, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2], + "%s:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n", + name, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]); #endif if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && @@ -2900,7 +2898,7 @@ } else { if (osst_write_error_recovery(STp, aSRpnt, 1)) { - printk(KERN_ERR "osst%d:E: Error on flush write.\n", dev); + printk(KERN_ERR "%s:E: Error on flush write.\n", name); result = (-EIO); } } @@ -2913,7 +2911,7 @@ } } #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Exit flush write buffer with code %d\n", dev, result); + printk(OSST_DEB_MSG "%s:D: Exit flush write buffer with code %d\n", name, result); #endif return result; } @@ -2926,7 +2924,7 @@ ST_partstat * STps; int backspace = 0, result = 0; #if DEBUG - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); #endif /* @@ -2947,7 +2945,7 @@ return 0; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Reached flush (read) buffer\n", dev); + printk(OSST_DEB_MSG "%s:D: Reached flush (read) buffer\n", name); #endif if (!STp->can_bsr) { @@ -2988,12 +2986,12 @@ Scsi_Request * SRpnt; int blks; #if DEBUG - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); #endif if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */ #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Reaching config partition.\n", dev); + printk(OSST_DEB_MSG "%s:D: Reaching config partition.\n", name); #endif if (osst_flush_drive_buffer(STp, aSRpnt) < 0) { return (-EIO); @@ -3001,7 +2999,7 @@ /* error recovery may have bumped us past the header partition */ if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Skipping over config partition.\n", dev); + printk(OSST_DEB_MSG "%s:D: Skipping over config partition.\n", name); #endif osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8); } @@ -3023,7 +3021,7 @@ blks = STp->buffer->buffer_bytes / STp->block_size; #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Writing %d blocks to frame %d, lblks %d-%d\n", dev, blks, + printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", name, blks, STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1); #endif osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++, @@ -3043,7 +3041,7 @@ if (STp->buffer->syscall_result != 0) { #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Error on write:\n", dev); + printk(OSST_DEB_MSG "%s:D: Error on write:\n", name); #endif if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && (SRpnt->sr_sense_buffer[2] & 0x40)) { @@ -3070,19 +3068,17 @@ /* Write command */ static ssize_t osst_write(struct file * filp, const char * buf, size_t count, loff_t *ppos) { - struct inode *inode = filp->f_dentry->d_inode; ssize_t total, retval = 0; ssize_t i, do_count, blks, transfer; int write_threshold; int doing_write = 0; const char *b_point; Scsi_Request * SRpnt = NULL; - OS_Scsi_Tape * STp; ST_mode * STm; ST_partstat * STps; - int dev = TAPE_NR(inode->i_rdev); + OS_Scsi_Tape * STp = filp->private_data; + char *name = tape_name(STp); - STp = os_scsi_tapes[dev]; if (down_interruptible(&STp->lock)) return (-ERESTARTSYS); @@ -3130,7 +3126,7 @@ #if DEBUG if (!STp->in_use) { - printk(OSST_DEB_MSG "osst%d:D: Incorrect device.\n", dev); + printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name); retval = (-EIO); goto out; } @@ -3143,16 +3139,16 @@ /* Write must be integral number of blocks */ if (STp->block_size != 0 && (count % STp->block_size) != 0) { - printk(KERN_ERR "osst%d:E: Write (%ld bytes) not multiple of tape block size (%d%c).\n", - dev, (unsigned long)count, STp->block_size<1024? + printk(KERN_ERR "%s:E: Write (%ld bytes) not multiple of tape block size (%d%c).\n", + name, (unsigned long)count, STp->block_size<1024? STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k'); retval = (-EINVAL); goto out; } if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) { - printk(KERN_ERR "osst%d:E: Write truncated at EOM early warning (frame %d).\n", - dev, STp->first_frame_position); + printk(KERN_ERR "%s:E: Write truncated at EOM early warning (frame %d).\n", + name, STp->first_frame_position); retval = (-ENOSPC); goto out; } @@ -3177,8 +3173,8 @@ (STps->drv_file == 0 && STps->drv_block == 0)) { STp->wrt_pass_cntr++; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Allocating next write pass counter: %d\n", - dev, STp->wrt_pass_cntr); + printk(OSST_DEB_MSG "%s:D: Allocating next write pass counter: %d\n", + name, STp->wrt_pass_cntr); #endif osst_reset_header(STp, &SRpnt); STps->drv_file = STps->drv_block = 0; @@ -3195,7 +3191,7 @@ /* We have no idea where the tape is positioned - give up */ #if DEBUG printk(OSST_DEB_MSG - "osst%d:D: Cannot write at indeterminate position.\n", dev); + "%s:D: Cannot write at indeterminate position.\n", name); #endif retval = (-EIO); goto out; @@ -3206,15 +3202,15 @@ STp->last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]); printk(KERN_WARNING - "osst%d:W: Overwriting file %d with old write pass counter %d\n", - dev, STps->drv_file, STp->wrt_pass_cntr); + "%s:W: Overwriting file %d with old write pass counter %d\n", + name, STps->drv_file, STp->wrt_pass_cntr); printk(KERN_WARNING - "osst%d:W: may lead to stale data being accepted on reading back!\n", - dev); + "%s:W: may lead to stale data being accepted on reading back!\n", + name); #if DEBUG printk(OSST_DEB_MSG - "osst%d:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n", - dev, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn); + "%s:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n", + name, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn); #endif } } @@ -3222,19 +3218,19 @@ } if (!STp->header_ok) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Write cannot proceed without valid headers\n", dev); + printk(OSST_DEB_MSG "%s:D: Write cannot proceed without valid headers\n", name); #endif retval = (-EIO); goto out; } if ((STp->buffer)->writing) { -if (SRpnt) printk(KERN_ERR "osst%d:A: Not supposed to have SRpnt at line %d\n", dev, __LINE__); +if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name, __LINE__); osst_write_behind_check(STp); if ((STp->buffer)->syscall_result) { #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Async write error (write) %x.\n", dev, + printk(OSST_DEB_MSG "%s:D: Async write error (write) %x.\n", name, (STp->buffer)->midlevel_result); #endif if ((STp->buffer)->midlevel_result == INT_MAX) @@ -3271,8 +3267,8 @@ total = count; #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Writing %d bytes to file %d block %d lblk %d fseq %d fppos %d\n", - dev, count, STps->drv_file, STps->drv_block, + printk(OSST_DEB_MSG "%s:D: Writing %d bytes to file %d block %d lblk %d fseq %d fppos %d\n", + name, count, STps->drv_file, STps->drv_block, STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position); #endif b_point = buf; @@ -3307,8 +3303,8 @@ retval = (-ENOSPC); /* EOM within current request */ #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: EOM with %d bytes unwritten.\n", - dev, transfer); + printk(OSST_DEB_MSG "%s:D: EOM with %d bytes unwritten.\n", + name, transfer); #endif } else { @@ -3317,7 +3313,7 @@ retval = (-EIO); /* EOM for old data */ #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: EOM with lost data.\n", dev); + printk(OSST_DEB_MSG "%s:D: EOM with lost data.\n", name); #endif } } @@ -3399,17 +3395,15 @@ /* Read command */ static ssize_t osst_read(struct file * filp, char * buf, size_t count, loff_t *ppos) { - struct inode * inode = filp->f_dentry->d_inode; ssize_t total, retval = 0; ssize_t i, transfer; int special; - OS_Scsi_Tape * STp; ST_mode * STm; ST_partstat * STps; Scsi_Request *SRpnt = NULL; - int dev = TAPE_NR(inode->i_rdev); + OS_Scsi_Tape * STp = filp->private_data; + char *name = tape_name(STp); - STp = os_scsi_tapes[dev]; if (down_interruptible(&STp->lock)) return (-ERESTARTSYS); @@ -3445,7 +3439,7 @@ } #if DEBUG if (!STp->in_use) { - printk(OSST_DEB_MSG "osst%d:D: Incorrect device.\n", dev); + printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name); retval = (-EIO); goto out; } @@ -3471,13 +3465,13 @@ if ((count % STp->block_size) != 0) { printk(KERN_WARNING - "osst%d:W: Read (%Zd bytes) not multiple of tape block size (%d%c).\n", dev, count, + "%s:W: Read (%Zd bytes) not multiple of tape block size (%d%c).\n", name, count, STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k'); } #if DEBUG if (debugging && STps->eof != ST_NOEOF) - printk(OSST_DEB_MSG "osst%d:D: EOF/EOM flag up (%d). Bytes %d\n", dev, + printk(OSST_DEB_MSG "%s:D: EOF/EOM flag up (%d). Bytes %d\n", name, STps->eof, (STp->buffer)->buffer_bytes); #endif if ((STp->buffer)->buffer_bytes == 0 && @@ -3520,7 +3514,7 @@ if ((STp->buffer)->buffer_bytes > 0) { #if DEBUG if (debugging && STps->eof != ST_NOEOF) - printk(OSST_DEB_MSG "osst%d:D: EOF up (%d). Left %d, needed %d.\n", dev, + printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name, STps->eof, (STp->buffer)->buffer_bytes, count - total); #endif transfer = (((STp->buffer)->buffer_bytes < count - total ? @@ -3541,8 +3535,8 @@ if ((STp->buffer)->buffer_bytes == 0) { #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Finished with frame %d\n", - dev, STp->frame_seq_number); + printk(OSST_DEB_MSG "%s:D: Finished with frame %d\n", + name, STp->frame_seq_number); #endif STp->frame_in_buffer = 0; STp->frame_seq_number++; /* frame to look for next time */ @@ -3581,25 +3575,25 @@ /* Set the driver options */ -static void osst_log_options(OS_Scsi_Tape *STp, ST_mode *STm, int dev) +static void osst_log_options(OS_Scsi_Tape *STp, ST_mode *STm, char *name) { printk(KERN_INFO -"osst%d:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n", - dev, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, +"%s:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n", + name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, STm->do_read_ahead); printk(KERN_INFO -"osst%d:I: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n", - dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); +"%s:I: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n", + name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); printk(KERN_INFO -"osst%d:I: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n", - dev, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, +"%s:I: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n", + name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, STp->scsi2_logical); printk(KERN_INFO -"osst%d:I: sysv: %d\n", dev, STm->sysv); +"%s:I: sysv: %d\n", name, STm->sysv); #if DEBUG printk(KERN_INFO - "osst%d:D: debugging: %d\n", - dev, debugging); + "%s:D: debugging: %d\n", + name, debugging); #endif } @@ -3609,7 +3603,7 @@ int value; long code; ST_mode *STm; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); STm = &(STp->modes[STp->current_mode]); if (!STm->defined) { @@ -3617,8 +3611,8 @@ modes_defined = TRUE; #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Initialized mode %d definition from mode 0\n", - dev, STp->current_mode); + printk(OSST_DEB_MSG "%s:D: Initialized mode %d definition from mode 0\n", + name, STp->current_mode); #endif } @@ -3640,7 +3634,7 @@ #if DEBUG debugging = (options & MT_ST_DEBUGGING) != 0; #endif - osst_log_options(STp, STm, dev); + osst_log_options(STp, STm, name); } else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { value = (code == MT_ST_SETBOOLEANS); @@ -3673,46 +3667,46 @@ if ((options & MT_ST_DEBUGGING) != 0) debugging = value; #endif - osst_log_options(STp, STm, dev); + osst_log_options(STp, STm, name); } else if (code == MT_ST_WRITE_THRESHOLD) { value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE; if (value < 1 || value > osst_buffer_size) { - printk(KERN_WARNING "osst%d:W: Write threshold %d too small or too large.\n", - dev, value); + printk(KERN_WARNING "%s:W: Write threshold %d too small or too large.\n", + name, value); return (-EIO); } STp->write_threshold = value; - printk(KERN_INFO "osst%d:I: Write threshold set to %d bytes.\n", - dev, value); + printk(KERN_INFO "%s:I: Write threshold set to %d bytes.\n", + name, value); } else if (code == MT_ST_DEF_BLKSIZE) { value = (options & ~MT_ST_OPTIONS); if (value == ~MT_ST_OPTIONS) { STm->default_blksize = (-1); - printk(KERN_INFO "osst%d:I: Default block size disabled.\n", dev); + printk(KERN_INFO "%s:I: Default block size disabled.\n", name); } else { if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) { - printk(KERN_WARNING "osst%d:W: Default block size cannot be set to %d.\n", - dev, value); + printk(KERN_WARNING "%s:W: Default block size cannot be set to %d.\n", + name, value); return (-EINVAL); } STm->default_blksize = value; - printk(KERN_INFO "osst%d:I: Default block size set to %d bytes.\n", - dev, STm->default_blksize); + printk(KERN_INFO "%s:I: Default block size set to %d bytes.\n", + name, STm->default_blksize); } } else if (code == MT_ST_TIMEOUTS) { value = (options & ~MT_ST_OPTIONS); if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) { STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ; - printk(KERN_INFO "osst%d:I: Long timeout set to %d seconds.\n", dev, + printk(KERN_INFO "%s:I: Long timeout set to %d seconds.\n", name, (value & ~MT_ST_SET_LONG_TIMEOUT)); } else { STp->timeout = value * HZ; - printk(KERN_INFO "osst%d:I: Normal timeout set to %d seconds.\n", dev, value); + printk(KERN_INFO "%s:I: Normal timeout set to %d seconds.\n", name, value); } } else if (code == MT_ST_DEF_OPTIONS) { @@ -3721,34 +3715,34 @@ if (code == MT_ST_DEF_DENSITY) { if (value == MT_ST_CLEAR_DEFAULT) { STm->default_density = (-1); - printk(KERN_INFO "osst%d:I: Density default disabled.\n", dev); + printk(KERN_INFO "%s:I: Density default disabled.\n", name); } else { STm->default_density = value & 0xff; - printk(KERN_INFO "osst%d:I: Density default set to %x\n", - dev, STm->default_density); + printk(KERN_INFO "%s:I: Density default set to %x\n", + name, STm->default_density); } } else if (code == MT_ST_DEF_DRVBUFFER) { if (value == MT_ST_CLEAR_DEFAULT) { STp->default_drvbuffer = 0xff; - printk(KERN_INFO "osst%d:I: Drive buffer default disabled.\n", dev); + printk(KERN_INFO "%s:I: Drive buffer default disabled.\n", name); } else { STp->default_drvbuffer = value & 7; - printk(KERN_INFO "osst%d:I: Drive buffer default set to %x\n", - dev, STp->default_drvbuffer); + printk(KERN_INFO "%s:I: Drive buffer default set to %x\n", + name, STp->default_drvbuffer); } } else if (code == MT_ST_DEF_COMPRESSION) { if (value == MT_ST_CLEAR_DEFAULT) { STm->default_compression = ST_DONT_TOUCH; - printk(KERN_INFO "osst%d:I: Compression default disabled.\n", dev); + printk(KERN_INFO "%s:I: Compression default disabled.\n", name); } else { STm->default_compression = (value & 1 ? ST_YES : ST_NO); - printk(KERN_INFO "osst%d:I: Compression default set to %x\n", - dev, (value & 1)); + printk(KERN_INFO "%s:I: Compression default set to %x\n", + name, (value & 1)); } } } @@ -3771,7 +3765,7 @@ ST_partstat * STps; int fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num; int datalen = 0, direction = SCSI_DATA_NONE; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); if (STp->ready != ST_READY && cmd_in != MTLOAD) { if (STp->ready == ST_NO_TAPE) @@ -3820,8 +3814,8 @@ case MTBSR: #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Skipping %lu blocks %s from logical block %d\n", - dev, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num); + printk(OSST_DEB_MSG "%s:D: Skipping %lu blocks %s from logical block %d\n", + name, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num); #endif if (cmd_in == MTFSR) { logical_blk_num += arg; @@ -3845,7 +3839,7 @@ cmd[4] = arg; #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Spacing tape forward %d setmarks.\n", dev, + printk(OSST_DEB_MSG "%s:D: Spacing tape forward %d setmarks.\n", name, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); #endif if (arg != 0) { @@ -3865,8 +3859,8 @@ if (cmd[2] & 0x80) ltmp = 0xff000000; ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; - printk(OSST_DEB_MSG "osst%d:D: Spacing tape backward %ld setmarks.\n", - dev, (-ltmp)); + printk(OSST_DEB_MSG "%s:D: Spacing tape backward %ld setmarks.\n", + name, (-ltmp)); } #endif if (arg != 0) { @@ -3881,7 +3875,7 @@ ioctl_result = 0; #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Writing %ld filemark(s).\n", dev, arg); + printk(OSST_DEB_MSG "%s:D: Writing %ld filemark(s).\n", name, arg); #endif for (i=0; itimeout; #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Writing %d setmark(s).\n", dev, + printk(OSST_DEB_MSG "%s:D: Writing %d setmark(s).\n", name, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); #endif if (fileno >= 0) @@ -3932,16 +3926,16 @@ if (debugging) { switch (cmd_in) { case MTUNLOAD: - printk(OSST_DEB_MSG "osst%d:D: Unloading tape.\n", dev); + printk(OSST_DEB_MSG "%s:D: Unloading tape.\n", name); break; case MTLOAD: - printk(OSST_DEB_MSG "osst%d:D: Loading tape.\n", dev); + printk(OSST_DEB_MSG "%s:D: Loading tape.\n", name); break; case MTRETEN: - printk(OSST_DEB_MSG "osst%d:D: Retensioning tape.\n", dev); + printk(OSST_DEB_MSG "%s:D: Retensioning tape.\n", name); break; case MTOFFL: - printk(OSST_DEB_MSG "osst%d:D: Ejecting tape.\n", dev); + printk(OSST_DEB_MSG "%s:D: Ejecting tape.\n", name); break; } } @@ -3951,14 +3945,14 @@ case MTNOP: #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: No-op on tape.\n", dev); + printk(OSST_DEB_MSG "%s:D: No-op on tape.\n", name); #endif return 0; /* Should do something ? */ break; case MTEOM: #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Spacing to end of recorded medium.\n", dev); + printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name); #endif osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0); if (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0) { @@ -3967,7 +3961,7 @@ } if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: No EOD frame found where expected.\n", dev); + printk(OSST_DEB_MSG "%s:D: No EOD frame found where expected.\n", name); #endif ioctl_result = -EIO; goto os_bypass; @@ -3993,7 +3987,7 @@ cmd[1] = 1; #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Rewinding tape, Immed=%d.\n", dev, cmd[1]); + printk(OSST_DEB_MSG "%s:D: Rewinding tape, Immed=%d.\n", name, cmd[1]); #endif fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ; break; @@ -4004,7 +3998,7 @@ cmd[4] = SCSI_REMOVAL_PREVENT; #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Locking drive door.\n", dev); + printk(OSST_DEB_MSG "%s:D: Locking drive door.\n", name); #endif break; @@ -4014,7 +4008,7 @@ cmd[4] = SCSI_REMOVAL_ALLOW; #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Unlocking drive door.\n", dev); + printk(OSST_DEB_MSG "%s:D: Unlocking drive door.\n", name); #endif break; @@ -4030,7 +4024,7 @@ ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block || (arg & MT_ST_BLKSIZE_MASK) > STp->max_block || (arg & MT_ST_BLKSIZE_MASK) > osst_buffer_size)) { - printk(KERN_WARNING "osst%d:W: Illegal block size.\n", dev); + printk(KERN_WARNING "%s:W: Illegal block size.\n", name); return (-EINVAL); } return 0; /* FIXME silently ignore if block size didn't change */ @@ -4045,7 +4039,7 @@ if (!SRpnt) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Couldn't exec scsi cmd for IOCTL\n", dev); + printk(OSST_DEB_MSG "%s:D: Couldn't exec scsi cmd for IOCTL\n", name); #endif return ioctl_result; } @@ -4058,7 +4052,7 @@ os_bypass: #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: IOCTL (%d) Result=%d\n", dev, cmd_in, ioctl_result); + printk(OSST_DEB_MSG "%s:D: IOCTL (%d) Result=%d\n", name, cmd_in, ioctl_result); #endif if (!ioctl_result) { /* success */ @@ -4158,18 +4152,22 @@ ST_mode * STm; ST_partstat * STps; int dev = TAPE_NR(inode->i_rdev); + char *name; int mode = TAPE_MODE(inode->i_rdev); if (dev >= osst_template.dev_max || (STp = os_scsi_tapes[dev]) == NULL || !STp->device) return (-ENXIO); + filp->private_data = STp; + name = tape_name(STp); + if( !scsi_block_when_processing_errors(STp->device) ) { return -ENXIO; } if (STp->in_use) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Device already in use.\n", dev); + printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name); #endif return (-EBUSY); } @@ -4185,8 +4183,8 @@ if (mode != STp->current_mode) { #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Mode change from %d to %d.\n", - dev, STp->current_mode, mode); + printk(OSST_DEB_MSG "%s:D: Mode change from %d to %d.\n", + name, STp->current_mode, mode); #endif new_session = TRUE; STp->current_mode = mode; @@ -4209,7 +4207,7 @@ if (i >= osst_nbr_buffers) { STp->buffer = new_tape_buffer(FALSE, need_dma_buffer); if (STp->buffer == NULL) { - printk(KERN_WARNING "osst%d:W: Can't allocate tape buffer.\n", dev); + printk(KERN_WARNING "%s:W: Can't allocate tape buffer.\n", name); retval = (-EBUSY); goto err_out; } @@ -4252,7 +4250,7 @@ (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY && SRpnt->sr_sense_buffer[12] == 4 ) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Unit not ready, cause %x\n", dev, SRpnt->sr_sense_buffer[13]); + printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sr_sense_buffer[13]); #endif if (SRpnt->sr_sense_buffer[13] == 2) { /* initialize command required (LOAD) */ memset (cmd, 0, MAX_COMMAND_SIZE); @@ -4267,7 +4265,7 @@ if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Unit wants attention\n", dev); + printk(OSST_DEB_MSG "%s:D: Unit wants attention\n", name); #endif STp->header_ok = 0; @@ -4320,7 +4318,7 @@ STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' || STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4' ) { #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Signature was changed to %c%c%c%c\n", dev, + printk(OSST_DEB_MSG "%s:D: Signature was changed to %c%c%c%c\n", name, STp->buffer->b_data[MODE_HEADER_LENGTH + 2], STp->buffer->b_data[MODE_HEADER_LENGTH + 3], STp->buffer->b_data[MODE_HEADER_LENGTH + 4], @@ -4332,7 +4330,7 @@ if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) { if (STp->door_locked == ST_UNLOCKED) { if (osst_int_ioctl(STp, &SRpnt, MTLOCK, 0)) - printk(KERN_INFO "osst%d:I: Can't lock drive door\n", dev); + printk(KERN_INFO "%s:I: Can't lock drive door\n", name); else STp->door_locked = ST_LOCKED_AUTO; } @@ -4348,8 +4346,8 @@ } #if DEBUG if (i != STp->first_frame_position) - printk(OSST_DEB_MSG "osst%d:D: Tape position changed from %d to %d\n", - dev, i, STp->first_frame_position); + printk(OSST_DEB_MSG "%s:D: Tape position changed from %d to %d\n", + name, i, STp->first_frame_position); #endif STp->header_ok = 0; } @@ -4373,7 +4371,7 @@ (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3; #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Applying soft reset\n", dev); + printk(OSST_DEB_MSG "%s:D: Applying soft reset\n", name); #endif SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, STp->timeout, 0, TRUE); @@ -4410,7 +4408,7 @@ } if (osst_wait_ready(STp, &SRpnt, 15 * 60)) /* FIXME - not allowed with NOBLOCK */ - printk(KERN_INFO "osst%i:I: Device did not become Ready in open\n",dev); + printk(KERN_INFO "%s:I: Device did not become Ready in open\n",name); if ((STp->buffer)->syscall_result != 0) { if ((STp->device)->scsi_level >= SCSI_2 && @@ -4437,7 +4435,7 @@ if (OS_FRAME_SIZE > (STp->buffer)->buffer_size && !enlarge_buffer(STp->buffer, OS_FRAME_SIZE, STp->restr_dma)) { - printk(KERN_NOTICE "osst%d:A: Framesize %d too large for buffer.\n", dev, + printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name, OS_FRAME_SIZE); retval = (-EIO); goto err_out; @@ -4449,9 +4447,9 @@ b_size += STp->buffer->sg[i++].length); STp->buffer->aux = (os_aux_t *) (page_address(STp->buffer->sg[i].page) + OS_DATA_SIZE - b_size); #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: b_data points to %p in segment 0 at %p\n", dev, + printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name, STp->buffer->b_data, page_address(STp->buffer->sg[0].page)); - printk(OSST_DEB_MSG "osst%d:D: AUX points to %p in segment %d at %p\n", dev, + printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name, STp->buffer->aux, i, page_address(STp->buffer->sg[i].page)); #endif } else @@ -4466,8 +4464,8 @@ #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n", - dev, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size, + printk(OSST_DEB_MSG "%s:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n", + name, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size, (STp->buffer)->buffer_blocks); #endif @@ -4475,7 +4473,7 @@ STp->write_prot = 1; #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Write protected\n", dev); + printk(OSST_DEB_MSG "%s:D: Write protected\n", name); #endif if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) { retval = (-EROFS); @@ -4486,7 +4484,7 @@ if (new_session) { /* Change the drive parameters for the new mode */ #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: New Session\n", dev); + printk(OSST_DEB_MSG "%s:D: New Session\n", name); #endif STp->density_changed = STp->blksize_changed = FALSE; STp->compression_changed = FALSE; @@ -4497,7 +4495,7 @@ */ if (STp->door_locked == ST_UNLOCKED) { if (osst_int_ioctl(STp, &SRpnt, MTLOCK, 0)) - printk(KERN_INFO "osst%d:I: Can't lock drive door\n", dev); + printk(KERN_INFO "%s:I: Can't lock drive door\n", name); else STp->door_locked = ST_LOCKED_AUTO; } @@ -4533,22 +4531,14 @@ static int os_scsi_tape_flush(struct file * filp) { int result = 0, result2; - OS_Scsi_Tape * STp; - ST_mode * STm; - ST_partstat * STps; + OS_Scsi_Tape * STp = filp->private_data; + ST_mode * STm = &(STp->modes[STp->current_mode]); + ST_partstat * STps = &(STp->ps[STp->partition]); Scsi_Request *SRpnt = NULL; - - struct inode *inode = filp->f_dentry->d_inode; - kdev_t devt = inode->i_rdev; - int dev; + char *name = tape_name(STp); if (file_count(filp) > 1) - return 0; - - dev = TAPE_NR(devt); - STp = os_scsi_tapes[dev]; - STm = &(STp->modes[STp->current_mode]); - STps = &(STp->ps[STp->partition]); + return 0; if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) { result = osst_flush_write_buffer(STp, &SRpnt); @@ -4559,10 +4549,10 @@ #if DEBUG if (debugging) { - printk(OSST_DEB_MSG "osst%d:D: File length %ld bytes.\n", - dev, (long)(filp->f_pos)); - printk(OSST_DEB_MSG "osst%d:D: Async write waits %d, finished %d.\n", - dev, STp->nbr_waits, STp->nbr_finished); + printk(OSST_DEB_MSG "%s:D: File length %ld bytes.\n", + name, (long)(filp->f_pos)); + printk(OSST_DEB_MSG "%s:D: Async write waits %d, finished %d.\n", + name, STp->nbr_waits, STp->nbr_finished); } #endif if (STp->write_type != OS_WRITE_NEW_MARK) { @@ -4583,8 +4573,8 @@ #if DEBUG if (debugging) - printk(OSST_DEB_MSG "osst%d:D: Buffer flushed, %d EOF(s) written\n", - dev, 1+STp->two_fm); + printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n", + name, 1+STp->two_fm); #endif } else if (!STp->rew_at_close) { @@ -4624,7 +4614,7 @@ if (SRpnt) scsi_release_request(SRpnt); if (STp->recover_count) { - printk(KERN_INFO "osst%d:I: %d recovered errors in", dev, STp->recover_count); + printk(KERN_INFO "%s:I: %d recovered errors in", name, STp->recover_count); if (STp->write_count) printk(" %d frames written", STp->write_count); if (STp->read_count) @@ -4643,15 +4633,9 @@ static int os_scsi_tape_close(struct inode * inode, struct file * filp) { int result = 0; - OS_Scsi_Tape * STp; + OS_Scsi_Tape * STp = filp->private_data; Scsi_Request * SRpnt = NULL; - kdev_t devt = inode->i_rdev; - int dev; - - dev = TAPE_NR(devt); - STp = os_scsi_tapes[dev]; - if (STp->door_locked == ST_LOCKED_AUTO) osst_int_ioctl(STp, &SRpnt, MTUNLOCK, 0); if (SRpnt) scsi_release_request(SRpnt); @@ -4680,20 +4664,18 @@ { int i, cmd_nr, cmd_type, retval = 0; unsigned int blk; - OS_Scsi_Tape *STp; ST_mode *STm; ST_partstat *STps; Scsi_Request *SRpnt = NULL; - int dev = TAPE_NR(inode->i_rdev); - - STp = os_scsi_tapes[dev]; + OS_Scsi_Tape *STp = file->private_data; + char *name = tape_name(STp); if (down_interruptible(&STp->lock)) return -ERESTARTSYS; #if DEBUG if (debugging && !STp->in_use) { - printk(OSST_DEB_MSG "osst%d:D: Incorrect device.\n", dev); + printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name); retval = (-EIO); goto out; } @@ -4715,7 +4697,7 @@ cmd_type = _IOC_TYPE(cmd_in); cmd_nr = _IOC_NR(cmd_in); #if DEBUG - printk(OSST_DEB_MSG "osst%d:D: Ioctl %d,%d in %s mode\n", dev, + printk(OSST_DEB_MSG "%s:D: Ioctl %d,%d in %s mode\n", name, cmd_type, cmd_nr, STp->raw?"raw":"normal"); #endif if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) { @@ -4733,7 +4715,7 @@ } if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) { - printk(KERN_WARNING "osst%d:W: MTSETDRVBUFFER only allowed for root.\n", dev); + printk(KERN_WARNING "%s:W: MTSETDRVBUFFER only allowed for root.\n", name); retval = (-EPERM); goto out; } @@ -4793,8 +4775,8 @@ if (STp->door_locked != ST_UNLOCKED && STp->door_locked != ST_LOCK_FAILS) { if (osst_int_ioctl(STp, &SRpnt, MTLOCK, 0)) { - printk(KERN_NOTICE "osst%d:I: Could not relock door after bus reset.\n", - dev); + printk(KERN_NOTICE "%s:I: Could not relock door after bus reset.\n", + name); STp->door_locked = ST_UNLOCKED; } } @@ -5421,6 +5403,7 @@ ST_mode * STm; ST_partstat * STps; int i, dev; + struct gendisk *disk; #ifdef CONFIG_DEVFS_FS int mode; #endif @@ -5428,8 +5411,13 @@ if (SDp->type != TYPE_TAPE || !osst_supports(SDp)) return 1; + disk = alloc_disk(1); + if (!disk) + return 1; + if (osst_template.nr_dev >= osst_template.dev_max) { SDp->attached--; + put_disk(disk); return 1; } @@ -5442,6 +5430,7 @@ if (tpnt == NULL) { SDp->attached--; printk(KERN_WARNING "osst :W: Can't allocate device descriptor.\n"); + put_disk(disk); return 1; } memset(tpnt, 0, sizeof(OS_Scsi_Tape)); @@ -5493,7 +5482,10 @@ #endif tpnt->device = SDp; - tpnt->devt = mk_kdev(MAJOR_NR, i); + disk->private_data = &tpnt->driver; + sprintf(disk->disk_name, "osst%d", i); + tpnt->driver = &osst_template; + tpnt->disk = disk; tpnt->dirty = 0; tpnt->in_use = 0; tpnt->drv_buffer = 1; /* Try buffering if no mode sense */ @@ -5558,8 +5550,8 @@ osst_template.nr_dev++; printk(KERN_INFO - "osst :I: Attached OnStream %.5s tape at scsi%d, channel %d, id %d, lun %d as osst%d\n", - SDp->model, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun, dev); + "osst :I: Attached OnStream %.5s tape at scsi%d, channel %d, id %d, lun %d as %s\n", + SDp->model, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun, tape_name(tpnt)); return 0; }; @@ -5578,52 +5570,53 @@ /* Driver initialization (not __initfunc because may be called later) */ static int osst_init() { - int i; + int i; + + if (osst_template.dev_noticed == 0) + return 0; - if (osst_template.dev_noticed == 0) return 0; + if (!osst_registered) { + if (register_chrdev(MAJOR_NR,"osst",&osst_fops)) { + printk(KERN_ERR "osst :W: Unable to get major %d for OnStream tapes\n",MAJOR_NR); + return 1; + } + osst_registered++; + } - if(!osst_registered) { - if (register_chrdev(MAJOR_NR,"osst",&osst_fops)) { - printk(KERN_ERR "osst :W: Unable to get major %d for OnStream tapes\n",MAJOR_NR); + if (os_scsi_tapes) + return 0; + osst_template.dev_max = OSST_MAX_TAPES; + if (osst_template.dev_max > 128 / ST_NBR_MODES) + printk(KERN_INFO "osst :I: Only %d tapes accessible.\n", 128 / ST_NBR_MODES); + os_scsi_tapes = kmalloc(osst_template.dev_max * sizeof(OS_Scsi_Tape *), + GFP_ATOMIC); + if (!os_scsi_tapes) { + printk(KERN_ERR "osst :W: Unable to allocate array for OnStream SCSI tapes.\n"); + unregister_chrdev(MAJOR_NR, "osst"); return 1; } - osst_registered++; - } - - if (os_scsi_tapes) return 0; - osst_template.dev_max = OSST_MAX_TAPES; - if (osst_template.dev_max > 128 / ST_NBR_MODES) - printk(KERN_INFO "osst :I: Only %d tapes accessible.\n", 128 / ST_NBR_MODES); - os_scsi_tapes = - (OS_Scsi_Tape **)kmalloc(osst_template.dev_max * sizeof(OS_Scsi_Tape *), - GFP_ATOMIC); - if (os_scsi_tapes == NULL) { - printk(KERN_ERR "osst :W: Unable to allocate array for OnStream SCSI tapes.\n"); - unregister_chrdev(MAJOR_NR, "osst"); - return 1; - } - for (i=0; i < osst_template.dev_max; ++i) os_scsi_tapes[i] = NULL; + for (i=0; i < osst_template.dev_max; ++i) + os_scsi_tapes[i] = NULL; - /* Allocate the buffer pointers */ - osst_buffers = - (OSST_buffer **)kmalloc(osst_template.dev_max * sizeof(OSST_buffer *), - GFP_ATOMIC); - if (osst_buffers == NULL) { - printk(KERN_ERR "osst :W: Unable to allocate tape buffer pointers.\n"); - unregister_chrdev(MAJOR_NR, "osst"); - kfree(os_scsi_tapes); - return 1; - } - osst_nbr_buffers = 0; + /* Allocate the buffer pointers */ + osst_buffers = kmalloc(osst_template.dev_max * sizeof(OSST_buffer *), + GFP_ATOMIC); + if (!osst_buffers) { + printk(KERN_ERR "osst :W: Unable to allocate tape buffer pointers.\n"); + unregister_chrdev(MAJOR_NR, "osst"); + kfree(os_scsi_tapes); + return 1; + } + osst_nbr_buffers = 0; - printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid); + printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid); #if DEBUG - printk(OSST_DEB_MSG "osst :D: Buffer size %d bytes, write threshold %d bytes.\n", - osst_buffer_size, osst_write_threshold); + printk(OSST_DEB_MSG "osst :D: Buffer size %d bytes, write threshold %d bytes.\n", + osst_buffer_size, osst_write_threshold); #endif - return 0; + return 0; } @@ -5641,12 +5634,13 @@ tpnt->device = NULL; #ifdef CONFIG_DEVFS_FS for (mode = 0; mode < ST_NBR_MODES; ++mode) { - devfs_unregister (tpnt->de_r[mode]); - tpnt->de_r[mode] = NULL; - devfs_unregister (tpnt->de_n[mode]); - tpnt->de_n[mode] = NULL; + devfs_unregister (tpnt->de_r[mode]); + tpnt->de_r[mode] = NULL; + devfs_unregister (tpnt->de_n[mode]); + tpnt->de_n[mode] = NULL; } #endif + put_disk(tpnt->disk); kfree(tpnt); os_scsi_tapes[i] = NULL; SDp->attached--; @@ -5666,34 +5660,37 @@ static void __exit exit_osst (void) { - int i; - OS_Scsi_Tape * STp; + int i; + OS_Scsi_Tape * STp; - scsi_unregister_device(&osst_template); - unregister_chrdev(MAJOR_NR, "osst"); - osst_registered--; - if(os_scsi_tapes != NULL) { - for (i=0; i < osst_template.dev_max; ++i) { - if ((STp = os_scsi_tapes[i])) { - if (STp->header_cache != NULL) vfree(STp->header_cache); - kfree(STp); + scsi_unregister_device(&osst_template); + unregister_chrdev(MAJOR_NR, "osst"); + osst_registered--; + if (os_scsi_tapes) { + for (i=0; i < osst_template.dev_max; ++i) { + STp = os_scsi_tapes[i]; + if (!STp) + continue; + if (STp->header_cache) + vfree(STp->header_cache); + put_disk(STp->disk); + kfree(STp); + } + kfree(os_scsi_tapes); + + if (osst_buffers) { + for (i=0; i < osst_nbr_buffers; i++) { + if (osst_buffers[i]) { + osst_buffers[i]->orig_sg_segs = 0; + normalize_buffer(osst_buffers[i]); + kfree(osst_buffers[i]); + } + } + kfree(osst_buffers); } } - kfree(os_scsi_tapes); - - if (osst_buffers != NULL) { - for (i=0; i < osst_nbr_buffers; i++) - if (osst_buffers[i] != NULL) { - osst_buffers[i]->orig_sg_segs = 0; - normalize_buffer(osst_buffers[i]); - kfree(osst_buffers[i]); - } - - kfree(osst_buffers); - } - } - osst_template.dev_max = 0; - printk(KERN_INFO "osst :I: Unloaded.\n"); + osst_template.dev_max = 0; + printk(KERN_INFO "osst :I: Unloaded.\n"); } module_init(init_osst); diff -Nru a/drivers/scsi/osst.h b/drivers/scsi/osst.h --- a/drivers/scsi/osst.h Mon Nov 4 14:31:02 2002 +++ b/drivers/scsi/osst.h Mon Nov 4 14:31:02 2002 @@ -532,7 +532,7 @@ /* The tape drive descriptor */ typedef struct { - kdev_t devt; + struct Scsi_Device_Template *driver; unsigned capacity; Scsi_Device* device; struct semaphore lock; /* for serialization */ @@ -628,6 +628,7 @@ unsigned char last_cmnd[6]; unsigned char last_sense[16]; #endif + struct gendisk *disk; } OS_Scsi_Tape; /* Values of write_type */ diff -Nru a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h --- a/drivers/scsi/qla1280.h Mon Nov 4 14:31:03 2002 +++ b/drivers/scsi/qla1280.h Mon Nov 4 14:31:03 2002 @@ -1331,6 +1331,9 @@ release: qla1280_release, \ info: qla1280_info, \ queuecommand: qla1280_queuecommand, \ +/* use_new_eh_code: 0, */ \ + abort: qla1280_abort, \ + reset: qla1280_reset, \ slave_attach: qla1280_slave_attach, \ bios_param: qla1280_biosparam, \ can_queue: 255, /* max simultaneous cmds */\ diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c --- a/drivers/scsi/scsi.c Mon Nov 4 14:31:02 2002 +++ b/drivers/scsi/scsi.c Mon Nov 4 14:31:02 2002 @@ -2171,7 +2171,8 @@ SCpnt->target, SCpnt->lun, - kdevname(SCpnt->request->rq_dev), + SCpnt->request->rq_disk ? + SCpnt->request->rq_disk->disk_name : "?", (unsigned long long)SCpnt->request->sector, SCpnt->request->nr_sectors, (long)SCpnt->request->current_nr_sectors, diff -Nru a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h --- a/drivers/scsi/scsi.h Mon Nov 4 14:31:01 2002 +++ b/drivers/scsi/scsi.h Mon Nov 4 14:31:01 2002 @@ -164,8 +164,6 @@ #define SCSI_OWNER_BH_HANDLER 0x104 #define SCSI_OWNER_NOBODY 0x105 -#define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7] - #define IDENTIFY_BASE 0x80 #define IDENTIFY(can_disconnect, lun) (IDENTIFY_BASE |\ ((can_disconnect) ? 0x40 : 0) |\ @@ -415,7 +413,6 @@ extern unsigned int scsi_need_isa_buffer; /* True if some devices need indirection * buffers */ extern volatile int in_scan_scsis; -extern const unsigned char scsi_command_size[8]; extern struct bus_type scsi_driverfs_bus_type; diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c --- a/drivers/scsi/scsi_lib.c Mon Nov 4 14:31:02 2002 +++ b/drivers/scsi/scsi_lib.c Mon Nov 4 14:31:02 2002 @@ -635,7 +635,7 @@ break; case NOT_READY: printk(KERN_INFO "Device %s not ready.\n", - kdevname(req->rq_dev)); + req->rq_disk ? req->rq_disk->disk_name : ""); SCpnt = scsi_end_request(SCpnt, 0, this_count); return; break; @@ -703,36 +703,8 @@ */ struct Scsi_Device_Template *scsi_get_request_dev(struct request *req) { - struct Scsi_Device_Template *spnt; - kdev_t dev = req->rq_dev; - int major = major(dev); - - for (spnt = scsi_devicelist; spnt; spnt = spnt->next) { - /* - * Search for a block device driver that supports this - * major. - */ - if (spnt->blk && spnt->major == major) { - return spnt; - } - /* - * I am still not entirely satisfied with this solution, - * but it is good enough for now. Disks have a number of - * major numbers associated with them, the primary - * 8, which we test above, and a secondary range of 7 - * different consecutive major numbers. If this ever - * becomes insufficient, then we could add another function - * to the structure, and generalize this completely. - */ - if( spnt->min_major != 0 - && spnt->max_major != 0 - && major >= spnt->min_major - && major <= spnt->max_major ) - { - return spnt; - } - } - return NULL; + struct gendisk *p = req->rq_disk; + return p ? *(struct Scsi_Device_Template **)p->private_data : NULL; } /* diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c --- a/drivers/scsi/sd.c Mon Nov 4 14:31:02 2002 +++ b/drivers/scsi/sd.c Mon Nov 4 14:31:02 2002 @@ -73,6 +73,7 @@ struct scsi_disk { struct list_head list; /* list of all scsi_disks */ + struct Scsi_Device_Template *driver; /* always &sd_template */ struct scsi_device *device; struct gendisk *disk; sector_t capacity; /* size in 512-byte sectors */ @@ -105,9 +106,6 @@ .name = "disk", .tag = "sd", .scsi_type = TYPE_DISK, - .major = SCSI_DISK0_MAJOR, - .min_major = SCSI_DISK1_MAJOR, - .max_major = SCSI_DISK7_MAJOR, .blk = 1, .detect = sd_detect, .attach = sd_attach, @@ -144,6 +142,11 @@ list_del(&sdkp->list); spin_unlock(&sd_devlist_lock); } + +static inline struct scsi_disk *scsi_disk(struct gendisk *disk) +{ + return container_of(disk->private_data, struct scsi_disk, driver); +} /** * sd_ioctl - process an ioctl @@ -164,7 +167,7 @@ { struct block_device *bdev = inode->i_bdev; struct gendisk *disk = bdev->bd_disk; - struct scsi_disk *sdkp = disk->private_data; + struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; sector_t capacity = sdkp->capacity; struct Scsi_Host *host; @@ -431,7 +434,7 @@ static int sd_open(struct inode *inode, struct file *filp) { struct gendisk *disk = inode->i_bdev->bd_disk; - struct scsi_disk *sdkp = disk->private_data; + struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device * sdp = sdkp->device; int retval = -ENXIO; @@ -516,7 +519,7 @@ static int sd_release(struct inode *inode, struct file *filp) { struct gendisk *disk = inode->i_bdev->bd_disk; - struct scsi_disk *sdkp = disk->private_data; + struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; SCSI_LOG_HLQUEUE(3, printk("sd_release: disk=%s\n", disk->disk_name)); @@ -670,7 +673,7 @@ **/ static int check_scsidisk_media_change(struct gendisk *disk) { - struct scsi_disk *sdkp = disk->private_data; + struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; int retval; int flag = 0; /* <<<< what is this for?? */ @@ -697,15 +700,17 @@ * check_disk_change */ } - /* Using Start/Stop enables differentiation between drive with + /* Using TEST_UNIT_READY enables differentiation between drive with * no cartridge loaded - NOT READY, drive with changed cartridge - * UNIT ATTENTION, or with same cartridge - GOOD STATUS. - * This also handles drives that auto spin down. eg iomega jaz 1GB - * as this will spin up the drive. + * + * Drives that auto spin down. eg iomega jaz 1G, will be started + * by sd_spinup_disk() from sd_init_onedisk(), which happens whenever + * sd_revalidate() is called. */ retval = -ENODEV; if (scsi_block_when_processing_errors(sdp)) - retval = scsi_ioctl(sdp, SCSI_IOCTL_START_UNIT, NULL); + retval = scsi_ioctl(sdp, SCSI_IOCTL_TEST_UNIT_READY, NULL); if (retval) { /* Unable to test, unit probably not ready. * This usually means there is no disc in the @@ -791,10 +796,9 @@ if (sd_media_not_present(sdkp, SRpnt)) return; - /* Look for non-removable devices that return NOT_READY. + /* Look for devices that return NOT_READY. * Issue command to spin up drive for these cases. */ - if (the_result && !sdp->removable && - SRpnt->sr_sense_buffer[2] == NOT_READY) { + if (the_result && SRpnt->sr_sense_buffer[2] == NOT_READY) { unsigned long time1; if (!spintime) { printk(KERN_NOTICE "%s: Spinning up disk...", @@ -1227,6 +1231,7 @@ dsk_nr = sd_template.nr_dev++; sdkp->device = sdp; + sdkp->driver = &sd_template; sdkp->disk = gd; sd_init_onedisk(sdkp, gd); @@ -1243,7 +1248,7 @@ gd->flags = GENHD_FL_DRIVERFS | GENHD_FL_DEVFS; if (sdp->removable) gd->flags |= GENHD_FL_REMOVABLE; - gd->private_data = sdkp; + gd->private_data = &sdkp->driver; gd->queue = &sdkp->device->request_queue; sd_devlist_insert(sdkp); @@ -1266,7 +1271,7 @@ static int sd_revalidate(struct gendisk *disk) { - struct scsi_disk *sdkp = disk->private_data; + struct scsi_disk *sdkp = scsi_disk(disk); if (!sdkp->device) return -ENODEV; diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c --- a/drivers/scsi/sg.c Mon Nov 4 14:31:01 2002 +++ b/drivers/scsi/sg.c Mon Nov 4 14:31:01 2002 @@ -125,7 +125,6 @@ .name = "generic", .tag = "sg", .scsi_type = 0xff, - .major = SCSI_GENERIC_MAJOR, .detect = sg_detect, .init = sg_init, .attach = sg_attach, @@ -180,16 +179,17 @@ } Sg_fd; typedef struct sg_device { /* holds the state of each scsi generic device */ + struct Scsi_Device_Template *driver; Scsi_Device *device; wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */ int sg_tablesize; /* adapter's max scatter-gather table size */ Sg_fd *headfp; /* first open fd belonging to this device */ devfs_handle_t de; - kdev_t i_rdev; /* holds device major+minor number */ volatile char detached; /* 0->attached, 1->detached pending removal */ volatile char exclude; /* opened for exclusive access */ char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ struct device sg_driverfs_dev; + struct gendisk *disk; } Sg_device; static int sg_fasync(int fd, struct file *filp, int mode); @@ -330,7 +330,7 @@ if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; - SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", minor(sdp->i_rdev))); + SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name)); sg_fasync(-1, filp, 0); /* remove filp from async notification list */ if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */ if (!sdp->detached) { @@ -359,8 +359,8 @@ if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; - SCSI_LOG_TIMEOUT(3, printk("sg_read: dev=%d, count=%d\n", - minor(sdp->i_rdev), (int) count)); + SCSI_LOG_TIMEOUT(3, printk("sg_read: %s, count=%d\n", + sdp->disk->disk_name, (int) count)); if (ppos != &filp->f_pos) ; /* FIXME: Hmm. Seek to the right place, or fail? */ if ((k = verify_area(VERIFY_WRITE, buf, count))) return k; @@ -514,8 +514,8 @@ if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; - SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n", - minor(sdp->i_rdev), (int) count)); + SCSI_LOG_TIMEOUT(3, printk("sg_write: %s, count=%d\n", + sdp->disk->disk_name, (int) count)); if (sdp->detached) return -ENODEV; if (!((filp->f_flags & O_NONBLOCK) || @@ -702,7 +702,7 @@ srp->my_cmdp = SRpnt; q = &SRpnt->sr_device->request_queue; - SRpnt->sr_request->rq_dev = sdp->i_rdev; + SRpnt->sr_request->rq_disk = sdp->disk; SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_cmd_len = hp->cmd_len; SRpnt->sr_use_sg = srp->data.k_use_sg; @@ -753,8 +753,8 @@ if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; - SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: dev=%d, cmd=0x%x\n", - minor(sdp->i_rdev), (int) cmd_in)); + SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: %s, cmd=0x%x\n", + sdp->disk->disk_name, (int) cmd_in)); read_only = (O_RDWR != (filp->f_flags & O_ACCMODE)); switch (cmd_in) { @@ -1056,8 +1056,8 @@ res |= POLLOUT | POLLWRNORM; } else if (count < SG_MAX_QUEUE) res |= POLLOUT | POLLWRNORM; - SCSI_LOG_TIMEOUT(3, printk("sg_poll: dev=%d, res=0x%x\n", - minor(sdp->i_rdev), (int) res)); + SCSI_LOG_TIMEOUT(3, printk("sg_poll: %s, res=0x%x\n", + sdp->disk->disk_name, (int) res)); return res; } @@ -1070,8 +1070,8 @@ if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; - SCSI_LOG_TIMEOUT(3, printk("sg_fasync: dev=%d, mode=%d\n", - minor(sdp->i_rdev), mode)); + SCSI_LOG_TIMEOUT(3, printk("sg_fasync: %s, mode=%d\n", + sdp->disk->disk_name, mode)); retval = fasync_helper(fd, filp, mode, &sfp->async_qp); return (retval < 0) ? retval : 0; @@ -1257,13 +1257,13 @@ SRpnt->sr_bufflen = 0; SRpnt->sr_buffer = NULL; SRpnt->sr_underflow = 0; - SRpnt->sr_request->rq_dev = mk_kdev(0, 0); /* "sg" _disowns_ request blk */ + SRpnt->sr_request->rq_disk = NULL; /* "sg" _disowns_ request blk */ srp->my_cmdp = NULL; srp->done = 1; - SCSI_LOG_TIMEOUT(4, printk("sg_cmd_done: dev=%d, pack_id=%d, res=0x%x\n", - minor(sdp->i_rdev), srp->header.pack_id, (int) SRpnt->sr_result)); + SCSI_LOG_TIMEOUT(4, printk("sg_cmd_done: %s, pack_id=%d, res=0x%x\n", + sdp->disk->disk_name, srp->header.pack_id, (int) SRpnt->sr_result)); srp->header.resid = SCpnt->resid; /* N.B. unit of duration changes here from jiffies to millisecs */ srp->header.duration = @@ -1420,7 +1420,8 @@ size_t count, loff_t off) { Sg_device *sdp = list_entry(driverfs_dev, Sg_device, sg_driverfs_dev); - return off ? 0 : sprintf(page, "%x\n", sdp->i_rdev.value); + return off ? 0 : sprintf(page, "%x\n", MKDEV(sdp->disk->major, + sdp->disk->first_minor)); } static DEVICE_ATTR(kdev,S_IRUGO,sg_device_kdev_read,NULL); @@ -1436,10 +1437,13 @@ static int sg_attach(Scsi_Device * scsidp) { + struct gendisk *disk = alloc_disk(1); Sg_device *sdp = NULL; unsigned long iflags; int k; + if (!disk) + return 1; write_lock_irqsave(&sg_dev_arr_lock, iflags); if (sg_template.nr_dev >= sg_template.dev_max) { /* try to resize */ Sg_device **tmp_da; @@ -1452,6 +1456,7 @@ scsidp->attached--; printk(KERN_ERR "sg_attach: device array cannot be resized\n"); + put_disk(disk); return 1; } write_lock_irqsave(&sg_dev_arr_lock, iflags); @@ -1477,6 +1482,7 @@ scsidp->lun, scsidp->type, SG_MAX_DEVS_MASK); if (NULL != sdp) vfree((char *) sdp); + put_disk(disk); return 1; } if (k < sg_template.dev_max) { @@ -1493,11 +1499,18 @@ scsidp->attached--; write_unlock_irqrestore(&sg_dev_arr_lock, iflags); printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n"); + put_disk(disk); return 1; } SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k)); memset(sdp, 0, sizeof(*sdp)); + sdp->driver = &sg_template; + disk->private_data = &sdp->driver; + sprintf(disk->disk_name, "sg%d", k); + disk->major = SCSI_GENERIC_MAJOR; + disk->first_minor = k; + sdp->disk = disk; sdp->device = scsidp; init_waitqueue_head(&sdp->o_excl_wait); sdp->headfp = NULL; @@ -1505,7 +1518,6 @@ sdp->sgdebug = 0; sdp->detached = 0; sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0; - sdp->i_rdev = mk_kdev(SCSI_GENERIC_MAJOR, k); memset(&sdp->sg_driverfs_dev, 0, sizeof (struct device)); sprintf(sdp->sg_driverfs_dev.bus_id, "%s:gen", @@ -1608,6 +1620,8 @@ device_remove_file(&sdp->sg_driverfs_dev, &dev_attr_type); device_remove_file(&sdp->sg_driverfs_dev, &dev_attr_kdev); device_unregister(&sdp->sg_driverfs_dev); + put_disk(sdp->disk); + sdp->disk = NULL; if (NULL == sdp->headfp) vfree((char *) sdp); } @@ -2972,18 +2986,16 @@ PRINT_PROC(" def_reserved_size=%d\n", sg_big_buff); for (j = 0; j < max_dev; ++j) { if ((sdp = sg_get_dev(j))) { - struct scsi_device *scsidp; - int dev; + struct scsi_device *scsidp = sdp->device; - scsidp = sdp->device; if (NULL == scsidp) { PRINT_PROC("device %d detached ??\n", j); continue; } - dev = minor(sdp->i_rdev); if (sg_get_nth_sfp(sdp, 0)) { - PRINT_PROC(" >>> device=sg%d ", dev); + PRINT_PROC(" >>> device=%s ", + sdp->disk->disk_name); if (sdp->detached) PRINT_PROC("detached pending close "); else diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c --- a/drivers/scsi/sr.c Mon Nov 4 14:31:01 2002 +++ b/drivers/scsi/sr.c Mon Nov 4 14:31:01 2002 @@ -77,7 +77,6 @@ .name = "cdrom", .tag = "sr", .scsi_type = TYPE_ROM, - .major = SCSI_CDROM_MAJOR, .blk = 1, .detect = sr_detect, .init = sr_init, @@ -177,6 +176,11 @@ } return retval; } + +static inline struct scsi_cd *scsi_cd(struct gendisk *disk) +{ + return container_of(disk->private_data, struct scsi_cd, driver); +} /* * rw_intr is the interrupt routine for the device driver. @@ -190,7 +194,7 @@ int this_count = SCpnt->bufflen >> 9; int good_sectors = (result == 0 ? this_count : 0); int block_sectors = 0; - struct scsi_cd *cd = SCpnt->request->rq_disk->private_data; + struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk); #ifdef DEBUG printk("sr.c done: %x %p\n", result, SCpnt->request->bh->b_data); @@ -243,7 +247,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt) { int block=0, this_count, s_size, timeout = SR_TIMEOUT; - struct scsi_cd *cd = SCpnt->request->rq_disk->private_data; + struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk); SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %s, block = %d\n", cd->disk->disk_name, block)); @@ -395,26 +399,26 @@ static int sr_block_open(struct inode *inode, struct file *file) { - struct scsi_cd *cd = inode->i_bdev->bd_disk->private_data; + struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk); return cdrom_open(&cd->cdi, inode, file); } static int sr_block_release(struct inode *inode, struct file *file) { - struct scsi_cd *cd = inode->i_bdev->bd_disk->private_data; + struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk); return cdrom_release(&cd->cdi, file); } static int sr_block_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long arg) { - struct scsi_cd *cd = inode->i_bdev->bd_disk->private_data; + struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk); return cdrom_ioctl(&cd->cdi, inode, cmd, arg); } static int sr_block_media_changed(struct gendisk *disk) { - struct scsi_cd *cd = disk->private_data; + struct scsi_cd *cd = scsi_cd(disk); return cdrom_media_changed(&cd->cdi); } @@ -766,6 +770,7 @@ strcpy(disk->disk_name, cd->cdi.name); disk->fops = &sr_bdops; disk->flags = GENHD_FL_CD; + cd->driver = &sr_template; cd->disk = disk; cd->capacity = 0x1fffff; cd->device->sector_size = 2048;/* A guess, just in case */ @@ -798,7 +803,7 @@ disk->driverfs_dev = &cd->device->sdev_driverfs_dev; register_cdrom(&cd->cdi); set_capacity(disk, cd->capacity); - disk->private_data = cd; + disk->private_data = &cd->driver; disk->queue = &cd->device->request_queue; add_disk(disk); diff -Nru a/drivers/scsi/sr.h b/drivers/scsi/sr.h --- a/drivers/scsi/sr.h Mon Nov 4 14:31:01 2002 +++ b/drivers/scsi/sr.h Mon Nov 4 14:31:01 2002 @@ -25,6 +25,7 @@ #define IOCTL_TIMEOUT 30*HZ typedef struct scsi_cd { + struct Scsi_Device_Template *driver; unsigned capacity; /* size in blocks */ Scsi_Device *device; unsigned int vendor; /* vendor code, see sr_vendor.c */ diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c --- a/drivers/scsi/st.c Mon Nov 4 14:31:02 2002 +++ b/drivers/scsi/st.c Mon Nov 4 14:31:02 2002 @@ -175,7 +175,6 @@ .name = "tape", .tag = "st", .scsi_type = TYPE_TAPE, - .major = SCSI_TAPE_MAJOR, .detect = st_detect, .attach = st_attach, .detach = st_detach @@ -230,13 +229,18 @@ } +static inline char *tape_name(Scsi_Tape *tape) +{ + return tape->disk->disk_name; +} + /* Convert the result to success code */ static int st_chk_result(Scsi_Tape *STp, Scsi_Request * SRpnt) { - int dev; int result = SRpnt->sr_result; unsigned char *sense = SRpnt->sr_sense_buffer, scode; DEB(const char *stp;) + char *name = tape_name(STp); if (!result) { sense[0] = 0; /* We don't have sense data if this byte is zero */ @@ -250,11 +254,10 @@ scode = 0; } - dev = TAPE_NR(SRpnt->sr_request->rq_dev); DEB( if (debugging) { - printk(ST_DEB_MSG "st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n", - dev, result, + printk(ST_DEB_MSG "%s: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n", + name, result, SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2], SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5], SRpnt->sr_bufflen); @@ -271,12 +274,12 @@ SRpnt->sr_cmnd[0] != MODE_SENSE && SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ if (driver_byte(result) & DRIVER_SENSE) { - printk(KERN_WARNING "st%d: Error with sense data: ", dev); + printk(KERN_WARNING "%s: Error with sense data: ", name); print_req_sense("st", SRpnt); } else printk(KERN_WARNING - "st%d: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", - dev, result, suggestion(result), + "%s: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", + name, result, suggestion(result), driver_byte(result) & DRIVER_MASK, host_byte(result)); } @@ -311,7 +314,7 @@ stp = "write"; else stp = "ioctl"; - printk(ST_DEB_MSG "st%d: Recovered %s error (%d).\n", dev, stp, + printk(ST_DEB_MSG "%s: Recovered %s error (%d).\n", name, stp, STp->recover_count); } ) /* end DEB */ @@ -325,14 +328,10 @@ /* Wakeup from interrupt */ static void st_sleep_done(Scsi_Cmnd * SCpnt) { - unsigned int st_nbr; int remainder; - Scsi_Tape *STp; + Scsi_Tape *STp = container_of(SCpnt->request->rq_disk->private_data, + Scsi_Tape, driver); - st_nbr = TAPE_NR(SCpnt->request->rq_dev); - read_lock(&st_dev_arr_lock); - STp = scsi_tapes[st_nbr]; - read_unlock(&st_dev_arr_lock); if ((STp->buffer)->writing && (SCpnt->sense_buffer[0] & 0x70) == 0x70 && (SCpnt->sense_buffer[2] & 0x40)) { @@ -358,7 +357,6 @@ complete(SCpnt->request->waiting); } - /* Do the scsi command. Waits until command performed if do_wait is true. Otherwise write_behind_check() is used to check that the command has finished. */ @@ -371,8 +369,8 @@ if (SRpnt == NULL) { SRpnt = scsi_allocate_request(STp->device); if (SRpnt == NULL) { - DEBC( printk(KERN_ERR "st%d: Can't get SCSI request.\n", - TAPE_NR(STp->devt)); ); + DEBC( printk(KERN_ERR "%s: Can't get SCSI request.\n", + tape_name(STp)); ); if (signal_pending(current)) (STp->buffer)->syscall_result = (-EINTR); else @@ -394,7 +392,7 @@ SRpnt->sr_cmd_len = 0; SRpnt->sr_request->waiting = &(STp->wait); SRpnt->sr_request->rq_status = RQ_SCSI_BUSY; - SRpnt->sr_request->rq_dev = STp->devt; + SRpnt->sr_request->rq_disk = STp->disk; scsi_do_req(SRpnt, (void *) cmd, bp, bytes, st_sleep_done, timeout, retries); @@ -459,8 +457,8 @@ cmd[2] = cmd[3] = cmd[4] = 0xff; /* -1 filemarks */ cmd[5] = 0; - DEBC(printk(ST_DEB_MSG "st%d: Stepping over filemark %s.\n", - TAPE_NR(STp->devt), forward ? "forward" : "backward")); + DEBC(printk(ST_DEB_MSG "%s: Stepping over filemark %s.\n", + tape_name(STp), forward ? "forward" : "backward")); SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_RETRIES, TRUE); @@ -471,8 +469,8 @@ SRpnt = NULL; if ((STp->buffer)->midlevel_result != 0) - printk(KERN_ERR "st%d: Stepping over filemark %s failed.\n", - TAPE_NR(STp->devt), forward ? "forward" : "backward"); + printk(KERN_ERR "%s: Stepping over filemark %s failed.\n", + tape_name(STp), forward ? "forward" : "backward"); return (STp->buffer)->syscall_result; } @@ -491,8 +489,8 @@ write_behind_check(STp); if ((STp->buffer)->syscall_result) { DEBC(printk(ST_DEB_MSG - "st%d: Async write error (flush) %x.\n", - TAPE_NR(STp->devt), (STp->buffer)->midlevel_result)) + "%s: Async write error (flush) %x.\n", + tape_name(STp), (STp->buffer)->midlevel_result)) if ((STp->buffer)->midlevel_result == INT_MAX) return (-ENOSPC); return (-EIO); @@ -507,8 +505,8 @@ offset = (STp->buffer)->buffer_bytes; transfer = ((offset + STp->block_size - 1) / STp->block_size) * STp->block_size; - DEBC(printk(ST_DEB_MSG "st%d: Flushing %d bytes.\n", - TAPE_NR(STp->devt), transfer)); + DEBC(printk(ST_DEB_MSG "%s: Flushing %d bytes.\n", + tape_name(STp), transfer)); memset((STp->buffer)->b_data + offset, 0, transfer - offset); @@ -534,8 +532,8 @@ (STp->buffer)->buffer_bytes = 0; result = (-ENOSPC); } else { - printk(KERN_ERR "st%d: Error on flush.\n", - TAPE_NR(STp->devt)); + printk(KERN_ERR "%s: Error on flush.\n", + tape_name(STp)); result = (-EIO); } STps->drv_block = (-1); @@ -613,7 +611,7 @@ { int set_it = FALSE; unsigned long arg; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); if (!STp->density_changed && STm->default_density >= 0 && @@ -633,8 +631,8 @@ if (set_it && st_int_ioctl(STp, SET_DENS_AND_BLK, arg)) { printk(KERN_WARNING - "st%d: Can't set default block size to %d bytes and density %x.\n", - dev, STm->default_blksize, STm->default_density); + "%s: Can't set default block size to %d bytes and density %x.\n", + name, STm->default_blksize, STm->default_density); if (modes_defined) return (-EINVAL); } @@ -646,11 +644,11 @@ static int do_door_lock(Scsi_Tape * STp, int do_lock) { int retval, cmd; - DEB(int dev = TAPE_NR(STp->devt);) + DEB(char *name = tape_name(STp);) cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK; - DEBC(printk(ST_DEB_MSG "st%d: %socking drive door.\n", dev, + DEBC(printk(ST_DEB_MSG "%s: %socking drive door.\n", name, do_lock ? "L" : "Unl")); retval = scsi_ioctl(STp->device, cmd, NULL); if (!retval) { @@ -779,15 +777,15 @@ Scsi_Request *SRpnt = NULL; ST_mode *STm; ST_partstat *STps; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); struct inode *inode = filp->f_dentry->d_inode; int mode = TAPE_MODE(inode->i_rdev); STp->ready = ST_READY; if (mode != STp->current_mode) { - DEBC(printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n", - dev, STp->current_mode, mode)); + DEBC(printk(ST_DEB_MSG "%s: Mode change from %d to %d.\n", + name, STp->current_mode, mode)); new_session = TRUE; STp->current_mode = mode; } @@ -858,12 +856,12 @@ (STp->buffer)->b_data[5]; if ( DEB( debugging || ) !STp->inited) printk(KERN_WARNING - "st%d: Block limits %d - %d bytes.\n", dev, + "%s: Block limits %d - %d bytes.\n", name, STp->min_block, STp->max_block); } else { STp->min_block = STp->max_block = (-1); - DEBC(printk(ST_DEB_MSG "st%d: Can't read block limits.\n", - dev)); + DEBC(printk(ST_DEB_MSG "%s: Can't read block limits.\n", + name)); } } @@ -879,14 +877,14 @@ } if ((STp->buffer)->syscall_result != 0) { - DEBC(printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev)); + DEBC(printk(ST_DEB_MSG "%s: No Mode Sense.\n", name)); STp->block_size = ST_DEFAULT_BLOCK; /* Educated guess (?) */ (STp->buffer)->syscall_result = 0; /* Prevent error propagation */ STp->drv_write_prot = 0; } else { DEBC(printk(ST_DEB_MSG - "st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n", - dev, + "%s: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n", + name, (STp->buffer)->b_data[0], (STp->buffer)->b_data[1], (STp->buffer)->b_data[2], (STp->buffer)->b_data[3])); @@ -896,8 +894,8 @@ STp->block_size = (STp->buffer)->b_data[9] * 65536 + (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11]; DEBC(printk(ST_DEB_MSG - "st%d: Density %x, tape length: %x, drv buffer: %d\n", - dev, STp->density, (STp->buffer)->b_data[5] * 65536 + + "%s: Density %x, tape length: %x, drv buffer: %d\n", + name, STp->density, (STp->buffer)->b_data[5] * 65536 + (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7], STp->drv_buffer)); } @@ -915,14 +913,14 @@ (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0; DEBC(printk(ST_DEB_MSG - "st%d: Block size: %d, buffer size: %d (%d blocks).\n", dev, + "%s: Block size: %d, buffer size: %d (%d blocks).\n", name, STp->block_size, (STp->buffer)->buffer_size, (STp->buffer)->buffer_blocks)); if (STp->drv_write_prot) { STp->write_prot = 1; - DEBC(printk(ST_DEB_MSG "st%d: Write protected\n", dev)); + DEBC(printk(ST_DEB_MSG "%s: Write protected\n", name)); if ((st_flags & O_ACCMODE) == O_WRONLY || (st_flags & O_ACCMODE) == O_RDWR) { @@ -936,7 +934,7 @@ after the driver has been initialized with tape in the drive and the partition support has been enabled. */ DEBC(printk(ST_DEB_MSG - "st%d: Updating partition number in status.\n", dev)); + "%s: Updating partition number in status.\n", name)); if ((STp->partition = find_partition(STp)) < 0) { retval = STp->partition; goto err_out; @@ -955,8 +953,8 @@ if (STp->default_drvbuffer != 0xff) { if (st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer)) printk(KERN_WARNING - "st%d: Can't set default drive buffering to %d.\n", - dev, STp->default_drvbuffer); + "%s: Can't set default drive buffering to %d.\n", + name, STp->default_drvbuffer); } } @@ -975,6 +973,7 @@ Scsi_Tape *STp; ST_partstat *STps; int dev = TAPE_NR(inode->i_rdev); + char *name; write_lock(&st_dev_arr_lock); if (dev >= st_template.dev_max || scsi_tapes == NULL || @@ -982,10 +981,12 @@ write_unlock(&st_dev_arr_lock); return (-ENXIO); } + filp->private_data = STp; + name = tape_name(STp); if (STp->in_use) { write_unlock(&st_dev_arr_lock); - DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); ) + DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); ) return (-EBUSY); } STp->in_use = 1; @@ -1003,7 +1004,7 @@ /* See that we have at least a one page buffer available */ if (!enlarge_buffer(STp->buffer, PAGE_SIZE, STp->restr_dma)) { - printk(KERN_WARNING "st%d: Can't allocate tape buffer.\n", dev); + printk(KERN_WARNING "%s: Can't allocate tape buffer.\n", name); retval = (-EOVERFLOW); goto err_out; } @@ -1049,24 +1050,14 @@ int result = 0, result2; unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request *SRpnt; - Scsi_Tape *STp; - ST_mode *STm; - ST_partstat *STps; - - struct inode *inode = filp->f_dentry->d_inode; - kdev_t devt = inode->i_rdev; - int dev; + Scsi_Tape *STp = filp->private_data; + ST_mode *STm = &(STp->modes[STp->current_mode]); + ST_partstat *STps = &(STp->ps[STp->partition]); + char *name = tape_name(STp); if (file_count(filp) > 1) return 0; - dev = TAPE_NR(devt); - read_lock(&st_dev_arr_lock); - STp = scsi_tapes[dev]; - read_unlock(&st_dev_arr_lock); - STm = &(STp->modes[STp->current_mode]); - STps = &(STp->ps[STp->partition]); - if (STps->rw == ST_WRITING && !STp->pos_unknown) { result = flush_write_buffer(STp); if (result != 0 && result != (-ENOSPC)) @@ -1076,22 +1067,22 @@ if (STp->can_partitions && (result2 = switch_partition(STp)) < 0) { DEBC(printk(ST_DEB_MSG - "st%d: switch_partition at close failed.\n", dev)); + "%s: switch_partition at close failed.\n", name)); if (result == 0) result = result2; goto out; } DEBC( if (STp->nbr_requests) - printk(KERN_WARNING "st%d: Number of r/w requests %d, dio used in %d, pages %d (%d).\n", - dev, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable)); + printk(KERN_WARNING "%s: Number of r/w requests %d, dio used in %d, pages %d (%d).\n", + name, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable)); if (STps->rw == ST_WRITING && !STp->pos_unknown) { - DEBC(printk(ST_DEB_MSG "st%d: File length %ld bytes.\n", - dev, (long) (filp->f_pos)); - printk(ST_DEB_MSG "st%d: Async write waits %d, finished %d.\n", - dev, STp->nbr_waits, STp->nbr_finished); + DEBC(printk(ST_DEB_MSG "%s: File length %ld bytes.\n", + name, (long) (filp->f_pos)); + printk(ST_DEB_MSG "%s: Async write waits %d, finished %d.\n", + name, STp->nbr_waits, STp->nbr_finished); ) memset(cmd, 0, MAX_COMMAND_SIZE); @@ -1115,7 +1106,7 @@ /* Filter out successful write at EOM */ scsi_release_request(SRpnt); SRpnt = NULL; - printk(KERN_ERR "st%d: Error on write filemark.\n", dev); + printk(KERN_ERR "%s: Error on write filemark.\n", name); if (result == 0) result = (-EIO); } else { @@ -1129,8 +1120,8 @@ STps->eof = ST_FM; } - DEBC(printk(ST_DEB_MSG "st%d: Buffer flushed, %d EOF(s) written\n", - dev, cmd[4])); + DEBC(printk(ST_DEB_MSG "%s: Buffer flushed, %d EOF(s) written\n", + name, cmd[4])); } else if (!STp->rew_at_close) { STps = &(STp->ps[STp->partition]); if (!STm->sysv || STps->rw != ST_READING) { @@ -1171,15 +1162,7 @@ static int st_release(struct inode *inode, struct file *filp) { int result = 0; - Scsi_Tape *STp; - - kdev_t devt = inode->i_rdev; - int dev; - - dev = TAPE_NR(devt); - read_lock(&st_dev_arr_lock); - STp = scsi_tapes[dev]; - read_unlock(&st_dev_arr_lock); + Scsi_Tape *STp = filp->private_data; if (STp->door_locked == ST_LOCKED_AUTO) do_door_lock(STp, 0); @@ -1245,8 +1228,7 @@ DEB( if (!STp->in_use) { - int dev = TAPE_NR(filp->f_dentry->d_inode->i_rdev); - printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev); + printk(ST_DEB_MSG "%s: Incorrect device.\n", tape_name(STp)); retval = (-EIO); goto out; } ) /* end DEB */ @@ -1328,7 +1310,6 @@ static ssize_t st_write(struct file *filp, const char *buf, size_t count, loff_t * ppos) { - struct inode *inode = filp->f_dentry->d_inode; ssize_t total; ssize_t i, do_count, blks, transfer; ssize_t retval; @@ -1337,15 +1318,11 @@ unsigned char cmd[MAX_COMMAND_SIZE]; const char *b_point; Scsi_Request *SRpnt = NULL; - Scsi_Tape *STp; + Scsi_Tape *STp = filp->private_data; ST_mode *STm; ST_partstat *STps; ST_buffer *STbp; - int dev = TAPE_NR(inode->i_rdev); - - read_lock(&st_dev_arr_lock); - STp = scsi_tapes[dev]; - read_unlock(&st_dev_arr_lock); + char *name = tape_name(STp); if (down_interruptible(&STp->lock)) return -ERESTARTSYS; @@ -1356,8 +1333,8 @@ /* Write must be integral number of blocks */ if (STp->block_size != 0 && (count % STp->block_size) != 0) { - printk(KERN_WARNING "st%d: Write not multiple of tape block size.\n", - dev); + printk(KERN_WARNING "%s: Write not multiple of tape block size.\n", + name); retval = (-EINVAL); goto out; } @@ -1383,8 +1360,8 @@ if (STm->default_compression != ST_DONT_TOUCH && !(STp->compression_changed)) { if (st_compression(STp, (STm->default_compression == ST_YES))) { - printk(KERN_WARNING "st%d: Can't set default compression.\n", - dev); + printk(KERN_WARNING "%s: Can't set default compression.\n", + name); if (modes_defined) { retval = (-EINVAL); goto out; @@ -1397,8 +1374,8 @@ if (STbp->writing) { write_behind_check(STp); if (STbp->syscall_result) { - DEBC(printk(ST_DEB_MSG "st%d: Async write error (write) %x.\n", - dev, STbp->midlevel_result)); + DEBC(printk(ST_DEB_MSG "%s: Async write error (write) %x.\n", + name, STbp->midlevel_result)); if (STbp->midlevel_result == INT_MAX) STps->eof = ST_EOM_OK; else @@ -1508,7 +1485,7 @@ } if (STbp->syscall_result != 0) { - DEBC(printk(ST_DEB_MSG "st%d: Error on write:\n", dev)); + DEBC(printk(ST_DEB_MSG "%s: Error on write:\n", name)); if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && (SRpnt->sr_sense_buffer[2] & 0x40)) { if ((SRpnt->sr_sense_buffer[0] & 0x80) != 0) @@ -1540,8 +1517,8 @@ undone > 0 || count == 0) retval = (-ENOSPC); /* EOM within current request */ DEBC(printk(ST_DEB_MSG - "st%d: EOM with %d bytes unwritten.\n", - dev, transfer)); + "%s: EOM with %d bytes unwritten.\n", + name, transfer)); } else { /* Previously buffered data not written */ count -= do_count; @@ -1550,8 +1527,8 @@ STps->drv_block = (-1); /* Too cautious? */ retval = (-EIO); /* EOM for old data */ DEBC(printk(ST_DEB_MSG - "st%d: EOM with lost data.\n", - dev)); + "%s: EOM with lost data.\n", + name)); } } else { filp->f_pos -= do_count; @@ -1608,8 +1585,8 @@ ST_mode *STm; ST_partstat *STps; ST_buffer *STbp; - int dev = TAPE_NR(STp->devt); int retval = 0; + char *name = tape_name(STp); if (count == 0) return 0; @@ -1655,8 +1632,8 @@ /* Something to check */ if (STbp->syscall_result) { retval = 1; - DEBC(printk(ST_DEB_MSG "st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", - dev, + DEBC(printk(ST_DEB_MSG "%s: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", + name, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[1], SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[3], SRpnt->sr_sense_buffer[4], SRpnt->sr_sense_buffer[5], @@ -1691,7 +1668,7 @@ scsi_release_request(SRpnt); SRpnt = *aSRpnt = NULL; if (transfer == blks) { /* We did not get anything, error */ - printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev); + printk(KERN_NOTICE "%s: Incorrect block size.\n", name); if (STps->drv_block >= 0) STps->drv_block += blks - transfer + 1; st_int_ioctl(STp, MTBSR, 1); @@ -1701,8 +1678,8 @@ STbp->buffer_bytes = (blks - transfer) * STp->block_size; DEBC(printk(ST_DEB_MSG - "st%d: ILI but enough data received %ld %d.\n", - dev, count, STbp->buffer_bytes)); + "%s: ILI but enough data received %ld %d.\n", + name, count, STbp->buffer_bytes)); if (STps->drv_block >= 0) STps->drv_block += 1; if (st_int_ioctl(STp, MTBSR, 1)) @@ -1719,8 +1696,8 @@ STbp->buffer_bytes = bytes - transfer * STp->block_size; DEBC(printk(ST_DEB_MSG - "st%d: EOF detected (%d bytes read).\n", - dev, STbp->buffer_bytes)); + "%s: EOF detected (%d bytes read).\n", + name, STbp->buffer_bytes)); } else if (SRpnt->sr_sense_buffer[2] & 0x40) { if (STps->eof == ST_FM) STps->eof = ST_EOD_1; @@ -1732,20 +1709,20 @@ STbp->buffer_bytes = bytes - transfer * STp->block_size; - DEBC(printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n", - dev, STbp->buffer_bytes)); + DEBC(printk(ST_DEB_MSG "%s: EOM detected (%d bytes read).\n", + name, STbp->buffer_bytes)); } } /* end of EOF, EOM, ILI test */ else { /* nonzero sense key */ DEBC(printk(ST_DEB_MSG - "st%d: Tape error while reading.\n", dev)); + "%s: Tape error while reading.\n", name)); STps->drv_block = (-1); if (STps->eof == ST_FM && (SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK) { DEBC(printk(ST_DEB_MSG - "st%d: Zero returned for first BLANK CHECK after EOF.\n", - dev)); + "%s: Zero returned for first BLANK CHECK after EOF.\n", + name)); STps->eof = ST_EOD_2; /* First BLANK_CHECK after FM */ } else /* Some other extended sense code */ retval = (-EIO); @@ -1775,22 +1752,16 @@ static ssize_t st_read(struct file *filp, char *buf, size_t count, loff_t * ppos) { - struct inode *inode = filp->f_dentry->d_inode; ssize_t total; ssize_t retval = 0; ssize_t i, transfer; int special; Scsi_Request *SRpnt = NULL; - Scsi_Tape *STp; + Scsi_Tape *STp = filp->private_data; ST_mode *STm; ST_partstat *STps; - ST_buffer *STbp; - int dev = TAPE_NR(inode->i_rdev); - - read_lock(&st_dev_arr_lock); - STp = scsi_tapes[dev]; - read_unlock(&st_dev_arr_lock); - STbp = STp->buffer; + ST_buffer *STbp = STp->buffer; + DEB( char *name = tape_name(STp); ) if (down_interruptible(&STp->lock)) return -ERESTARTSYS; @@ -1815,7 +1786,7 @@ } DEB( if (debugging && STps->eof != ST_NOEOF) - printk(ST_DEB_MSG "st%d: EOF/EOM flag up (%d). Bytes %d\n", dev, + printk(ST_DEB_MSG "%s: EOF/EOM flag up (%d). Bytes %d\n", name, STps->eof, STbp->buffer_bytes); ) /* end DEB */ @@ -1866,7 +1837,7 @@ DEB( if (debugging && STps->eof != ST_NOEOF) printk(ST_DEB_MSG - "st%d: EOF up (%d). Left %d, needed %d.\n", dev, + "%s: EOF up (%d). Left %d, needed %d.\n", name, STps->eof, STbp->buffer_bytes, count - total); ) /* end DEB */ @@ -1926,24 +1897,24 @@ /* Set the driver options */ -static void st_log_options(Scsi_Tape * STp, ST_mode * STm, int dev) +static void st_log_options(Scsi_Tape * STp, ST_mode * STm, char *name) { printk(KERN_INFO - "st%d: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n", - dev, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, + "%s: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n", + name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, STm->do_read_ahead); printk(KERN_INFO - "st%d: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n", - dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); + "%s: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n", + name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); printk(KERN_INFO - "st%d: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n", - dev, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, + "%s: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n", + name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, STp->scsi2_logical); printk(KERN_INFO - "st%d: sysv: %d nowait: %d\n", dev, STm->sysv, STp->immediate); + "%s: sysv: %d nowait: %d\n", name, STm->sysv, STp->immediate); DEB(printk(KERN_INFO - "st%d: debugging: %d\n", - dev, debugging);) + "%s: debugging: %d\n", + name, debugging);) } @@ -1952,15 +1923,15 @@ int value; long code; ST_mode *STm; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); STm = &(STp->modes[STp->current_mode]); if (!STm->defined) { memcpy(STm, &(STp->modes[0]), sizeof(ST_mode)); modes_defined = TRUE; DEBC(printk(ST_DEB_MSG - "st%d: Initialized mode %d definition from mode 0\n", - dev, STp->current_mode)); + "%s: Initialized mode %d definition from mode 0\n", + name, STp->current_mode)); } code = options & MT_ST_OPTIONS; @@ -1980,7 +1951,7 @@ STp->immediate = (options & MT_ST_NOWAIT) != 0; STm->sysv = (options & MT_ST_SYSV) != 0; DEB( debugging = (options & MT_ST_DEBUGGING) != 0; ) - st_log_options(STp, STm, dev); + st_log_options(STp, STm, name); } else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { value = (code == MT_ST_SETBOOLEANS); if ((options & MT_ST_BUFFER_WRITES) != 0) @@ -2013,27 +1984,27 @@ DEB( if ((options & MT_ST_DEBUGGING) != 0) debugging = value; ) - st_log_options(STp, STm, dev); + st_log_options(STp, STm, name); } else if (code == MT_ST_WRITE_THRESHOLD) { value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE; if (value < 1 || value > st_fixed_buffer_size) { printk(KERN_WARNING - "st%d: Write threshold %d too small or too large.\n", - dev, value); + "%s: Write threshold %d too small or too large.\n", + name, value); return (-EIO); } STp->write_threshold = value; - printk(KERN_INFO "st%d: Write threshold set to %d bytes.\n", - dev, value); + printk(KERN_INFO "%s: Write threshold set to %d bytes.\n", + name, value); } else if (code == MT_ST_DEF_BLKSIZE) { value = (options & ~MT_ST_OPTIONS); if (value == ~MT_ST_OPTIONS) { STm->default_blksize = (-1); - printk(KERN_INFO "st%d: Default block size disabled.\n", dev); + printk(KERN_INFO "%s: Default block size disabled.\n", name); } else { STm->default_blksize = value; - printk(KERN_INFO "st%d: Default block size set to %d bytes.\n", - dev, STm->default_blksize); + printk(KERN_INFO "%s: Default block size set to %d bytes.\n", + name, STm->default_blksize); if (STp->ready == ST_READY) { STp->blksize_changed = FALSE; set_mode_densblk(STp, STm); @@ -2043,12 +2014,12 @@ value = (options & ~MT_ST_OPTIONS); if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) { STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ; - printk(KERN_INFO "st%d: Long timeout set to %d seconds.\n", dev, + printk(KERN_INFO "%s: Long timeout set to %d seconds.\n", name, (value & ~MT_ST_SET_LONG_TIMEOUT)); } else { STp->timeout = value * HZ; - printk(KERN_INFO "st%d: Normal timeout set to %d seconds.\n", - dev, value); + printk(KERN_INFO "%s: Normal timeout set to %d seconds.\n", + name, value); } } else if (code == MT_ST_SET_CLN) { value = (options & ~MT_ST_OPTIONS) & 0xff; @@ -2059,20 +2030,20 @@ STp->cln_sense_mask = (options >> 8) & 0xff; STp->cln_sense_value = (options >> 16) & 0xff; printk(KERN_INFO - "st%d: Cleaning request mode %d, mask %02x, value %02x\n", - dev, value, STp->cln_sense_mask, STp->cln_sense_value); + "%s: Cleaning request mode %d, mask %02x, value %02x\n", + name, value, STp->cln_sense_mask, STp->cln_sense_value); } else if (code == MT_ST_DEF_OPTIONS) { code = (options & ~MT_ST_CLEAR_DEFAULT); value = (options & MT_ST_CLEAR_DEFAULT); if (code == MT_ST_DEF_DENSITY) { if (value == MT_ST_CLEAR_DEFAULT) { STm->default_density = (-1); - printk(KERN_INFO "st%d: Density default disabled.\n", - dev); + printk(KERN_INFO "%s: Density default disabled.\n", + name); } else { STm->default_density = value & 0xff; - printk(KERN_INFO "st%d: Density default set to %x\n", - dev, STm->default_density); + printk(KERN_INFO "%s: Density default set to %x\n", + name, STm->default_density); if (STp->ready == ST_READY) { STp->density_changed = FALSE; set_mode_densblk(STp, STm); @@ -2082,12 +2053,12 @@ if (value == MT_ST_CLEAR_DEFAULT) { STp->default_drvbuffer = 0xff; printk(KERN_INFO - "st%d: Drive buffer default disabled.\n", dev); + "%s: Drive buffer default disabled.\n", name); } else { STp->default_drvbuffer = value & 7; printk(KERN_INFO - "st%d: Drive buffer default set to %x\n", - dev, STp->default_drvbuffer); + "%s: Drive buffer default set to %x\n", + name, STp->default_drvbuffer); if (STp->ready == ST_READY) st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer); } @@ -2095,17 +2066,17 @@ if (value == MT_ST_CLEAR_DEFAULT) { STm->default_compression = ST_DONT_TOUCH; printk(KERN_INFO - "st%d: Compression default disabled.\n", dev); + "%s: Compression default disabled.\n", name); } else { if ((value & 0xff00) != 0) { STp->c_algo = (value & 0xff00) >> 8; - printk(KERN_INFO "st%d: Compression algorithm set to 0x%x.\n", - dev, STp->c_algo); + printk(KERN_INFO "%s: Compression algorithm set to 0x%x.\n", + name, STp->c_algo); } if ((value & 0xff) != 0xff) { STm->default_compression = (value & 1 ? ST_YES : ST_NO); - printk(KERN_INFO "st%d: Compression default set to %x\n", - dev, (value & 1)); + printk(KERN_INFO "%s: Compression default set to %x\n", + name, (value & 1)); if (STp->ready == ST_READY) { STp->compression_changed = FALSE; st_compression(STp, (STm->default_compression == ST_YES)); @@ -2217,7 +2188,7 @@ int retval; int mpoffs; /* Offset to mode page start */ unsigned char *b_data = (STp->buffer)->b_data; - DEB( int dev = TAPE_NR(STp->devt); ) + DEB( char *name = tape_name(STp); ) if (STp->ready != ST_READY) return (-EIO); @@ -2225,18 +2196,18 @@ /* Read the current page contents */ retval = read_mode_page(STp, COMPRESSION_PAGE, FALSE); if (retval) { - DEBC(printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n", - dev)); + DEBC(printk(ST_DEB_MSG "%s: Compression mode page not supported.\n", + name)); return (-EIO); } mpoffs = MODE_HEADER_LENGTH + b_data[MH_OFF_BDESCS_LENGTH]; - DEBC(printk(ST_DEB_MSG "st%d: Compression state is %d.\n", dev, + DEBC(printk(ST_DEB_MSG "%s: Compression state is %d.\n", name, (b_data[mpoffs + CP_OFF_DCE_DCC] & DCE_MASK ? 1 : 0))); /* Check if compression can be changed */ if ((b_data[mpoffs + CP_OFF_DCE_DCC] & DCC_MASK) == 0) { - DEBC(printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev)); + DEBC(printk(ST_DEB_MSG "%s: Compression not supported.\n", name)); return (-EIO); } @@ -2254,11 +2225,11 @@ retval = write_mode_page(STp, COMPRESSION_PAGE); if (retval) { - DEBC(printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev)); + DEBC(printk(ST_DEB_MSG "%s: Compression change failed.\n", name)); return (-EIO); } - DEBC(printk(ST_DEB_MSG "st%d: Compression state changed to %d.\n", - dev, state)); + DEBC(printk(ST_DEB_MSG "%s: Compression state changed to %d.\n", + name, state)); STp->compression_changed = TRUE; return 0; @@ -2269,7 +2240,7 @@ static int do_load_unload(Scsi_Tape *STp, struct file *filp, int load_code) { int retval = (-EIO), timeout; - DEB(int dev = TAPE_NR(STp->devt);) + DEB( char *name = tape_name(STp); ) unsigned char cmd[MAX_COMMAND_SIZE]; ST_partstat *STps; Scsi_Request *SRpnt; @@ -2290,8 +2261,8 @@ */ if (load_code >= 1 + MT_ST_HPLOADER_OFFSET && load_code <= 6 + MT_ST_HPLOADER_OFFSET) { - DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2d.\n", - dev, (cmd[4]) ? "" : "un", + DEBC(printk(ST_DEB_MSG "%s: Enhanced %sload slot %2d.\n", + name, (cmd[4]) ? "" : "un", load_code - MT_ST_HPLOADER_OFFSET)); cmd[3] = load_code - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */ } @@ -2304,9 +2275,9 @@ DEBC( if (!load_code) - printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev); + printk(ST_DEB_MSG "%s: Unloading tape.\n", name); else - printk(ST_DEB_MSG "st%d: Loading tape.\n", dev); + printk(ST_DEB_MSG "%s: Loading tape.\n", name); ); SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, @@ -2351,7 +2322,7 @@ ST_partstat *STps; int fileno, blkno, at_sm, undone; int datalen = 0, direction = SCSI_DATA_NONE; - int dev = TAPE_NR(STp->devt); + char *name = tape_name(STp); if (STp->ready != ST_READY) { if (STp->ready == ST_NO_TAPE) @@ -2375,8 +2346,8 @@ cmd[2] = (arg >> 16); cmd[3] = (arg >> 8); cmd[4] = arg; - DEBC(printk(ST_DEB_MSG "st%d: Spacing tape forward over %d filemarks.\n", - dev, cmd[2] * 65536 + cmd[3] * 256 + cmd[4])); + DEBC(printk(ST_DEB_MSG "%s: Spacing tape forward over %d filemarks.\n", + name, cmd[2] * 65536 + cmd[3] * 256 + cmd[4])); if (fileno >= 0) fileno += arg; blkno = 0; @@ -2396,8 +2367,8 @@ ltmp = 0xff000000; ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; printk(ST_DEB_MSG - "st%d: Spacing tape backward over %ld filemarks.\n", - dev, (-ltmp)); + "%s: Spacing tape backward over %ld filemarks.\n", + name, (-ltmp)); ) if (fileno >= 0) fileno -= arg; @@ -2410,7 +2381,7 @@ cmd[2] = (arg >> 16); cmd[3] = (arg >> 8); cmd[4] = arg; - DEBC(printk(ST_DEB_MSG "st%d: Spacing tape forward %d blocks.\n", dev, + DEBC(printk(ST_DEB_MSG "%s: Spacing tape forward %d blocks.\n", name, cmd[2] * 65536 + cmd[3] * 256 + cmd[4])); if (blkno >= 0) blkno += arg; @@ -2428,7 +2399,7 @@ ltmp = 0xff000000; ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; printk(ST_DEB_MSG - "st%d: Spacing tape backward %ld blocks.\n", dev, (-ltmp)); + "%s: Spacing tape backward %ld blocks.\n", name, (-ltmp)); ) if (blkno >= 0) blkno -= arg; @@ -2440,7 +2411,7 @@ cmd[2] = (arg >> 16); cmd[3] = (arg >> 8); cmd[4] = arg; - DEBC(printk(ST_DEB_MSG "st%d: Spacing tape forward %d setmarks.\n", dev, + DEBC(printk(ST_DEB_MSG "%s: Spacing tape forward %d setmarks.\n", name, cmd[2] * 65536 + cmd[3] * 256 + cmd[4])); if (arg != 0) { blkno = fileno = (-1); @@ -2458,8 +2429,8 @@ if (cmd[2] & 0x80) ltmp = 0xff000000; ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; - printk(ST_DEB_MSG "st%d: Spacing tape backward %ld setmarks.\n", - dev, (-ltmp)); + printk(ST_DEB_MSG "%s: Spacing tape backward %ld setmarks.\n", + name, (-ltmp)); ) if (arg != 0) { blkno = fileno = (-1); @@ -2479,10 +2450,10 @@ timeout = STp->timeout; DEBC( if (cmd_in == MTWEOF) - printk(ST_DEB_MSG "st%d: Writing %d filemarks.\n", dev, + printk(ST_DEB_MSG "%s: Writing %d filemarks.\n", name, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); else - printk(ST_DEB_MSG "st%d: Writing %d setmarks.\n", dev, + printk(ST_DEB_MSG "%s: Writing %d setmarks.\n", name, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); ) if (fileno >= 0) @@ -2496,11 +2467,11 @@ cmd[1] = 1; /* Don't wait for completion */ timeout = STp->timeout; } - DEBC(printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev)); + DEBC(printk(ST_DEB_MSG "%s: Rewinding tape.\n", name)); fileno = blkno = at_sm = 0; break; case MTNOP: - DEBC(printk(ST_DEB_MSG "st%d: No op on tape.\n", dev)); + DEBC(printk(ST_DEB_MSG "%s: No op on tape.\n", name)); return 0; /* Should do something ? */ break; case MTRETEN: @@ -2510,7 +2481,7 @@ timeout = STp->timeout; } cmd[4] = 3; - DEBC(printk(ST_DEB_MSG "st%d: Retensioning tape.\n", dev)); + DEBC(printk(ST_DEB_MSG "%s: Retensioning tape.\n", name)); fileno = blkno = at_sm = 0; break; case MTEOM: @@ -2528,8 +2499,8 @@ fileno = (-1); cmd[0] = SPACE; cmd[1] = 3; - DEBC(printk(ST_DEB_MSG "st%d: Spacing to end of recorded medium.\n", - dev)); + DEBC(printk(ST_DEB_MSG "%s: Spacing to end of recorded medium.\n", + name)); blkno = 0; at_sm = 0; break; @@ -2545,7 +2516,7 @@ else timeout = STp->long_timeout * 8; - DEBC(printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev)); + DEBC(printk(ST_DEB_MSG "%s: Erasing tape.\n", name)); fileno = blkno = at_sm = 0; break; case MTSETBLK: /* Set block length */ @@ -2560,7 +2531,7 @@ STp->max_block > 0 && ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block || (arg & MT_ST_BLKSIZE_MASK) > STp->max_block)) { - printk(KERN_WARNING "st%d: Illegal block size.\n", dev); + printk(KERN_WARNING "%s: Illegal block size.\n", name); return (-EINVAL); } cmd[0] = MODE_SELECT; @@ -2596,17 +2567,17 @@ DEBC( if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) printk(ST_DEB_MSG - "st%d: Setting block size to %d bytes.\n", dev, + "%s: Setting block size to %d bytes.\n", name, (STp->buffer)->b_data[9] * 65536 + (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11]); if (cmd_in == MTSETDENSITY || cmd_in == SET_DENS_AND_BLK) printk(ST_DEB_MSG - "st%d: Setting density code to %x.\n", dev, + "%s: Setting density code to %x.\n", name, (STp->buffer)->b_data[4]); if (cmd_in == MTSETDRVBUFFER) printk(ST_DEB_MSG - "st%d: Setting drive buffer code to %d.\n", dev, + "%s: Setting drive buffer code to %d.\n", name, ((STp->buffer)->b_data[2] >> 4) & 7); ) break; @@ -2759,7 +2730,7 @@ int result; unsigned char scmd[MAX_COMMAND_SIZE]; Scsi_Request *SRpnt; - DEB( int dev = TAPE_NR(STp->devt); ) + DEB( char *name = tape_name(STp); ) if (STp->ready != ST_READY) return (-EIO); @@ -2782,7 +2753,7 @@ (STp->device->scsi_level >= SCSI_2 && ((STp->buffer)->b_data[0] & 4) != 0)) { *block = *partition = 0; - DEBC(printk(ST_DEB_MSG "st%d: Can't read tape position.\n", dev)); + DEBC(printk(ST_DEB_MSG "%s: Can't read tape position.\n", name)); result = (-EIO); } else { result = 0; @@ -2801,7 +2772,7 @@ (STp->buffer)->b_data[1] == 0) /* BOP of partition 0 */ STp->ps[0].drv_block = STp->ps[0].drv_file = 0; } - DEBC(printk(ST_DEB_MSG "st%d: Got tape pos. blk %d part %d.\n", dev, + DEBC(printk(ST_DEB_MSG "%s: Got tape pos. blk %d part %d.\n", name, *block, *partition)); } scsi_release_request(SRpnt); @@ -2822,15 +2793,15 @@ int timeout; unsigned char scmd[MAX_COMMAND_SIZE]; Scsi_Request *SRpnt; - DEB( int dev = TAPE_NR(STp->devt); ) + DEB( char *name = tape_name(STp); ) if (STp->ready != ST_READY) return (-EIO); timeout = STp->long_timeout; STps = &(STp->ps[STp->partition]); - DEBC(printk(ST_DEB_MSG "st%d: Setting block to %d and partition to %d.\n", - dev, block, partition)); + DEBC(printk(ST_DEB_MSG "%s: Setting block to %d and partition to %d.\n", + name, block, partition)); DEB(if (partition < 0) return (-EIO); ) @@ -2845,8 +2816,8 @@ STps->last_block_valid = TRUE; STps->last_block_visited = blk; DEBC(printk(ST_DEB_MSG - "st%d: Visited block %d for partition %d saved.\n", - dev, blk, STp->partition)); + "%s: Visited block %d for partition %d saved.\n", + name, blk, STp->partition)); } } @@ -2869,8 +2840,8 @@ scmd[1] |= 2; scmd[8] = partition; DEBC(printk(ST_DEB_MSG - "st%d: Trying to change partition from %d to %d\n", - dev, STp->partition, partition)); + "%s: Trying to change partition from %d to %d\n", + name, STp->partition, partition)); } } if (STp->immediate) { @@ -2961,7 +2932,7 @@ static int nbr_partitions(Scsi_Tape *STp) { int result; - DEB( int dev = TAPE_NR(STp->devt) ); + DEB( char *name = tape_name(STp); ) if (STp->ready != ST_READY) return (-EIO); @@ -2969,13 +2940,13 @@ result = read_mode_page(STp, PART_PAGE, TRUE); if (result) { - DEBC(printk(ST_DEB_MSG "st%d: Can't read medium partition page.\n", - dev)); + DEBC(printk(ST_DEB_MSG "%s: Can't read medium partition page.\n", + name)); result = (-EIO); } else { result = (STp->buffer)->b_data[MODE_HEADER_LENGTH + PP_OFF_NBR_ADD_PARTS] + 1; - DEBC(printk(ST_DEB_MSG "st%d: Number of partitions %d.\n", dev, result)); + DEBC(printk(ST_DEB_MSG "%s: Number of partitions %d.\n", name, result)); } return result; @@ -3003,20 +2974,21 @@ */ static int partition_tape(Scsi_Tape *STp, int size) { - int dev = TAPE_NR(STp->devt), result; + char *name = tape_name(STp); + int result; int pgo, psd_cnt, psdo; unsigned char *bp; result = read_mode_page(STp, PART_PAGE, FALSE); if (result) { - DEBC(printk(ST_DEB_MSG "st%d: Can't read partition mode page.\n", dev)); + DEBC(printk(ST_DEB_MSG "%s: Can't read partition mode page.\n", name)); return result; } /* The mode page is in the buffer. Let's modify it and write it. */ bp = (STp->buffer)->b_data; pgo = MODE_HEADER_LENGTH + bp[MH_OFF_BDESCS_LENGTH]; - DEBC(printk(ST_DEB_MSG "st%d: Partition page length is %d bytes.\n", - dev, bp[pgo + MP_OFF_PAGE_LENGTH] + 2)); + DEBC(printk(ST_DEB_MSG "%s: Partition page length is %d bytes.\n", + name, bp[pgo + MP_OFF_PAGE_LENGTH] + 2)); psd_cnt = (bp[pgo + MP_OFF_PAGE_LENGTH] + 2 - PART_PAGE_FIXED_LENGTH) / 2; psdo = pgo + PART_PAGE_FIXED_LENGTH; @@ -3026,7 +2998,7 @@ } memset(bp + psdo, 0, bp[pgo + PP_OFF_NBR_ADD_PARTS] * 2); - DEBC(printk("st%d: psd_cnt %d, max.parts %d, nbr_parts %d\n", dev, + DEBC(printk("%s: psd_cnt %d, max.parts %d, nbr_parts %d\n", name, psd_cnt, bp[pgo + PP_OFF_MAX_ADD_PARTS], bp[pgo + PP_OFF_NBR_ADD_PARTS])); @@ -3034,8 +3006,8 @@ bp[pgo + PP_OFF_NBR_ADD_PARTS] = 0; if (psd_cnt <= bp[pgo + PP_OFF_MAX_ADD_PARTS]) bp[pgo + MP_OFF_PAGE_LENGTH] = 6; - DEBC(printk(ST_DEB_MSG "st%d: Formatting tape with one partition.\n", - dev)); + DEBC(printk(ST_DEB_MSG "%s: Formatting tape with one partition.\n", + name)); } else { bp[psdo] = (size >> 8) & 0xff; bp[psdo + 1] = size & 0xff; @@ -3043,8 +3015,8 @@ if (bp[pgo + MP_OFF_PAGE_LENGTH] < 8) bp[pgo + MP_OFF_PAGE_LENGTH] = 8; DEBC(printk(ST_DEB_MSG - "st%d: Formatting tape with two partitions (1 = %d MB).\n", - dev, size)); + "%s: Formatting tape with two partitions (1 = %d MB).\n", + name, size)); } bp[pgo + PP_OFF_PART_UNITS] = 0; bp[pgo + PP_OFF_RESERVED] = 0; @@ -3052,7 +3024,7 @@ result = write_mode_page(STp, PART_PAGE); if (result) { - printk(KERN_INFO "st%d: Partitioning of tape failed.\n", dev); + printk(KERN_INFO "%s: Partitioning of tape failed.\n", name); result = (-EIO); } @@ -3068,21 +3040,17 @@ int i, cmd_nr, cmd_type, bt; int retval = 0; unsigned int blk; - Scsi_Tape *STp; + Scsi_Tape *STp = file->private_data; ST_mode *STm; ST_partstat *STps; - int dev = TAPE_NR(inode->i_rdev); - - read_lock(&st_dev_arr_lock); - STp = scsi_tapes[dev]; - read_unlock(&st_dev_arr_lock); + char *name = tape_name(STp); if (down_interruptible(&STp->lock)) return -ERESTARTSYS; DEB( if (debugging && !STp->in_use) { - printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev); + printk(ST_DEB_MSG "%s: Incorrect device.\n", name); retval = (-EIO); goto out; } ) /* end DEB */ @@ -3119,7 +3087,7 @@ if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) { printk(KERN_WARNING - "st%d: MTSETDRVBUFFER only allowed for root.\n", dev); + "%s: MTSETDRVBUFFER only allowed for root.\n", name); retval = (-EPERM); goto out; } @@ -3677,6 +3645,7 @@ static int st_attach(Scsi_Device * SDp) { + struct gendisk *disk; Scsi_Tape *tpnt; ST_mode *STm; ST_partstat *STps; @@ -3704,6 +3673,12 @@ return 1; } + disk = alloc_disk(1); + if (!disk) { + printk(KERN_ERR "st: out of memory. Device not attached.\n"); + return 1; + } + write_lock(&st_dev_arr_lock); if (st_template.nr_dev >= st_template.dev_max) { Scsi_Tape **tmp_da; @@ -3718,6 +3693,7 @@ write_unlock(&st_dev_arr_lock); printk(KERN_ERR "st: Too many tape devices (max. %d).\n", ST_MAX_TAPES); + put_disk(disk); return 1; } @@ -3731,6 +3707,7 @@ SDp->attached--; write_unlock(&st_dev_arr_lock); printk(KERN_ERR "st: Can't extend device array.\n"); + put_disk(disk); return 1; } @@ -3756,9 +3733,14 @@ SDp->attached--; write_unlock(&st_dev_arr_lock); printk(KERN_ERR "st: Can't allocate device descriptor.\n"); + put_disk(disk); return 1; } memset(tpnt, 0, sizeof(Scsi_Tape)); + tpnt->disk = disk; + sprintf(disk->disk_name, "st%d", i); + disk->private_data = &tpnt->driver; + tpnt->driver = &st_template; scsi_tapes[i] = tpnt; dev_num = i; @@ -3770,8 +3752,7 @@ tpnt->buffer = buffer; - tpnt->inited = 0; - tpnt->devt = mk_kdev(SCSI_TAPE_MAJOR, i); + tpnt->inited = 0; tpnt->dirty = 0; tpnt->in_use = 0; tpnt->drv_buffer = 1; /* Try buffering if no mode sense */ @@ -3890,10 +3871,10 @@ devfs_register_tape (tpnt->de_r[0]); printk(KERN_WARNING - "Attached scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n", - dev_num, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); - printk(KERN_WARNING "st%d: try direct i/o: %s, max page reachable by HBA %lu\n", - dev_num, tpnt->try_dio ? "yes" : "no", tpnt->max_pfn); + "Attached scsi tape %s at scsi%d, channel %d, id %d, lun %d\n", + tape_name(tpnt), SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); + printk(KERN_WARNING "%s: try direct i/o: %s, max page reachable by HBA %lu\n", + tape_name(tpnt), tpnt->try_dio ? "yes" : "no", tpnt->max_pfn); return 0; }; @@ -3945,6 +3926,7 @@ normalize_buffer(tpnt->buffer); kfree(tpnt->buffer); } + put_disk(tpnt->disk); kfree(tpnt); return; } @@ -3981,8 +3963,10 @@ unregister_chrdev(SCSI_TAPE_MAJOR, "st"); if (scsi_tapes != NULL) { for (i=0; i < st_template.dev_max; ++i) - if (scsi_tapes[i]) + if (scsi_tapes[i]) { + put_disk(scsi_tapes[i]->disk); kfree(scsi_tapes[i]); + } kfree(scsi_tapes); } st_template.dev_max = 0; diff -Nru a/drivers/scsi/st.h b/drivers/scsi/st.h --- a/drivers/scsi/st.h Mon Nov 4 14:31:02 2002 +++ b/drivers/scsi/st.h Mon Nov 4 14:31:02 2002 @@ -71,7 +71,7 @@ /* The tape drive descriptor */ typedef struct { - kdev_t devt; + struct Scsi_Device_Template *driver; Scsi_Device *device; struct semaphore lock; /* For serialization */ struct completion wait; /* For SCSI commands */ @@ -147,6 +147,7 @@ unsigned char last_cmnd[6]; unsigned char last_sense[16]; #endif + struct gendisk *disk; } Scsi_Tape; /* Bit masks for use_pf */ diff -Nru a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c --- a/drivers/scsi/sun3_NCR5380.c Mon Nov 4 14:31:00 2002 +++ b/drivers/scsi/sun3_NCR5380.c Mon Nov 4 14:31:00 2002 @@ -270,6 +270,9 @@ #define HOSTNO instance->host_no #define H_NO(cmd) (cmd)->host->host_no +#define SGADDR(buffer) (void *)(((unsigned long)page_address((buffer)->page)) + \ + (buffer)->offset) + #ifdef SUPPORT_TAGS /* @@ -476,10 +479,10 @@ for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1; cmd->SCp.buffers_residual && - virt_to_phys(cmd->SCp.buffer[1].address) == endaddr; ) { + virt_to_phys(SGADDR(&(cmd->SCp.buffer[1]))) == endaddr; ) { MER_PRINTK("VTOP(%p) == %08lx -> merging\n", - cmd->SCp.buffer[1].address, endaddr); + SGADDR(&(cmd->SCp.buffer[1])), endaddr); #if (NDEBUG & NDEBUG_MERGING) ++cnt; #endif @@ -514,12 +517,13 @@ if (cmd->use_sg) { cmd->SCp.buffer = (struct scatterlist *) cmd->buffer; cmd->SCp.buffers_residual = cmd->use_sg - 1; - cmd->SCp.ptr = (char *) cmd->SCp.buffer->address; + cmd->SCp.ptr = (char *) SGADDR(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; + /* ++roman: Try to merge some scatter-buffers if they are at * contiguous physical addresses. */ - merge_contiguous_buffers( cmd ); +// merge_contiguous_buffers( cmd ); } else { cmd->SCp.buffer = NULL; cmd->SCp.buffers_residual = 0; @@ -613,11 +617,11 @@ status = NCR5380_read(STATUS_REG); if (!(status & SR_REQ)) - printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO); + printk("scsi%d: REQ not asserted, phase unknown.\n", HOSTNO); else { for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i); - printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name); + printk("scsi%d: phase %s\n", HOSTNO, phases[i].name); } } @@ -751,11 +755,8 @@ static char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length); -#ifndef NCR5380_proc_info -static -#endif -int NCR5380_proc_info (char *buffer, char **start, off_t offset, - int length, int hostno, int inout) +static int NCR5380_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout) { char *pos = buffer; struct Scsi_Host *instance; @@ -910,10 +911,7 @@ */ /* Only make static if a wrapper function is used */ -#ifndef NCR5380_queue_command -static -#endif -int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { SETUP_HOSTDATA(cmd->host); Scsi_Cmnd *tmp; @@ -1211,7 +1209,7 @@ HOSTNO, NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG)); - if((sun3scsi_dma_finish(hostdata->connected->request->cmd))) { + if((sun3scsi_dma_finish(rq_data_dir(hostdata->connected->request)))) { printk("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n", HOSTNO); printk("please e-mail sammy@sammy.net with a description of how this\n"); printk("error was produced.\n"); @@ -1315,11 +1313,14 @@ { /* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */ if (basr & BASR_PHASE_MATCH) - printk(KERN_NOTICE "scsi%d: unknown interrupt, " + INT_PRINTK("scsi%d: unknown interrupt, " "BASR 0x%x, MR 0x%x, SR 0x%x\n", HOSTNO, basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); +#ifdef SUN3_SCSI_VME + dregs->csr |= CSR_DMA_ENABLE; +#endif } } /* if !(SELECTION || PARITY) */ } /* BASR & IRQ */ @@ -1329,6 +1330,9 @@ "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); +#ifdef SUN3_SCSI_VME + dregs->csr |= CSR_DMA_ENABLE; +#endif } if (!done) { @@ -1691,7 +1695,9 @@ #ifndef SUPPORT_TAGS hostdata->busy[cmd->target] |= (1 << cmd->lun); #endif - +#ifdef SUN3_SCSI_VME + dregs->csr |= CSR_INTR; +#endif initialize_SCp(cmd); @@ -1918,19 +1924,18 @@ printk("scsi%d: transfer_dma without setup!\n", HOSTNO); BUG(); } - hostdata->dma_len = c; DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n", HOSTNO, (p & SR_IO) ? "reading" : "writing", - c, (p & SR_IO) ? "to" : "from", d); + c, (p & SR_IO) ? "to" : "from", *data); /* netbsd turns off ints here, why not be safe and do it too */ save_flags(flags); cli(); /* send start chain */ - sun3_udc_write(UDC_CHN_START, UDC_CSR); + sun3scsi_dma_start(c, *data); if (p & SR_IO) { NCR5380_write(TARGET_COMMAND_REG, 1); @@ -1946,6 +1951,10 @@ NCR5380_write(START_DMA_SEND_REG, 0); } +#ifdef SUN3_SCSI_VME + dregs->csr |= CSR_DMA_ENABLE; +#endif + restore_flags(flags); sun3_dma_active = 1; @@ -1984,6 +1993,10 @@ unsigned char phase, tmp, extended_msg[10], old_phase=0xff; Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; +#ifdef SUN3_SCSI_VME + dregs->csr |= CSR_INTR; +#endif + while (1) { tmp = NCR5380_read(STATUS_REG); /* We only have a valid SCSI phase when REQ is asserted */ @@ -2000,7 +2013,7 @@ if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { count = cmd->SCp.buffer->length; - d = cmd->SCp.buffer->address; + d = SGADDR(cmd->SCp.buffer); } else { count = cmd->SCp.this_residual; d = cmd->SCp.ptr; @@ -2010,13 +2023,16 @@ if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done != cmd)) { - if((cmd->request->cmd == 0) || (cmd->request->cmd == 1)) { + if(cmd->request->flags & REQ_CMD) { sun3scsi_dma_setup(d, count, - cmd->request->cmd); + rq_data_dir(cmd->request)); sun3_dma_setup_done = cmd; } } #endif +#ifdef SUN3_SCSI_VME + dregs->csr |= CSR_INTR; +#endif } @@ -2052,7 +2068,7 @@ ++cmd->SCp.buffer; --cmd->SCp.buffers_residual; cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = cmd->SCp.buffer->address; + cmd->SCp.ptr = SGADDR(cmd->SCp.buffer); /* ++roman: Try to merge some scatter-buffers if * they are at contiguous physical addresses. @@ -2132,7 +2148,7 @@ NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */ NCR5380_transfer_pio(instance, &phase, &len, &data); cmd->SCp.Message = tmp; - + switch (tmp) { /* * Linking lets us reduce the time required to get the @@ -2338,6 +2354,9 @@ /* Wait for bus free to avoid nasty timeouts */ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) barrier(); +#ifdef SUN3_SCSI_VME + dregs->csr |= CSR_DMA_ENABLE; +#endif return; /* * The SCSI data pointer is *IMPLICITLY* saved on a disconnect @@ -2607,24 +2626,22 @@ /* engage dma setup for the command we just saw */ { void *d; - unsigned long count; + unsigned long count; - if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) { - count = tmp->SCp.buffer->length; - d = tmp->SCp.buffer->address; - } else { - count = tmp->SCp.this_residual; - d = tmp->SCp.ptr; - } -#ifdef REAL_DMA - /* setup this command for dma if not already */ - if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done - != tmp)) - { - sun3scsi_dma_setup(d, count, - tmp->request->cmd); - sun3_dma_setup_done = tmp; - } + if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) { + count = tmp->SCp.buffer->length; + d = SGADDR(tmp->SCp.buffer); + } else { + count = tmp->SCp.this_residual; + d = tmp->SCp.ptr; + } +#ifdef REAL_DMA + /* setup this command for dma if not already */ + if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done != tmp)) + { + sun3scsi_dma_setup(d, count, rq_data_dir(tmp->request)); + sun3_dma_setup_done = tmp; + } #endif } #endif @@ -2675,10 +2692,7 @@ * called where the loop started in NCR5380_main(). */ -#ifndef NCR5380_abort -static -#endif -int NCR5380_abort (Scsi_Cmnd *cmd) +static int NCR5380_abort (Scsi_Cmnd *cmd) { struct Scsi_Host *instance = cmd->host; SETUP_HOSTDATA(instance); @@ -2872,7 +2886,7 @@ * */ -int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) +static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) { SETUP_HOSTDATA(cmd->host); int i; diff -Nru a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c --- a/drivers/scsi/sun3_scsi.c Mon Nov 4 14:31:00 2002 +++ b/drivers/scsi/sun3_scsi.c Mon Nov 4 14:31:00 2002 @@ -1,7 +1,7 @@ /* * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl) * - * Sun3 DMA routines added by Sam Creasey (sammy@oh.verio.com) + * Sun3 DMA routines added by Sam Creasey (sammy@sammy.net) * * Adapted from mac_scsinew.c: */ @@ -79,8 +79,10 @@ #include "sun3_scsi.h" #include "NCR5380.h" +/* #define OLDDMA */ + #define USE_WRAPPER -#define RESET_BOOT +/*#define RESET_BOOT */ #define DRIVER_SETUP #define NDEBUG 0 @@ -93,7 +95,7 @@ #undef DRIVER_SETUP #endif -#undef SUPPORT_TAGS +/* #define SUPPORT_TAGS */ #define ENABLE_IRQ() enable_irq( IRQ_SUN3_SCSI ); @@ -103,12 +105,17 @@ static inline void sun3scsi_write(int reg, int value); static int setup_can_queue = -1; +MODULE_PARM(setup_can_queue, "i"); static int setup_cmd_per_lun = -1; +MODULE_PARM(setup_cmd_per_lun, "i"); static int setup_sg_tablesize = -1; +MODULE_PARM(setup_sg_tablesize, "i"); #ifdef SUPPORT_TAGS static int setup_use_tagged_queuing = -1; +MODULE_PARM(setup_use_tagged_queuing, "i"); #endif static int setup_hostid = -1; +MODULE_PARM(setup_hostid, "i"); static Scsi_Cmnd *sun3_dma_setup_done = NULL; @@ -125,7 +132,9 @@ static volatile unsigned char *sun3_scsi_regp; static volatile struct sun3_dma_regs *dregs; +#ifdef OLDDMA static unsigned char *dmabuf = NULL; /* dma memory buffer */ +#endif static struct sun3_udc_regs *udc_regs = NULL; static unsigned char *sun3_dma_orig_addr = NULL; static unsigned long sun3_dma_orig_count = 0; @@ -187,8 +196,7 @@ int sun3scsi_detect(Scsi_Host_Template * tpnt) { - unsigned long ioaddr, iopte; - int count = 0; + unsigned long ioaddr; static int called = 0; struct Scsi_Host *instance; @@ -222,28 +230,9 @@ tpnt->this_id = 7; } - /* Taken from Sammy's lance driver: */ - /* IOBASE_SUN3_SCSI can be found within the IO pmeg with some effort */ - for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 + SUN3_PMEG_SIZE); - ioaddr += SUN3_PTE_SIZE) { - - iopte = sun3_get_pte(ioaddr); - if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */ - continue; - - if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) == - IOBASE_SUN3_SCSI) { - count = 1; - break; - } - } - - if(!count) { - printk("No Sun3 NCR5380 found!\n"); - return 0; - } - + ioaddr = (unsigned long)ioremap(IOBASE_SUN3_SCSI, PAGE_SIZE); sun3_scsi_regp = (unsigned char *)ioaddr; + dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8); if((udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs))) @@ -259,7 +248,7 @@ #endif #ifdef SUPPORT_TAGS if (setup_use_tagged_queuing < 0) - setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING; + setup_use_tagged_queuing = USE_TAGGED_QUEUING; #endif instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); @@ -309,16 +298,25 @@ dregs->fifo_count = 0; called = 1; + +#ifdef RESET_BOOT + sun3_scsi_reset_boot(instance); +#endif + return 1; } +#ifdef MODULE int sun3scsi_release (struct Scsi_Host *shpnt) { if (shpnt->irq != IRQ_NONE) free_irq (shpnt->irq, NULL); + iounmap(sun3_scsi_regp); + return 0; } +#endif #ifdef RESET_BOOT /* @@ -340,7 +338,7 @@ printk( "Sun3 SCSI: resetting the SCSI bus..." ); /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */ - sun3_disable_irq( IRQ_SUN3_SCSI ); +// sun3_disable_irq( IRQ_SUN3_SCSI ); /* get in phase */ NCR5380_write( TARGET_COMMAND_REG, @@ -360,7 +358,7 @@ barrier(); /* switch on SCSI IRQ again */ - sun3_enable_irq( IRQ_SUN3_SCSI ); +// sun3_enable_irq( IRQ_SUN3_SCSI ); printk( " done\n" ); } @@ -426,8 +424,12 @@ #else void *addr; + if(sun3_dma_orig_addr != NULL) + dvma_unmap(sun3_dma_orig_addr); + // addr = sun3_dvma_page((unsigned long)data, (unsigned long)dmabuf); addr = (void *)dvma_map((unsigned long) data, count); + sun3_dma_orig_addr = addr; sun3_dma_orig_count = count; #endif @@ -453,7 +455,6 @@ dregs->csr &= ~CSR_FIFO; dregs->csr |= CSR_FIFO; - if(dregs->fifo_count != count) { printk("scsi%d: fifo_mismatch %04x not %04x\n", default_instance->host_no, dregs->fifo_count, @@ -518,12 +519,20 @@ static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd, int write_flag) { - if((cmd->request->cmd == 0) || (cmd->request->cmd == 1)) + if(cmd->request->flags & REQ_CMD) return wanted; else return 0; } +static inline int sun3scsi_dma_start(unsigned long count, unsigned char *data) +{ + + sun3_udc_write(UDC_CHN_START, UDC_CSR); + + return 0; +} + /* clean up after our dma is done */ static int sun3scsi_dma_finish(int write_flag) { @@ -532,7 +541,7 @@ int ret = 0; sun3_dma_active = 0; - +#if 1 // check to empty the fifo on a read if(!write_flag) { int tmo = 200000; /* 2 sec */ @@ -541,13 +550,15 @@ if(dregs->csr & CSR_FIFO_EMPTY) break; - if(--tmo <= 0) + if(--tmo <= 0) { + printk("sun3scsi: fifo failed to empty!\n"); return 1; - + } udelay(10); } } +#endif count = sun3scsi_dma_count(default_instance); #ifdef OLDDMA @@ -587,6 +598,7 @@ } dvma_unmap(sun3_dma_orig_addr); + sun3_dma_orig_addr = NULL; #endif sun3_udc_write(UDC_RESET, UDC_CSR); dregs->fifo_count = 0; diff -Nru a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h --- a/drivers/scsi/sun3_scsi.h Mon Nov 4 14:31:00 2002 +++ b/drivers/scsi/sun3_scsi.h Mon Nov 4 14:31:00 2002 @@ -1,7 +1,7 @@ /* * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl) * - * Sun3 DMA additions by Sam Creasey (sammy@oh.verio.com) + * Sun3 DMA additions by Sam Creasey (sammy@sammy.net) * * Adapted from mac_scsinew.h: */ @@ -36,6 +36,11 @@ #ifndef SUN3_NCR5380_H #define SUN3_NCR5380_H +#ifndef NULL +#define NULL 0 +#endif + + #define SUN3SCSI_PUBLIC_RELEASE 1 /* @@ -45,17 +50,19 @@ #define IRQ_SUN3_SCSI 2 #define IOBASE_SUN3_SCSI 0x00140000 -int sun3scsi_abort (Scsi_Cmnd *); -int sun3scsi_detect (Scsi_Host_Template *); -int sun3scsi_release (struct Scsi_Host *); -const char *sun3scsi_info (struct Scsi_Host *); -int sun3scsi_reset(Scsi_Cmnd *, unsigned int); -int sun3scsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -int sun3scsi_proc_info (char *buffer, char **start, off_t offset, - int length, int hostno, int inout); +#define IOBASE_SUN3_VMESCSI 0xff200000 -#ifndef NULL -#define NULL 0 +static int sun3scsi_abort (Scsi_Cmnd *); +static int sun3scsi_detect (Scsi_Host_Template *); +static const char *sun3scsi_info (struct Scsi_Host *); +static int sun3scsi_reset(Scsi_Cmnd *, unsigned int); +static int sun3scsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +static int sun3scsi_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout); +#ifdef MODULE +static int sun3scsi_release (struct Scsi_Host *); +#else +#define sun3scsi_release NULL #endif #ifndef CMD_PER_LUN @@ -70,26 +77,36 @@ #define SG_TABLESIZE SG_NONE #endif +#ifndef MAX_TAGS +#define MAX_TAGS 32 +#endif + #ifndef USE_TAGGED_QUEUING -#define USE_TAGGED_QUEUING 0 +#define USE_TAGGED_QUEUING 1 #endif #include +#ifdef SUN3_SCSI_VME +#define SUN3_SCSI_NAME "Sun3 NCR5380 VME SCSI" +#else +#define SUN3_SCSI_NAME "Sun3 NCR5380 SCSI" +#endif + #define SUN3_NCR5380 { \ -name: "Sun3 NCR5380 SCSI", \ -detect: sun3scsi_detect, \ -release: sun3scsi_release, /* Release */ \ -info: sun3scsi_info, \ -queuecommand: sun3scsi_queue_command, \ -abort: sun3scsi_abort, \ -reset: sun3scsi_reset, \ -can_queue: CAN_QUEUE, /* can queue */ \ -this_id: 7, /* id */ \ -sg_tablesize: SG_ALL, /* sg_tablesize */ \ -cmd_per_lun: CMD_PER_LUN, /* cmd per lun */ \ -unchecked_isa_dma: 0, /* unchecked_isa_dma */ \ -use_clustering: DISABLE_CLUSTERING \ +.name = SUN3_SCSI_NAME, \ +.detect = sun3scsi_detect, \ +.release = sun3scsi_release, /* Release */ \ +.info = sun3scsi_info, \ +.queuecommand = sun3scsi_queue_command, \ +.abort = sun3scsi_abort, \ +.reset = sun3scsi_reset, \ +.can_queue = CAN_QUEUE, /* can queue */ \ +.this_id = 7, /* id */ \ +.sg_tablesize = SG_TABLESIZE, /* sg_tablesize */ \ +.cmd_per_lun = CMD_PER_LUN, /* cmd per lun */ \ +.unchecked_isa_dma = 0, /* unchecked_isa_dma */ \ +.use_clustering = DISABLE_CLUSTERING \ } #ifndef HOSTS_C @@ -124,13 +141,20 @@ /* additional registers - mainly DMA control regs */ /* these start at regbase + 8 -- directly after the NCR regs */ struct sun3_dma_regs { - unsigned short vmeregs[4]; /* unimpl vme stuff */ - unsigned short udc_data; /* udc dma data reg */ - unsigned short udc_addr; /* uda dma addr reg */ + unsigned short dma_addr_hi; /* vme only */ + unsigned short dma_addr_lo; /* vme only */ + unsigned short dma_count_hi; /* vme only */ + unsigned short dma_count_lo; /* vme only */ + unsigned short udc_data; /* udc dma data reg (obio only) */ + unsigned short udc_addr; /* uda dma addr reg (obio only) */ unsigned short fifo_data; /* fifo data reg, holds extra byte on odd dma reads */ unsigned short fifo_count; unsigned short csr; /* control/status reg */ + unsigned short bpack_hi; /* vme only */ + unsigned short bpack_lo; /* vme only */ + unsigned short ivect; /* vme only */ + unsigned short fifo_count_hi; /* vme only */ }; /* ucd chip specific regs - live in dvma space */ @@ -179,11 +203,21 @@ #define CSR_SDB_INT 0x200 /* sbc interrupt pending */ #define CSR_DMA_INT 0x100 /* dma interrupt pending */ +#define CSR_LEFT 0xc0 +#define CSR_LEFT_3 0xc0 +#define CSR_LEFT_2 0x80 +#define CSR_LEFT_1 0x40 +#define CSR_PACK_ENABLE 0x20 + +#define CSR_DMA_ENABLE 0x10 + #define CSR_SEND 0x8 /* 1 = send 0 = recv */ #define CSR_FIFO 0x2 /* reset fifo */ #define CSR_INTR 0x4 /* interrupt enable */ #define CSR_SCSI 0x1 +#define VME_DATA24 0x3d00 + // debugging printk's, taken from atari_scsi.h /* Debugging printk definitions: * @@ -364,8 +398,6 @@ #define NCR_PRINT_STATUS(mask) \ ((NDEBUG & (mask)) ? NCR5380_print_status(instance) : (void)0) - -#define NDEBUG_ANY 0xffffffff diff -Nru a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/sun3_scsi_vme.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,567 @@ +/* + * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl) + * + * Sun3 DMA routines added by Sam Creasey (sammy@sammy.net) + * + * VME support added by Sam Creasey + * + * Adapted from sun3_scsi.c -- see there for other headers + * + * TODO: modify this driver to support multiple Sun3 SCSI VME boards + * + */ + +#define AUTOSENSE + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#define SUN3_SCSI_VME + +#undef SUN3_SCSI_DEBUG + +/* dma on! */ +#define REAL_DMA + +#include "scsi.h" +#include "hosts.h" +#include "sun3_scsi.h" +#include "NCR5380.h" + +extern int sun3_map_test(unsigned long, char *); + +#define USE_WRAPPER +/*#define RESET_BOOT */ +#define DRIVER_SETUP + +#define NDEBUG 0 + +/* + * BUG can be used to trigger a strange code-size related hang on 2.1 kernels + */ +#ifdef BUG +#undef RESET_BOOT +#undef DRIVER_SETUP +#endif + +/* #define SUPPORT_TAGS */ + +//#define ENABLE_IRQ() enable_irq( SUN3_VEC_VMESCSI0 ); +#define ENABLE_IRQ() + + +static void scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp); +static inline unsigned char sun3scsi_read(int reg); +static inline void sun3scsi_write(int reg, int value); + +static int setup_can_queue = -1; +MODULE_PARM(setup_can_queue, "i"); +static int setup_cmd_per_lun = -1; +MODULE_PARM(setup_cmd_per_lun, "i"); +static int setup_sg_tablesize = -1; +MODULE_PARM(setup_sg_tablesize, "i"); +#ifdef SUPPORT_TAGS +static int setup_use_tagged_queuing = -1; +MODULE_PARM(setup_use_tagged_queuing, "i"); +#endif +static int setup_hostid = -1; +MODULE_PARM(setup_hostid, "i"); + +static Scsi_Cmnd *sun3_dma_setup_done = NULL; + +#define AFTER_RESET_DELAY (HZ/2) + +/* ms to wait after hitting dma regs */ +#define SUN3_DMA_DELAY 10 + +/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */ +#define SUN3_DVMA_BUFSIZE 0xe000 + +/* minimum number of bytes to do dma on */ +#define SUN3_DMA_MINSIZE 128 + +static volatile unsigned char *sun3_scsi_regp; +static volatile struct sun3_dma_regs *dregs; +#ifdef OLDDMA +static unsigned char *dmabuf = NULL; /* dma memory buffer */ +#endif +static unsigned char *sun3_dma_orig_addr = NULL; +static unsigned long sun3_dma_orig_count = 0; +static int sun3_dma_active = 0; +static unsigned long last_residual = 0; + +/* + * NCR 5380 register access functions + */ + +static inline unsigned char sun3scsi_read(int reg) +{ + return( sun3_scsi_regp[reg] ); +} + +static inline void sun3scsi_write(int reg, int value) +{ + sun3_scsi_regp[reg] = value; +} + +/* + * XXX: status debug + */ +static struct Scsi_Host *default_instance; + +/* + * Function : int sun3scsi_detect(Scsi_Host_Template * tpnt) + * + * Purpose : initializes mac NCR5380 driver based on the + * command line / compile time port and irq definitions. + * + * Inputs : tpnt - template for this SCSI adapter. + * + * Returns : 1 if a host adapter was found, 0 if not. + * + */ + +static int sun3scsi_detect(Scsi_Host_Template * tpnt) +{ + unsigned long ioaddr, irq; + static int called = 0; + struct Scsi_Host *instance; + int i; + unsigned long addrs[3] = { IOBASE_SUN3_VMESCSI, + IOBASE_SUN3_VMESCSI + 0x4000, + 0 }; + unsigned long vecs[3] = { SUN3_VEC_VMESCSI0, + SUN3_VEC_VMESCSI1, + 0 }; + /* check that this machine has an onboard 5380 */ + switch(idprom->id_machtype) { + case SM_SUN3|SM_3_160: + case SM_SUN3|SM_3_260: + break; + + default: + return 0; + } + + if(called) + return 0; + + tpnt->proc_name = "Sun3 5380 VME SCSI"; + + /* setup variables */ + tpnt->can_queue = + (setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE; + tpnt->cmd_per_lun = + (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN; + tpnt->sg_tablesize = + (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE; + + if (setup_hostid >= 0) + tpnt->this_id = setup_hostid; + else { + /* use 7 as default */ + tpnt->this_id = 7; + } + + ioaddr = 0; + for(i = 0; addrs[i] != 0; i++) { + unsigned char x; + + ioaddr = (unsigned long)sun3_ioremap(addrs[i], PAGE_SIZE, + SUN3_PAGE_TYPE_VME16); + irq = vecs[i]; + sun3_scsi_regp = (unsigned char *)ioaddr; + + dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8); + + if(sun3_map_test((unsigned long)dregs, &x)) { + unsigned short oldcsr; + + oldcsr = dregs->csr; + dregs->csr = 0; + udelay(SUN3_DMA_DELAY); + if(dregs->csr == 0x1400) + break; + + dregs->csr = oldcsr; + } + + iounmap((void *)ioaddr); + ioaddr = 0; + } + + if(!ioaddr) + return 0; + +#ifdef SUPPORT_TAGS + if (setup_use_tagged_queuing < 0) + setup_use_tagged_queuing = USE_TAGGED_QUEUING; +#endif + + instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); + if(instance == NULL) + return 0; + + default_instance = instance; + + instance->io_port = (unsigned long) ioaddr; + instance->irq = irq; + + NCR5380_init(instance, 0); + + instance->n_io_port = 32; + + ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0; + + if (request_irq(instance->irq, scsi_sun3_intr, + 0, "Sun3SCSI-5380VME", NULL)) { +#ifndef REAL_DMA + printk("scsi%d: IRQ%d not free, interrupts disabled\n", + instance->host_no, instance->irq); + instance->irq = IRQ_NONE; +#else + printk("scsi%d: IRQ%d not free, bailing out\n", + instance->host_no, instance->irq); + return 0; +#endif + } + + printk("scsi%d: Sun3 5380 VME at port %lX irq", instance->host_no, instance->io_port); + if (instance->irq == IRQ_NONE) + printk ("s disabled"); + else + printk (" %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", + instance->can_queue, instance->cmd_per_lun, + SUN3SCSI_PUBLIC_RELEASE); + printk("\nscsi%d:", instance->host_no); + NCR5380_print_options(instance); + printk("\n"); + + dregs->csr = 0; + udelay(SUN3_DMA_DELAY); + dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR; + udelay(SUN3_DMA_DELAY); + dregs->fifo_count = 0; + dregs->fifo_count_hi = 0; + dregs->dma_addr_hi = 0; + dregs->dma_addr_lo = 0; + dregs->dma_count_hi = 0; + dregs->dma_count_lo = 0; + + dregs->ivect = VME_DATA24 | (instance->irq & 0xff); + + called = 1; + +#ifdef RESET_BOOT + sun3_scsi_reset_boot(instance); +#endif + + return 1; +} + +#ifdef MODULE +int sun3scsi_release (struct Scsi_Host *shpnt) +{ + if (shpnt->irq != IRQ_NONE) + free_irq (shpnt->irq, NULL); + + iounmap(sun3_scsi_regp); + + return 0; +} +#endif + +#ifdef RESET_BOOT +/* + * Our 'bus reset on boot' function + */ + +static void sun3_scsi_reset_boot(struct Scsi_Host *instance) +{ + unsigned long end; + + NCR5380_local_declare(); + NCR5380_setup(instance); + + /* + * Do a SCSI reset to clean up the bus during initialization. No + * messing with the queues, interrupts, or locks necessary here. + */ + + printk( "Sun3 SCSI: resetting the SCSI bus..." ); + + /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */ +// sun3_disable_irq( IRQ_SUN3_SCSI ); + + /* get in phase */ + NCR5380_write( TARGET_COMMAND_REG, + PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) )); + + /* assert RST */ + NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST ); + + /* The min. reset hold time is 25us, so 40us should be enough */ + udelay( 50 ); + + /* reset RST and interrupt */ + NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); + NCR5380_read( RESET_PARITY_INTERRUPT_REG ); + + for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); ) + barrier(); + + /* switch on SCSI IRQ again */ +// sun3_enable_irq( IRQ_SUN3_SCSI ); + + printk( " done\n" ); +} +#endif + +static const char * sun3scsi_info (struct Scsi_Host *spnt) { + return ""; +} + +// safe bits for the CSR +#define CSR_GOOD 0x060f + +static void scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp) +{ + unsigned short csr = dregs->csr; + + dregs->csr &= ~CSR_DMA_ENABLE; + + +#ifdef SUN3_SCSI_DEBUG + printk("scsi_intr csr %x\n", csr); +#endif + + if(csr & ~CSR_GOOD) { + if(csr & CSR_DMA_BUSERR) { + printk("scsi%d: bus error in dma\n", default_instance->host_no); +#ifdef SUN3_SCSI_DEBUG + printk("scsi: residual %x count %x addr %p dmaaddr %x\n", + dregs->fifo_count, + dregs->dma_count_lo | (dregs->dma_count_hi << 16), + sun3_dma_orig_addr, + dregs->dma_addr_lo | (dregs->dma_addr_hi << 16)); +#endif + } + + if(csr & CSR_DMA_CONFLICT) { + printk("scsi%d: dma conflict\n", default_instance->host_no); + } + } + + if(csr & (CSR_SDB_INT | CSR_DMA_INT)) + NCR5380_intr(irq, dummy, fp); +} + +/* + * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk; + * reentering NCR5380_print_status seems to have ugly side effects + */ + +/* this doesn't seem to get used at all -- sam */ +#if 0 +void sun3_sun3_debug (void) +{ + unsigned long flags; + NCR5380_local_declare(); + + if (default_instance) { + save_flags(flags); + cli(); + NCR5380_print_status(default_instance); + restore_flags(flags); + } +} +#endif + + +/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */ +static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag) +{ + void *addr; + + if(sun3_dma_orig_addr != NULL) + dvma_unmap(sun3_dma_orig_addr); + +// addr = sun3_dvma_page((unsigned long)data, (unsigned long)dmabuf); + addr = (void *)dvma_map_vme((unsigned long) data, count); + + sun3_dma_orig_addr = addr; + sun3_dma_orig_count = count; + +#ifdef SUN3_SCSI_DEBUG + printk("scsi: dma_setup addr %p count %x\n", addr, count); +#endif + +// dregs->fifo_count = 0; +#if 0 + /* reset fifo */ + dregs->csr &= ~CSR_FIFO; + dregs->csr |= CSR_FIFO; +#endif + /* set direction */ + if(write_flag) + dregs->csr |= CSR_SEND; + else + dregs->csr &= ~CSR_SEND; + + /* reset fifo */ +// dregs->csr &= ~CSR_FIFO; +// dregs->csr |= CSR_FIFO; + + dregs->csr |= CSR_PACK_ENABLE; + + dregs->dma_addr_hi = ((unsigned long)addr >> 16); + dregs->dma_addr_lo = ((unsigned long)addr & 0xffff); + + dregs->dma_count_hi = 0; + dregs->dma_count_lo = 0; + dregs->fifo_count_hi = 0; + dregs->fifo_count = 0; + +#ifdef SUN3_SCSI_DEBUG + printk("scsi: dma_setup done csr %x\n", dregs->csr); +#endif + return count; + +} + +static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance) +{ + return last_residual; +} + +static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd, + int write_flag) +{ + if(cmd->request->flags & REQ_CMD) + return wanted; + else + return 0; +} + +static int sun3scsi_dma_start(unsigned long count, char *data) +{ + + unsigned short csr; + + csr = dregs->csr; +#ifdef SUN3_SCSI_DEBUG + printk("scsi: dma_start data %p count %x csr %x fifo %x\n", data, count, csr, dregs->fifo_count); +#endif + + dregs->dma_count_hi = (sun3_dma_orig_count >> 16); + dregs->dma_count_lo = (sun3_dma_orig_count & 0xffff); + + dregs->fifo_count_hi = (sun3_dma_orig_count >> 16); + dregs->fifo_count = (sun3_dma_orig_count & 0xffff); + +// if(!(csr & CSR_DMA_ENABLE)) +// dregs->csr |= CSR_DMA_ENABLE; + + return 0; +} + +/* clean up after our dma is done */ +static int sun3scsi_dma_finish(int write_flag) +{ + unsigned short fifo; + int ret = 0; + + sun3_dma_active = 0; + + dregs->csr &= ~CSR_DMA_ENABLE; + + fifo = dregs->fifo_count; + if(write_flag) { + if((fifo > 0) && (fifo < sun3_dma_orig_count)) + fifo++; + } + + last_residual = fifo; +#ifdef SUN3_SCSI_DEBUG + printk("scsi: residual %x total %x\n", fifo, sun3_dma_orig_count); +#endif + /* empty bytes from the fifo which didn't make it */ + if((!write_flag) && (dregs->csr & CSR_LEFT)) { + unsigned char *vaddr; + +#ifdef SUN3_SCSI_DEBUG + printk("scsi: got left over bytes\n"); +#endif + + vaddr = (unsigned char *)dvma_vmetov(sun3_dma_orig_addr); + + vaddr += (sun3_dma_orig_count - fifo); + vaddr--; + + switch(dregs->csr & CSR_LEFT) { + case CSR_LEFT_3: + *vaddr = (dregs->bpack_lo & 0xff00) >> 8; + vaddr--; + + case CSR_LEFT_2: + *vaddr = (dregs->bpack_hi & 0x00ff); + vaddr--; + + case CSR_LEFT_1: + *vaddr = (dregs->bpack_hi & 0xff00) >> 8; + break; + } + + + } + + dvma_unmap(sun3_dma_orig_addr); + sun3_dma_orig_addr = NULL; + + dregs->dma_addr_hi = 0; + dregs->dma_addr_lo = 0; + dregs->dma_count_hi = 0; + dregs->dma_count_lo = 0; + + dregs->fifo_count = 0; + dregs->fifo_count_hi = 0; + + dregs->csr &= ~CSR_SEND; + +// dregs->csr |= CSR_DMA_ENABLE; + +#if 0 + /* reset fifo */ + dregs->csr &= ~CSR_FIFO; + dregs->csr |= CSR_FIFO; +#endif + sun3_dma_setup_done = NULL; + + return ret; + +} + +#include "sun3_NCR5380.c" + +static Scsi_Host_Template driver_template = SUN3_NCR5380; + +#include "scsi_module.c" + diff -Nru a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c --- a/drivers/scsi/sun3x_esp.c Mon Nov 4 14:31:02 2002 +++ b/drivers/scsi/sun3x_esp.c Mon Nov 4 14:31:02 2002 @@ -343,27 +343,28 @@ static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp) { int sz = sp->SCp.buffers_residual; - struct mmu_sglist *sg = (struct mmu_sglist *) sp->SCp.buffer; + struct scatterlist *sg = sp->SCp.buffer; while (sz >= 0) { - sg[sz].dvma_addr = dvma_map((unsigned long)sg[sz].addr, sg[sz].len); - sz--; + sg[sz].dvma_address = dvma_map((unsigned long)page_address(sg[sz].page) + + sg[sz].offset, sg[sz].length); + sz--; } sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dvma_address); } static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp) { - dvma_unmap(sp->SCp.have_data_in); + dvma_unmap((char *)sp->SCp.have_data_in); } static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp) { int sz = sp->use_sg - 1; - struct mmu_sglist *sg = (struct mmu_sglist *)sp->buffer; + struct scatterlist *sg = (struct scatterlist *)sp->buffer; while(sz >= 0) { - dvma_unmap(sg[sz].dvma_addr); + dvma_unmap((char *)sg[sz].dvma_address); sz--; } } diff -Nru a/drivers/scsi/sym53c8xx.h b/drivers/scsi/sym53c8xx.h --- a/drivers/scsi/sym53c8xx.h Mon Nov 4 14:31:01 2002 +++ b/drivers/scsi/sym53c8xx.h Mon Nov 4 14:31:01 2002 @@ -91,6 +91,8 @@ info: sym53c8xx_info, \ queuecommand: sym53c8xx_queue_command,\ slave_attach: sym53c8xx_slave_attach, \ + abort: sym53c8xx_abort, \ + reset: sym53c8xx_reset, \ can_queue: SCSI_NCR_CAN_QUEUE, \ this_id: 7, \ sg_tablesize: SCSI_NCR_SG_TABLESIZE, \ diff -Nru a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c --- a/drivers/scsi/u14-34f.c Mon Nov 4 14:31:01 2002 +++ b/drivers/scsi/u14-34f.c Mon Nov 4 14:31:01 2002 @@ -1,6 +1,15 @@ /* * u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters. * + * 28 Oct 2002 Rev. 8.00 for linux 2.5.44-ac4 + * + Use new tcq and adjust_queue_depth api. + * + New command line option (tm:[0-2]) to choose the type of tags: + * 0 -> disable tagging ; 1 -> simple tags ; 2 -> ordered tags. + * Default is tm:0 (tagged commands disabled). + * For compatibility the "tc:" option is an alias of the "tm:" + * option; tc:n is equivalent to tm:0 and tc:y is equivalent to + * tm:1. + * * 10 Oct 2002 Rev. 7.70 for linux 2.5.42 * + Foreport from revision 6.70. * @@ -304,19 +313,22 @@ * et:n use disk geometry jumpered on the board; * lc:y enables linked commands; * lc:n disables linked commands; + * tm:0 disables tagged commands (same as tc:n); + * tm:1 use simple queue tags (same as tc:y); + * tm:2 use ordered queue tags (same as tc:2); * of:y enables old firmware support; * of:n disables old firmware support; * mq:xx set the max queue depth to the value xx (2 <= xx <= 8). * - * The default value is: "u14-34f=lc:n,of:n,mq:8,et:n". + * The default value is: "u14-34f=lc:n,of:n,mq:8,tm:0,et:n". * An example using the list of detection probes could be: - * "u14-34f=0x230,0x340,lc:y,of:n,mq:4,et:n". + * "u14-34f=0x230,0x340,lc:y,tm:2,of:n,mq:4,et:n". * * When loading as a module, parameters can be specified as well. * The above example would be (use 1 in place of y and 0 in place of n): * * modprobe u14-34f io_port=0x230,0x340 linked_comm=1 have_old_firmware=0 \ - * max_queue_depth=4 ext_tran=0 + * max_queue_depth=4 ext_tran=0 tag_mode=2 * * ---------------------------------------------------------------------------- * In this implementation, linked commands are designed to work with any DISK @@ -374,6 +386,7 @@ MODULE_PARM(have_old_firmware, "i"); MODULE_PARM(link_statistics, "i"); MODULE_PARM(max_queue_depth, "i"); +MODULE_PARM(tag_mode, "i"); MODULE_PARM(ext_tran, "i"); MODULE_AUTHOR("Dario Ballabio"); @@ -400,6 +413,7 @@ #include #include #include +#include #if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD) #error "Adjust your defines" @@ -460,6 +474,9 @@ #define ABORTING 6 #define NO_DMA 0xff #define MAXLOOP 10000 +#define TAG_DISABLED 0 +#define TAG_SIMPLE 1 +#define TAG_ORDERED 2 #define REG_LCL_MASK 0 #define REG_LCL_INTR 1 @@ -593,6 +610,12 @@ static int have_old_firmware = FALSE; #endif +#if defined(CONFIG_SCSI_U14_34F_TAGGED_QUEUE) +static int tag_mode = TAG_SIMPLE; +#else +static int tag_mode = TAG_DISABLED; +#endif + #if defined(CONFIG_SCSI_U14_34F_LINKED_COMMANDS) static int linked_comm = TRUE; #else @@ -605,61 +628,56 @@ static int max_queue_depth = MAX_CMD_PER_LUN; #endif -static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) { - Scsi_Device *dev; - int j, ntag = 0, nuntag = 0, tqd, utqd; +static int u14_34f_slave_attach(Scsi_Device *dev) { + int j, tqd, utqd; + char *tag_suffix, *link_suffix; + struct Scsi_Host *host = dev->host; j = ((struct hostdata *) host->hostdata)->board_number; - for(dev = devlist; dev; dev = dev->next) { - - if (dev->host != host) continue; - - if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm)) - ntag++; - else - nuntag++; - } - utqd = MAX_CMD_PER_LUN; + tqd = max_queue_depth; - tqd = (host->can_queue - utqd * nuntag) / (ntag ? ntag : 1); + if (TLDEV(dev->type) && dev->tagged_supported) - if (tqd > max_queue_depth) tqd = max_queue_depth; - - if (tqd < MAX_CMD_PER_LUN) tqd = MAX_CMD_PER_LUN; - - for(dev = devlist; dev; dev = dev->next) { - char *tag_suffix = "", *link_suffix = ""; - - if (dev->host != host) continue; - - if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm)) - dev->queue_depth = tqd; - else - dev->queue_depth = utqd; - - if (TLDEV(dev->type)) { - if (linked_comm && dev->queue_depth > 2) - link_suffix = ", sorted"; - else - link_suffix = ", unsorted"; + if (tag_mode == TAG_SIMPLE) { + scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, tqd); + tag_suffix = ", simple tags"; + } + else if (tag_mode == TAG_ORDERED) { + scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, tqd); + tag_suffix = ", ordered tags"; + } + else { + scsi_adjust_queue_depth(dev, 0, tqd); + tag_suffix = ", no tags"; } - if (dev->tagged_supported && TLDEV(dev->type) && dev->tagged_queue) - tag_suffix = ", soft-tagged"; - else if (dev->tagged_supported && TLDEV(dev->type)) - tag_suffix = ", tagged"; - - printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n", - BN(j), host->host_no, dev->channel, dev->id, dev->lun, - dev->queue_depth, link_suffix, tag_suffix); + else if (TLDEV(dev->type) && linked_comm) { + scsi_adjust_queue_depth(dev, 0, tqd); + tag_suffix = ", untagged"; } - return; + else { + scsi_adjust_queue_depth(dev, 0, utqd); + tag_suffix = ""; + } + + if (TLDEV(dev->type) && linked_comm && dev->new_queue_depth > 2) + link_suffix = ", sorted"; + else if (TLDEV(dev->type)) + link_suffix = ", unsorted"; + else + link_suffix = ""; + + printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n", + BN(j), host->host_no, dev->channel, dev->id, dev->lun, + dev->new_queue_depth, link_suffix, tag_suffix); + + return FALSE; } -static inline int wait_on_busy(unsigned long iobase, unsigned int loop) { +static int wait_on_busy(unsigned long iobase, unsigned int loop) { while (inb(iobase + REG_LCL_INTR) & BSY_ASSERTED) { udelay(1L); @@ -721,7 +739,7 @@ return FALSE; } -static inline int port_detect \ +static int port_detect \ (unsigned long port_base, unsigned int j, Scsi_Host_Template *tpnt) { unsigned char irq, dma_channel, subversion, i; unsigned char in_byte; @@ -843,7 +861,6 @@ sh[j]->this_id = config_2.ha_scsi_id; sh[j]->can_queue = MAX_MAILBOXES; sh[j]->cmd_per_lun = MAX_CMD_PER_LUN; - sh[j]->select_queue_depths = select_queue_depths; #if defined(DEBUG_DETECT) { @@ -930,11 +947,14 @@ if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN; + if (tag_mode != TAG_DISABLED && tag_mode != TAG_SIMPLE) + tag_mode = TAG_ORDERED; + if (j == 0) { printk("UltraStor 14F/34F: Copyright (C) 1994-2002 Dario Ballabio.\n"); - printk("%s config options -> of:%c, lc:%c, mq:%d, et:%c.\n", - driver_name, YESNO(have_old_firmware), YESNO(linked_comm), - max_queue_depth, YESNO(ext_tran)); + printk("%s config options -> of:%c, tm:%d, lc:%c, mq:%d, et:%c.\n", + driver_name, YESNO(have_old_firmware), tag_mode, + YESNO(linked_comm), max_queue_depth, YESNO(ext_tran)); } printk("%s: %s 0x%03lx, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d.\n", @@ -975,6 +995,8 @@ if (!strncmp(cur, "lc:", 3)) linked_comm = val; else if (!strncmp(cur, "of:", 3)) have_old_firmware = val; + else if (!strncmp(cur, "tm:", 3)) tag_mode = val; + else if (!strncmp(cur, "tc:", 3)) tag_mode = val; else if (!strncmp(cur, "mq:", 3)) max_queue_depth = val; else if (!strncmp(cur, "ls:", 3)) link_statistics = val; else if (!strncmp(cur, "et:", 3)) ext_tran = val; @@ -1001,7 +1023,7 @@ return 1; } -int u14_34f_detect(Scsi_Host_Template *tpnt) { +static int u14_34f_detect(Scsi_Host_Template *tpnt) { unsigned int j = 0, k; unsigned long spin_flags; @@ -1033,7 +1055,7 @@ return j; } -static inline void map_dma(unsigned int i, unsigned int j) { +static void map_dma(unsigned int i, unsigned int j) { unsigned int data_len = 0; unsigned int k, count, pci_dir; struct scatterlist *sgpnt; @@ -1123,7 +1145,7 @@ DEV2H(cpp->data_len), pci_dir); } -static inline void scsi_to_dev_dir(unsigned int i, unsigned int j) { +static void scsi_to_dev_dir(unsigned int i, unsigned int j) { unsigned int k; static const unsigned char data_out_cmds[] = { @@ -1176,7 +1198,7 @@ } -static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { +static int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { unsigned int i, j, k; struct mscp *cpp; @@ -1232,7 +1254,7 @@ /* Map DMA buffers and SG list */ map_dma(i, j); - if (linked_comm && SCpnt->device->queue_depth > 2 + if (linked_comm && SCpnt->device->new_queue_depth > 2 && TLDEV(SCpnt->device->type)) { HD(j)->cp_stat[i] = READY; flush_dev(SCpnt->device, SCpnt->request->sector, j, FALSE); @@ -1257,14 +1279,7 @@ return 0; } -int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { - int rtn; - - rtn = do_qcomm(SCpnt, done); - return rtn; -} - -static inline int do_abort(Scsi_Cmnd *SCarg) { +static int u14_34f_eh_abort(Scsi_Cmnd *SCarg) { unsigned int i, j; j = ((struct hostdata *) SCarg->host->hostdata)->board_number; @@ -1338,12 +1353,7 @@ panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i); } -int u14_34f_abort(Scsi_Cmnd *SCarg) { - - return do_abort(SCarg); -} - -static inline int do_reset(Scsi_Cmnd *SCarg) { +static int u14_34f_eh_host_reset(Scsi_Cmnd *SCarg) { unsigned int i, j, time, k, c, limit = 0; int arg_done = FALSE; Scsi_Cmnd *SCpnt; @@ -1476,28 +1486,23 @@ return SUCCESS; } -int u14_34f_reset(Scsi_Cmnd *SCarg) { - - return do_reset(SCarg); -} - -int u14_34f_biosparam(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int *dkinfo) { +static int u14_34f_bios_param(Disk *disk, struct block_device *bdev, + int *dkinfo) { unsigned int j = 0; - int size = capacity; + int size = disk->capacity; dkinfo[0] = HD(j)->heads; dkinfo[1] = HD(j)->sectors; dkinfo[2] = size / (HD(j)->heads * HD(j)->sectors); - if (ext_tran && (scsicam_bios_param(bdev, capacity, dkinfo) < 0)) { + if (ext_tran && (scsicam_bios_param(disk, bdev, dkinfo) < 0)) { dkinfo[0] = 255; dkinfo[1] = 63; dkinfo[2] = size / (dkinfo[0] * dkinfo[1]); } #if defined (DEBUG_GEOMETRY) - printk ("%s: biosparam, head=%d, sec=%d, cyl=%d.\n", driver_name, + printk ("%s: bios_param, head=%d, sec=%d, cyl=%d.\n", driver_name, dkinfo[0], dkinfo[1], dkinfo[2]); #endif @@ -1529,7 +1534,7 @@ return; } -static inline int reorder(unsigned int j, unsigned long cursec, +static int reorder(unsigned int j, unsigned long cursec, unsigned int ihdlr, unsigned int il[], unsigned int n_ready) { Scsi_Cmnd *SCpnt; struct mscp *cpp; @@ -1666,7 +1671,7 @@ } -static inline void ihdlr(int irq, unsigned int j) { +static void ihdlr(int irq, unsigned int j) { Scsi_Cmnd *SCpnt; unsigned int i, k, c, status, tstatus, reg, ret; struct mscp *spp, *cpp; @@ -1746,7 +1751,7 @@ sync_dma(i, j); - if (linked_comm && SCpnt->device->queue_depth > 2 + if (linked_comm && SCpnt->device->new_queue_depth > 2 && TLDEV(SCpnt->device->type)) flush_dev(SCpnt->device, SCpnt->request->sector, j, TRUE); @@ -1888,7 +1893,7 @@ spin_unlock_irqrestore(sh[j]->host_lock, spin_flags); } -int u14_34f_release(struct Scsi_Host *shpnt) { +static int u14_34f_release(struct Scsi_Host *shpnt) { unsigned int i, j; for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++); diff -Nru a/drivers/scsi/u14-34f.h b/drivers/scsi/u14-34f.h --- a/drivers/scsi/u14-34f.h Mon Nov 4 14:31:02 2002 +++ b/drivers/scsi/u14-34f.h Mon Nov 4 14:31:02 2002 @@ -1,20 +1,16 @@ /* * u14-34f.h - used by the low-level driver for UltraStor 14F/34F */ -#ifndef _U14_34F_H -#define _U14_34F_H -#include +static int u14_34f_detect(Scsi_Host_Template *); +static int u14_34f_release(struct Scsi_Host *); +static int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +static int u14_34f_eh_abort(Scsi_Cmnd *); +static int u14_34f_eh_host_reset(Scsi_Cmnd *); +static int u14_34f_bios_param(Disk *, struct block_device *, int *); +static int u14_34f_slave_attach(Scsi_Device *); -int u14_34f_detect(Scsi_Host_Template *); -int u14_34f_release(struct Scsi_Host *); -int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -int u14_34f_abort(Scsi_Cmnd *); -int u14_34f_reset(Scsi_Cmnd *); -int u14_34f_biosparam(struct scsi_device *, struct block_device *, - sector_t, int *); - -#define U14_34F_VERSION "7.70.00" +#define U14_34F_VERSION "8.00.00" #define ULTRASTOR_14_34F { \ name: "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \ @@ -23,14 +19,13 @@ queuecommand: u14_34f_queuecommand, \ abort: NULL, \ reset: NULL, \ - eh_abort_handler: u14_34f_abort, \ + eh_abort_handler: u14_34f_eh_abort, \ eh_device_reset_handler: NULL, \ eh_bus_reset_handler: NULL, \ - eh_host_reset_handler: u14_34f_reset, \ - bios_param: u14_34f_biosparam, \ + eh_host_reset_handler: u14_34f_eh_host_reset, \ + bios_param: u14_34f_bios_param, \ + slave_attach: u14_34f_slave_attach, \ this_id: 7, \ unchecked_isa_dma: 1, \ - use_clustering: ENABLE_CLUSTERING, \ + use_clustering: ENABLE_CLUSTERING \ } - -#endif diff -Nru a/drivers/serial/21285.c b/drivers/serial/21285.c --- a/drivers/serial/21285.c Mon Nov 4 14:31:02 2002 +++ b/drivers/serial/21285.c Mon Nov 4 14:31:02 2002 @@ -171,7 +171,7 @@ } while (--count > 0 && !(*CSR_UARTFLG & 0x20)); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_event(port, EVT_WRITE_WAKEUP); + uart_write_wakeup(port); if (uart_circ_empty(xmit)) serial21285_stop_tx(port, 0); @@ -485,11 +485,7 @@ static struct uart_driver serial21285_reg = { .owner = THIS_MODULE, .driver_name = "ttyFB", -#ifdef CONFIG_DEVFS_FS .dev_name = "ttyFB%d", -#else - .dev_name = "ttyFB", -#endif .major = SERIAL_21285_MAJOR, .minor = SERIAL_21285_MINOR, .nr = 1, diff -Nru a/drivers/serial/8250.c b/drivers/serial/8250.c --- a/drivers/serial/8250.c Mon Nov 4 14:31:00 2002 +++ b/drivers/serial/8250.c Mon Nov 4 14:31:00 2002 @@ -124,6 +124,8 @@ unsigned char ier; unsigned char rev; unsigned char lcr; + unsigned char mcr_mask; /* mask of user bits */ + unsigned char mcr_force; /* mask of forced bits */ unsigned int lsr_break_flag; /* @@ -342,10 +344,9 @@ * * What evil have men's minds wrought... */ -static void -autoconfig_startech_uarts(struct uart_8250_port *up) +static void autoconfig_has_efr(struct uart_8250_port *up) { - unsigned char scratch, scratch2, scratch3, scratch4; + unsigned char id1, id2, id3, rev, saved_dll, saved_dlm; /* * First we check to see if it's an Oxford Semiconductor UART. @@ -354,31 +355,32 @@ * Semiconductor clone chips lock up if you try writing to the * LSR register (which serial_icr_read does) */ - if (up->port.type == PORT_16550A) { - /* - * EFR [4] must be set else this test fails - * - * This shouldn't be necessary, but Mike Hudson - * (Exoray@isys.ca) claims that it's needed for 952 - * dual UART's (which are not recommended for new designs). - */ - up->acr = 0; - serial_out(up, UART_LCR, 0xBF); - serial_out(up, UART_EFR, 0x10); - serial_out(up, UART_LCR, 0x00); - /* Check for Oxford Semiconductor 16C950 */ - scratch = serial_icr_read(up, UART_ID1); - scratch2 = serial_icr_read(up, UART_ID2); - scratch3 = serial_icr_read(up, UART_ID3); - - if (scratch == 0x16 && scratch2 == 0xC9 && - (scratch3 == 0x50 || scratch3 == 0x52 || - scratch3 == 0x54)) { - up->port.type = PORT_16C950; - up->rev = serial_icr_read(up, UART_REV) | - (scratch3 << 8); - return; - } + + /* + * Check for Oxford Semiconductor 16C950. + * + * EFR [4] must be set else this test fails. + * + * This shouldn't be necessary, but Mike Hudson (Exoray@isys.ca) + * claims that it's needed for 952 dual UART's (which are not + * recommended for new designs). + */ + up->acr = 0; + serial_out(up, UART_LCR, 0xBF); + serial_out(up, UART_EFR, UART_EFR_ECB); + serial_out(up, UART_LCR, 0x00); + id1 = serial_icr_read(up, UART_ID1); + id2 = serial_icr_read(up, UART_ID2); + id3 = serial_icr_read(up, UART_ID3); + rev = serial_icr_read(up, UART_REV); + + DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev); + + if (id1 == 0x16 && id2 == 0xC9 && + (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) { + up->port.type = PORT_16C950; + up->rev = rev | (id3 << 8); + return; } /* @@ -389,34 +391,28 @@ * 0x12 - XR16C2850. * 0x14 - XR16C854. */ - - /* Save the DLL and DLM */ - serial_outp(up, UART_LCR, UART_LCR_DLAB); - scratch3 = serial_inp(up, UART_DLL); - scratch4 = serial_inp(up, UART_DLM); - + saved_dll = serial_inp(up, UART_DLL); + saved_dlm = serial_inp(up, UART_DLM); serial_outp(up, UART_DLL, 0); serial_outp(up, UART_DLM, 0); - scratch2 = serial_inp(up, UART_DLL); - scratch = serial_inp(up, UART_DLM); - serial_outp(up, UART_LCR, 0); - - if (scratch == 0x10 || scratch == 0x12 || scratch == 0x14) { - if (scratch == 0x10) - up->rev = scratch2; + id2 = serial_inp(up, UART_DLL); + id1 = serial_inp(up, UART_DLM); + serial_outp(up, UART_DLL, saved_dll); + serial_outp(up, UART_DLM, saved_dlm); + + DEBUG_AUTOCONF("850id=%02x:%02x ", id1, id2); + + if (id1 == 0x10 || id1 == 0x12 || id1 == 0x14) { + if (id1 == 0x10) + up->rev = id2; up->port.type = PORT_16850; return; } - /* Restore the DLL and DLM */ - - serial_outp(up, UART_LCR, UART_LCR_DLAB); - serial_outp(up, UART_DLL, scratch3); - serial_outp(up, UART_DLM, scratch4); - serial_outp(up, UART_LCR, 0); - /* + * It wasn't an XR16C850. + * * We distinguish between the '654 and the '650 by counting * how many bytes are in the FIFO. I'm using this for now, * since that's the technique that was sent to me in the @@ -430,6 +426,85 @@ } /* + * We detected a chip without a FIFO. Only two fall into + * this category - the original 8250 and the 16450. The + * 16450 has a scratch register (accessible with LCR=0) + */ +static void autoconfig_8250(struct uart_8250_port *up) +{ + unsigned char scratch, status1, status2; + + up->port.type = PORT_8250; + + scratch = serial_in(up, UART_SCR); + serial_outp(up, UART_SCR, 0xa5); + status1 = serial_in(up, UART_SCR); + serial_outp(up, UART_SCR, 0x5a); + status2 = serial_in(up, UART_SCR); + serial_outp(up, UART_SCR, scratch); + + if (status1 == 0xa5 && status2 == 0x5a) + up->port.type = PORT_16450; +} + +/* + * We know that the chip has FIFOs. Does it have an EFR? The + * EFR is located in the same register position as the IIR and + * we know the top two bits of the IIR are currently set. The + * EFR should contain zero. Try to read the EFR. + */ +static void autoconfig_16550a(struct uart_8250_port *up) +{ + unsigned char status1, status2; + + up->port.type = PORT_16550A; + + /* + * Check for presence of the EFR when DLAB is set. + * Only ST16C650V1 UARTs pass this test. + */ + serial_outp(up, UART_LCR, UART_LCR_DLAB); + if (serial_in(up, UART_EFR) == 0) { + DEBUG_AUTOCONF("EFRv1 "); + up->port.type = PORT_16650; + return; + } + + /* + * Maybe it requires 0xbf to be written to the LCR. + * (other ST16C650V2 UARTs, TI16C752A, etc) + */ + serial_outp(up, UART_LCR, 0xBF); + if (serial_in(up, UART_EFR) == 0) { + DEBUG_AUTOCONF("EFRv2 "); + autoconfig_has_efr(up); + return; + } + + /* + * No EFR. Try to detect a TI16750, which only sets bit 5 of + * the IIR when 64 byte FIFO mode is enabled when DLAB is set. + * Try setting it with and without DLAB set. Cheap clones + * set bit 5 without DLAB set. + */ + serial_outp(up, UART_LCR, 0); + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + status1 = serial_in(up, UART_IIR) >> 5; + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(up, UART_LCR, UART_LCR_DLAB); + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + status2 = serial_in(up, UART_IIR) >> 5; + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + + DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2); + + if (status1 == 6 && status2 == 7) { + up->port.type = PORT_16750; + return; + } +} + +/* * This routine is called by rs_init() to initialize a specific serial * port. It determines what type of UART chip this serial port is * using: 8250, 16450, 16550, 16550A. The important question is @@ -438,16 +513,16 @@ */ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) { - unsigned char status1, status2, scratch, scratch2, scratch3; + unsigned char status1, scratch, scratch2, scratch3; unsigned char save_lcr, save_mcr; unsigned long flags; - DEBUG_AUTOCONF("Testing ttyS%d (0x%04x, 0x%08lx)...\n", - up->port.line, up->port.iobase, up->port.membase); - if (!up->port.iobase && !up->port.membase) return; + DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%08lx): ", + up->port.line, up->port.iobase, up->port.membase); + /* * We really do need global IRQs disabled here - we're going to * be frobbing the chips IRQ enable register to see if it exists. @@ -455,7 +530,7 @@ spin_lock_irqsave(&up->port.lock, flags); // save_flags(flags); cli(); - if (!(up->port.flags & ASYNC_BUGGY_UART)) { + if (!(up->port.flags & UPF_BUGGY_UART)) { /* * Do a simple existence test first; if we fail this, * there's no point trying anything else. @@ -465,6 +540,9 @@ * assumption is that 0x80 is a non-existent port; * which should be safe since include/asm/io.h also * makes this assumption. + * + * Note: this is safe as long as MCR bit 4 is clear + * and the device is in "PC" mode. */ scratch = serial_inp(up, UART_IER); serial_outp(up, UART_IER, 0); @@ -482,9 +560,8 @@ /* * We failed; there's nothing here */ - DEBUG_AUTOCONF("serial: ttyS%d: simple autoconfig " - "failed (%02x, %02x)\n", - up->port.line, scratch2, scratch3); + DEBUG_AUTOCONF("IER test failed (%02x, %02x) ", + scratch2, scratch3); goto out; } } @@ -501,69 +578,50 @@ * manufacturer would be stupid enough to design a board * that conflicts with COM 1-4 --- we hope! */ - if (!(up->port.flags & ASYNC_SKIP_TEST)) { + if (!(up->port.flags & UPF_SKIP_TEST)) { serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A); status1 = serial_inp(up, UART_MSR) & 0xF0; serial_outp(up, UART_MCR, save_mcr); if (status1 != 0x90) { - DEBUG_AUTOCONF("serial: ttyS%d: no UART loopback " - "failed\n", up->port.line); + DEBUG_AUTOCONF("LOOP test failed (%02x) ", + status1); goto out; } } - serial_outp(up, UART_LCR, 0xBF); /* set up for StarTech test */ - serial_outp(up, UART_EFR, 0); /* EFR is the same as FCR */ + + /* + * We're pretty sure there's a port here. Lets find out what + * type of port it is. The IIR top two bits allows us to find + * out if its 8250 or 16450, 16550, 16550A or later. This + * determines what we test for next. + * + * We also initialise the EFR (if any) to zero for later. The + * EFR occupies the same register location as the FCR and IIR. + */ + serial_outp(up, UART_LCR, 0xBF); + serial_outp(up, UART_EFR, 0); serial_outp(up, UART_LCR, 0); + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); scratch = serial_in(up, UART_IIR) >> 6; + + DEBUG_AUTOCONF("iir=%d ", scratch); + switch (scratch) { - case 0: - up->port.type = PORT_16450; - break; - case 1: - up->port.type = PORT_UNKNOWN; - break; - case 2: - up->port.type = PORT_16550; - break; - case 3: - up->port.type = PORT_16550A; - break; - } - if (up->port.type == PORT_16550A) { - /* Check for Startech UART's */ - serial_outp(up, UART_LCR, UART_LCR_DLAB); - if (serial_in(up, UART_EFR) == 0) { - up->port.type = PORT_16650; - } else { - serial_outp(up, UART_LCR, 0xBF); - if (serial_in(up, UART_EFR) == 0) - autoconfig_startech_uarts(up); - } - } - if (up->port.type == PORT_16550A) { - /* Check for TI 16750 */ - serial_outp(up, UART_LCR, save_lcr | UART_LCR_DLAB); - serial_outp(up, UART_FCR, - UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - scratch = serial_in(up, UART_IIR) >> 5; - if (scratch == 7) { - /* - * If this is a 16750, and not a cheap UART - * clone, then it should only go into 64 byte - * mode if the UART_FCR7_64BYTE bit was set - * while UART_LCR_DLAB was latched. - */ - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_outp(up, UART_LCR, 0); - serial_outp(up, UART_FCR, - UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - scratch = serial_in(up, UART_IIR) >> 5; - if (scratch == 6) - up->port.type = PORT_16750; - } - serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + case 0: + autoconfig_8250(up); + break; + case 1: + up->port.type = PORT_UNKNOWN; + break; + case 2: + up->port.type = PORT_16550; + break; + case 3: + autoconfig_16550a(up); + break; } + #if defined(CONFIG_SERIAL_8250_RSA) && defined(MODULE) /* * Only probe for RSA ports if we got the region. @@ -586,17 +644,6 @@ } #endif serial_outp(up, UART_LCR, save_lcr); - if (up->port.type == PORT_16450) { - scratch = serial_in(up, UART_SCR); - serial_outp(up, UART_SCR, 0xa5); - status1 = serial_in(up, UART_SCR); - serial_outp(up, UART_SCR, 0x5a); - status2 = serial_in(up, UART_SCR); - serial_outp(up, UART_SCR, scratch); - - if ((status1 != 0xa5) || (status2 != 0x5a)) - up->port.type = PORT_8250; - } up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size; @@ -628,6 +675,7 @@ "serial_rsa"); } #endif + DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name); } static void autoconfig_irq(struct uart_8250_port *up) @@ -638,7 +686,7 @@ unsigned long irqs; int irq; - if (up->port.flags & ASYNC_FOURPORT) { + if (up->port.flags & UPF_FOURPORT) { ICP = (up->port.iobase & 0xfe0) | 0x1f; save_ICP = inb_p(ICP); outb_p(0x80, ICP); @@ -654,7 +702,7 @@ irqs = probe_irq_on(); serial_outp(up, UART_MCR, 0); udelay (10); - if (up->port.flags & ASYNC_FOURPORT) { + if (up->port.flags & UPF_FOURPORT) { serial_outp(up, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); } else { @@ -673,7 +721,7 @@ serial_outp(up, UART_MCR, save_mcr); serial_outp(up, UART_IER, save_ier); - if (up->port.flags & ASYNC_FOURPORT) + if (up->port.flags & UPF_FOURPORT) outb_p(save_ICP, ICP); up->port.irq = (irq > 0) ? irq : 0; @@ -839,7 +887,7 @@ } while (--count > 0); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_event(&up->port, EVT_WRITE_WAKEUP); + uart_write_wakeup(&up->port); DEBUG_INTR("THRE..."); @@ -948,10 +996,26 @@ * line being stuck active, and, since ISA irqs are edge triggered, * no more IRQs will be seen. */ +static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up) +{ + spin_lock_irq(&i->lock); + + if (!list_empty(i->head)) { + if (i->head == &up->list) + i->head = i->head->next; + list_del(&up->list); + } else { + BUG_ON(i->head != &up->list); + i->head = NULL; + } + + spin_unlock_irq(&i->lock); +} + static int serial_link_irq_chain(struct uart_8250_port *up) { struct irq_info *i = irq_lists + up->port.irq; - int ret, irq_flags = share_irqs ? SA_SHIRQ : 0; + int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? SA_SHIRQ : 0; spin_lock_irq(&i->lock); @@ -967,6 +1031,8 @@ ret = request_irq(up->port.irq, serial8250_interrupt, irq_flags, "serial", i); + if (ret) + serial_do_unlink(i, up); } return ret; @@ -981,18 +1047,7 @@ if (list_empty(i->head)) free_irq(up->port.irq, i); - spin_lock_irq(&i->lock); - - if (!list_empty(i->head)) { - if (i->head == &up->list) - i->head = i->head->next; - list_del(&up->list); - } else { - BUG_ON(i->head != &up->list); - i->head = NULL; - } - - spin_unlock_irq(&i->lock); + serial_do_unlink(i, up); } /* @@ -1058,7 +1113,7 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct uart_8250_port *up = (struct uart_8250_port *)port; - unsigned char mcr = ALPHA_KLUDGE_MCR; + unsigned char mcr = 0; if (mctrl & TIOCM_RTS) mcr |= UART_MCR_RTS; @@ -1071,6 +1126,8 @@ if (mctrl & TIOCM_LOOP) mcr |= UART_MCR_LOOP; + mcr = (mcr & up->mcr_mask) | up->mcr_force; + serial_out(up, UART_MCR, mcr); } @@ -1139,7 +1196,7 @@ * if it is, then bail out, because there's likely no UART * here. */ - if (!(up->port.flags & ASYNC_BUGGY_UART) && + if (!(up->port.flags & UPF_BUGGY_UART) && (serial_inp(up, UART_LSR) == 0xff)) { printk("ttyS%d: LSR safety check engaged!\n", up->port.line); return -ENODEV; @@ -1169,7 +1226,7 @@ serial_outp(up, UART_LCR, UART_LCR_WLEN8); spin_lock_irqsave(&up->port.lock, flags); - if (up->port.flags & ASYNC_FOURPORT) { + if (up->port.flags & UPF_FOURPORT) { if (!is_real_interrupt(up->port.irq)) up->port.mctrl |= TIOCM_OUT1; } else @@ -1190,7 +1247,7 @@ up->ier = UART_IER_RLSI | UART_IER_RDI; serial_outp(up, UART_IER, up->ier); - if (up->port.flags & ASYNC_FOURPORT) { + if (up->port.flags & UPF_FOURPORT) { unsigned int icp; /* * Enable interrupts on the AST Fourport board @@ -1223,7 +1280,7 @@ serial_outp(up, UART_IER, 0); spin_lock_irqsave(&up->port.lock, flags); - if (up->port.flags & ASYNC_FOURPORT) { + if (up->port.flags & UPF_FOURPORT) { /* reset interrupts on the AST Fourport board */ inb((up->port.iobase & 0xfe0) | 0x1f); up->port.mctrl |= TIOCM_OUT1; @@ -1604,7 +1661,7 @@ /* * Don't probe for MCA ports on non-MCA machines. */ - if (up->port.flags & ASYNC_BOOT_ONLYMCA && !MCA_bus) + if (up->port.flags & UPF_BOOT_ONLYMCA && !MCA_bus) return; #endif @@ -1704,6 +1761,8 @@ up->port.iotype = old_serial_port[i].io_type; up->port.regshift = old_serial_port[i].iomem_reg_shift; up->port.ops = &serial8250_pops; + if (share_irqs) + up->port.flags |= UPF_SHARE_IRQ; } } @@ -1714,11 +1773,20 @@ serial8250_isa_init_ports(); for (i = 0; i < UART_NR; i++) { - serial8250_ports[i].port.line = i; - serial8250_ports[i].port.ops = &serial8250_pops; - init_timer(&serial8250_ports[i].timer); - serial8250_ports[i].timer.function = serial8250_timeout; - uart_add_one_port(drv, &serial8250_ports[i].port); + struct uart_8250_port *up = &serial8250_ports[i]; + + up->port.line = i; + up->port.ops = &serial8250_pops; + init_timer(&up->timer); + up->timer.function = serial8250_timeout; + + /* + * ALPHA_KLUDGE_MCR needs to be killed. + */ + up->mcr_mask = ~ALPHA_KLUDGE_MCR; + up->mcr_force = ALPHA_KLUDGE_MCR; + + uart_add_one_port(drv, &up->port); } } @@ -1746,7 +1814,7 @@ } while ((status & BOTH_EMPTY) != BOTH_EMPTY); /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & ASYNC_CONS_FLOW) { + if (up->port.flags & UPF_CONS_FLOW) { tmout = 1000000; while (--tmout && ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0)) @@ -1857,7 +1925,7 @@ #ifdef CONFIG_DEVFS_FS .dev_name = "tts/%d", #else - .dev_name = "ttyS", + .dev_name = "ttyS%d", #endif .major = TTY_MAJOR, .minor = 64, @@ -1881,8 +1949,11 @@ port.fifosize = req->xmit_fifo_size; port.regshift = req->iomem_reg_shift; port.iotype = req->io_type; - port.flags = req->flags | ASYNC_BOOT_AUTOCONF; + port.flags = req->flags | UPF_BOOT_AUTOCONF; port.line = line; + + if (share_irqs) + port.flags |= UPF_SHARE_IRQ; if (HIGH_BITS_OFFSET) port.iobase |= (long) req->port_high << HIGH_BITS_OFFSET; diff -Nru a/drivers/serial/8250_cs.c b/drivers/serial/8250_cs.c --- a/drivers/serial/8250_cs.c Mon Nov 4 14:31:01 2002 +++ b/drivers/serial/8250_cs.c Mon Nov 4 14:31:02 2002 @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -306,7 +307,7 @@ memset(&serial, 0, sizeof (serial)); serial.port = port; serial.irq = irq; - serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ; + serial.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ; line = register_serial(&serial); if (line < 0) { printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx," diff -Nru a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/serial/8250_gsc.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,133 @@ +/* + * Serial Device Initialisation for Lasi/Asp/Wax/Dino + * + * (c) Copyright Matthew Wilcox 2001-2002 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static void setup_parisc_serial(struct serial_struct *serial, + unsigned long address, int irq, int line) +{ + memset(serial, 0, sizeof(struct serial_struct)); + + /* autoconfig() sets state->type. This sets info->type */ + serial->type = PORT_16550A; + + serial->line = line; + serial->iomem_base = ioremap(address, 0x8); + + serial->irq = irq; + serial->io_type = SERIAL_IO_MEM; /* define access method */ + serial->flags = 0; + serial->xmit_fifo_size = 16; + serial->custom_divisor = 0; + serial->baud_base = LASI_BASE_BAUD; +} + +static int __init +serial_init_chip(struct parisc_device *dev) +{ + static int serial_line_nr; + unsigned long address; + int err; + + struct serial_struct *serial; + + if (!dev->irq) { + /* We find some unattached serial ports by walking native + * busses. These should be silently ignored. Otherwise, + * what we have here is a missing parent device, so tell + * the user what they're missing. + */ + if (dev->parent->id.hw_type != HPHW_IOA) { + printk(KERN_INFO "Serial: device 0x%lx not configured.\n" + "Enable support for Wax, Lasi, Asp or Dino.\n", dev->hpa); + } + return -ENODEV; + } + + serial = kmalloc(sizeof(*serial), GFP_KERNEL); + if (!serial) + return -ENOMEM; + + address = dev->hpa; + if (dev->id.sversion != 0x8d) { + address += 0x800; + } + + setup_parisc_serial(serial, address, dev->irq, serial_line_nr++); + err = register_serial(serial); + if (err < 0) { + printk(KERN_WARNING "register_serial returned error %d\n", err); + kfree(serial); + return -ENODEV; + } + + return 0; +} + +static struct parisc_device_id serial_tbl[] = { + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00075 }, + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008c }, + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008d }, + { 0 } +}; + +/* Hack. Dino's serial port will get listed first on some machines. + * So we register this driver first which knows about Lasi's serial port. + * This needs to get fixed properly somehow. + */ +static struct parisc_device_id serial1_tbl[] = { + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03B, 0x0008C }, /* C1xx/C1xxL */ + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03C, 0x0008C }, /* B132L */ + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03D, 0x0008C }, /* B160L */ + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03E, 0x0008C }, /* B132L+ */ + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03F, 0x0008C }, /* B180L+ */ + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x046, 0x0008C }, /* Rocky2 120 */ + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x047, 0x0008C }, /* Rocky2 150 */ + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x04E, 0x0008C }, /* Kiji L2 132 */ + { HPHW_FIO, HVERSION_REV_ANY_ID, 0x056, 0x0008C }, /* Raven+ */ + { 0 } +}; + + +MODULE_DEVICE_TABLE(parisc, serial_tbl); + +static struct parisc_driver serial1_driver = { + name: "Serial RS232", + id_table: serial1_tbl, + probe: serial_init_chip, +}; + +static struct parisc_driver serial_driver = { + name: "Serial RS232", + id_table: serial_tbl, + probe: serial_init_chip, +}; + +int __init probe_serial_gsc(void) +{ + register_parisc_driver(&serial1_driver); + register_parisc_driver(&serial_driver); + return 0; +} + +module_init(probe_serial_gsc); diff -Nru a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c --- a/drivers/serial/8250_pci.c Mon Nov 4 14:31:02 2002 +++ b/drivers/serial/8250_pci.c Mon Nov 4 14:31:02 2002 @@ -11,7 +11,7 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License. * - * $Id: 8250_pci.c,v 1.24 2002/07/29 14:39:56 rmk Exp $ + * $Id: 8250_pci.c,v 1.28 2002/11/02 11:14:18 rmk Exp $ */ #include #include @@ -21,7 +21,6 @@ #include #include #include - #include #include @@ -55,14 +54,19 @@ int line[0]; }; +/* + * init_fn returns: + * > 0 - number of ports + * = 0 - use board->num_ports + * < 0 - error + */ struct pci_board { int flags; int num_ports; int base_baud; int uart_offset; int reg_shift; - int (*init_fn)(struct pci_dev *dev, struct pci_board *board, - int enable); + int (*init_fn)(struct pci_dev *dev, int enable); int first_uart_offset; }; @@ -201,8 +205,7 @@ * seems to be mainly needed on card using the PLX which also use I/O * mapped memory. */ -static int __devinit -pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable) +static int __devinit pci_plx9050_fn(struct pci_dev *dev, int enable) { u8 *p, irq_config = 0; @@ -264,8 +267,7 @@ #define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc) #define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8) -static int __devinit -pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable) +static int __devinit pci_siig10x_fn(struct pci_dev *dev, int enable) { u16 data, *p; @@ -296,8 +298,7 @@ #define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc) #define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc) -static int __devinit -pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable) +static int __devinit pci_siig20x_fn(struct pci_dev *dev, int enable) { u8 data; @@ -318,8 +319,7 @@ } /* Added for EKF Intel i960 serial boards */ -static int __devinit -pci_inteli960ni_fn(struct pci_dev *dev, struct pci_board *board, int enable) +static int __devinit pci_inteli960ni_fn(struct pci_dev *dev, int enable) { unsigned long oldval; @@ -378,8 +378,7 @@ { 0, 0 } }; -static int __devinit -pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable) +static int __devinit pci_timedia_fn(struct pci_dev *dev, int enable) { int i, j; unsigned short *ids; @@ -389,12 +388,9 @@ for (i = 0; timedia_data[i].num; i++) { ids = timedia_data[i].ids; - for (j = 0; ids[j]; j++) { - if (pci_get_subdevice(dev) == ids[j]) { - board->num_ports = timedia_data[i].num; - return 0; - } - } + for (j = 0; ids[j]; j++) + if (pci_get_subdevice(dev) == ids[j]) + return timedia_data[i].num; } return 0; } @@ -406,9 +402,10 @@ * and Keystone have one Diva chip with 3 UARTs. Some later machines have * one Diva chip, but it has been expanded to 5 UARTs. */ -static int __devinit -pci_hp_diva(struct pci_dev *dev, struct pci_board *board, int enable) +static int __devinit pci_hp_diva(struct pci_dev *dev, int enable) { + int rc = 0; + if (!enable) return 0; @@ -417,25 +414,24 @@ case PCI_DEVICE_ID_HP_DIVA_HALFDOME: case PCI_DEVICE_ID_HP_DIVA_KEYSTONE: case PCI_DEVICE_ID_HP_DIVA_EVEREST: - board->num_ports = 3; + rc = 3; break; case PCI_DEVICE_ID_HP_DIVA_TOSCA2: - board->num_ports = 2; + rc = 2; break; case PCI_DEVICE_ID_HP_DIVA_MAESTRO: - board->num_ports = 4; + rc = 4; break; case PCI_DEVICE_ID_HP_DIVA_POWERBAR: - board->num_ports = 1; + rc = 1; break; } - return 0; + return rc; } -static int __devinit -pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable) +static int __devinit pci_xircom_fn(struct pci_dev *dev, int enable) { __set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); @@ -579,8 +575,11 @@ 0x400, 7, pci_plx9050_fn }, { SPCI_FL_BASE2, 4, 921600, /* pbn_plx_romulus */ 0x20, 2, pci_plx9050_fn, 0x03 }, - /* This board uses the size of PCI Base region 0 to - * signal now many ports are available */ + + /* + * This board uses the size of PCI Base region 0 to + * signal now many ports are available + */ { SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 }, /* pbn_oxsemi */ { SPCI_FL_BASE_TABLE, 1, 921600, /* pbn_timedia */ 0, 0, pci_timedia_fn }, @@ -645,9 +644,9 @@ * later?) */ if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) && - ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) || + ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) || (dev->class & 0xff) > 6) - return 1; + return -ENODEV; for (i = 0; i < 6; i++) { if (IS_PCI_REGION_IOPORT(dev, i)) { @@ -667,20 +666,31 @@ board->flags = first_port; return 0; } - return 1; + return -ENODEV; +} + +static inline int +serial_pci_matches(struct pci_board *board, int index) +{ + return + board->base_baud == pci_boards[index].base_baud && + board->num_ports == pci_boards[index].num_ports && + board->uart_offset == pci_boards[index].uart_offset && + board->reg_shift == pci_boards[index].reg_shift && + board->first_uart_offset == pci_boards[index].first_uart_offset; } /* - * return an error code to refuse. - * - * serial_struct is 60 bytes. + * Probe one serial board. Unfortunately, there is no rhyme nor reason + * to the arrangement of serial ports on a PCI card. */ -static int __devinit pci_init_one(struct pci_dev *dev, const struct pci_device_id *ent) +static int __devinit +pci_init_one(struct pci_dev *dev, const struct pci_device_id *ent) { struct serial_private *priv; struct pci_board *board, tmp; struct serial_struct serial_req; - int base_baud, rc, k; + int base_baud, rc, nr_ports, i; if (ent->driver_data >= ARRAY_SIZE(pci_boards)) { printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n", @@ -694,67 +704,98 @@ if (rc) return rc; - if (ent->driver_data == pbn_default && - serial_pci_guess_board(dev, board)) { - pci_disable_device(dev); - return -ENODEV; - } else if (serial_pci_guess_board(dev, &tmp) == 0) { - printk(KERN_INFO "Redundant entry in serial pci_table. " - "Please send the output of\n" - "lspci -vv, this message (%d,%d,%d,%d)\n" - "and the manufacturer and name of " - "serial board or modem board\n" - "to serial-pci-info@lists.sourceforge.net.\n", - dev->vendor, dev->device, - pci_get_subvendor(dev), pci_get_subdevice(dev)); + if (ent->driver_data == pbn_default) { + /* + * Use a copy of the pci_board entry for this; + * avoid changing entries in the table. + */ + memcpy(&tmp, board, sizeof(struct pci_board)); + board = &tmp; + + /* + * We matched one of our class entries. Try to + * determine the parameters of this board. + */ + rc = serial_pci_guess_board(dev, board); + if (rc) + goto disable; + } else { + /* + * We matched an explicit entry. If we are able to + * detect this boards settings with our heuristic, + * then we no longer need this entry. + */ + rc = serial_pci_guess_board(dev, &tmp); + if (rc == 0 && serial_pci_matches(board, pbn_default)) { + printk(KERN_INFO + "Redundant entry in serial pci_table. Please send the output\n" + "of lspci -vv, this message (0x%04x,0x%04x,0x%04x,0x%04x),\n" + "the manufacturer and name of serial board or modem board to\n" + "rmk@arm.linux.org.uk.\n", + dev->vendor, dev->device, + pci_get_subvendor(dev), pci_get_subdevice(dev)); + } } - priv = kmalloc(sizeof(struct serial_private) + - sizeof(unsigned int) * board->num_ports, - GFP_KERNEL); - if (!priv) { - pci_disable_device(dev); - return -ENOMEM; - } + nr_ports = board->num_ports; /* - * Run the initialization function, if any + * Run the initialization function, if any. The initialization + * function returns: + * <0 - error + * 0 - use board->num_ports + * >0 - number of ports */ if (board->init_fn) { - rc = board->init_fn(dev, board, 1); - if (rc != 0) { - pci_disable_device(dev); - kfree(priv); - return rc; - } + rc = board->init_fn(dev, 1); + if (rc < 0) + goto disable; + + if (rc) + nr_ports = rc; + } + + priv = kmalloc(sizeof(struct serial_private) + + sizeof(unsigned int) * nr_ports, + GFP_KERNEL); + if (!priv) { + rc = -ENOMEM; + goto deinit; } base_baud = board->base_baud; if (!base_baud) base_baud = BASE_BAUD; memset(&serial_req, 0, sizeof(serial_req)); - for (k = 0; k < board->num_ports; k++) { - serial_req.irq = get_pci_irq(dev, board, k); - if (get_pci_port(dev, board, &serial_req, k)) + for (i = 0; i < nr_ports; i++) { + serial_req.irq = get_pci_irq(dev, board, i); + if (get_pci_port(dev, board, &serial_req, i)) break; #ifdef SERIAL_DEBUG_PCI - printk("Setup PCI/PNP port: port %x, irq %d, type %d\n", + printk("Setup PCI port: port %x, irq %d, type %d\n", serial_req.port, serial_req.irq, serial_req.io_type); #endif serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE; serial_req.baud_base = base_baud; - priv->line[k] = register_serial(&serial_req); - if (priv->line[k] < 0) + priv->line[i] = register_serial(&serial_req); + if (priv->line[i] < 0) break; } priv->board = board; - priv->nr = k; + priv->nr = i; pci_set_drvdata(dev, priv); return 0; + + deinit: + if (board->init_fn) + board->init_fn(dev, 0); + disable: + pci_disable_device(dev); + return rc; } static void __devexit pci_remove_one(struct pci_dev *dev) @@ -769,7 +810,7 @@ unregister_serial(priv->line[i]); if (priv->board->init_fn) - priv->board->init_fn(dev, priv->board, 0); + priv->board->init_fn(dev, 0); pci_disable_device(dev); @@ -1160,18 +1201,23 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_dci_pccom8 }, + /* + * These entries match devices with class + * COMMUNICATION_SERIAL, COMMUNICATION_MODEM + * or COMMUNICATION_MULTISERIAL + */ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_COMMUNICATION_SERIAL << 8, - 0xffff00, }, + 0xffff00, pbn_default }, { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_COMMUNICATION_MODEM << 8, - 0xffff00, }, + 0xffff00, pbn_default }, { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, - 0xffff00, }, + 0xffff00, pbn_default }, { 0, } }; diff -Nru a/drivers/serial/Makefile b/drivers/serial/Makefile --- a/drivers/serial/Makefile Mon Nov 4 14:31:01 2002 +++ b/drivers/serial/Makefile Mon Nov 4 14:31:01 2002 @@ -7,6 +7,7 @@ export-objs := core.o 8250.o suncore.o serial-8250-y := +serial-8250-$(CONFIG_GSC) += 8250_gsc.o serial-8250-$(CONFIG_PCI) += 8250_pci.o serial-8250-$(CONFIG_PNP) += 8250_pnp.o obj-$(CONFIG_SERIAL_CORE) += core.o diff -Nru a/drivers/serial/amba.c b/drivers/serial/amba.c --- a/drivers/serial/amba.c Mon Nov 4 14:31:00 2002 +++ b/drivers/serial/amba.c Mon Nov 4 14:31:00 2002 @@ -245,7 +245,7 @@ } while (--count > 0); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_event(port, EVT_WRITE_WAKEUP); + uart_write_wakeup(port); if (uart_circ_empty(xmit)) ambauart_stop_tx(port); @@ -706,11 +706,7 @@ static struct uart_driver amba_reg = { .owner = THIS_MODULE, .driver_name = "ttyAM", -#ifdef CONFIG_DEVFS_FS .dev_name = "ttyAM%d", -#else - .dev_name = "ttyAM", -#endif .major = SERIAL_AMBA_MAJOR, .minor = SERIAL_AMBA_MINOR, .nr = UART_NR, diff -Nru a/drivers/serial/anakin.c b/drivers/serial/anakin.c --- a/drivers/serial/anakin.c Mon Nov 4 14:31:01 2002 +++ b/drivers/serial/anakin.c Mon Nov 4 14:31:01 2002 @@ -161,7 +161,7 @@ anakin_transmit_buffer(port); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_event(port, EVT_WRITE_WAKEUP); + uart_write_wakeup(port); } static void diff -Nru a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c --- a/drivers/serial/clps711x.c Mon Nov 4 14:31:01 2002 +++ b/drivers/serial/clps711x.c Mon Nov 4 14:31:01 2002 @@ -50,14 +50,12 @@ #define UART_NR 2 #ifndef CONFIG_SERIAL_CLPS711X_OLD_NAME -#define SERIAL_CLPS711X_NAME "ttyCL" #define SERIAL_CLPS711X_MAJOR 204 #define SERIAL_CLPS711X_MINOR 40 #define SERIAL_CLPS711X_NR UART_NR #else #warning The old names/device number for this driver if compatabity is needed -#define SERIAL_CLPS711X_NAME "ttyAM" #define SERIAL_CLPS711X_MAJOR 204 #define SERIAL_CLPS711X_MINOR 16 #define SERIAL_CLPS711X_NR UART_NR @@ -209,7 +207,7 @@ } while (--count > 0); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_event(port, EVT_WRITE_WAKEUP); + uart_write_wakeup(port); if (uart_circ_empty(xmit)) clps711xuart_stop_tx(port); @@ -545,7 +543,7 @@ } static struct console clps711x_console = { - .name = SERIAL_CLPS711X_NAME, + .name = "ttyCL", .write = clps711xuart_console_write, .device = clps711xuart_console_device, .setup = clps711xuart_console_setup, @@ -565,12 +563,7 @@ static struct uart_driver clps711x_reg = { .driver_name = "ttyCL", -#ifdef CONFIG_DEVFS_FS - .dev_name = SERIAL_CLPS711X_NAME, -#else - .dev_name = SERIAL_CLPS711X_NAME, -#endif - + .dev_name = "ttyCL%d", .major = SERIAL_CLPS711X_MAJOR, .minor = SERIAL_CLPS711X_MINOR, .nr = UART_NR, diff -Nru a/drivers/serial/core.c b/drivers/serial/core.c --- a/drivers/serial/core.c Mon Nov 4 14:31:01 2002 +++ b/drivers/serial/core.c Mon Nov 4 14:31:01 2002 @@ -65,11 +65,9 @@ * This routine is used by the interrupt handler to schedule processing in * the software interrupt portion of the driver. */ -void uart_event(struct uart_port *port, int event) +void uart_write_wakeup(struct uart_port *port) { struct uart_info *info = port->info; - - set_bit(0, &info->event); tasklet_schedule(&info->tlet); } @@ -112,13 +110,12 @@ struct tty_struct *tty; tty = info->tty; - if (!tty || !test_and_clear_bit(EVT_WRITE_WAKEUP, &info->event)) - return; - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); + if (tty) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + tty->ldisc.write_wakeup(tty); + wake_up_interruptible(&tty->write_wait); + } } static inline void @@ -1981,7 +1978,8 @@ static inline void uart_report_port(struct uart_driver *drv, struct uart_port *port) { - printk("%s%d at ", drv->dev_name, port->line); + printk(drv->dev_name, port->line); + printk(" at "); switch (port->iotype) { case UPIO_PORT: printk("I/O 0x%x", port->iobase); @@ -2005,7 +2003,6 @@ state->port = port; spin_lock_init(&port->lock); - port->type = PORT_UNKNOWN; port->cons = drv->cons; port->info = state->info; @@ -2022,8 +2019,10 @@ flags = UART_CONFIG_TYPE; if (port->flags & UPF_AUTO_IRQ) flags |= UART_CONFIG_IRQ; - if (port->flags & UPF_BOOT_AUTOCONF) + if (port->flags & UPF_BOOT_AUTOCONF) { + port->type = PORT_UNKNOWN; port->ops->config_port(port, flags); + } /* * Register the port whether it's detected or not. This allows @@ -2439,8 +2438,9 @@ struct uart_state *state; if (line < 0 || line >= drv->nr) { - printk(KERN_ERR "Attempt to unregister %s%d\n", - drv->dev_name, line); + printk(KERN_ERR "Attempt to unregister "); + printk(drv->dev_name, line); + printk("\n"); return; } @@ -2453,7 +2453,7 @@ up(&port_sem); } -EXPORT_SYMBOL(uart_event); +EXPORT_SYMBOL(uart_write_wakeup); EXPORT_SYMBOL(uart_register_driver); EXPORT_SYMBOL(uart_unregister_driver); EXPORT_SYMBOL(uart_register_port); diff -Nru a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c --- a/drivers/serial/sa1100.c Mon Nov 4 14:31:01 2002 +++ b/drivers/serial/sa1100.c Mon Nov 4 14:31:01 2002 @@ -305,7 +305,7 @@ } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_event(&sport->port, EVT_WRITE_WAKEUP); + uart_write_wakeup(&sport->port); if (uart_circ_empty(xmit)) sa1100_stop_tx(&sport->port, 0); @@ -661,7 +661,7 @@ void __init sa1100_register_uart(int idx, int port) { if (idx >= NR_PORTS) { - printk(KERN_ERR __FUNCTION__ ": bad index number %d\n", idx); + printk(KERN_ERR "%s: bad index number %d\n", __FUNCTION__, idx); return; } @@ -688,7 +688,7 @@ break; default: - printk(KERN_ERR __FUNCTION__ ": bad port number %d\n", port); + printk(KERN_ERR "%s: bad port number %d\n", __FUNCTION__, port); } } @@ -827,11 +827,7 @@ static struct uart_driver sa1100_reg = { .owner = THIS_MODULE, .driver_name = "ttySA", -#ifdef CONFIG_DEVFS_FS .dev_name = "ttySA%d", -#else - .dev_name = "ttySA", -#endif .major = SERIAL_SA1100_MAJOR, .minor = MINOR_START, .nr = NR_PORTS, diff -Nru a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c --- a/drivers/serial/sunsab.c Mon Nov 4 14:31:01 2002 +++ b/drivers/serial/sunsab.c Mon Nov 4 14:31:01 2002 @@ -266,7 +266,7 @@ writeb(SAB82532_CMDR_XF, &up->regs->w.cmdr); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_event(&up->port, EVT_WRITE_WAKEUP); + uart_write_wakeup(&up->port); if (uart_circ_empty(xmit)) sunsab_stop_tx(&up->port, 0); @@ -843,7 +843,7 @@ #ifdef CONFIG_DEVFS_FS .dev_name = "tts/%d", #else - .dev_name = "ttyS", + .dev_name = "ttyS%d", #endif .major = TTY_MAJOR, }; diff -Nru a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c --- a/drivers/serial/sunsu.c Mon Nov 4 14:31:01 2002 +++ b/drivers/serial/sunsu.c Mon Nov 4 14:31:01 2002 @@ -431,7 +431,7 @@ } while (--count > 0); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_event(&up->port, EVT_WRITE_WAKEUP); + uart_write_wakeup(&up->port); if (uart_circ_empty(xmit)) sunsu_stop_tx(&up->port, 0); @@ -1262,7 +1262,7 @@ #ifdef CONFIG_DEVFS_FS .dev_name = "tts/%d", #else - .dev_name = "ttyS", + .dev_name = "ttyS%d", #endif .major = TTY_MAJOR, }; diff -Nru a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c --- a/drivers/serial/sunzilog.c Mon Nov 4 14:31:03 2002 +++ b/drivers/serial/sunzilog.c Mon Nov 4 14:31:03 2002 @@ -523,7 +523,7 @@ up->port.icount.tx++; if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_event(&up->port, EVT_WRITE_WAKEUP); + uart_write_wakeup(&up->port); if (!uart_circ_empty(xmit)) return; @@ -1003,7 +1003,7 @@ #ifdef CONFIG_DEVFS_FS .dev_name = "ttyS%d", #else - .dev_name = "ttyS", + .dev_name = "ttyS%d", #endif .major = TTY_MAJOR, }; diff -Nru a/drivers/serial/uart00.c b/drivers/serial/uart00.c --- a/drivers/serial/uart00.c Mon Nov 4 14:31:01 2002 +++ b/drivers/serial/uart00.c Mon Nov 4 14:31:01 2002 @@ -215,7 +215,7 @@ } while (--count > 0); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_event(port, EVT_WRITE_WAKEUP); + uart_write_wakeup(port); if (uart_circ_empty(xmit)) uart00_stop_tx(port, 0); diff -Nru a/drivers/video/Kconfig b/drivers/video/Kconfig --- a/drivers/video/Kconfig Mon Nov 4 14:31:00 2002 +++ b/drivers/video/Kconfig Mon Nov 4 14:31:00 2002 @@ -350,9 +350,8 @@ console or the IODC BIOS. config FB_MAC - bool + bool "Generic Macintosh display support" depends on FB && MAC - default y # bool ' Apple DAFB display support' CONFIG_FB_DAFB config FB_HP300 diff -Nru a/drivers/video/fbcon.c b/drivers/video/fbcon.c --- a/drivers/video/fbcon.c Mon Nov 4 14:31:01 2002 +++ b/drivers/video/fbcon.c Mon Nov 4 14:31:01 2002 @@ -627,7 +627,7 @@ } if (!fontwidthvalid(p,fontwidth(p))) { -#ifdef CONFIG_FBCON_MAC +#if defined(CONFIG_FBCON_MAC) && defined(CONFIG_MAC) if (MACH_IS_MAC) /* ++Geert: hack to make 6x11 fonts work on mac */ p->dispsw = &fbcon_mac; diff -Nru a/drivers/video/hpfb.c b/drivers/video/hpfb.c --- a/drivers/video/hpfb.c Mon Nov 4 14:31:02 2002 +++ b/drivers/video/hpfb.c Mon Nov 4 14:31:02 2002 @@ -78,29 +78,29 @@ unsigned blue, unsigned transp, struct fb_info *info) { - while (readw(fb_regs + 0x6002) & 0x4) udelay(1); - writew(0, fb_regs + 0x60f0); - writew(regno, fb_regs + 0x60b8); - writew(red, fb_regs + 0x60b2); - writew(green, fb_regs + 0x60b4); - writew(blue, fb_regs + 0x60b6); - writew(0xff, fb_regs + 0x60f0); + while (in_be16(fb_regs + 0x6002) & 0x4) udelay(1); + out_be16(fb_regs + 0x60f0, 0); + out_be16(fb_regs + 0x60b8, regno); + out_be16(fb_regs + 0x60b2, red); + out_be16(fb_regs + 0x60b4, green); + out_be16(fb_regs + 0x60b6, blue); + out_be16(fb_regs + 0x60f0, 0xff); udelay(100); - writew(0xffff, fb_regs + 0x60ba); + out_be16(fb_regs + 0x60ba, 0xffff); return 0; } void hpfb_copyarea(struct fb_info *info, struct fb_copyarea *area) { - while (readb(fb_regs + BUSY) & fb_bitmask); - writeb(0x3, fb_regs + WMRR); - writew(area->sx, fb_regs + SOURCE_X); - writew(area->sy, fb_regs + SOURCE_Y); - writew(area->dx, fb_regs + DEST_X); - writew(area->dy, fb_regs + DEST_Y); - writew(area->height, fb_regs + WHEIGHT); - writew(area->width, fb_regs + WWIDTH); - writeb(fb_bitmask, fb_regs + WMOVE); + while (in_8(fb_regs + BUSY) & fb_bitmask); + out_8(fb_regs + WMRR, 0x3); + out_be16(fb_regs + SOURCE_X, area->sx); + out_be16(fb_regs + SOURCE_Y, area->sy); + out_be16(fb_regs + DEST_X, area->dx); + out_be16(fb_regs + DEST_Y, area->dy); + out_be16(fb_regs + WHEIGHT, area->height); + out_be16(fb_regs + WWIDTH, area->width); + out_8(fb_regs + WMOVE, fb_bitmask); } static struct fb_ops hpfb_ops = { @@ -121,38 +121,37 @@ { unsigned long fboff; - fboff = (readb(base + TOPCAT_FBOMSB) << 8) - | readb(base + TOPCAT_FBOLSB); + fboff = (in_8(base + TOPCAT_FBOMSB) << 8) | in_8(base + TOPCAT_FBOLSB); - hpfb_fix.smem_start = 0xf0000000 | (readb(base + fboff) << 16); + hpfb_fix.smem_start = 0xf0000000 | (in_8(base + fboff) << 16); fb_regs = base; #if 0 /* This is the magic incantation NetBSD uses to make Catseye boards work. */ - writeb(0, base+0x4800); - writeb(0, base+0x4510); - writeb(0, base+0x4512); - writeb(0, base+0x4514); - writeb(0, base+0x4516); - writeb(0x90, base+0x4206); + out_8(base+0x4800, 0); + out_8(base+0x4510, 0); + out_8(base+0x4512, 0); + out_8(base+0x4514, 0); + out_8(base+0x4516, 0); + out_8(base+0x4206, 0x90); #endif /* * Give the hardware a bit of a prod and work out how many bits per * pixel are supported. */ - writeb(0xff, base + TC_WEN); - writeb(0xff, base + TC_FBEN); - writeb(0xff, hpfb_fix.smem_start); - fb_bitmask = readb(hpfb_fix.smem_start); + out_8(base + TC_WEN, 0xff); + out_8(base + TC_FBEN, 0xff); + out_8(hpfb_fix.smem_start, 0xff); + fb_bitmask = in_8(hpfb_fix.smem_start); /* * Enable reading/writing of all the planes. */ - writeb(fb_bitmask, base + TC_WEN); - writeb(fb_bitmask, base + TC_REN); - writeb(fb_bitmask, base + TC_FBEN); - writeb(0x1, base + TC_NBLANK); + out_8(base + TC_WEN, fb_bitmask); + out_8(base + TC_REN, fb_bitmask); + out_8(base + TC_FBEN, fb_bitmask); + out_8(base + TC_NBLANK, 0x1); /* * Let there be consoles.. diff -Nru a/drivers/zorro/proc.c b/drivers/zorro/proc.c --- a/drivers/zorro/proc.c Mon Nov 4 14:31:00 2002 +++ b/drivers/zorro/proc.c Mon Nov 4 14:31:00 2002 @@ -51,7 +51,7 @@ struct proc_dir_entry *dp = PDE(ino); struct zorro_dev *dev = dp->data; struct ConfigDev cd; - int pos = *ppos; + loff_t pos = *ppos; if (pos >= sizeof(struct ConfigDev)) return 0; diff -Nru a/drivers/zorro/zorro.ids b/drivers/zorro/zorro.ids --- a/drivers/zorro/zorro.ids Mon Nov 4 14:31:02 2002 +++ b/drivers/zorro/zorro.ids Mon Nov 4 14:31:02 2002 @@ -4,7 +4,7 @@ # Maintained by Geert Uytterhoeven # If you have any new entries, please send them to the maintainer. # -# $Id: zorro.ids,v 1.17 2001/10/25 08:21:39 geert Exp $ +# $Id: zorro.ids,v 1.19 2002/10/14 13:08:58 geert Exp $ # # Manufacturers and Products. Please keep sorted. @@ -364,7 +364,13 @@ 1300 Warp Engine 40xx [Accelerator, SCSI Host Adapter and RAM Expansion] 089e ElBox Computer 0600 1200/4 [RAM Expansion] - 1900 PowerFlyer [IDE Interface] + 0800 FastATA 1200 [IDE Interface] + 1200 FastATA 1200 [IDE Interface] + 1300 FastATA 1200 [IDE Interface] + 1800 FastATA 1200 [IDE Interface] + 1900 FastATA 4000 [IDE Interface] + 1d00 FastATA 4000 [IDE Interface] + 1e00 FastATA ZIV [IDE Interface] 0a00 Harms Professional 1000 030 Plus [Accelerator] d000 3500 Professional [Accelerator and RAM Expansion] diff -Nru a/fs/Kconfig b/fs/Kconfig --- a/fs/Kconfig Mon Nov 4 14:31:02 2002 +++ b/fs/Kconfig Mon Nov 4 14:31:02 2002 @@ -289,6 +289,31 @@ of your root partition (the one containing the directory /) cannot be compiled as a module, and so this may be dangerous. +config EXT3_FS_XATTR + bool "Ext3 extended attributes" + depends on EXT3_FS + default y + ---help--- + Extended attributes are name:value pairs associated with inodes by + the kernel or by users (see the attr(5) manual page, or visit + for details). + + If unsure, say N. + + You need this for POSIX ACL support on ext3. + +config EXT3_FS_POSIX_ACL + bool "Ext3 POSIX Access Control Lists" + depends on EXT3_FS_XATTR + ---help--- + Posix Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the Posix ACLs for + Linux website . + + If you don't know what Access Control Lists are, say N + # CONFIG_JBD could be its own option (even modular), but until there are # other users than ext3, we will simply make it be the same as CONFIG_EXT3_FS # dep_tristate ' Journal Block Device support (JBD for ext3)' CONFIG_JBD $CONFIG_EXT3_FS @@ -578,6 +603,10 @@ say M here and read . The module will be called ramfs.o. +config HUGETLBFS + bool "HugeTLB file system support" + depends on HUGETLB_PAGE + config ISO9660_FS tristate "ISO 9660 CDROM file system support" ---help--- @@ -626,6 +655,18 @@ If you do not intend to use the JFS filesystem, say N. +config JFS_POSIX_ACL + bool "JFS POSIX Access Control Lists" + depends on JFS_FS + ---help--- + Posix Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the Posix ACLs for + Linux website . + + If you don't know what Access Control Lists are, say N + config JFS_DEBUG bool "JFS debugging" depends on JFS_FS @@ -935,6 +976,28 @@ be compiled as a module, and so this could be dangerous. Most everyone wants to say Y here. +config EXT2_FS_XATTR + bool "Ext2 extended attributes" + depends on EXT2_FS + ---help--- + Extended attributes are name:value pairs associated with inodes by + the kernel or by users (see the attr(5) manual page, or visit + for details). + + If unsure, say N. + +config EXT2_FS_POSIX_ACL + bool "Ext2 POSIX Access Control Lists" + depends on EXT2_FS_XATTR + ---help--- + Posix Access Control Lists (ACLs) support permissions for users and + groups beyond the owner/group/world scheme. + + To learn more about Access Control Lists, visit the Posix ACLs for + Linux website . + + If you don't know what Access Control Lists are, say N + config SYSV_FS tristate "System V/Xenix/V7/Coherent file system support" ---help--- @@ -1406,6 +1469,18 @@ depends on ZISOFS default ISO9660_FS +# Meta block cache for Extended Attributes (ext2/ext3) +config FS_MBCACHE + tristate + depends on EXT2_FS_XATTR || EXT3_FS_XATTR + default y if EXT2_FS=y || EXT3_FS=y + default m if EXT2_FS=m || EXT3_FS=m + +# Posix ACL utility routines (for now, only ext2/ext3/jfs) +config FS_POSIX_ACL + bool + depends on EXT2_FS_POSIX_ACL || EXT3_FS_POSIX_ACL || JFS_POSIX_ACL + default y menu "Partition Types" diff -Nru a/fs/Makefile b/fs/Makefile --- a/fs/Makefile Mon Nov 4 14:31:02 2002 +++ b/fs/Makefile Mon Nov 4 14:31:02 2002 @@ -6,14 +6,14 @@ # export-objs := open.o dcache.o buffer.o bio.o inode.o dquot.o mpage.o aio.o \ - fcntl.o read_write.o dcookies.o fcblist.o + fcntl.o read_write.o dcookies.o mbcache.o posix_acl.o xattr_acl.o obj-y := open.o read_write.o devices.o file_table.o buffer.o \ bio.o super.o block_dev.o char_dev.o stat.o exec.o pipe.o \ namei.o fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \ dcache.o inode.o attr.o bad_inode.o file.o dnotify.o \ filesystems.o namespace.o seq_file.o xattr.o libfs.o \ - fs-writeback.o mpage.o direct-io.o aio.o fcblist.o + fs-writeback.o mpage.o direct-io.o aio.o eventpoll.o ifneq ($(CONFIG_NFSD),n) ifneq ($(CONFIG_NFSD),) @@ -29,6 +29,11 @@ obj-y += binfmt_script.o obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o +obj-$(CONFIG_BINFMT_SOM) += binfmt_som.o +obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o + +obj-$(CONFIG_FS_MBCACHE) += mbcache.o +obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o obj-$(CONFIG_QUOTA) += dquot.o obj-$(CONFIG_QFMT_V1) += quota_v1.o @@ -37,7 +42,7 @@ obj-$(CONFIG_PROC_FS) += proc/ obj-y += partitions/ -obj-y += driverfs/ sysfs/ +obj-y += sysfs/ obj-y += devpts/ obj-$(CONFIG_PROFILING) += dcookies.o @@ -48,6 +53,7 @@ obj-$(CONFIG_EXT2_FS) += ext2/ obj-$(CONFIG_CRAMFS) += cramfs/ obj-$(CONFIG_RAMFS) += ramfs/ +obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ obj-$(CONFIG_CODA_FS) += coda/ obj-$(CONFIG_INTERMEZZO_FS) += intermezzo/ obj-$(CONFIG_MINIX_FS) += minix/ diff -Nru a/fs/afs/Makefile b/fs/afs/Makefile --- a/fs/afs/Makefile Mon Nov 4 14:31:02 2002 +++ b/fs/afs/Makefile Mon Nov 4 14:31:02 2002 @@ -23,14 +23,6 @@ vnode.o \ volume.o -# cache.o - -obj-m := kafs.o - -# superfluous for 2.5, but needed for 2.4.. -ifeq "$(VERSION).$(PATCHLEVEL)" "2.4" -kafs.o: $(kafs-objs) - $(LD) -r -o kafs.o $(kafs-objs) -endif +obj-$(CONFIG_AFS_FS) := kafs.o include $(TOPDIR)/Rules.make diff -Nru a/fs/afs/dir.c b/fs/afs/dir.c --- a/fs/afs/dir.c Mon Nov 4 14:31:01 2002 +++ b/fs/afs/dir.c Mon Nov 4 14:31:01 2002 @@ -38,19 +38,17 @@ struct inode_operations afs_dir_inode_operations = { .lookup = afs_dir_lookup, -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) .getattr = afs_inode_getattr, -#else - .revalidate = afs_inode_revalidate, +#if 0 /* TODO */ + .create = afs_dir_create, + .link = afs_dir_link, + .unlink = afs_dir_unlink, + .symlink = afs_dir_symlink, + .mkdir = afs_dir_mkdir, + .rmdir = afs_dir_rmdir, + .mknod = afs_dir_mknod, + .rename = afs_dir_rename, #endif -// .create = afs_dir_create, -// .link = afs_dir_link, -// .unlink = afs_dir_unlink, -// .symlink = afs_dir_symlink, -// .mkdir = afs_dir_mkdir, -// .rmdir = afs_dir_rmdir, -// .mknod = afs_dir_mknod, -// .rename = afs_dir_rename, }; static struct dentry_operations afs_fs_dentry_operations = { @@ -72,7 +70,7 @@ u8 name[16]; u8 overflow[4]; /* if any char of the name (inc NUL) reaches here, consume * the next dirent too */ - }; + } parts; u8 extended_name[32]; } afs_dirent_t; @@ -250,7 +248,7 @@ /* skip entries marked unused in the bitmap */ if (!(block->pagehdr.bitmap[offset/8] & (1 << (offset % 8)))) { - _debug("ENT[%u.%u]: unused\n",blkoff/sizeof(afs_dir_block_t),offset); + _debug("ENT[%Zu.%u]: unused\n",blkoff/sizeof(afs_dir_block_t),offset); if (offset>=curr) *fpos = blkoff + next * sizeof(afs_dirent_t); continue; @@ -258,28 +256,28 @@ /* got a valid entry */ dire = &block->dirents[offset]; - nlen = strnlen(dire->name,sizeof(*block) - offset*sizeof(afs_dirent_t)); + nlen = strnlen(dire->parts.name,sizeof(*block) - offset*sizeof(afs_dirent_t)); - _debug("ENT[%u.%u]: %s %u \"%.*s\"\n", + _debug("ENT[%Zu.%u]: %s %Zu \"%s\"\n", blkoff/sizeof(afs_dir_block_t),offset, - offsetname); + (offsetu.name); /* work out where the next possible entry is */ for (tmp=nlen; tmp>15; tmp-=sizeof(afs_dirent_t)) { if (next>=AFS_DIRENT_PER_BLOCK) { - _debug("ENT[%u.%u]:" - " %u travelled beyond end dir block (len %u/%u)\n", + _debug("ENT[%Zu.%u]:" + " %u travelled beyond end dir block (len %u/%Zu)\n", blkoff/sizeof(afs_dir_block_t),offset,next,tmp,nlen); return -EIO; } if (!(block->pagehdr.bitmap[next/8] & (1 << (next % 8)))) { - _debug("ENT[%u.%u]: %u unmarked extension (len %u/%u)\n", + _debug("ENT[%Zu.%u]: %u unmarked extension (len %u/%Zu)\n", blkoff/sizeof(afs_dir_block_t),offset,next,tmp,nlen); return -EIO; } - _debug("ENT[%u.%u]: ext %u/%u\n", + _debug("ENT[%Zu.%u]: ext %u/%Zu\n", blkoff/sizeof(afs_dir_block_t),next,tmp,nlen); next++; } @@ -290,11 +288,11 @@ /* found the next entry */ ret = filldir(cookie, - dire->name, + dire->parts.name, nlen, blkoff + offset * sizeof(afs_dirent_t), - ntohl(dire->vnode), - filldir==afs_dir_lookup_filldir ? dire->unique : DT_UNKNOWN); + ntohl(dire->parts.vnode), + filldir==afs_dir_lookup_filldir ? dire->parts.unique : DT_UNKNOWN); if (ret<0) { _leave(" = 0 [full]"); return 0; @@ -397,7 +395,7 @@ { struct afs_dir_lookup_cookie *cookie = _cookie; - _enter("{%s,%u},%s,%u,,%lu,%u",cookie->name,cookie->nlen,name,nlen,ino,ntohl(dtype)); + _enter("{%s,%Zu},%s,%u,,%lu,%u",cookie->name,cookie->nlen,name,nlen,ino,ntohl(dtype)); if (cookie->nlen != nlen || memcmp(cookie->name,name,nlen)!=0) { _leave(" = 0 [no]"); @@ -471,7 +469,7 @@ } dentry->d_op = &afs_fs_dentry_operations; - dentry->d_fsdata = (void*) (unsigned) vnode->status.version; + dentry->d_fsdata = (void*) (unsigned long) vnode->status.version; d_add(dentry,inode); _leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%lu }", @@ -500,15 +498,9 @@ _enter("%s,%x",dentry->d_name.name,flags); /* lock down the parent dentry so we can peer at it */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) read_lock(&dparent_lock); parent = dget(dentry->d_parent); read_unlock(&dparent_lock); -#else - lock_kernel(); - parent = dget(dentry->d_parent); - unlock_kernel(); -#endif dir = parent->d_inode; inode = dentry->d_inode; @@ -541,10 +533,10 @@ goto out_bad; } - if ((unsigned)dentry->d_fsdata != (unsigned)AFS_FS_I(dir)->status.version) { - _debug("%s: parent changed %u -> %u", + if ((unsigned long)dentry->d_fsdata != (unsigned long)AFS_FS_I(dir)->status.version) { + _debug("%s: parent changed %lu -> %u", dentry->d_name.name, - (unsigned)dentry->d_fsdata, + (unsigned long)dentry->d_fsdata, (unsigned)AFS_FS_I(dir)->status.version); /* search the directory for this vnode */ @@ -585,7 +577,7 @@ goto out_bad; } - dentry->d_fsdata = (void*) (unsigned) AFS_FS_I(dir)->status.version; + dentry->d_fsdata = (void*) (unsigned long) AFS_FS_I(dir)->status.version; } out_valid: diff -Nru a/fs/afs/errors.h b/fs/afs/errors.h --- a/fs/afs/errors.h Mon Nov 4 14:31:03 2002 +++ b/fs/afs/errors.h Mon Nov 4 14:31:03 2002 @@ -9,8 +9,8 @@ * 2 of the License, or (at your option) any later version. */ -#ifndef _H_DB712916_5113_11D6_9A6D_0002B3163499 -#define _H_DB712916_5113_11D6_9A6D_0002B3163499 +#ifndef _LINUX_AFS_ERRORS_H +#define _LINUX_AFS_ERRORS_H #include "types.h" @@ -31,4 +31,4 @@ extern int afs_abort_to_error(int abortcode); -#endif /* _H_DB712916_5113_11D6_9A6D_0002B3163499 */ +#endif /* _LINUX_AFS_ERRORS_H */ diff -Nru a/fs/afs/file.c b/fs/afs/file.c --- a/fs/afs/file.c Mon Nov 4 14:31:02 2002 +++ b/fs/afs/file.c Mon Nov 4 14:31:02 2002 @@ -21,52 +21,33 @@ #include #include "internal.h" -//static int afs_file_open(struct inode *inode, struct file *file); -//static int afs_file_release(struct inode *inode, struct file *file); +#if 0 +static int afs_file_open(struct inode *inode, struct file *file); +static int afs_file_release(struct inode *inode, struct file *file); +#endif static int afs_file_readpage(struct file *file, struct page *page); -//static ssize_t afs_file_read(struct file *file, char *buf, size_t size, loff_t *off); - static ssize_t afs_file_write(struct file *file, const char *buf, size_t size, loff_t *off); struct inode_operations afs_file_inode_operations = { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) .getattr = afs_inode_getattr, -#else - .revalidate = afs_inode_revalidate, -#endif }; struct file_operations afs_file_file_operations = { -// .open = afs_file_open, -// .release = afs_file_release, - .read = generic_file_read, //afs_file_read, + .read = generic_file_read, .write = afs_file_write, .mmap = generic_file_mmap, -// .fsync = afs_file_fsync, +#if 0 + .open = afs_file_open, + .release = afs_file_release, + .fsync = afs_file_fsync, +#endif }; struct address_space_operations afs_fs_aops = { .readpage = afs_file_readpage, }; - -/*****************************************************************************/ -/* - * AFS file read - */ -#if 0 -static ssize_t afs_file_read(struct file *file, char *buf, size_t size, loff_t *off) -{ - struct afs_inode_info *ai; - - ai = AFS_FS_I(file->f_dentry->d_inode); - if (ai->flags & AFS_INODE_DELETED) - return -ESTALE; - - return -EIO; -} /* end afs_file_read() */ -#endif /*****************************************************************************/ /* diff -Nru a/fs/afs/fsclient.c b/fs/afs/fsclient.c --- a/fs/afs/fsclient.c Mon Nov 4 14:31:02 2002 +++ b/fs/afs/fsclient.c Mon Nov 4 14:31:02 2002 @@ -426,7 +426,7 @@ int ret; u32 *bp; - _enter("%p,{fid={%u,%u,%u},sz=%u,of=%lu}", + _enter("%p,{fid={%u,%u,%u},sz=%Zu,of=%lu}", server, desc->fid.vid, desc->fid.vnode, diff -Nru a/fs/afs/inode.c b/fs/afs/inode.c --- a/fs/afs/inode.c Mon Nov 4 14:31:01 2002 +++ b/fs/afs/inode.c Mon Nov 4 14:31:01 2002 @@ -28,9 +28,6 @@ struct afs_iget_data { afs_fid_t fid; afs_volume_t *volume; /* volume on which resides */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - afs_vnode_t *new_vnode; /* new vnode record */ -#endif }; /*****************************************************************************/ @@ -41,7 +38,7 @@ { struct inode *inode = AFS_VNODE_TO_I(vnode); - _debug("FS: ft=%d lk=%d sz=%u ver=%Lu mod=%hu", + _debug("FS: ft=%d lk=%d sz=%Zu ver=%Lu mod=%hu", vnode->status.type, vnode->status.nlink, vnode->status.size, @@ -117,7 +114,6 @@ /* * iget5() comparator */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) static int afs_iget5_test(struct inode *inode, void *opaque) { struct afs_iget_data *data = opaque; @@ -125,13 +121,11 @@ /* only match inodes with the same version number */ return inode->i_ino==data->fid.vnode && inode->i_version==data->fid.unique; } /* end afs_iget5_test() */ -#endif /*****************************************************************************/ /* * iget5() inode initialiser */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) static int afs_iget5_set(struct inode *inode, void *opaque) { struct afs_iget_data *data = opaque; @@ -144,71 +138,6 @@ return 0; } /* end afs_iget5_set() */ -#endif - -/*****************************************************************************/ -/* - * iget4() comparator - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -static int afs_iget4_test(struct inode *inode, ino_t ino, void *opaque) -{ - struct afs_iget_data *data = opaque; - - /* only match inodes with the same version number */ - return inode->i_ino==data->fid.vnode && inode->i_version==data->fid.unique; -} /* end afs_iget4_test() */ -#endif - -/*****************************************************************************/ -/* - * read an inode (2.4 only) - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -void afs_read_inode2(struct inode *inode, void *opaque) -{ - struct afs_iget_data *data = opaque; - afs_vnode_t *vnode; - int ret; - - _enter(",{{%u,%u,%u},%p}",data->fid.vid,data->fid.vnode,data->fid.unique,data->volume); - - if (inode->u.generic_ip) BUG(); - - /* attach a pre-allocated vnode record */ - inode->u.generic_ip = vnode = data->new_vnode; - data->new_vnode = NULL; - - memset(vnode,0,sizeof(*vnode)); - vnode->inode = inode; - init_waitqueue_head(&vnode->update_waitq); - spin_lock_init(&vnode->lock); - INIT_LIST_HEAD(&vnode->cb_link); - INIT_LIST_HEAD(&vnode->cb_hash_link); - afs_timer_init(&vnode->cb_timeout,&afs_vnode_cb_timed_out_ops); - vnode->flags |= AFS_VNODE_CHANGED; - vnode->volume = data->volume; - vnode->fid = data->fid; - - /* ask the server for a status check */ - ret = afs_vnode_fetch_status(vnode); - if (ret<0) { - make_bad_inode(inode); - _leave(" [bad inode]"); - return; - } - - ret = afs_inode_map_status(vnode); - if (ret<0) { - make_bad_inode(inode); - _leave(" [bad inode]"); - return; - } - - _leave(""); - return; -} /* end afs_read_inode2() */ -#endif /*****************************************************************************/ /* @@ -227,7 +156,6 @@ as = sb->s_fs_info; data.volume = as->volume; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) inode = iget5_locked(sb,fid->vnode,afs_iget5_test,afs_iget5_set,&data); if (!inode) { _leave(" = -ENOMEM"); @@ -253,13 +181,6 @@ if (ret<0) goto bad_inode; -#if 0 - /* find a cache entry for it */ - ret = afs_cache_lookup_vnode(as->volume,vnode); - if (ret<0) - goto bad_inode; -#endif - /* success */ unlock_new_inode(inode); @@ -280,42 +201,12 @@ _leave(" = %d [bad]",ret); return ret; - -#else - - /* pre-allocate a vnode record so that afs_read_inode2() doesn't have to return an inode - * without one attached - */ - data.new_vnode = kmalloc(sizeof(afs_vnode_t),GFP_KERNEL); - if (!data.new_vnode) { - _leave(" = -ENOMEM"); - return -ENOMEM; - } - - inode = iget4(sb,fid->vnode,afs_iget4_test,&data); - if (data.new_vnode) kfree(data.new_vnode); - if (!inode) { - _leave(" = -ENOMEM"); - return -ENOMEM; - } - - vnode = AFS_FS_I(inode); - *_inode = inode; - _leave(" = 0 [CB { v=%u x=%lu t=%u nix=%u }]", - vnode->cb_version, - vnode->cb_timeout.timo_jif, - vnode->cb_type, - vnode->nix - ); - return 0; -#endif } /* end afs_iget() */ /*****************************************************************************/ /* * read the attributes of an inode */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct inode *inode; @@ -349,44 +240,6 @@ return 0; } /* end afs_inode_getattr() */ -#endif - -/*****************************************************************************/ -/* - * revalidate the inode - */ -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) -int afs_inode_revalidate(struct dentry *dentry) -{ - struct inode *inode; - afs_vnode_t *vnode; - int ret; - - inode = dentry->d_inode; - - _enter("{ ino=%lu v=%lu }",inode->i_ino,inode->i_version); - - vnode = AFS_FS_I(inode); - - ret = afs_inode_fetch_status(inode); - if (ret==-ENOENT) { - _leave(" = %d [%d %p]",ret,atomic_read(&dentry->d_count),dentry->d_inode); - return ret; - } - else if (ret<0) { - make_bad_inode(inode); - _leave(" = %d",ret); - return ret; - } - - _leave(" = 0 CB { v=%u x=%u t=%u }", - vnode->cb_version, - vnode->cb_expiry, - vnode->cb_type); - - return 0; -} /* end afs_inode_revalidate() */ -#endif /*****************************************************************************/ /* @@ -409,10 +262,6 @@ if (inode->i_ino!=vnode->fid.vnode) BUG(); afs_vnode_give_up_callback(vnode); - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) - if (inode->u.generic_ip) kfree(inode->u.generic_ip); -#endif _leave(""); } /* end afs_clear_inode() */ diff -Nru a/fs/afs/internal.h b/fs/afs/internal.h --- a/fs/afs/internal.h Mon Nov 4 14:31:01 2002 +++ b/fs/afs/internal.h Mon Nov 4 14:31:01 2002 @@ -21,34 +21,24 @@ /* * debug tracing */ -#define kenter(FMT,...) printk("==> %s("FMT")\n",__FUNCTION__,##__VA_ARGS__) -#define kleave(FMT,...) printk("<== %s()"FMT"\n",__FUNCTION__,##__VA_ARGS__) -#define kdebug(FMT,...) printk(FMT"\n",##__VA_ARGS__) -#define kproto(FMT,...) printk("### "FMT"\n",##__VA_ARGS__) -#define knet(FMT,...) printk(FMT"\n",##__VA_ARGS__) +#define kenter(FMT, a...) printk("==> %s("FMT")\n",__FUNCTION__ , ## a) +#define kleave(FMT, a...) printk("<== %s()"FMT"\n",__FUNCTION__ , ## a) +#define kdebug(FMT, a...) printk(FMT"\n" , ## a) +#define kproto(FMT, a...) printk("### "FMT"\n" , ## a) +#define knet(FMT, a...) printk(FMT"\n" , ## a) #if 0 -#define _enter(FMT,...) kenter(FMT,##__VA_ARGS__) -#define _leave(FMT,...) kleave(FMT,##__VA_ARGS__) -#define _debug(FMT,...) kdebug(FMT,##__VA_ARGS__) -#define _proto(FMT,...) kproto(FMT,##__VA_ARGS__) -#define _net(FMT,...) knet(FMT,##__VA_ARGS__) +#define _enter(FMT, a...) kenter(FMT , ## a) +#define _leave(FMT, a...) kleave(FMT , ## a) +#define _debug(FMT, a...) kdebug(FMT , ## a) +#define _proto(FMT, a...) kproto(FMT , ## a) +#define _net(FMT, a...) knet(FMT , ## a) #else -#define _enter(FMT,...) do { } while(0) -#define _leave(FMT,...) do { } while(0) -#define _debug(FMT,...) do { } while(0) -#define _proto(FMT,...) do { } while(0) -#define _net(FMT,...) do { } while(0) -#endif - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) -#define wait_on_page_locked wait_on_page -#define PageUptodate Page_Uptodate - -static inline struct proc_dir_entry *PDE(const struct inode *inode) -{ - return (struct proc_dir_entry *)inode->u.generic_ip; -} +#define _enter(FMT, a...) do { } while(0) +#define _leave(FMT, a...) do { } while(0) +#define _debug(FMT, a...) do { } while(0) +#define _proto(FMT, a...) do { } while(0) +#define _net(FMT, a...) do { } while(0) #endif static inline void afs_discard_my_signals(void) @@ -85,12 +75,7 @@ * inode.c */ extern int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inode); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) extern int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); -#else -extern void afs_read_inode2(struct inode *inode, void *opaque); -extern int afs_inode_revalidate(struct dentry *dentry); -#endif extern void afs_clear_inode(struct inode *inode); /* @@ -113,7 +98,7 @@ extern spinlock_t afs_cb_hash_lock; #define afs_cb_hash(SRV,FID) \ - afs_cb_hash_tbl[((unsigned)(SRV) + (FID)->vid + (FID)->vnode + (FID)->unique) % \ + afs_cb_hash_tbl[((unsigned long)(SRV) + (FID)->vid + (FID)->vnode + (FID)->unique) % \ AFS_CB_HASH_COUNT] /* diff -Nru a/fs/afs/kafsasyncd.c b/fs/afs/kafsasyncd.c --- a/fs/afs/kafsasyncd.c Mon Nov 4 14:31:01 2002 +++ b/fs/afs/kafsasyncd.c Mon Nov 4 14:31:01 2002 @@ -103,11 +103,7 @@ /* only certain signals are of interest */ spin_lock_irq(¤t->sig->siglock); siginitsetinv(¤t->blocked,0); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,3) recalc_sigpending(); -#else - recalc_sigpending(current); -#endif spin_unlock_irq(¤t->sig->siglock); /* loop around looking for things to attend to */ diff -Nru a/fs/afs/kafstimod.c b/fs/afs/kafstimod.c --- a/fs/afs/kafstimod.c Mon Nov 4 14:31:02 2002 +++ b/fs/afs/kafstimod.c Mon Nov 4 14:31:02 2002 @@ -80,11 +80,7 @@ /* only certain signals are of interest */ spin_lock_irq(¤t->sig->siglock); siginitsetinv(¤t->blocked,0); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,3) recalc_sigpending(); -#else - recalc_sigpending(current); -#endif spin_unlock_irq(¤t->sig->siglock); /* loop around looking for things to attend to */ diff -Nru a/fs/afs/main.c b/fs/afs/main.c --- a/fs/afs/main.c Mon Nov 4 14:31:01 2002 +++ b/fs/afs/main.c Mon Nov 4 14:31:01 2002 @@ -173,8 +173,8 @@ _debug("Discarding peer %08x (rtt=%lu.%lumS)\n", ntohl(peer->addr.s_addr), - peer->rtt/1000, - peer->rtt%1000); + (long)(peer->rtt/1000), + (long)(peer->rtt%1000)); /* uncross-point the structs under a global lock */ spin_lock(&afs_server_peer_lock); diff -Nru a/fs/afs/mntpt.c b/fs/afs/mntpt.c --- a/fs/afs/mntpt.c Mon Nov 4 14:31:01 2002 +++ b/fs/afs/mntpt.c Mon Nov 4 14:31:01 2002 @@ -31,11 +31,7 @@ struct inode_operations afs_mntpt_inode_operations = { .lookup = afs_mntpt_lookup, .readlink = page_readlink, -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) .getattr = afs_inode_getattr, -#else - .revalidate = afs_inode_revalidate, -#endif }; /*****************************************************************************/ @@ -70,7 +66,7 @@ /* examine the symlink's contents */ size = vnode->status.size; - _debug("symlink to %*.*s",size,size,buf); + _debug("symlink to %*.*s",size,(int)size,buf); if (size>2 && (buf[0]=='%' || buf[0]=='#') && diff -Nru a/fs/afs/proc.c b/fs/afs/proc.c --- a/fs/afs/proc.c Mon Nov 4 14:31:01 2002 +++ b/fs/afs/proc.c Mon Nov 4 14:31:01 2002 @@ -412,6 +412,7 @@ afs_put_cell(cell); + return ret; } /* end afs_proc_cell_volumes_release() */ /*****************************************************************************/ @@ -536,6 +537,7 @@ afs_put_cell(cell); + return ret; } /* end afs_proc_cell_vlservers_release() */ /*****************************************************************************/ @@ -651,6 +653,7 @@ afs_put_cell(cell); + return ret; } /* end afs_proc_cell_servers_release() */ /*****************************************************************************/ diff -Nru a/fs/afs/super.c b/fs/afs/super.c --- a/fs/afs/super.c Mon Nov 4 14:31:01 2002 +++ b/fs/afs/super.c Mon Nov 4 14:31:01 2002 @@ -39,12 +39,8 @@ static void afs_i_init_once(void *foo, kmem_cache_t *cachep, unsigned long flags); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) static struct super_block *afs_get_sb(struct file_system_type *fs_type, int flags, char *dev_name, void *data); -#else -static struct super_block *afs_read_super(struct super_block *sb, void *data, int); -#endif static struct inode *afs_alloc_inode(struct super_block *sb); @@ -55,30 +51,20 @@ static struct file_system_type afs_fs_type = { .owner = THIS_MODULE, .name = "afs", -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) .get_sb = afs_get_sb, .kill_sb = kill_anon_super, -#else - .read_super = afs_read_super, -#endif }; static struct super_operations afs_super_ops = { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) .statfs = simple_statfs, .alloc_inode = afs_alloc_inode, .drop_inode = generic_delete_inode, .destroy_inode = afs_destroy_inode, -#else - .read_inode2 = afs_read_inode2, -#endif .clear_inode = afs_clear_inode, .put_super = afs_put_super, }; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) static kmem_cache_t *afs_inode_cachep; -#endif /*****************************************************************************/ /* @@ -90,23 +76,6 @@ kenter(""); - /* open the cache */ -#if 0 - ret = -EINVAL; - if (!cachedev) { - printk(KERN_NOTICE "kAFS: No cache device specified as module parm\n"); - printk(KERN_NOTICE "kAFS: Set with \"cachedev=\" on insmod's cmdline\n"); - return ret; - } - - ret = afs_cache_open(cachedev,&afs_cache); - if (ret<0) { - printk(KERN_NOTICE "kAFS: Failed to open cache device\n"); - return ret; - } -#endif - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) /* create ourselves an inode cache */ ret = -ENOMEM; afs_inode_cachep = kmem_cache_create("afs_inode_cache", @@ -117,22 +86,13 @@ NULL); if (!afs_inode_cachep) { printk(KERN_NOTICE "kAFS: Failed to allocate inode cache\n"); -#if 0 - afs_put_cache(afs_cache); -#endif return ret; } -#endif /* now export our filesystem to lesser mortals */ ret = register_filesystem(&afs_fs_type); if (ret<0) { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) kmem_cache_destroy(afs_inode_cachep); -#endif -#if 0 - afs_put_cache(afs_cache); -#endif kleave(" = %d",ret); return ret; } @@ -148,16 +108,10 @@ void __exit afs_fs_exit(void) { /* destroy our private inode cache */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) kmem_cache_destroy(afs_inode_cachep); -#endif unregister_filesystem(&afs_fs_type); -#if 0 - if (afs_cache) - afs_put_cache(afs_cache); -#endif } /* end afs_fs_exit() */ /*****************************************************************************/ @@ -453,7 +407,6 @@ * get an AFS superblock * - TODO: don't use get_sb_nodev(), but rather call sget() directly */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) static struct super_block *afs_get_sb(struct file_system_type *fs_type, int flags, char *dev_name, @@ -482,39 +435,6 @@ _leave(""); return sb; } /* end afs_get_sb() */ -#endif - -/*****************************************************************************/ -/* - * read an AFS superblock - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -static struct super_block *afs_read_super(struct super_block *sb, void *options, int silent) -{ - void *data[2] = { NULL, options }; - int ret; - - _enter(",,%s",(char*)options); - - /* start the cache manager */ - ret = afscm_start(); - if (ret<0) { - _leave(" = NULL (%d)",ret); - return NULL; - } - - /* allocate a deviceless superblock */ - ret = afs_fill_super(sb,data,silent); - if (ret<0) { - afscm_stop(); - _leave(" = NULL (%d)",ret); - return NULL; - } - - _leave(" = %p",sb); - return sb; -} /* end afs_read_super() */ -#endif /*****************************************************************************/ /* @@ -540,7 +460,6 @@ /* * initialise an inode cache slab element prior to any use */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) static void afs_i_init_once(void *_vnode, kmem_cache_t *cachep, unsigned long flags) { afs_vnode_t *vnode = (afs_vnode_t *) _vnode; @@ -556,13 +475,11 @@ } } /* end afs_i_init_once() */ -#endif /*****************************************************************************/ /* * allocate an AFS inode struct from our slab cache */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) static struct inode *afs_alloc_inode(struct super_block *sb) { afs_vnode_t *vnode; @@ -580,16 +497,13 @@ return &vnode->vfs_inode; } /* end afs_alloc_inode() */ -#endif /*****************************************************************************/ /* * destroy an AFS inode struct */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) static void afs_destroy_inode(struct inode *inode) { _enter("{%lu}",inode->i_ino); kmem_cache_free(afs_inode_cachep, AFS_FS_I(inode)); } /* end afs_destroy_inode() */ -#endif diff -Nru a/fs/afs/vlclient.c b/fs/afs/vlclient.c --- a/fs/afs/vlclient.c Mon Nov 4 14:31:00 2002 +++ b/fs/afs/vlclient.c Mon Nov 4 14:31:00 2002 @@ -626,7 +626,7 @@ case RXRPC_CSTATE_CLNT_GOT_REPLY: if (call->app_read_count==0) break; - printk("kAFS: Reply bigger than expected {cst=%u asyn=%d mark=%d rdy=%u pr=%u%s}", + printk("kAFS: Reply bigger than expected {cst=%u asyn=%d mark=%Zu rdy=%Zu pr=%u%s}", call->app_call_state, call->app_async_read, call->app_mark, diff -Nru a/fs/afs/vnode.h b/fs/afs/vnode.h --- a/fs/afs/vnode.h Mon Nov 4 14:31:00 2002 +++ b/fs/afs/vnode.h Mon Nov 4 14:31:00 2002 @@ -27,11 +27,7 @@ */ struct afs_vnode { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) struct inode vfs_inode; /* the VFS's inode record */ -#else - struct inode *inode; /* the VFS's inode */ -#endif afs_volume_t *volume; /* volume on which vnode resides */ afs_fid_t fid; /* the file identifier for this inode */ @@ -59,20 +55,12 @@ static inline afs_vnode_t *AFS_FS_I(struct inode *inode) { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) - return list_entry(inode,afs_vnode_t,vfs_inode); -#else - return inode->u.generic_ip; -#endif + return container_of(inode,afs_vnode_t,vfs_inode); } static inline struct inode *AFS_VNODE_TO_I(afs_vnode_t *vnode) { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) return &vnode->vfs_inode; -#else - return vnode->inode; -#endif } extern int afs_vnode_fetch_status(afs_vnode_t *vnode); diff -Nru a/fs/attr.c b/fs/attr.c --- a/fs/attr.c Mon Nov 4 14:31:00 2002 +++ b/fs/attr.c Mon Nov 4 14:31:00 2002 @@ -95,7 +95,7 @@ return error; } -static int setattr_mask(unsigned int ia_valid) +int setattr_mask(unsigned int ia_valid) { unsigned long dn_mask = 0; diff -Nru a/fs/binfmt_aout.c b/fs/binfmt_aout.c --- a/fs/binfmt_aout.c Mon Nov 4 14:31:01 2002 +++ b/fs/binfmt_aout.c Mon Nov 4 14:31:01 2002 @@ -307,6 +307,7 @@ (current->mm->start_data = N_DATADDR(ex)); current->mm->brk = ex.a_bss + (current->mm->start_brk = N_BSSADDR(ex)); + current->mm->free_area_cache = TASK_UNMAPPED_BASE; current->mm->rss = 0; current->mm->mmap = NULL; @@ -425,8 +426,12 @@ regs->gp = ex.a_gpvalue; #endif start_thread(regs, ex.a_entry, current->mm->start_stack); - if (current->ptrace & PT_PTRACED) - send_sig(SIGTRAP, current, 0); + if (unlikely(current->ptrace & PT_PTRACED)) { + if (current->ptrace & PT_TRACE_EXEC) + ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP); + else + send_sig(SIGTRAP, current, 0); + } return 0; } diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c --- a/fs/binfmt_elf.c Mon Nov 4 14:31:01 2002 +++ b/fs/binfmt_elf.c Mon Nov 4 14:31:01 2002 @@ -619,6 +619,7 @@ /* Do this so that we can load the interpreter, if need be. We will change some of these later */ current->mm->rss = 0; + current->mm->free_area_cache = TASK_UNMAPPED_BASE; retval = setup_arg_pages(bprm); if (retval < 0) { send_sig(SIGKILL, current, 0); @@ -792,8 +793,12 @@ #endif start_thread(regs, elf_entry, bprm->p); - if (current->ptrace & PT_PTRACED) - send_sig(SIGTRAP, current, 0); + if (unlikely(current->ptrace & PT_PTRACED)) { + if (current->ptrace & PT_TRACE_EXEC) + ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP); + else + send_sig(SIGTRAP, current, 0); + } retval = 0; out: return retval; diff -Nru a/fs/binfmt_flat.c b/fs/binfmt_flat.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/binfmt_flat.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,659 @@ +/* + * linux/fs/binfmt_flat.c + * + * Copyright (C) 2000, 2001 Lineo, by David McCullough + * Copyright (C) 2002 Greg Ungerer + * + * based heavily on: + * + * linux/fs/binfmt_aout.c: + * Copyright (C) 1991, 1992, 1996 Linus Torvalds + * linux/fs/binfmt_flat.c for 2.0 kernel + * Copyright (C) 1998 Kenneth Albanowski + * JAN/99 -- coded full program relocation (gerg@snapgear.com) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#undef DEBUG +#ifdef DEBUG +#define DBG_FLT(a...) printk(##a) +#else +#define DBG_FLT(a...) +#endif + +static int load_flat_binary(struct linux_binprm *, struct pt_regs * regs); +static int load_flat_library(struct file*); +extern void dump_thread(struct pt_regs *, struct user *); + +static struct linux_binfmt flat_format = { + NULL, THIS_MODULE, load_flat_binary, load_flat_library, NULL, PAGE_SIZE +}; + + +/* + * create_flat_tables() parses the env- and arg-strings in new user + * memory and creates the pointer tables from them, and puts their + * addresses on the "stack", returning the new stack pointer value. + */ +static unsigned long create_flat_tables( + unsigned long pp, + struct linux_binprm * bprm) +{ + unsigned long *argv,*envp; + unsigned long * sp; + char * p = (char*)pp; + int argc = bprm->argc; + int envc = bprm->envc; + char dummy; + + sp = (unsigned long *) ((-(unsigned long)sizeof(char *))&(unsigned long) p); + + sp -= envc+1; + envp = sp; + sp -= argc+1; + argv = sp; + put_user((unsigned long) envp, --sp); + put_user((unsigned long) argv, --sp); + put_user(argc,--sp); + current->mm->arg_start = (unsigned long) p; + while (argc-->0) { + put_user((unsigned long) p, argv++); + do { + get_user(dummy, p); p++; + } while (dummy); + } + put_user((unsigned long) NULL, argv); + current->mm->arg_end = current->mm->env_start = (unsigned long) p; + while (envc-->0) { + put_user((unsigned long)p, envp); envp++; + do { + get_user(dummy, p); p++; + } while (dummy); + } + put_user((unsigned long) NULL, envp); + current->mm->env_end = (unsigned long) p; + return (unsigned long)sp; +} + + +#ifdef CONFIG_BINFMT_ZFLAT + +#include + +#define LBUFSIZE 4000 + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +static int decompress_exec( + struct linux_binprm *bprm, + unsigned long offset, + char *dst, + long len, + int fd) +{ + unsigned char *buf; + z_stream strm; + loff_t fpos; + int ret; + + DBG_FLT("decompress_exec(offset=%x,buf=%x,len=%x)\n",(int)offset, (int)dst, (int)len); + + memset(&strm, 0, sizeof(strm)); + strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); + if (strm.workspace == NULL) { + DBG_FLT("binfmt_flat: no memory for decompress workspace\n"); + return -ENOMEM; + } + buf = kmalloc(LBUFSIZE, GFP_KERNEL); + if (buf == NULL) { + DBG_FLT("binfmt_flat: no memory for read buffer\n"); + return -ENOMEM; + } + + /* Read in first chunk of data and parse gzip header. */ + fpos = offset; + ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos); + + strm.next_in = buf; + strm.avail_in = ret; + strm.total_in = 0; + + /* Check minimum size -- gzip header */ + if (ret < 10) { + DBG_FLT("binfmt_flat: file too small?\n"); + return -ENOEXEC; + } + + /* Check gzip magic number */ + if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) { + DBG_FLT("binfmt_flat: unknown compression magic?\n"); + return -ENOEXEC; + } + + /* Check gzip method */ + if (buf[2] != 8) { + DBG_FLT("binfmt_flat: unknown compression method?\n"); + return -ENOEXEC; + } + /* Check gzip flags */ + if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) || + (buf[3] & RESERVED)) { + DBG_FLT("binfmt_flat: unknown flags?\n"); + return -ENOEXEC; + } + + ret = 10; + if (buf[3] & EXTRA_FIELD) + ret += 2 + buf[10] + (buf[11] << 8); + if (buf[3] & ORIG_NAME) { + for (; (buf[ret] != 0); ret++) + ; + } + if (buf[3] & COMMENT) { + for (; (buf[ret] != 0); ret++) + ; + } + + strm.next_in += ret; + strm.avail_in -= ret; + + strm.next_out = dst; + strm.avail_out = len; + strm.total_out = 0; + + if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) { + DBG_FLT("binfmt_flat: zlib init failed?\n"); + return -ENOEXEC; + } + + while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) { + ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos); + if (ret == 0) + break; + if (ret >= (unsigned long) -4096) + break; + len -= ret; + + strm.next_in = buf; + strm.avail_in = ret; + strm.total_in = 0; + } + + if (ret < 0) { + DBG_FLT("binfmt_flat: decompression failed (%d), %s\n", + ret, strm.msg); + return -ENOEXEC; + } + + zlib_inflateEnd(&strm); + kfree(buf); + kfree(strm.workspace); + return 0; +} + +#endif /* CONFIG_BINFMT_ZFLAT */ + + +static unsigned long +calc_reloc(unsigned long r, unsigned long text_len) +{ + unsigned long addr; + + if (r > current->mm->start_brk - current->mm->start_data + text_len) { + printk("BINFMT_FLAT: reloc outside program 0x%x (0 - 0x%x), killing!\n", + (int) r,(int)(current->mm->start_brk-current->mm->start_code)); + send_sig(SIGSEGV, current, 0); + return(current->mm->start_brk); /* return something safe to write to */ + } + + if (r < text_len) { + /* In text segment */ + return r + current->mm->start_code; + } + + /* + * we allow inclusive ranges here so that programs may do things + * like reference the end of data (_end) without failing these tests + */ + addr = r - text_len + current->mm->start_data; + if (addr >= current->mm->start_code && + addr <= current->mm->start_code + text_len) + return(addr); + + if (addr >= current->mm->start_data && + addr <= current->mm->start_brk) + return(addr); + + printk("BINFMT_FLAT: reloc addr outside text/data 0x%x " + "code(0x%x - 0x%x) data(0x%x - 0x%x) killing\n", (int) addr, + (int) current->mm->start_code, + (int) (current->mm->start_code + text_len), + (int) current->mm->start_data, + (int) current->mm->start_brk); + send_sig(SIGSEGV, current, 0); + + return(current->mm->start_brk); /* return something safe to write to */ +} + + +void old_reloc(unsigned long rl) +{ +#ifdef DEBUG + char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" }; +#endif + flat_v2_reloc_t r; + unsigned long *ptr; + + r.value = rl; +#if defined(CONFIG_COLDFIRE) + ptr = (unsigned long *) (current->mm->start_code + r.reloc.offset); +#else + ptr = (unsigned long *) (current->mm->start_data + r.reloc.offset); +#endif + +#ifdef DEBUG + printk("Relocation of variable at DATASEG+%x " + "(address %p, currently %x) into segment %s\n", + r.reloc.offset, ptr, (int)*ptr, segment[r.reloc.type]); +#endif + + switch (r.reloc.type) { + case OLD_FLAT_RELOC_TYPE_TEXT: + *ptr += current->mm->start_code; + break; + case OLD_FLAT_RELOC_TYPE_DATA: + *ptr += current->mm->start_data; + break; + case OLD_FLAT_RELOC_TYPE_BSS: + *ptr += current->mm->end_data; + break; + default: + printk("BINFMT_FLAT: Unknown relocation type=%x\n", r.reloc.type); + break; + } + +#ifdef DEBUG + printk("Relocation became %x\n", (int)*ptr); +#endif +} + + +/* + * These are the functions used to load flat style executables and shared + * libraries. There is no binary dependent code anywhere else. + */ + +static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) +{ + struct flat_hdr * hdr; + unsigned long textpos = 0, datapos = 0, result; + unsigned long text_len, data_len, bss_len, stack_len, flags; + unsigned long memp = 0, memkasked = 0; /* for finding the brk area */ + unsigned long extra, rlim; + unsigned long p = bprm->p; + unsigned long *reloc = 0, *rp; + struct inode *inode; + int i, rev, relocs = 0; + loff_t fpos; + + DBG_FLT("BINFMT_FLAT: Loading file: %x\n", bprm->file); + + hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */ + inode = bprm->file->f_dentry->d_inode; + + text_len = ntohl(hdr->data_start); + data_len = ntohl(hdr->data_end) - ntohl(hdr->data_start); + bss_len = ntohl(hdr->bss_end) - ntohl(hdr->data_end); + stack_len = ntohl(hdr->stack_size); + relocs = ntohl(hdr->reloc_count); + flags = ntohl(hdr->flags); + rev = ntohl(hdr->rev); + + /* + * We have to add the size of our arguments to our stack size + * otherwise it's too easy for users to create stack overflows + * by passing in a huge argument list. And yes, we have to be + * pedantic and include space for the argv/envp array as it may have + * a lot of entries. + */ + #define TOP_OF_ARGS (PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *)) + stack_len += TOP_OF_ARGS - bprm->p; /* the strings */ + stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */ + stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */ + + if (strncmp(hdr->magic, "bFLT", 4) || + (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION)) { + /* + * because a lot of people do not manage to produce good + * flat binaries, we leave this printk to help them realise + * the problem. We only print the error if its * not a script file + */ + if (strncmp(hdr->magic, "#!", 2)) + printk("BINFMT_FLAT: bad magic/rev (0x%x, need 0x%x)\n", + rev, (int) FLAT_VERSION); + return -ENOEXEC; + } + + /* + * fix up the flags for the older format, there were all kinds + * of endian hacks, this only works for the simple cases + */ + if (rev == OLD_FLAT_VERSION && flags) + flags = FLAT_FLAG_RAM; + +#ifndef CONFIG_BINFMT_ZFLAT + if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) { + printk("Support for ZFLAT executables is not enabled.\n"); + return -ENOEXEC; + } +#endif + + /* + * Check initial limits. This avoids letting people circumvent + * size limits imposed on them by creating programs with large + * arrays in the data or bss. + */ + rlim = current->rlim[RLIMIT_DATA].rlim_cur; + if (rlim >= RLIM_INFINITY) + rlim = ~0; + if (data_len + bss_len > rlim) + return -ENOMEM; + + /* Flush all traces of the currently running executable */ + result = flush_old_exec(bprm); + if (result) + return result; + + /* OK, This is the point of no return */ + set_personality(PER_LINUX); + + /* + * there are a couple of cases here, the seperate code/data + * case, and then the fully copied to RAM case which lumps + * it all together. + */ + if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) { + /* + * this should give us a ROM ptr, but if it doesn't we don't + * really care + */ + DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n"); + + down_write(¤t->mm->mmap_sem); + textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, 0, 0); + up_write(¤t->mm->mmap_sem); + if (!textpos || textpos >= (unsigned long) -4096) { + if (!textpos) + textpos = (unsigned long) -ENOMEM; + printk("Unable to mmap process text, errno %d\n", (int)-textpos); + } + + extra = max(bss_len + stack_len, relocs * sizeof(unsigned long)), + + down_write(¤t->mm->mmap_sem); + datapos = do_mmap(0, 0, data_len + extra, + PROT_READ|PROT_WRITE|PROT_EXEC, 0, 0); + up_write(¤t->mm->mmap_sem); + + if (datapos == 0 || datapos >= (unsigned long)-4096) { + if (!datapos) + datapos = (unsigned long) -ENOMEM; + printk("Unable to allocate RAM for process data, errno %d\n", + (int)-datapos); + do_munmap(current->mm, textpos, text_len); + return datapos; + } + + DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n", + data_len + bss_len + stack_len, datapos); + + fpos = ntohl(hdr->data_start); +#ifdef CONFIG_BINFMT_ZFLAT + if (flags & FLAT_FLAG_GZDATA) { + result = decompress_exec(bprm, fpos, (char *) datapos, + data_len + (relocs * sizeof(unsigned long)), 0); + } else +#endif + { + result = bprm->file->f_op->read(bprm->file, + (char *) datapos, data_len + extra, &fpos); + } + if (result >= (unsigned long)-4096) { + printk("Unable to read data+bss, errno %d\n", (int)-result); + do_munmap(current->mm, textpos, text_len); + do_munmap(current->mm, datapos, data_len + extra); + return result; + } + + reloc = (unsigned long *) (datapos+(ntohl(hdr->reloc_start)-text_len)); + memp = datapos; + memkasked = data_len + extra; + + } else { + + /* + * calculate the extra space we need to map in + */ + + extra = max(bss_len + stack_len, relocs * sizeof(unsigned long)), + + down_write(¤t->mm->mmap_sem); + textpos = do_mmap(0, 0, text_len + data_len + extra, + PROT_READ | PROT_EXEC | PROT_WRITE, 0, 0); + up_write(¤t->mm->mmap_sem); + if (!textpos || textpos >= (unsigned long) -4096) { + if (!textpos) + textpos = (unsigned long) -ENOMEM; + printk("Unable to allocate RAM for process text/data, errno %d\n", + (int)-textpos); + } + + datapos = textpos + ntohl (hdr->data_start); + reloc = (unsigned long *) (textpos + ntohl(hdr->reloc_start)); + memp = textpos; + memkasked = text_len + data_len + extra; + +#ifdef CONFIG_BINFMT_ZFLAT + /* + * load it all in and treat it like a RAM load from now on + */ + if (flags & FLAT_FLAG_GZIP) { + result = decompress_exec(bprm, sizeof (struct flat_hdr), + (((char *) textpos) + sizeof (struct flat_hdr)), + (text_len + data_len + (relocs * sizeof(unsigned long)) + - sizeof (struct flat_hdr)), + 0); + } else if (flags & FLAT_FLAG_GZDATA) { + fpos = 0; + result = bprm->file->f_op->read(bprm->file, + (char *) textpos, text_len, &fpos); + if (result < (unsigned long) -4096) + result = decompress_exec(bprm, text_len, (char *) datapos, + data_len + (relocs * sizeof(unsigned long)), 0); + } + else +#endif + { + fpos = 0; + result = bprm->file->f_op->read(bprm->file, + (char *) textpos, text_len + data_len + extra, &fpos); + } + if (result >= (unsigned long)-4096) { + printk("Unable to read code+data+bss, errno %d\n",(int)-result); + do_munmap(current->mm, textpos, text_len + data_len + extra); + return result; + } + } + + DBG_FLT("Mapping is %x, Entry point is %x, data_start is %x\n", + textpos, ntohl(hdr->entry), ntohl(hdr->data_start)); + + current->mm->start_code = textpos + sizeof (struct flat_hdr); + current->mm->end_code = textpos + text_len; + current->mm->start_data = datapos; + current->mm->end_data = datapos + data_len; + /* + * set up the brk stuff (uses any slack left in data/bss/stack allocation + * We put the brk after the bss (between the bss and stack) like other + * platforms. + */ + current->mm->start_brk = datapos + data_len + bss_len; + current->mm->brk = (current->mm->start_brk + 3) & ~3; + current->mm->context.end_brk = memp + ksize((void *) memp) - stack_len; + current->mm->rss = 0; + + DBG_FLT("Load %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n", + bprm->filename, + (int) current->mm->start_code, (int) current->mm->end_code, + (int) current->mm->start_data, (int) current->mm->end_data, + (int) current->mm->end_data, (int) current->mm->brk); + + text_len -= sizeof(struct flat_hdr); /* the real code len */ + + /* + * We just load the allocations into some temporary memory to + * help simplify all this mumbo jumbo + * + * We've got two different sections of relocation entries. + * The first is the GOT which resides at the begining of the data segment + * and is terminated with a -1. This one can be relocated in place. + * The second is the extra relocation entries tacked after the image's + * data segment. These require a little more processing as the entry is + * really an offset into the image which contains an offset into the + * image. + */ + + if (flags & FLAT_FLAG_GOTPIC) { + for (rp = (unsigned long *)datapos; *rp != 0xffffffff; rp++) + *rp = calc_reloc(*rp, text_len); + } + + /* + * Now run through the relocation entries. + * We've got to be careful here as C++ produces relocatable zero + * entries in the constructor and destructor tables which are then + * tested for being not zero (which will always occur unless we're + * based from address zero). This causes an endless loop as __start + * is at zero. The solution used is to not relocate zero addresses. + * This has the negative side effect of not allowing a global data + * reference to be statically initialised to _stext (I've moved + * __start to address 4 so that is okay). + */ + + if (rev > OLD_FLAT_VERSION) { + for (i=0; i < relocs; i++) { + unsigned long addr; + + /* Get the address of the pointer to be + relocated (of course, the address has to be + relocated first). */ + rp = (unsigned long *) calc_reloc(ntohl(reloc[i]), text_len); + + /* Get the pointer's value. */ + addr = get_unaligned (rp); + + if (addr != 0) { + /* + * Do the relocation. PIC relocs in the data section are + * already in target order + */ + addr = calc_reloc( + (flags & FLAT_FLAG_GOTPIC) ? addr : ntohl(addr), + text_len); + /* Write back the relocated pointer. */ + put_unaligned (addr, rp); + } + } + } else { + for (i=0; i < relocs; i++) + old_reloc(ntohl(reloc[i])); + } + + /* zero the BSS, BRK and stack areas */ + memset((void*)(datapos + data_len), 0, bss_len + + (current->mm->context.end_brk - current->mm->start_brk) + + stack_len); + + compute_creds(bprm); + current->flags &= ~PF_FORKNOEXEC; + + flush_icache_range(current->mm->start_code, current->mm->end_code); + + set_binfmt(&flat_format); + + p = ((current->mm->context.end_brk + stack_len + 3) & ~3) - 4; + DBG_FLT("p=%x\n", p); + + /* copy the arg pages onto the stack, this could be more efficient :-) */ + for (i = TOP_OF_ARGS - 1; i >= bprm->p; i--) + * (char *) --p = + ((char *) page_address(bprm->page[i/PAGE_SIZE]))[i % PAGE_SIZE]; + + current->mm->start_stack = (unsigned long) create_flat_tables(p, bprm); + + DBG_FLT("start_thread(regs=0x%x, entry=0x%x, start_stack=0x%x)\n", + regs, textpos + ntohl(hdr->entry), current->mm->start_stack); + start_thread(regs, + textpos + ntohl(hdr->entry), + current->mm->start_stack); + + if (current->ptrace & PT_PTRACED) + send_sig(SIGTRAP, current, 0); + + return 0; +} + +static int load_flat_library(struct file *file) +{ + return(-ENOEXEC); +} + +static int __init init_flat_binfmt(void) +{ + return register_binfmt(&flat_format); +} + +static void __exit exit_flat_binfmt(void) +{ + unregister_binfmt(&flat_format); +} + +EXPORT_NO_SYMBOLS; + +module_init(init_flat_binfmt); +module_exit(exit_flat_binfmt); diff -Nru a/fs/binfmt_som.c b/fs/binfmt_som.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/binfmt_som.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,329 @@ +/* + * linux/fs/binfmt_som.c + * + * These are the functions used to load SOM format executables as used + * by HP-UX. + * + * Copyright 1999 Matthew Wilcox + * based on binfmt_elf which is + * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com). + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +static int load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs); +static int load_som_library(struct file *); + +/* + * If we don't support core dumping, then supply a NULL so we + * don't even try. + */ +#if 0 +static int som_core_dump(long signr, struct pt_regs * regs); +#else +#define som_core_dump NULL +#endif + +#define SOM_PAGESTART(_v) ((_v) & ~(unsigned long)(SOM_PAGESIZE-1)) +#define SOM_PAGEOFFSET(_v) ((_v) & (SOM_PAGESIZE-1)) +#define SOM_PAGEALIGN(_v) (((_v) + SOM_PAGESIZE - 1) & ~(SOM_PAGESIZE - 1)) + +static struct linux_binfmt som_format = { + NULL, THIS_MODULE, load_som_binary, load_som_library, som_core_dump, SOM_PAGESIZE +}; + +/* + * create_som_tables() parses the env- and arg-strings in new user + * memory and creates the pointer tables from them, and puts their + * addresses on the "stack", returning the new stack pointer value. + */ +static void create_som_tables(struct linux_binprm *bprm) +{ + char **argv, **envp; + int argc = bprm->argc; + int envc = bprm->envc; + unsigned long p; + unsigned long *sp; + + /* Word-align the stack pointer */ + sp = (unsigned long *)((bprm->p + 3) & ~3); + + envp = (char **) sp; + sp += envc + 1; + argv = (char **) sp; + sp += argc + 1; + + __put_user((unsigned long) envp,++sp); + __put_user((unsigned long) argv,++sp); + + __put_user(argc, ++sp); + + bprm->p = (unsigned long) sp; + + p = current->mm->arg_start; + while (argc-- > 0) { + __put_user((char *)p,argv++); + p += strlen_user((char *)p); + } + __put_user(NULL, argv); + current->mm->arg_end = current->mm->env_start = p; + while (envc-- > 0) { + __put_user((char *)p,envp++); + p += strlen_user((char *)p); + } + __put_user(NULL, envp); + current->mm->env_end = p; +} + +static int check_som_header(struct som_hdr *som_ex) +{ + int *buf = (int *)som_ex; + int i, ck; + + if (som_ex->system_id != SOM_SID_PARISC_1_0 && + som_ex->system_id != SOM_SID_PARISC_1_1 && + som_ex->system_id != SOM_SID_PARISC_2_0) + return -ENOEXEC; + + if (som_ex->a_magic != SOM_EXEC_NONSHARE && + som_ex->a_magic != SOM_EXEC_SHARE && + som_ex->a_magic != SOM_EXEC_DEMAND) + return -ENOEXEC; + + if (som_ex->version_id != SOM_ID_OLD && + som_ex->version_id != SOM_ID_NEW) + return -ENOEXEC; + + ck = 0; + for (i=0; i<32; i++) + ck ^= buf[i]; + if (ck != 0) + return -ENOEXEC; + + return 0; +} + +static int map_som_binary(struct file *file, + const struct som_exec_auxhdr *hpuxhdr) +{ + unsigned long code_start, code_size, data_start, data_size; + unsigned long bss_start, som_brk; + int retval; + int prot = PROT_READ | PROT_EXEC; + int flags = MAP_FIXED|MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE; + + mm_segment_t old_fs = get_fs(); + set_fs(get_ds()); + + code_start = SOM_PAGESTART(hpuxhdr->exec_tmem); + code_size = SOM_PAGEALIGN(hpuxhdr->exec_tsize); + current->mm->start_code = code_start; + current->mm->end_code = code_start + code_size; + down_write(¤t->mm->mmap_sem); + retval = do_mmap(file, code_start, code_size, prot, + flags, SOM_PAGESTART(hpuxhdr->exec_tfile)); + up_write(¤t->mm->mmap_sem); + if (retval < 0 && retval > -1024) + goto out; + + data_start = SOM_PAGESTART(hpuxhdr->exec_dmem); + data_size = SOM_PAGEALIGN(hpuxhdr->exec_dsize); + current->mm->start_data = data_start; + current->mm->end_data = bss_start = data_start + data_size; + down_write(¤t->mm->mmap_sem); + retval = do_mmap(file, data_start, data_size, + prot | PROT_WRITE, flags, + SOM_PAGESTART(hpuxhdr->exec_dfile)); + up_write(¤t->mm->mmap_sem); + if (retval < 0 && retval > -1024) + goto out; + + som_brk = bss_start + SOM_PAGEALIGN(hpuxhdr->exec_bsize); + current->mm->start_brk = current->mm->brk = som_brk; + down_write(¤t->mm->mmap_sem); + retval = do_mmap(NULL, bss_start, som_brk - bss_start, + prot | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, 0); + up_write(¤t->mm->mmap_sem); + if (retval > 0 || retval < -1024) + retval = 0; +out: + set_fs(old_fs); + return retval; +} + + +/* + * These are the functions used to load SOM executables and shared + * libraries. There is no binary dependent code anywhere else. + */ + +static inline int +do_load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) +{ + int som_exec_fileno; + int retval; + unsigned int size; + unsigned long som_entry; + struct som_hdr *som_ex; + struct som_exec_auxhdr *hpuxhdr; + + /* Get the exec-header */ + som_ex = (struct som_hdr *) bprm->buf; + + retval = check_som_header(som_ex); + if (retval != 0) + goto out; + + /* Now read in the auxiliary header information */ + + retval = -ENOMEM; + size = som_ex->aux_header_size; + if (size > SOM_PAGESIZE) + goto out; + hpuxhdr = (struct som_exec_auxhdr *) kmalloc(size, GFP_KERNEL); + if (!hpuxhdr) + goto out; + + retval = kernel_read(bprm->file, som_ex->aux_header_location, + (char *) hpuxhdr, size); + if (retval < 0) + goto out_free; + + retval = get_unused_fd(); + if (retval < 0) + goto out_free; + get_file(bprm->file); + fd_install(som_exec_fileno = retval, bprm->file); + + /* Flush all traces of the currently running executable */ + retval = flush_old_exec(bprm); + if (retval) + goto out_free; + + /* OK, This is the point of no return */ + current->flags &= ~PF_FORKNOEXEC; + current->personality = PER_HPUX; + + /* Set the task size for HP-UX processes such that + * the gateway page is outside the address space. + * This can be fixed later, but for now, this is much + * easier. + */ + + current->thread.task_size = 0xc0000000; + + /* Set map base to allow enough room for hp-ux heap growth */ + + current->thread.map_base = 0x80000000; + + retval = map_som_binary(bprm->file, hpuxhdr); + if (retval < 0) + goto out_free; + + som_entry = hpuxhdr->exec_entry; + kfree(hpuxhdr); + + set_binfmt(&som_format); + compute_creds(bprm); + setup_arg_pages(bprm); + + create_som_tables(bprm); + + current->mm->start_stack = bprm->p; + current->mm->rss = 0; + +#if 0 + printk("(start_brk) %08lx\n" , (unsigned long) current->mm->start_brk); + printk("(end_code) %08lx\n" , (unsigned long) current->mm->end_code); + printk("(start_code) %08lx\n" , (unsigned long) current->mm->start_code); + printk("(end_data) %08lx\n" , (unsigned long) current->mm->end_data); + printk("(start_stack) %08lx\n" , (unsigned long) current->mm->start_stack); + printk("(brk) %08lx\n" , (unsigned long) current->mm->brk); +#endif + + map_hpux_gateway_page(current,current->mm); + + start_thread_som(regs, som_entry, bprm->p); + if (current->ptrace & PT_PTRACED) + send_sig(SIGTRAP, current, 0); + return 0; + + /* error cleanup */ +out_free: + kfree(hpuxhdr); +out: + return retval; +} + +static int +load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) +{ + int retval; + + MOD_INC_USE_COUNT; + retval = do_load_som_binary(bprm, regs); + MOD_DEC_USE_COUNT; + return retval; +} + +static inline int +do_load_som_library(struct file *f) +{ +/* No lib support in SOM yet. gizza chance.. */ + return -ENOEXEC; +} + +static int load_som_library(struct file *f) +{ + int retval; + + MOD_INC_USE_COUNT; + retval = do_load_som_library(f); + MOD_DEC_USE_COUNT; + return retval; +} + + /* Install the SOM loader. + * N.B. We *rely* on the table being the right size with the + * right number of free slots... + */ + +static int __init init_som_binfmt(void) +{ + return register_binfmt(&som_format); +} + +static void __exit exit_som_binfmt(void) +{ + /* Remove the SOM loader. */ + unregister_binfmt(&som_format); +} + +module_init(init_som_binfmt); +module_exit(exit_som_binfmt); + diff -Nru a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS --- a/fs/cifs/AUTHORS Mon Nov 4 14:31:00 2002 +++ b/fs/cifs/AUTHORS Mon Nov 4 14:31:00 2002 @@ -14,3 +14,9 @@ the other members of the Storage Network Industry Association CIFS Technical Workgroup for their work specifying this highly complex protocol and finally thanks to the Samba team for their technical advice and encouragement. + +Patch Contributors +------------------ +Zwane Mwaikambo +Andi Kleen + diff -Nru a/fs/cifs/CHANGES b/fs/cifs/CHANGES --- a/fs/cifs/CHANGES Mon Nov 4 14:31:02 2002 +++ b/fs/cifs/CHANGES Mon Nov 4 14:31:02 2002 @@ -1,3 +1,24 @@ +Version 0.58 +------------ +Changed read and write to go through pagecache. Added additional address space operations. +Memory mapped operations now working. + +Version 0.57 +------------ +Added writepage code for additional memory mapping support. Fixed leak in xids causing +the simultaneous operations counter (/proc/fs/cifs/SimultaneousOps) to increase on +every stat call. Additional formatting cleanup. + +Version 0.56 +------------ +Fix bigendian bug in order of time conversion. Merge 2.5 to 2.4 version. Formatting cleanup. + +Version 0.55 +------------ +Fixes from Zwane Mwaikambo for adding missing return code checking in a few places. +Also included a modified version of his fix to protect global list manipulation of +the smb session and tree connection and mid related global variables. + Version 0.54 ------------ Fix problem with captive thread hanging around at unmount time. Adjust to 2.5.42-pre diff -Nru a/fs/cifs/TODO b/fs/cifs/TODO --- a/fs/cifs/TODO Mon Nov 4 14:31:01 2002 +++ b/fs/cifs/TODO Mon Nov 4 14:31:01 2002 @@ -31,9 +31,6 @@ j) finish off the mount helper, mount.cifs - (started) -k) support for memory mapped files only partially works until support for -MS_INVALIDATE implemented. readpage and writepage code not finished (started) - KNOWN BUGS (updated October 8nd, 2002) ==================================== 1) symbolic links (Windows reparse points) are recognized but @@ -42,6 +39,8 @@ symlink text beginning with slash 2) delete of file with read-only attribute set will fail (may be ok) 3) autoreconnection logic is only partially complete. +4) there may be a problem with truncating a memmapped file to smaller than 4k with +the size being reported as exactly 4k. Misc testing to do ================= diff -Nru a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c --- a/fs/cifs/cifs_debug.c Mon Nov 4 14:31:01 2002 +++ b/fs/cifs/cifs_debug.c Mon Nov 4 14:31:01 2002 @@ -79,18 +79,20 @@ buf += length; i = 0; + read_lock(&GlobalSMBSeslock); list_for_each(tmp, &GlobalSMBSessionList) { i++; ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); length = sprintf(buf, - "\n%d) Name: %s Domain: %s HowManyMounts: %d LocalUsersToSameServer: %d\n\t ServerOS: %s ServerNOS: %s Capabilities: 0x%x ", - i, ses->serverName, ses->serverDomain, - atomic_read(&ses->inUse), - atomic_read(&ses->server->socketUseCount), - ses->serverOS, ses->serverNOS, ses->capabilities); + "\n%d) Name: %s Domain: %s HowManyMounts: %d ServerOS: %s ServerNOS: %s Capabilities: 0x%x\n", + i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse), + ses->serverOS, ses->serverNOS, ses->capabilities); buf += length; + if(ses->server) + buf += sprintf(buf, "\tLocal Users To Same Server: %d ",atomic_read(&ses->server->socketUseCount)); } + read_unlock(&GlobalSMBSeslock); sprintf(buf, "\n"); buf++; printk("\nTotal Buffer so far: %s\n", buf_start); @@ -99,6 +101,7 @@ buf += length; i = 0; + read_lock(&GlobalSMBSeslock); list_for_each(tmp, &GlobalTreeConnectionList) { i++; tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); @@ -122,6 +125,7 @@ tcon->fsDevInfo.DeviceType); buf += length; } + read_unlock(&GlobalSMBSeslock); length = sprintf(buf, "\n"); buf += length; *eof = 1; @@ -156,22 +160,22 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, int length, int *eof, void *data) { - int item_length; + int item_length; length = sprintf(buf, "Currently Allocated structures\nCIFS Sessions: %d\n",sesInfoAllocCount.counter); - buf += length; - item_length = - sprintf(buf,"Shares (unique mount targets): %d\n",tconInfoAllocCount.counter); - length += item_length; - buf += item_length; - item_length = - sprintf(buf,"Allocated SMB Request and Response Buffers: %d\n",bufAllocCount.counter); - length += item_length; - buf += item_length; - item_length = - sprintf(buf,"Active Operations (MIDs in use): %d\n",midCount.counter); - length += item_length; + buf += length; + item_length = + sprintf(buf,"Shares (unique mount targets): %d\n",tconInfoAllocCount.counter); + length += item_length; + buf += item_length; + item_length = + sprintf(buf,"Allocated SMB Request and Response Buffers: %d\n",bufAllocCount.counter); + length += item_length; + buf += item_length; + item_length = + sprintf(buf,"Active Operations (MIDs in use): %d\n",midCount.counter); + length += item_length; return length; } @@ -262,10 +266,13 @@ remove_proc_entry("DebugData", proc_fs_cifs); remove_proc_entry("cifsFYI", proc_fs_cifs); remove_proc_entry("TraceSMB", proc_fs_cifs); - remove_proc_entry("MaxSimultaneousOps", proc_fs_cifs); + remove_proc_entry("SimultaneousOps", proc_fs_cifs); remove_proc_entry("TotalOps", proc_fs_cifs); remove_proc_entry("MultiuserMount", proc_fs_cifs); remove_proc_entry("oplockEnabled", proc_fs_cifs); + remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); + remove_proc_entry("ExtendedSecurity",proc_fs_cifs); + remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); remove_proc_entry("cifs", proc_root_fs); } diff -Nru a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c --- a/fs/cifs/cifsfs.c Mon Nov 4 14:31:02 2002 +++ b/fs/cifs/cifsfs.c Mon Nov 4 14:31:02 2002 @@ -64,8 +64,10 @@ struct cifs_sb_info *cifs_sb; int rc = 0; - sb->s_fs_info = kmalloc(sizeof(struct cifs_sb_info),GFP_KERNEL); + sb->s_fs_info = kmalloc(sizeof(struct cifs_sb_info),GFP_KERNEL); cifs_sb = CIFS_SB(sb); + if(cifs_sb == NULL) + return -ENOMEM; cifs_sb->local_nls = load_nls_default(); /* needed for ASCII cp to Unicode converts */ rc = cifs_mount(sb, cifs_sb, data, devname); @@ -97,13 +99,12 @@ if (inode) iput(inode); -/* rc = cifs_umount(sb); BB is CIFS unmount routine needed? */ if (rc) { - cERROR(1, ("cifs_umount failed with return code %d\n", rc)); + cERROR(1, ("cifs_mount failed with no root inode")); } out_mount_failed: - if(cifs_sb) - kfree(cifs_sb); + if(cifs_sb) + kfree(cifs_sb); return -EINVAL; } @@ -115,14 +116,16 @@ cFYI(1, ("In cifs_put_super\n")); cifs_sb = CIFS_SB(sb); - rc = cifs_umount(sb, cifs_sb); + if(cifs_sb == NULL) { + cFYI(1,("\nEmpty cifs superblock info passed to unmount")); + return; + } + rc = cifs_umount(sb, cifs_sb); if (rc) { cERROR(1, ("cifs_umount failed with return code %d\n", rc)); } - if(cifs_sb) { - unload_nls(cifs_sb->local_nls); - kfree(cifs_sb); - } + unload_nls(cifs_sb->local_nls); + kfree(cifs_sb); return; } @@ -155,7 +158,7 @@ __fsid_t f_fsid; int f_namelen; */ /* BB get from info put in tcon struct at mount time with call to QFSAttrInfo */ - + FreeXid(xid); return 0; /* always return success? what if volume is no longer available? */ } @@ -176,7 +179,7 @@ atomic_set(&cifs_inode->inUse, 0); cifs_inode->time = 0; cifs_inode->clientCanCache = 0; - INIT_LIST_HEAD(&cifs_inode->openFileList); + INIT_LIST_HEAD(&cifs_inode->openFileList); return &cifs_inode->vfs_inode; } @@ -258,6 +261,7 @@ struct inode_operations cifs_dir_inode_ops = { .create = cifs_create, .lookup = cifs_lookup, + .getattr = cifs_getattr, .unlink = cifs_unlink, .link = cifs_hardlink, .mkdir = cifs_mkdir, @@ -271,6 +275,7 @@ struct inode_operations cifs_file_inode_ops = { /* revalidate:cifs_revalidate, */ .setattr = cifs_setattr, + .getattr = cifs_getattr, .rename = cifs_rename, }; @@ -278,17 +283,18 @@ .readlink = cifs_readlink, .follow_link = cifs_follow_link, /* BB add the following two eventually */ - /* revalidate: cifs_revalidate, - setattr: cifs_notify_change, *//* BB do we need notify change */ + /* revalidate: cifs_revalidate, + setattr: cifs_notify_change, *//* BB do we need notify change */ }; struct file_operations cifs_file_ops = { - .read = cifs_read, - .write = cifs_write, + .read = generic_file_read, + .write = generic_file_write, .open = cifs_open, .release = cifs_close, .lock = cifs_lock, .fsync = cifs_fsync, + .mmap = cifs_file_mmap, }; struct file_operations cifs_dir_ops = { @@ -387,8 +393,11 @@ atomic_set(&tconInfoAllocCount, 0); atomic_set(&bufAllocCount, 0); atomic_set(&midCount, 0); + GlobalCurrentXid = 0; GlobalTotalActiveXid = 0; GlobalMaxActiveXid = 0; + GlobalSMBSeslock = RW_LOCK_UNLOCKED; + GlobalMid_Lock = RW_LOCK_UNLOCKED; rc = cifs_init_inodecache(); if (!rc) { @@ -419,7 +428,7 @@ #if CONFIG_PROC_FS cifs_proc_clean(); #endif - unregister_filesystem(&cifs_fs_type); + unregister_filesystem(&cifs_fs_type); cifs_destroy_inodecache(); cifs_destroy_mids(); cifs_destroy_request_bufs(); diff -Nru a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h --- a/fs/cifs/cifsfs.h Mon Nov 4 14:31:01 2002 +++ b/fs/cifs/cifsfs.h Mon Nov 4 14:31:01 2002 @@ -55,6 +55,7 @@ extern int cifs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); extern int cifs_revalidate(struct dentry *); +extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int cifs_setattr(struct dentry *, struct iattr *); extern struct inode_operations cifs_file_inode_ops; @@ -73,7 +74,7 @@ size_t write_size, loff_t * poffset); extern int cifs_lock(struct file *, int, struct file_lock *); extern int cifs_fsync(struct file *, struct dentry *, int); - +extern int cifs_file_mmap(struct file * , struct vm_area_struct *); extern struct file_operations cifs_dir_ops; extern int cifs_dir_open(struct inode *inode, struct file *file); extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); diff -Nru a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h --- a/fs/cifs/cifsglob.h Mon Nov 4 14:31:01 2002 +++ b/fs/cifs/cifsglob.h Mon Nov 4 14:31:01 2002 @@ -165,7 +165,7 @@ */ struct cifsTconInfo { struct list_head cifsConnectionList; - struct list_head openFileList; + struct list_head openFileList; struct semaphore tconSem; struct cifsSesInfo *ses; /* pointer to session associated with */ char treeName[MAX_TREE_SIZE + 1]; /* The ascii or unicode name of this resource depending on the ses->capabilities *//* BB fill in this field */ @@ -201,6 +201,7 @@ __u16 netfid; /* file id from remote */ /* BB add lock scope info here if needed */ ; /* lock scope id (0 if none) */ + struct file * pfile; /* needed for writepage */ int endOfSearch:1; /* we have reached end of search */ int closePend:1; /* file is marked to close */ }; @@ -212,12 +213,12 @@ struct cifsInodeInfo { struct list_head lockList; /* BB add in lists for dirty pages - i.e. write caching info for oplock */ - struct list_head openFileList; + struct list_head openFileList; __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system etc. */ atomic_t inUse; /* num concurrent users (local openers cifs) of file */ unsigned long time; /* jiffies of last update/check of inode */ int clientCanCache:1; /* oplocked. We need to extend cases beyond this i.e. what - if file read-only or if file locked? or if file on r/o vol? */ + if file read-only or if file locked? or if file on r/o vol? */ struct inode vfs_inode; }; @@ -244,7 +245,7 @@ struct cifsSesInfo *ses; /* smb was sent to this server */ struct task_struct *tsk; /* task waiting for response */ struct smb_hdr *resp_buf; /* response buffer */ - int midState; /* wish this could be an enum but can not pass that to wait_event */ + int midState; /* wish this were enum but can not pass to wait_event */ }; #define MID_FREE 0 @@ -292,13 +293,10 @@ */ GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH]; -GLOBAL_EXTERN struct list_head GlobalServerList; /* BB this one is not implemented yet */ +GLOBAL_EXTERN struct list_head GlobalServerList; /* BB not implemented yet */ GLOBAL_EXTERN struct list_head GlobalSMBSessionList; GLOBAL_EXTERN struct list_head GlobalTreeConnectionList; -/* - * Global list of free SMB structures - */ -GLOBAL_EXTERN void *GlobalFreeSMB; +GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ /* * Global transaction id (XID) information @@ -306,7 +304,8 @@ GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */ GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ - +GLOBAL_EXTERN rwlock_t GlobalMid_Lock; /* protects above and list operations */ + /* on midQ entries */ GLOBAL_EXTERN char Local_System_Name[15]; /* @@ -321,13 +320,12 @@ /* Misc globals */ GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions - to be established on existing mount if we - have the uid/password or Kerberos credential - or equivalent for current user */ + to be established on existing mount if we + have the uid/password or Kerberos credential + or equivalent for current user */ GLOBAL_EXTERN unsigned int oplockEnabled; GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent - with more secure ntlmssp2 challenge/resp */ + with more secure ntlmssp2 challenge/resp */ GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */ GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ - diff -Nru a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h --- a/fs/cifs/cifsproto.h Mon Nov 4 14:31:00 2002 +++ b/fs/cifs/cifsproto.h Mon Nov 4 14:31:00 2002 @@ -31,7 +31,7 @@ extern struct smb_hdr *buf_get(void); extern void buf_release(void *); extern int smb_send(struct socket *, struct smb_hdr *, - unsigned int /* length */ , struct sockaddr *); + unsigned int /* length */ , struct sockaddr *); extern unsigned int _GetXid(void); extern void _FreeXid(unsigned int); #define GetXid() (int)_GetXid(); cFYI(1,("\nCIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid)); @@ -41,70 +41,70 @@ extern void renew_parental_timestamps(struct dentry *direntry); extern void *kcalloc(size_t mem, int type); extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, - struct smb_hdr * /* input */ , - struct smb_hdr * /* out */ , - int * /* bytes returned */ , const int long_op); + struct smb_hdr * /* input */ , + struct smb_hdr * /* out */ , + int * /* bytes returned */ , const int long_op); extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); extern int is_valid_oplock_break(struct smb_hdr *smb); extern int smbCalcSize(struct smb_hdr *ptr); extern int decode_negTokenInit(unsigned char *security_blob, int length, - enum securityEnum *secType); + enum securityEnum *secType); extern int map_smb_to_linux_error(struct smb_hdr *smb); extern void header_assemble(struct smb_hdr *, char /* command */ , - const struct cifsTconInfo *, int - /* length of fixed section (word count) in two byte units */ - ); + const struct cifsTconInfo *, int + /* length of fixed section (word count) in two byte units */ + ); extern time_t cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ ); extern u64 cifs_UnixTimeToNT(time_t); extern void RevUcode_to_Ucode(char *revUnicode, char *UnicodeName); extern void Ucode_to_RevUcode(char *Unicode, char *revUnicodeName); extern void RevUcode_to_Ucode_with_Len(char *revUnicode, char *UnicodeName, - int Len); + int Len); extern void Ucode_to_RevUcode_with_Len(char *Unicode, char *revUnicodeName, - int Len); + int Len); extern int cifs_get_inode_info(struct inode **pinode, - const unsigned char *search_path, - struct super_block *sb); + const unsigned char *search_path, + struct super_block *sb); extern int cifs_get_inode_info_unix(struct inode **pinode, - const unsigned char *search_path, - struct super_block *sb); + const unsigned char *search_path, + struct super_block *sb); extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses, - char cryptokey[CIFS_CRYPTO_KEY_SIZE]); + char cryptokey[CIFS_CRYPTO_KEY_SIZE]); extern int CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, - char *user, char *domain, - char *session_key, char *ntlm_session_key, - const struct nls_table *); + char *user, char *domain, + char *session_key, char *ntlm_session_key, + const struct nls_table *); extern int CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, - char *user, char *domain, - char *SecurityBlob, - int SecurityBlobLength, - const struct nls_table *); + char *user, char *domain, + char *SecurityBlob, + int SecurityBlobLength, + const struct nls_table *); extern int CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, - struct cifsSesInfo *ses, - char *domain, - char *ntlm_session_key, - int *ntlmv2_flag, - const struct nls_table *); + struct cifsSesInfo *ses, + char *domain, + char *ntlm_session_key, + int *ntlmv2_flag, + const struct nls_table *); extern int CIFSNTLMSSPAuthSessSetup(unsigned int xid, - struct cifsSesInfo *ses, char *user, - char *domain, char *ntlm_session_key, - char *lanman_session_key, - int ntlmv2_flag, - const struct nls_table *); + struct cifsSesInfo *ses, char *user, + char *domain, char *ntlm_session_key, + char *lanman_session_key, + int ntlmv2_flag, + const struct nls_table *); extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, - const char *tree, struct cifsTconInfo *tcon, - const struct nls_table *); + const char *tree, struct cifsTconInfo *tcon, + const struct nls_table *); extern int CIFSFindFirst(const int xid, const struct cifsTconInfo *tcon, - const char *searchName, - FILE_DIRECTORY_INFO * findData, - T2_FFIRST_RSP_PARMS * findParms, - const struct nls_table *nls_codepage, - int *pUnicodeFlag, - int *pUnixFlag /* if Unix extensions used */ ); + const char *searchName, + FILE_DIRECTORY_INFO * findData, + T2_FFIRST_RSP_PARMS * findParms, + const struct nls_table *nls_codepage, + int *pUnicodeFlag, + int *pUnixFlag /* if Unix extensions used */ ); extern int CIFSFindNext(const int xid, const struct cifsTconInfo *tcon, FILE_DIRECTORY_INFO * findData, T2_FNEXT_RSP_PARMS * findParms, @@ -112,48 +112,48 @@ int *UnicodeFlag, int *pUnixFlag); extern int CIFSSMBQPathInfo(const int xid, const struct cifsTconInfo *tcon, - const unsigned char *searchName, - FILE_ALL_INFO * findData, - const struct nls_table *nls_codepage); + const unsigned char *searchName, + FILE_ALL_INFO * findData, + const struct nls_table *nls_codepage); extern int CIFSSMBUnixQPathInfo(const int xid, - const struct cifsTconInfo *tcon, - const unsigned char *searchName, - FILE_UNIX_BASIC_INFO * pFindData, - const struct nls_table *nls_codepage); + const struct cifsTconInfo *tcon, + const unsigned char *searchName, + FILE_UNIX_BASIC_INFO * pFindData, + const struct nls_table *nls_codepage); extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, - const unsigned char *searchName, - unsigned char **targetUNCs, - int *number_of_UNC_in_array, - const struct nls_table *nls_codepage); + const unsigned char *searchName, + unsigned char **targetUNCs, + int *number_of_UNC_in_array, + const struct nls_table *nls_codepage); extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, - const char *old_path, - const struct nls_table *nls_codepage); + const char *old_path, + const struct nls_table *nls_codepage); extern int CIFSSMBQFSInfo(const int xid, const struct cifsTconInfo *tcon, - struct statfs *FSData, - const struct nls_table *nls_codepage); + struct statfs *FSData, + const struct nls_table *nls_codepage); extern int CIFSSMBQFSAttributeInfo(const int xid, - struct cifsTconInfo *tcon, - const struct nls_table *nls_codepage); + struct cifsTconInfo *tcon, + const struct nls_table *nls_codepage); extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage); extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon, - const struct nls_table *nls_codepage); + const struct nls_table *nls_codepage); extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, - char *fileName, FILE_BASIC_INFO * data, - const struct nls_table *nls_codepage); + char *fileName, FILE_BASIC_INFO * data, + const struct nls_table *nls_codepage); extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, - char *fileName, __u64 size,int setAllocationSizeFlag, - const struct nls_table *nls_codepage); + char *fileName, __u64 size,int setAllocationSizeFlag, + const struct nls_table *nls_codepage); extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, __u16 fileHandle,__u32 opener_pid, int AllocSizeFlag); extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon, - char *full_path, __u64 mode, __u64 uid, - __u64 gid, const struct nls_table *nls_codepage); + char *full_path, __u64 mode, __u64 uid, + __u64 gid, const struct nls_table *nls_codepage); extern int CIFSSMBMkDir(const int xid, const struct cifsTconInfo *tcon, const char *newName, @@ -162,49 +162,49 @@ const char *name, const struct nls_table *nls_codepage); extern int CIFSSMBDelFile(const int xid, const struct cifsTconInfo *tcon, - const char *name, - const struct nls_table *nls_codepage); + const char *name, + const struct nls_table *nls_codepage); extern int CIFSSMBRename(const int xid, const struct cifsTconInfo *tcon, - const char *fromName, const char *toName, - const struct nls_table *nls_codepage); + const char *fromName, const char *toName, + const struct nls_table *nls_codepage); extern int CIFSCreateHardLink(const int xid, - const struct cifsTconInfo *tcon, - const char *fromName, const char *toName, - const struct nls_table *nls_codepage); + const struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage); extern int CIFSUnixCreateHardLink(const int xid, - const struct cifsTconInfo *tcon, - const char *fromName, const char *toName, - const struct nls_table *nls_codepage); + const struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage); extern int CIFSUnixCreateSymLink(const int xid, - const struct cifsTconInfo *tcon, - const char *fromName, const char *toName, - const struct nls_table *nls_codepage); + const struct cifsTconInfo *tcon, + const char *fromName, const char *toName, + const struct nls_table *nls_codepage); extern int CIFSSMBUnixQuerySymLink(const int xid, - const struct cifsTconInfo *tcon, - const unsigned char *searchName, - char *syminfo, const int buflen, - const struct nls_table *nls_codepage); + const struct cifsTconInfo *tcon, + const unsigned char *searchName, + char *syminfo, const int buflen, + const struct nls_table *nls_codepage); extern int CIFSSMBOpen(const int xid, const struct cifsTconInfo *tcon, - const char *fileName, const int disposition, - const int access_flags, const int omode, - __u16 * netfid, int *pOplock, - const struct nls_table *nls_codepage); + const char *fileName, const int disposition, + const int access_flags, const int omode, + __u16 * netfid, int *pOplock, + const struct nls_table *nls_codepage); extern int CIFSSMBClose(const int xid, const struct cifsTconInfo *tcon, const int smb_file_id); extern int CIFSSMBRead(const int xid, const struct cifsTconInfo *tcon, - const int netfid, unsigned int count, - const __u64 lseek, unsigned int *nbytes, char *buf); + const int netfid, unsigned int count, + const __u64 lseek, unsigned int *nbytes, char *buf); extern int CIFSSMBWrite(const int xid, const struct cifsTconInfo *tcon, const int netfid, const unsigned int count, const __u64 lseek, unsigned int *nbytes, const char *buf, const int long_op); extern int CIFSSMBLock(const int xid, const struct cifsTconInfo *tcon, - const __u16 netfid, const __u64 len, - const __u64 offset, const __u32 numUnlock, - const __u32 numLock, const __u8 lockType, - const int waitFlag); + const __u16 netfid, const __u64 len, + const __u64 offset, const __u32 numUnlock, + const __u32 numLock, const __u8 lockType, + const int waitFlag); extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon); extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses); @@ -220,32 +220,32 @@ /* BB routines below not implemented yet BB */ extern int CIFSBuildServerList(int xid, char *serverBufferList, - int recordlength, int *entries, - int *totalEntries, int *topoChangedFlag); + int recordlength, int *entries, + int *totalEntries, int *topoChangedFlag); extern int CIFSSMBQueryShares(int xid, struct cifsTconInfo *tcon, - struct shareInfo *shareList, int bufferLen, - int *entries, int *totalEntries); + struct shareInfo *shareList, int bufferLen, + int *entries, int *totalEntries); extern int CIFSSMBQueryAlias(int xid, struct cifsTconInfo *tcon, - struct aliasInfo *aliasList, int bufferLen, - int *entries, int *totalEntries); + struct aliasInfo *aliasList, int bufferLen, + int *entries, int *totalEntries); extern int CIFSSMBAliasInfo(int xid, struct cifsTconInfo *tcon, - char *aliasName, char *serverName, - char *shareName, char *comment); + char *aliasName, char *serverName, + char *shareName, char *comment); extern int CIFSSMBGetShareInfo(int xid, struct cifsTconInfo *tcon, - char *share, char *comment); + char *share, char *comment); extern int CIFSSMBGetUserPerms(int xid, struct cifsTconInfo *tcon, - char *userName, char *searchName, int *perms); + char *userName, char *searchName, int *perms); extern int CIFSSMBSync(int xid, struct cifsTconInfo *tcon, int netfid, int pid); extern int CIFSSMBSeek(int xid, - struct cifsTconInfo *tcon, - int netfid, - int pid, - int whence, unsigned long offset, long long *newoffset); + struct cifsTconInfo *tcon, + int netfid, + int pid, + int whence, unsigned long offset, long long *newoffset); extern int CIFSSMBCopy(int xid, - struct cifsTconInfo *ftcon, - char *fromName, - struct cifsTconInfo *ttcon, - char *toName, int ofun, int flags); -#endif /* _CIFSPROTO_H */ + struct cifsTconInfo *ftcon, + char *fromName, + struct cifsTconInfo *ttcon, + char *toName, int ofun, int flags); +#endif /* _CIFSPROTO_H */ diff -Nru a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c --- a/fs/cifs/cifssmb.c Mon Nov 4 14:31:01 2002 +++ b/fs/cifs/cifssmb.c Mon Nov 4 14:31:01 2002 @@ -487,7 +487,7 @@ (tcon->ses->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00)); pSMB->MaxCountHigh = 0; - pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */ + pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -497,15 +497,20 @@ } else { pSMBr->DataLength = le16_to_cpu(pSMBr->DataLength); *nbytes = pSMBr->DataLength; - /* BB check that DataLength would not go beyond end of SMB BB */ - if (pSMBr->DataLength > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) { + /*check that DataLength would not go beyond end of SMB */ + if ((pSMBr->DataLength > CIFS_MAX_MSGSIZE) + || (pSMBr->DataLength > count)) { rc = -EIO; *nbytes = 0; } else { pReadData = (char *) (&pSMBr->hdr.Protocol) + le16_to_cpu(pSMBr->DataOffset); - copy_to_user(buf, pReadData, pSMBr->DataLength); +/* if(rc = copy_to_user(buf, pReadData, pSMBr->DataLength)) { + cERROR(1,("\nFaulting on read rc = %d",rc)); + rc = -EFAULT; + }*/ /* can not use copy_to_user when using page cache*/ + memcpy(buf,pReadData,pSMBr->DataLength); } } @@ -544,7 +549,8 @@ pSMB->DataLengthHigh = 0; pSMB->DataOffset = cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); - copy_from_user(pSMB->Data, buf, pSMB->DataLengthLow); + + memcpy(pSMB->Data,buf,pSMB->DataLengthLow); pSMB->ByteCount += pSMB->DataLengthLow + 1 /* pad */ ; pSMB->DataLengthLow = cpu_to_le16(pSMB->DataLengthLow); diff -Nru a/fs/cifs/connect.c b/fs/cifs/connect.c --- a/fs/cifs/connect.c Mon Nov 4 14:31:02 2002 +++ b/fs/cifs/connect.c Mon Nov 4 14:31:02 2002 @@ -219,6 +219,7 @@ } task_to_wake = NULL; + read_lock(&GlobalMid_Lock); list_for_each(tmp, &server->pending_mid_q) { mid_entry = list_entry(tmp, struct mid_q_entry, @@ -234,7 +235,7 @@ MID_RESPONSE_RECEIVED; } } - + read_unlock(&GlobalMid_Lock); if (task_to_wake) { smb_buffer = NULL; /* will be freed by users thread after he is done */ wake_up_process(task_to_wake); @@ -256,12 +257,14 @@ } /* BB add code to lock SMB sessions while releasing */ if(server->ssocket) { - sock_release(csocket); + sock_release(csocket); server->ssocket = NULL; - } + } set_fs(temp_fs); if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */ buf_release(smb_buffer); + + read_lock(&GlobalSMBSeslock); if (list_empty(&server->pending_mid_q)) { /* loop through server session structures attached to this and mark them dead */ list_for_each(tmp, &GlobalSMBSessionList) { @@ -275,10 +278,12 @@ } kfree(server); } else /* BB need to more gracefully handle the rare negative session - response case because response will be still outstanding */ + response case because response will be still outstanding */ cERROR(1, ("\nThere are still active MIDs in queue and we are exiting but we can not delete mid_q_entries or TCP_Server_Info structure due to pending requests MEMORY LEAK!!\n ")); /* BB wake up waitors, and/or wait and/or free stale mids and try again? BB */ /* BB Need to fix bug in error path above - perhaps wait until smb requests time out and then free the tcp per server struct BB */ + read_unlock(&GlobalSMBSeslock); + cFYI(1, ("\nAbout to exit from demultiplex thread\n")); return 0; @@ -421,7 +426,7 @@ struct cifsSesInfo *ses; *psrvTcp = NULL; - + read_lock(&GlobalSMBSeslock); list_for_each(tmp, &GlobalSMBSessionList) { ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); if (ses->server) { @@ -432,12 +437,15 @@ /* BB check if reconnection needed */ if (strncmp (ses->userName, userName, - MAX_USERNAME_SIZE) == 0) + MAX_USERNAME_SIZE) == 0){ + read_unlock(&GlobalSMBSeslock); return ses; /* found exact match on both tcp and SMB sessions */ + } } } /* else tcp and smb sessions need reconnection */ } + read_unlock(&GlobalSMBSeslock); return NULL; } @@ -447,6 +455,7 @@ struct list_head *tmp; struct cifsTconInfo *tcon; + read_lock(&GlobalSMBSeslock); list_for_each(tmp, &GlobalTreeConnectionList) { cFYI(1, ("\nNext tcon - ")); tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); @@ -473,13 +482,16 @@ if (strncmp (tcon->ses->userName, userName, - MAX_USERNAME_SIZE) == 0) + MAX_USERNAME_SIZE) == 0) { + read_unlock(&GlobalSMBSeslock); return tcon;/* also matched user (smb session)*/ + } } } } } } + read_unlock(&GlobalSMBSeslock); return NULL; } @@ -599,7 +611,7 @@ { int rc = 0; int xid; - int ntlmv2_flag = FALSE; + int ntlmv2_flag = FALSE; struct socket *csocket; struct sockaddr_in sin_server; /* struct sockaddr_in6 sin_server6; */ @@ -616,7 +628,11 @@ xid = GetXid(); cFYI(0, ("\nEntering cifs_mount. Xid: %d with: %s\n", xid, mount_data)); - parse_mount_options(mount_data, devname, &volume_info); + if(parse_mount_options(mount_data, devname, &volume_info)) { + FreeXid(xid); + return -EINVAL; + } + if (volume_info.username) { cFYI(1, ("\nUsername: %s ", volume_info.username)); @@ -634,7 +650,7 @@ cERROR(1, ("\nCIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified ")); FreeXid(xid); - return -ENODEV; + return -EINVAL; } /* BB add support to use the multiuser_mount flag BB */ existingCifsSes = @@ -720,18 +736,18 @@ && (pSesInfo->secType == RawNTLMSSP)) { cFYI(1, ("\nNTLMSSP sesssetup ")); rc = CIFSNTLMSSPNegotiateSessSetup(xid, - pSesInfo, - cryptKey, - volume_info.domainname, - &ntlmv2_flag, - cifs_sb->local_nls); + pSesInfo, + cryptKey, + volume_info.domainname, + &ntlmv2_flag, + cifs_sb->local_nls); if (!rc) { - if(ntlmv2_flag) { - cFYI(1,("\nAble to use the more secure NTLM version 2 password hash")); - /* SMBNTv2encrypt( ...); */ /* BB fix this up - - and note that Samba client equivalent looks wrong */ - } else - SMBNTencrypt(password_with_pad,cryptKey,ntlm_session_key); + if(ntlmv2_flag) { + cFYI(1,("\nAble to use the more secure NTLM version 2 password hash")); + /* SMBNTv2encrypt( ...); */ /* BB fix this up - + and note that Samba client equivalent looks wrong */ + } else + SMBNTencrypt(password_with_pad,cryptKey,ntlm_session_key); /* for better security the weaker lanman hash not sent in AuthSessSetup so why bother calculating it */ @@ -742,13 +758,13 @@ cryptKey, session_key); */ rc = CIFSNTLMSSPAuthSessSetup(xid, - pSesInfo, - volume_info. - username, - volume_info.domainname, - ntlm_session_key, - session_key, - ntlmv2_flag, + pSesInfo, + volume_info. + username, + volume_info.domainname, + ntlm_session_key, + session_key, + ntlmv2_flag, cifs_sb->local_nls); } } else { /* old style NTLM 0.12 session setup */ @@ -805,6 +821,7 @@ "", cifs_sb-> local_nls); + FreeXid(xid); return -ENODEV; } else { rc = CIFSTCon(xid, pSesInfo, @@ -893,8 +910,8 @@ pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->maxBuf); pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->maxReq); - if(ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + if(ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; pSMB->req_no_secext.Capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS; @@ -928,8 +945,8 @@ *bcc_ptr = 0; bcc_ptr++; } - if(user == NULL) - bytes_returned = 0; /* skill null user */ + if(user == NULL) + bytes_returned = 0; /* skill null user */ else bytes_returned = cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage); @@ -960,10 +977,10 @@ bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; } else { - if(user != NULL) { + if(user != NULL) { strncpy(bcc_ptr, user, 200); bcc_ptr += strnlen(user, 200); - } + } *bcc_ptr = 0; bcc_ptr++; if (domain == NULL) { @@ -1065,7 +1082,6 @@ kcalloc(2, GFP_KERNEL); } } else { /* ASCII */ - len = strnlen(bcc_ptr, 1024); if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) @@ -1148,8 +1164,8 @@ pSMB->req.MaxBufferSize = cpu_to_le16(ses->maxBuf); pSMB->req.MaxMpxCount = cpu_to_le16(ses->maxReq); - if(ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + if(ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; pSMB->req.Capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | @@ -1394,7 +1410,7 @@ PCHALLENGE_MESSAGE SecurityBlob2; cFYI(1, ("\nIn NTLMSSP sesssetup (negotiate) ")); - *pNTLMv2_flag = FALSE; + *pNTLMv2_flag = FALSE; smb_buffer = buf_get(); if (smb_buffer == 0) { return -ENOMEM; @@ -1413,8 +1429,8 @@ pSMB->req.MaxBufferSize = cpu_to_le16(ses->maxBuf); pSMB->req.MaxMpxCount = cpu_to_le16(ses->maxReq); - if(ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + if(ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; pSMB->req.Capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | @@ -1441,8 +1457,8 @@ NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 | NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_128; - if(ntlmv2_support) - SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2; + if(ntlmv2_support) + SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2; /* setup pointers to domain name and workstation name */ bcc_ptr += SecurityBlobLength; @@ -1558,8 +1574,8 @@ memcpy(challenge_from_server, SecurityBlob2->Challenge, CIFS_CRYPTO_KEY_SIZE); - if(SecurityBlob2->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLMV2) - *pNTLMv2_flag = TRUE; + if(SecurityBlob2->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLMV2) + *pNTLMv2_flag = TRUE; if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) { if ((long) (bcc_ptr) % 2) { remaining_words = @@ -1645,7 +1661,6 @@ kcalloc(2, GFP_KERNEL); } } else { /* ASCII */ - len = strnlen(bcc_ptr, 1024); if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) @@ -1742,8 +1757,8 @@ pSMB->req.hdr.Uid = ses->Suid; - if(ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + if(ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; pSMB->req.Capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | @@ -1771,8 +1786,8 @@ NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | 0x80000000 | NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_128; - if(ntlmv2_flag) - SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2; + if(ntlmv2_flag) + SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2; /* setup pointers to domain name and workstation name */ @@ -2032,7 +2047,6 @@ ses->serverNOS = kcalloc(2, GFP_KERNEL); } } else { /* ASCII */ - len = strnlen(bcc_ptr, 1024); if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) @@ -2116,8 +2130,8 @@ bcc_ptr = &(pSMB->Password[0]); bcc_ptr++; /* skip password */ - if(ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + if(ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; if (ses->capabilities & CAP_STATUS32) { smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; @@ -2202,6 +2216,7 @@ struct cifsSesInfo *ses = NULL; xid = GetXid(); + if (cifs_sb->tcon) { ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/ rc = CIFSSMBTDis(xid, cifs_sb->tcon); @@ -2218,16 +2233,11 @@ FreeXid(xid); return 0; } - /* wake_up_process(ses->server->tsk);*/ /* was worth a try */ schedule_timeout(HZ / 4); /* give captive thread time to exit */ - if((ses->server) && (ses->server->ssocket)) { - cFYI(1,("\nWaking up socket by sending it signal ")); - send_sig(SIGINT,ses->server->tsk,1); - /* No luck figuring out a better way to_close socket */ - /*ses->server->ssocket->sk->prot->close(ses->server->ssocket->sk,0);*/ - /* ses->server->ssocket = NULL; */ /* serialize better */ - /* sock_wake_async(ses->server->ssocket,3,POLL_HUP); */ - } + if((ses->server) && (ses->server->ssocket)) { + cFYI(1,("\nWaking up socket by sending it signal ")); + send_sig(SIGINT,ses->server->tsk,1); + } } else cFYI(1, ("\nNo session or bad tcon")); } diff -Nru a/fs/cifs/file.c b/fs/cifs/file.c --- a/fs/cifs/file.c Mon Nov 4 14:31:00 2002 +++ b/fs/cifs/file.c Mon Nov 4 14:31:00 2002 @@ -35,6 +35,8 @@ #include "cifs_debug.h" #include "cifs_fs_sb.h" + + int cifs_open(struct inode *inode, struct file *file) { @@ -42,8 +44,8 @@ int xid, oplock; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; - struct cifsFileInfo *pCifsFile; - struct cifsInodeInfo *pCifsInode; + struct cifsFileInfo *pCifsFile; + struct cifsInodeInfo *pCifsInode; char *full_path = NULL; int desiredAccess = 0x20197; int disposition = FILE_OPEN; @@ -104,28 +106,27 @@ if (file->private_data) { memset(file->private_data, 0, sizeof (struct cifsFileInfo)); - pCifsFile = (struct cifsFileInfo *) file->private_data; + pCifsFile = (struct cifsFileInfo *) file->private_data; pCifsFile->netfid = netfid; pCifsFile->pid = current->pid; - list_add(&pCifsFile->tlist,&pTcon->openFileList); - pCifsInode = CIFS_I(file->f_dentry->d_inode); - list_add(&pCifsFile->flist,&pCifsInode->openFileList); - if(file->f_flags & O_CREAT) { - /* time to set mode which we can not - set earlier due to problems creating new read-only files */ - if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) - CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode, - 0xFFFFFFFFFFFFFFFF, - 0xFFFFFFFFFFFFFFFF, - cifs_sb->local_nls); - else {/* BB to be implemented via Windows secrty descriptors*/ - /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ - /* in the meantime we could set the r/o dos attribute - when perms are e.g.: - mode & 0222 == 0 */ - } - } - + pCifsFile->pfile = file; /* needed for writepage */ + list_add(&pCifsFile->tlist,&pTcon->openFileList); + pCifsInode = CIFS_I(file->f_dentry->d_inode); + list_add(&pCifsFile->flist,&pCifsInode->openFileList); + if(file->f_flags & O_CREAT) { + /* time to set mode which we can not set earlier due + to problems creating new read-only files */ + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) + CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode, + 0xFFFFFFFFFFFFFFFF, + 0xFFFFFFFFFFFFFFFF, + cifs_sb->local_nls); + else {/* BB implement via Windows security descriptors */ + /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ + /* in the meantime could set r/o dos attribute when perms are eg: + mode & 0222 == 0 */ + } + } } } @@ -151,10 +152,10 @@ cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; - if (pSMBFile) { - list_del(&pSMBFile->flist); - list_del(&pSMBFile->tlist); - rc = CIFSSMBClose(xid, pTcon, pSMBFile->netfid); + if (pSMBFile) { + list_del(&pSMBFile->flist); + list_del(&pSMBFile->tlist); + rc = CIFSSMBClose(xid, pTcon, pSMBFile->netfid); kfree(file->private_data); file->private_data = NULL; } else @@ -162,7 +163,6 @@ FreeXid(xid); return rc; - } int @@ -344,20 +344,24 @@ file->f_dentry->d_inode->i_size = *poffset; } mark_inode_dirty_sync(file->f_dentry->d_inode); + FreeXid(xid); return total_written; } static int -cifs_writepage(struct page *page) +cifs_partialpagewrite(struct page *page,unsigned from, unsigned to) { struct address_space *mapping = page->mapping; + loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; + char * write_data = kmap(page); int rc = -EFAULT; int bytes_written = 0; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; - int xid; struct inode *inode = page->mapping->host; - loff_t *poffset = NULL; + struct cifsInodeInfo *cifsInode; + struct cifsFileInfo *open_file = NULL; + int xid; xid = GetXid(); @@ -365,51 +369,90 @@ pTcon = cifs_sb->tcon; /* figure out which file struct to use - if (file->private_data == NULL) { + if (file->private_data == NULL) { FreeXid(xid); return -EBADF; - } + } */ if (!mapping) { FreeXid(xid); return -EFAULT; + } else if(!mapping->host) { + FreeXid(xid); + return -EFAULT; } - /* BB fix and add missing call to cifs_writepage_sync here */ + if((to > PAGE_CACHE_SIZE) || (from > to)) + return -EIO; - inode->i_ctime = inode->i_mtime = CURRENT_TIME; /* BB is this right? */ - if ((bytes_written > 0) && (poffset)) { - if (*poffset > inode->i_size) - inode->i_size = *poffset; + offset += (loff_t)from; + write_data += from; + + cifsInode = CIFS_I(mapping->host); + if(!list_empty(&(cifsInode->openFileList))) { + open_file = list_entry(cifsInode->openFileList.next, + struct cifsFileInfo, flist); + /* We could check if file is open for writing first */ + if(open_file->pfile) + bytes_written = cifs_write(open_file->pfile, write_data, + to-from, &offset); + /* Does mm or vfs already set times? */ + inode->i_atime = inode->i_mtime = CURRENT_TIME; + if ((bytes_written > 0) && (offset)) { + rc = 0; + if (offset > inode->i_size) + inode->i_size = offset; + } else if(bytes_written < 0) { + rc = bytes_written; + } + mark_inode_dirty_sync(inode); + } else { + cFYI(1,("\nNo open files to get file handle from")); + rc = -EIO; } - mark_inode_dirty_sync(inode); FreeXid(xid); return rc; } static int -cifs_prepare_write(struct file *file, struct page *page, unsigned offset, - unsigned to) +cifs_writepage(struct page* page) { - return 0; /* eventually add code to flush any incompatible requests */ + int rc = -EFAULT; + int xid; + + xid = GetXid(); + page_cache_get(page); + rc = cifs_partialpagewrite(page,0,PAGE_CACHE_SIZE); + /* insert call to SetPageToUpdate like function here? */ + unlock_page(page); + page_cache_release(page); + FreeXid(xid); + return rc; } static int cifs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) { - long rc = -EFAULT; - - lock_kernel(); -/* status = cifs_updatepage(file, page, offset, to-offset); */ + int xid,rc; + xid = GetXid(); -/* BB add - do we really need to lock the kernel here for so long ? */ + if(offset > to) + return -EIO; + rc = cifs_partialpagewrite(page,offset,to); - unlock_kernel(); + FreeXid(xid); return rc; } +static int +cifs_prepare_write(struct file *file, struct page *page, unsigned offset, + unsigned to) +{ + return 0; /* eventually add code to flush any incompatible requests */ +} + int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) { @@ -489,13 +532,30 @@ return total_read; } +int +cifs_file_mmap(struct file * file, struct vm_area_struct * vma) +{ + struct dentry * dentry = file->f_dentry; + int rc, xid; + + xid = GetXid(); + rc = cifs_revalidate(dentry); + if (rc) { + cFYI(1,("Validation prior to mmap failed, error=%d\n", rc)); + FreeXid(xid); + return rc; + } + rc = generic_file_mmap(file, vma); + FreeXid(xid); + return rc; +} + static int -cifs_readpage_sync(struct file *file, struct page *page) +cifs_readpage(struct file *file, struct page *page) { - unsigned int count = PAGE_CACHE_SIZE; + loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; + char * read_data; int rc = -EACCES; - int bytes_read = 0; - int total_read = 0; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; int xid; @@ -508,26 +568,33 @@ FreeXid(xid); return -EBADF; } + page_cache_get(page); + read_data = kmap(page); + /* for reads over a certain size we could initiate async read ahead */ - /* BB finish adding missing here */ + rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, &offset); - cFYI(1, - ("\nCount is %d total read %d bytes read %d ", count, total_read, - bytes_read)); + if (rc < 0) + goto io_error; + else { + cFYI(1,("\nBytes read %d ",rc)); + } - FreeXid(xid); - return rc; -} + file->f_dentry->d_inode->i_atime = CURRENT_TIME; -static int -cifs_readpage(struct file *file, struct page *page) -{ - int rc; + if(PAGE_CACHE_SIZE > rc) { + memset(read_data+rc, 0, PAGE_CACHE_SIZE - rc); + } + flush_dcache_page(page); + SetPageUptodate(page); + rc = 0; + +io_error: + kunmap(page); + unlock_page(page); - page_cache_get(page); - rc = cifs_readpage_sync(file, page); - /* for reads over a certain size we could initiate async read ahead */ page_cache_release(page); + FreeXid(xid); return rc; } @@ -546,11 +613,11 @@ /* Linux can not store file creation time unfortunately so we ignore it */ tmp_inode->i_atime = - le64_to_cpu(cifs_NTtimeToUnix(pfindData->LastAccessTime)); + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); tmp_inode->i_mtime = - le64_to_cpu(cifs_NTtimeToUnix(pfindData->LastWriteTime)); + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); tmp_inode->i_ctime = - le64_to_cpu(cifs_NTtimeToUnix(pfindData->ChangeTime)); + cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); /* should we treat the dos attribute of read-only as read-only mode bit e.g. 555 */ tmp_inode->i_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); /* 2767 perms - indicate mandatory locking */ cFYI(0, @@ -605,16 +672,12 @@ atomic_inc(&cifsInfo->inUse); tmp_inode->i_atime = - le64_to_cpu(cifs_NTtimeToUnix(pfindData->LastAccessTime)); + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); tmp_inode->i_mtime = - le64_to_cpu(cifs_NTtimeToUnix(pfindData->LastModificationTime)); + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime)); tmp_inode->i_ctime = - le64_to_cpu(cifs_NTtimeToUnix(pfindData->LastStatusChange)); + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange)); - /* tmp_inode->i_mtime = - cifs_NTtimeToUnix(pfindData->LastModificationTime); - tmp_inode->i_ctime = - cifs_NTtimeToUnix(pfindData->LastStatusChange); */ tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions); pfindData->Type = le32_to_cpu(pfindData->Type); if (pfindData->Type == UNIX_FILE) { @@ -1013,8 +1076,17 @@ struct address_space_operations cifs_addr_ops = { .readpage = cifs_readpage, - .sync_page = cifs_sync_page, .writepage = cifs_writepage, .prepare_write = cifs_prepare_write, - .commit_write = cifs_commit_write + .commit_write = cifs_commit_write, +/* .sync_page = cifs_sync_page, */ +}; + +/* change over to struct below when sync page tested and complete */ +struct address_space_operations cifs_addr_ops2 = { + .readpage = cifs_readpage, + .writepage = cifs_writepage, + .prepare_write = cifs_prepare_write, + .commit_write = cifs_commit_write, + .sync_page = cifs_sync_page, }; diff -Nru a/fs/cifs/inode.c b/fs/cifs/inode.c --- a/fs/cifs/inode.c Mon Nov 4 14:31:00 2002 +++ b/fs/cifs/inode.c Mon Nov 4 14:31:00 2002 @@ -52,9 +52,9 @@ if (rc) { if (rc == -EREMOTE) { /* rc = *//* CIFSGetDFSRefer(xid, pTcon->ses, search_path, - &referrals, - &num_referrals, - cifs_sb->local_nls); */ + &referrals, + &num_referrals, + cifs_sb->local_nls); */ tmp_path = kmalloc(strnlen (pTcon->treeName, @@ -99,12 +99,12 @@ atomic_inc(&cifsInfo->inUse); /* inc on every refresh of inode */ inode->i_atime = - le64_to_cpu(cifs_NTtimeToUnix(findData.LastAccessTime)); + cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime)); inode->i_mtime = - le64_to_cpu(cifs_NTtimeToUnix + cifs_NTtimeToUnix(le64_to_cpu (findData.LastModificationTime)); inode->i_ctime = - le64_to_cpu(cifs_NTtimeToUnix(findData.LastStatusChange)); + cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange)); inode->i_mode = le64_to_cpu(findData.Permissions); findData.Type = le32_to_cpu(findData.Type); if (findData.Type == UNIX_FILE) { @@ -140,6 +140,7 @@ cFYI(1, (" File inode ")); inode->i_op = &cifs_file_inode_ops; inode->i_fop = &cifs_file_ops; + inode->i_data.a_ops = &cifs_addr_ops; } else if (S_ISDIR(inode->i_mode)) { cFYI(1, (" Directory inode")); inode->i_op = &cifs_dir_inode_ops; @@ -182,9 +183,9 @@ if (rc == -EREMOTE) { /* BB add call to new func rc = GetDFSReferral(); */ /* rc = *//* CIFSGetDFSRefer(xid, pTcon->ses, search_path, - &referrals, - &num_referrals, - cifs_sb->local_nls); */ + &referrals, + &num_referrals, + cifs_sb->local_nls); */ tmp_path = kmalloc(strnlen (pTcon->treeName, @@ -265,6 +266,7 @@ cFYI(1, (" File inode ")); inode->i_op = &cifs_file_inode_ops; inode->i_fop = &cifs_file_ops; + inode->i_data.a_ops = &cifs_addr_ops; } else if (S_ISDIR(inode->i_mode)) { cFYI(1, (" Directory inode ")); inode->i_op = &cifs_dir_inode_ops; @@ -441,9 +443,11 @@ cifs_sb_source = CIFS_SB(source_inode->i_sb); pTcon = cifs_sb_source->tcon; - if (pTcon != cifs_sb_target->tcon) + if (pTcon != cifs_sb_target->tcon) { return -EXDEV; /* BB actually could be allowed if same server, but different share. Might eventually add support for this */ + FreeXid(xid); + } fromName = build_path_from_dentry(source_direntry); toName = build_path_from_dentry(target_direntry); @@ -455,6 +459,7 @@ if (toName) kfree(toName); + FreeXid(xid); return rc; } @@ -479,7 +484,7 @@ direntry->d_time, jiffies)); cifsInode = CIFS_I(direntry->d_inode); - +/* BB add check - do not need to revalidate oplocked files */ if ((time_before(jiffies, cifsInode->time + HZ)) && (direntry->d_inode->i_nlink == 1)) { cFYI(1, (" Do not need to revalidate ")); @@ -505,12 +510,20 @@ return rc; } +int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) +{ + int err = cifs_revalidate(dentry); + if (!err) + generic_fillattr(dentry->d_inode, stat); + return err; +} + void cifs_truncate_file(struct inode *inode) { /* BB remove - may not need this function after all BB */ int xid; int rc = 0; - struct cifsFileInfo *open_file = NULL; + struct cifsFileInfo *open_file = NULL; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; struct cifsInodeInfo *cifsInode; @@ -534,21 +547,19 @@ full_path = build_path_from_dentry(dirent); rc = CIFSSMBSetEOF(xid, pTcon, full_path, inode->i_size,FALSE, cifs_sb->local_nls); - cFYI(1,("\nSetEOF (truncate) rc = %d",rc)); - if(rc == -ETXTBSY) { - cifsInode = CIFS_I(inode); - if(!list_empty(&(cifsInode->openFileList))) { - open_file = list_entry(cifsInode->openFileList.next, - struct cifsFileInfo, flist); - /* We could check if file is open for writing first and - also we could also override the smb pid with the pid - of the file opener when sending the CIFS request */ - rc = CIFSSMBSetFileSize(xid, pTcon, inode->i_size, - open_file->netfid,open_file->pid,FALSE); - } else { - cFYI(1,("\nNo open files to get file handle from")); - } - } + cFYI(1,("\nSetEOF (truncate) rc = %d",rc)); + if(rc == -ETXTBSY) { + cifsInode = CIFS_I(inode); + if(!list_empty(&(cifsInode->openFileList))) { + open_file = list_entry(cifsInode->openFileList.next, + struct cifsFileInfo, flist); + /* We could check if file is open for writing first */ + rc = CIFSSMBSetFileSize(xid, pTcon, inode->i_size, + open_file->netfid,open_file->pid,FALSE); + } else { + cFYI(1,("\nNo open files to get file handle from")); + } + } if (!rc) CIFSSMBSetEOF(xid,pTcon,full_path,inode->i_size,TRUE,cifs_sb->local_nls); /* allocation size setting seems optional so ignore return code */ @@ -567,7 +578,7 @@ struct cifsTconInfo *pTcon; char *full_path = NULL; int rc = -EACCES; - struct cifsFileInfo *open_file = NULL; + struct cifsFileInfo *open_file = NULL; FILE_BASIC_INFO time_buf; int set_time = FALSE; __u64 mode = 0xFFFFFFFFFFFFFFFF; @@ -593,19 +604,19 @@ if (attrs->ia_valid & ATTR_SIZE) { rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE, cifs_sb->local_nls); - cFYI(1,("\nSetEOF (setattrs) rc = %d",rc)); + cFYI(1,("\nSetEOF (setattrs) rc = %d",rc)); - if(rc == -ETXTBSY) { - if(!list_empty(&(cifsInode->openFileList))) { - open_file = list_entry(cifsInode->openFileList.next, - struct cifsFileInfo, flist); + if(rc == -ETXTBSY) { + if(!list_empty(&(cifsInode->openFileList))) { + open_file = list_entry(cifsInode->openFileList.next, + struct cifsFileInfo, flist); /* We could check if file is open for writing first */ - rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, - open_file->netfid,open_file->pid,FALSE); - } else { - cFYI(1,("\nNo open files to get file handle from")); - } - } + rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, + open_file->netfid,open_file->pid,FALSE); + } else { + cFYI(1,("\nNo open files to get file handle from")); + } + } /* Set Allocation Size of file - might not even need to call the following but might as well and it does not hurt if it fails */ CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls); @@ -684,5 +695,4 @@ cFYI(1, ("In cifs_delete_inode, inode = 0x%p\n", inode)); /* may have to add back in when safe distributed caching of directories via e.g. FindNotify added */ - } diff -Nru a/fs/cifs/md5.h b/fs/cifs/md5.h --- a/fs/cifs/md5.h Mon Nov 4 14:31:00 2002 +++ b/fs/cifs/md5.h Mon Nov 4 14:31:00 2002 @@ -22,17 +22,17 @@ void MD5Init(struct MD5Context *context); void MD5Update(struct MD5Context *context, unsigned char const *buf, - unsigned len); + unsigned len); void MD5Final(unsigned char digest[16], struct MD5Context *context); /* The following definitions come from lib/hmacmd5.c */ void hmac_md5_init_rfc2104(unsigned char *key, int key_len, - struct HMACMD5Context *ctx); + struct HMACMD5Context *ctx); void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len, - struct HMACMD5Context *ctx); + struct HMACMD5Context *ctx); void hmac_md5_update(const unsigned char *text, int text_len, - struct HMACMD5Context *ctx); + struct HMACMD5Context *ctx); void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx); void hmac_md5(unsigned char key[16], unsigned char *data, int data_len, - unsigned char *digest); + unsigned char *digest); diff -Nru a/fs/cifs/misc.c b/fs/cifs/misc.c --- a/fs/cifs/misc.c Mon Nov 4 14:31:02 2002 +++ b/fs/cifs/misc.c Mon Nov 4 14:31:02 2002 @@ -28,7 +28,6 @@ extern kmem_cache_t *cifs_req_cachep; -static DECLARE_MUTEX(GlobalMid_Sem); /* also protects XID globals */ __u16 GlobalMid; /* multiplex id - rotating counter */ /* The xid serves as a useful identifier for each incoming vfs request, @@ -42,21 +41,21 @@ { unsigned int xid; - down(&GlobalMid_Sem); + write_lock(&GlobalMid_Lock); GlobalTotalActiveXid++; if (GlobalTotalActiveXid > GlobalMaxActiveXid) GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */ xid = GlobalCurrentXid++; - up(&GlobalMid_Sem); + write_unlock(&GlobalMid_Lock); return xid; } void _FreeXid(unsigned int xid) { - down(&GlobalMid_Sem); + write_lock(&GlobalMid_Lock); GlobalTotalActiveXid--; - up(&GlobalMid_Sem); + write_unlock(&GlobalMid_Lock); } struct cifsSesInfo * @@ -69,9 +68,11 @@ GFP_KERNEL); if (ret_buf) { memset(ret_buf, 0, sizeof (struct cifsSesInfo)); + write_lock(&GlobalSMBSeslock); atomic_inc(&sesInfoAllocCount); list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList); init_MUTEX(&ret_buf->sesSem); + write_unlock(&GlobalSMBSeslock); } return ret_buf; } @@ -84,8 +85,10 @@ return; } + write_lock(&GlobalSMBSeslock); atomic_dec(&sesInfoAllocCount); list_del(&buf_to_free->cifsSessionList); + write_unlock(&GlobalSMBSeslock); if (buf_to_free->serverOS) kfree(buf_to_free->serverOS); if (buf_to_free->serverDomain) @@ -104,11 +107,13 @@ GFP_KERNEL); if (ret_buf) { memset(ret_buf, 0, sizeof (struct cifsTconInfo)); + write_lock(&GlobalSMBSeslock); atomic_inc(&tconInfoAllocCount); list_add(&ret_buf->cifsConnectionList, &GlobalTreeConnectionList); - INIT_LIST_HEAD(&ret_buf->openFileList); + INIT_LIST_HEAD(&ret_buf->openFileList); init_MUTEX(&ret_buf->tconSem); + write_unlock(&GlobalSMBSeslock); } return ret_buf; } @@ -120,9 +125,10 @@ cFYI(1, ("\nNull buffer passed to tconInfoFree")); return; } - + write_lock(&GlobalSMBSeslock); atomic_dec(&tconInfoAllocCount); list_del(&buf_to_free->cifsConnectionList); + write_unlock(&GlobalSMBSeslock); if (buf_to_free->nativeFileSystem) kfree(buf_to_free->nativeFileSystem); kfree(buf_to_free); @@ -203,9 +209,10 @@ buffer->Pid = tmp & 0xFFFF; tmp >>= 16; buffer->PidHigh = tmp & 0xFFFF; - down(&GlobalMid_Sem); + write_lock(&GlobalMid_Lock); GlobalMid++; buffer->Mid = GlobalMid; + write_unlock(&GlobalMid_Lock); if (treeCon) { buffer->Tid = treeCon->tid; if (treeCon->ses) { @@ -218,13 +225,11 @@ } if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) buffer->Flags2 |= SMBFLG2_DFS; - if(treeCon->ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; - + if(treeCon->ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; } /* endian conversion of flags is now done just before sending */ - up(&GlobalMid_Sem); buffer->WordCount = (char) word_count; return; } @@ -233,17 +238,18 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid) { /* Make sure that this really is an SMB, that it is a response, - and that the message ids match */ - if ((*(unsigned int *) smb->Protocol == cpu_to_le32(0x424d53ff)) && (mid == smb->Mid)) { - if(smb->Flags & SMBFLG_RESPONSE) - return 0; - else { - /* only one valid case where server sends us request */ - if(smb->Command == SMB_COM_LOCKING_ANDX) - return 0; - else - cERROR(1, ("\n Rcvd Request not response ")); - } + and that the message ids match */ + if ((*(unsigned int *) smb->Protocol == cpu_to_le32(0x424d53ff)) && + (mid == smb->Mid)) { + if(smb->Flags & SMBFLG_RESPONSE) + return 0; + else { + /* only one valid case where server sends us request */ + if(smb->Command == SMB_COM_LOCKING_ANDX) + return 0; + else + cERROR(1, ("\n Rcvd Request not response ")); + } } else { /* bad signature or mid */ if (*(unsigned int *) smb->Protocol != cpu_to_le32(0x424d53ff)) cERROR(1, @@ -252,8 +258,8 @@ if (mid != smb->Mid) cERROR(1, ("\n Mids do not match \n")); } - cERROR(1, ("\nCIFS: bad smb detected. The Mid=%d\n", smb->Mid)); - return 1; + cERROR(1, ("\nCIFS: bad smb detected. The Mid=%d\n", smb->Mid)); + return 1; } int @@ -269,7 +275,7 @@ cERROR(1, ("\n Length less than 2 + sizeof smb_hdr ")); if ((length >= sizeof (struct smb_hdr) - 1) && (smb->Status.CifsError != 0)) - return 0; /* this is ok - some error cases do not return wct and bcc */ + return 0; /* some error cases do not return wct and bcc */ } if (4 + ntohl(smb->smb_buf_length) > @@ -298,30 +304,42 @@ int is_valid_oplock_break(struct smb_hdr *buf) { - struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf; - - /* could add check for smb response flag 0x80 */ - cFYI(1,("\nChecking for oplock break")); - if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX) - return FALSE; - if(pSMB->hdr.Flags & SMBFLG_RESPONSE) - return FALSE; /* server sends us "request" here */ - if(pSMB->hdr.WordCount != 8) - return FALSE; - - cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel)); - if(!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)) - return FALSE; - - /* BB Add following logic: - 1) look up tcon based on tid & uid - 2) look up inode from tcon->openFileList->file->f_dentry->d_inode - 3) flush dirty pages and cached byte range locks and mark inode - 4) depending on break type change to r/o caching or no caching - 5) send oplock break response to server */ - cFYI(1,("\nNeed to process oplock break ")); - - return TRUE; + struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf; + struct list_head *tmp; + struct cifsTconInfo *tcon; + + /* could add check for smb response flag 0x80 */ + cFYI(1,("\nChecking for oplock break")); + if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX) + return FALSE; + if(pSMB->hdr.Flags & SMBFLG_RESPONSE) + return FALSE; /* server sends us "request" here */ + if(pSMB->hdr.WordCount != 8) + return FALSE; + + cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel)); + if(!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)) + return FALSE; + + /* look up tcon based on tid & uid */ + read_lock(&GlobalSMBSeslock); + list_for_each(tmp, &GlobalTreeConnectionList) { + tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); + if (tcon->tid == buf->Tid) + if(tcon->ses->Suid == buf->Uid) { + /* BB Add following logic: + 2) look up inode from tcon->openFileList->file->f_dentry->d_inode + 3) flush dirty pages and cached byte range locks and mark inode + 4) depending on break type change to r/o caching or no caching + 5) send oplock break response to server */ + read_unlock(&GlobalSMBSeslock); + cFYI(1,("\nFound matching connection, process oplock break")); + return TRUE; + } + } + read_unlock(&GlobalSMBSeslock); + cFYI(1,("\nProcessing oplock break for non-existent connection")); + return TRUE; } void diff -Nru a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c --- a/fs/cifs/netmisc.c Mon Nov 4 14:31:02 2002 +++ b/fs/cifs/netmisc.c Mon Nov 4 14:31:02 2002 @@ -745,7 +745,28 @@ ERRDOS, ERRnoaccess, 0xc0000290}, { ERRDOS, ERRbadfunc, 0xc000029c},}; -void +/***************************************************************************** + Print an error message from the status code + *****************************************************************************/ +static void +cifs_print_status(__u32 status_code) +{ + int idx = 0; + + printk("\nStatus code returned: 0x%08x", status_code); + + while (nt_errs[idx].nt_errstr != NULL) { + if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) == + (status_code & 0xFFFFFF)) { + printk(nt_errs[idx].nt_errstr); + } + idx++; + } + return; +} + + +static void ntstatus_to_dos(__u32 ntstatus, __u8 * eclass, __u16 * ecode) { int i; @@ -781,9 +802,9 @@ if (smb->Flags2 & SMBFLG2_ERR_STATUS) { /* translate the newer STATUS codes to old style errors and then to POSIX errors */ - cFYI(1, - (" !!Mapping cifs error code %d ", smb->Status.CifsError)); smb->Status.CifsError = le32_to_cpu(smb->Status.CifsError); + if(cifsFYI) + cifs_print_status(smb->Status.CifsError); ntstatus_to_dos(smb->Status.CifsError, &smberrclass, &smberrcode); } else { diff -Nru a/fs/cifs/nterr.c b/fs/cifs/nterr.c --- a/fs/cifs/nterr.c Mon Nov 4 14:31:00 2002 +++ b/fs/cifs/nterr.c Mon Nov 4 14:31:00 2002 @@ -20,14 +20,9 @@ */ /* NT error codes - see nterr.h */ -#include "nterr.h" #include #include - -struct nt_err_code_struct { - char *nt_errstr; - __u32 nt_errcode; -}; +#include "nterr.h" const struct nt_err_code_struct nt_errs[] = { {"NT_STATUS_OK", NT_STATUS_OK}, @@ -690,23 +685,3 @@ {"STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED}, {NULL, 0} }; - -/***************************************************************************** - Print an error message from the status code - *****************************************************************************/ -/* void -cifs_print_status(__u32 status_code) -{ - int idx = 0; - - printk("\nStatus code returned: 0x%08x", status_code); - - while (nt_errs[idx].nt_errstr != NULL) { - if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) == - (status_code & 0xFFFFFF)) { - printk(nt_errs[idx].nt_errstr); - } - idx++; - } - return; -} */ diff -Nru a/fs/cifs/nterr.h b/fs/cifs/nterr.h --- a/fs/cifs/nterr.h Mon Nov 4 14:31:00 2002 +++ b/fs/cifs/nterr.h Mon Nov 4 14:31:00 2002 @@ -22,8 +22,17 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + #ifndef _NTERR_H #define _NTERR_H + +struct nt_err_code_struct { + char *nt_errstr; + __u32 nt_errcode; +}; + +extern const struct nt_err_code_struct nt_errs[]; /* Win32 Status codes. */ diff -Nru a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c --- a/fs/cifs/smbencrypt.c Mon Nov 4 14:31:01 2002 +++ b/fs/cifs/smbencrypt.c Mon Nov 4 14:31:01 2002 @@ -205,19 +205,26 @@ /* Does the NTLMv2 owfs of a user's password */ void ntv2_owf_gen(const unsigned char owf[16], const char *user_n, - const char *domain_n, unsigned char kr_buf[16], - const struct nls_table *nls_codepage) + const char *domain_n, unsigned char kr_buf[16], + const struct nls_table *nls_codepage) { - wchar_t user_u[1024]; - wchar_t dom_u[1024]; + wchar_t * user_u; + wchar_t * dom_u; + int user_l, domain_l; struct HMACMD5Context ctx; + /* might as well do one alloc to hold both (user_u and dom_u) */ + user_u = kmalloc(2048 * sizeof(wchar_t),GFP_KERNEL); + if(user_u == NULL) + return; + dom_u = user_u + 1024; + /* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */ - /* do not think it is supposed to be uppercased */ - int user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage); - int domain_l = cifs_strtoUCS(dom_u, domain_n, 511, nls_codepage); + /* do not think it is supposed to be uppercased */ + user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage); + domain_l = cifs_strtoUCS(dom_u, domain_n, 511, nls_codepage); user_l++; /* trailing null */ domain_l++; @@ -234,6 +241,7 @@ dump_data(100, owf, 16); dump_data(100, kr_buf, 16); #endif + kfree(user_u); } /* Does the des encryption from the NT or LM MD4 hash. */ diff -Nru a/fs/cifs/transport.c b/fs/cifs/transport.c --- a/fs/cifs/transport.c Mon Nov 4 14:31:01 2002 +++ b/fs/cifs/transport.c Mon Nov 4 14:31:01 2002 @@ -59,9 +59,11 @@ temp->tsk = current; } if (ses->status == CifsGood) { + write_lock(&GlobalMid_Lock); list_add_tail(&temp->qhead, &ses->server->pending_mid_q); atomic_inc(&midCount); temp->midState = MID_REQUEST_ALLOCATED; + write_unlock(&GlobalMid_Lock); } else { /* BB add reconnect code here BB */ cERROR(1, @@ -77,11 +79,13 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) { /* BB add spinlock to protect midq for each session BB */ + write_lock(&GlobalMid_Lock); midEntry->midState = MID_FREE; - buf_release(midEntry->resp_buf); list_del(&midEntry->qhead); - kmem_cache_free(cifs_mid_cachep, midEntry); atomic_dec(&midCount); + write_unlock(&GlobalMid_Lock); + buf_release(midEntry->resp_buf); + kmem_cache_free(cifs_mid_cachep, midEntry); } int @@ -93,8 +97,8 @@ struct iovec iov; mm_segment_t temp_fs; - if(ssocket == NULL) - return -ENOTSOCK; /* BB eventually add reconnect code here */ + if(ssocket == NULL) + return -ENOTSOCK; /* BB eventually add reconnect code here */ /* ssocket->sk->allocation = GFP_BUFFER; *//* BB is this spurious? */ iov.iov_base = smb_buffer; iov.iov_len = smb_buf_length + 4; @@ -159,8 +163,6 @@ rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, (struct sockaddr *) &(ses->server->sockAddr)); - cFYI(1, ("\ncifs smb_send rc %d", rc)); /* BB remove */ - /* BB add code to wait for response and copy to out_buf */ if (long_op > 1) /* writes past end of file can take a looooooong time */ timeout = 300 * HZ; else if (long_op == 1) @@ -174,10 +176,9 @@ /* Replace above line with wait_event to get rid of sleep_on per lk guidelines */ timeout = wait_event_interruptible_timeout(ses->server->response_q, - midQ-> - midState & - MID_RESPONSE_RECEIVED, - 15 * HZ); + midQ-> + midState & MID_RESPONSE_RECEIVED, + timeout); cFYI(1, (" with timeout %ld and Out_buf: %p midQ->resp_buf: %p ", timeout, out_buf, midQ->resp_buf)); @@ -240,6 +241,8 @@ rc = -EIO; } - DeleteMidQEntry(midQ); /* BB what if process is killed ? - BB add background daemon to clean up Mid entries from killed processes BB test killing process with active mid */ + DeleteMidQEntry(midQ); /* BB what if process is killed? + - BB add background daemon to clean up Mid entries from + killed processes & test killing process with active mid */ return rc; } diff -Nru a/fs/dcookies.c b/fs/dcookies.c --- a/fs/dcookies.c Mon Nov 4 14:31:00 2002 +++ b/fs/dcookies.c Mon Nov 4 14:31:00 2002 @@ -8,7 +8,7 @@ * non-transitory that can be processed at a later date. * This is done by locking the dentry/vfsmnt pair in the * kernel until released by the tasks needing the persistent - * objects. The tag is simply an u32 that refers + * objects. The tag is simply an unsigned long that refers * to the pair and can be looked up from userspace. */ @@ -46,19 +46,19 @@ /* The dentry is locked, its address will do for the cookie */ -static inline u32 dcookie_value(struct dcookie_struct * dcs) +static inline unsigned long dcookie_value(struct dcookie_struct * dcs) { - return (u32)dcs->dentry; + return (unsigned long)dcs->dentry; } -static size_t dcookie_hash(u32 dcookie) +static size_t dcookie_hash(unsigned long dcookie) { - return (dcookie >> 2) & (hash_size - 1); + return (dcookie >> L1_CACHE_SHIFT) & (hash_size - 1); } -static struct dcookie_struct * find_dcookie(u32 dcookie) +static struct dcookie_struct * find_dcookie(unsigned long dcookie) { struct dcookie_struct * found = 0; struct dcookie_struct * dcs; @@ -109,7 +109,7 @@ * value for a dentry/vfsmnt pair. */ int get_dcookie(struct dentry * dentry, struct vfsmount * vfsmnt, - u32 * cookie) + unsigned long * cookie) { int err = 0; struct dcookie_struct * dcs; @@ -142,11 +142,12 @@ /* And here is where the userspace process can look up the cookie value * to retrieve the path. */ -asmlinkage int sys_lookup_dcookie(u32 cookie, char * buf, size_t len) +asmlinkage int sys_lookup_dcookie(u64 cookie64, char * buf, size_t len) { + unsigned long cookie = (unsigned long)cookie64; + int err = -EINVAL; char * kbuf; char * path; - int err = -EINVAL; size_t pathlen; struct dcookie_struct * dcs; @@ -170,19 +171,18 @@ kbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!kbuf) goto out; - memset(kbuf, 0, PAGE_SIZE); /* FIXME: (deleted) ? */ path = d_path(dcs->dentry, dcs->vfsmnt, kbuf, PAGE_SIZE); - err = 0; - + err = -ERANGE; + pathlen = kbuf + PAGE_SIZE - path; - if (len > pathlen) - len = pathlen; - - if (copy_to_user(buf, path, len)) - err = -EFAULT; + if (pathlen <= len) { + err = pathlen; + if (copy_to_user(buf, path, pathlen)) + err = -EFAULT; + } kfree(kbuf); out: diff -Nru a/fs/direct-io.c b/fs/direct-io.c --- a/fs/direct-io.c Mon Nov 4 14:31:02 2002 +++ b/fs/direct-io.c Mon Nov 4 14:31:02 2002 @@ -139,7 +139,7 @@ */ if (dio->page_errors == 0) dio->page_errors = ret; - dio->pages[0] = ZERO_PAGE(dio->cur_user_address); + dio->pages[0] = ZERO_PAGE(dio->curr_user_address); dio->head = 0; dio->tail = 1; ret = 0; diff -Nru a/fs/driverfs/Makefile b/fs/driverfs/Makefile --- a/fs/driverfs/Makefile Mon Nov 4 14:31:03 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,9 +0,0 @@ -# -# Makefile for the driverfs virtual filesystem. -# - -export-objs := inode.o - -obj-y := inode.o - -include $(TOPDIR)/Rules.make diff -Nru a/fs/driverfs/inode.c b/fs/driverfs/inode.c --- a/fs/driverfs/inode.c Mon Nov 4 14:31:00 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,708 +0,0 @@ -/* - * driverfs.c - The device driver file system - * - * Copyright (c) 2001 Patrick Mochel - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This is a simple, ram-based filesystem, which allows kernel - * callbacks for read/write of files. - * - * Please see Documentation/filesystems/driverfs.txt for more information. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#undef DEBUG - -#ifdef DEBUG -# define DBG(x...) printk(x) -#else -# define DBG(x...) -#endif - -/* Random magic number */ -#define DRIVERFS_MAGIC 0x42454552 - -static struct super_operations driverfs_ops; -static struct file_operations driverfs_file_operations; -static struct inode_operations driverfs_dir_inode_operations; -static struct address_space_operations driverfs_aops; - -static struct vfsmount *driverfs_mount; -static spinlock_t mount_lock = SPIN_LOCK_UNLOCKED; -static int mount_count = 0; - -static struct backing_dev_info driverfs_backing_dev_info = { - .ra_pages = 0, /* No readahead */ - .memory_backed = 1, /* Does not contribute to dirty memory */ -}; - -static int driverfs_readpage(struct file *file, struct page * page) -{ - if (!PageUptodate(page)) { - void *kaddr = kmap_atomic(page, KM_USER0); - - memset(kaddr, 0, PAGE_CACHE_SIZE); - flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); - SetPageUptodate(page); - } - unlock_page(page); - return 0; -} - -static int driverfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) -{ - if (!PageUptodate(page)) { - void *kaddr = kmap_atomic(page, KM_USER0); - - memset(kaddr, 0, PAGE_CACHE_SIZE); - flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); - SetPageUptodate(page); - } - return 0; -} - -static int driverfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) -{ - struct inode *inode = page->mapping->host; - loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; - - set_page_dirty(page); - if (pos > inode->i_size) - inode->i_size = pos; - return 0; -} - - -struct inode *driverfs_get_inode(struct super_block *sb, int mode, int dev) -{ - struct inode *inode = new_inode(sb); - - if (inode) { - inode->i_mode = mode; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; - inode->i_blocks = 0; - inode->i_rdev = NODEV; - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inode->i_mapping->a_ops = &driverfs_aops; - inode->i_mapping->backing_dev_info = &driverfs_backing_dev_info; - switch (mode & S_IFMT) { - default: - init_special_inode(inode, mode, dev); - break; - case S_IFREG: - inode->i_fop = &driverfs_file_operations; - break; - case S_IFDIR: - inode->i_op = &driverfs_dir_inode_operations; - inode->i_fop = &simple_dir_operations; - - /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inode->i_nlink++; - break; - case S_IFLNK: - inode->i_op = &page_symlink_inode_operations; - break; - } - } - return inode; -} - -static int driverfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev) -{ - struct inode *inode; - int error = -ENOSPC; - - if (dentry->d_inode) - return -EEXIST; - - /* only allow create if ->d_fsdata is not NULL (so we can assume it - * comes from the driverfs API below. */ - inode = driverfs_get_inode(dir->i_sb, mode, dev); - if (inode) { - d_instantiate(dentry, inode); - error = 0; - } - return error; -} - -static int driverfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) -{ - int res; - mode = (mode & (S_IRWXUGO|S_ISVTX)) | S_IFDIR; - res = driverfs_mknod(dir, dentry, mode, 0); - if (!res) - dir->i_nlink++; - return res; -} - -static int driverfs_create(struct inode *dir, struct dentry *dentry, int mode) -{ - int res; - mode = (mode & S_IALLUGO) | S_IFREG; - res = driverfs_mknod(dir, dentry, mode, 0); - return res; -} - -static int driverfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname) -{ - struct inode *inode; - int error = -ENOSPC; - - if (dentry->d_inode) - return -EEXIST; - - inode = driverfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0); - if (inode) { - int l = strlen(symname)+1; - error = page_symlink(inode, symname, l); - if (!error) { - d_instantiate(dentry, inode); - dget(dentry); - } else - iput(inode); - } - return error; -} - -static inline int driverfs_positive(struct dentry *dentry) -{ - return (dentry->d_inode && !d_unhashed(dentry)); -} - -static int driverfs_empty(struct dentry *dentry) -{ - struct list_head *list; - - spin_lock(&dcache_lock); - - list_for_each(list, &dentry->d_subdirs) { - struct dentry *de = list_entry(list, struct dentry, d_child); - if (driverfs_positive(de)) { - spin_unlock(&dcache_lock); - return 0; - } - } - - spin_unlock(&dcache_lock); - return 1; -} - -static int driverfs_unlink(struct inode *dir, struct dentry *dentry) -{ - struct inode *inode = dentry->d_inode; - down(&inode->i_sem); - dentry->d_inode->i_nlink--; - up(&inode->i_sem); - d_invalidate(dentry); - dput(dentry); - return 0; -} - -/** - * driverfs_read_file - "read" data from a file. - * @file: file pointer - * @buf: buffer to fill - * @count: number of bytes to read - * @ppos: starting offset in file - * - * Userspace wants data from a file. It is up to the creator of the file to - * provide that data. - * There is a struct device_attribute embedded in file->private_data. We - * obtain that and check if the read callback is implemented. If so, we call - * it, passing the data field of the file entry. - * Said callback is responsible for filling the buffer and returning the number - * of bytes it put in it. We update @ppos correctly. - */ -static ssize_t -driverfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos) -{ - struct attribute * attr = file->f_dentry->d_fsdata; - struct driver_dir_entry * dir; - unsigned char *page; - ssize_t retval = 0; - - dir = file->f_dentry->d_parent->d_fsdata; - if (!dir->ops->show) - return 0; - - if (count > PAGE_SIZE) - count = PAGE_SIZE; - - page = (unsigned char*)__get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - while (count > 0) { - ssize_t len; - - len = dir->ops->show(dir,attr,page,count,*ppos); - - if (len <= 0) { - if (len < 0) - retval = len; - break; - } else if (len > count) - len = count; - - if (copy_to_user(buf,page,len)) { - retval = -EFAULT; - break; - } - - *ppos += len; - count -= len; - buf += len; - retval += len; - } - free_page((unsigned long)page); - return retval; -} - -/** - * driverfs_write_file - "write" to a file - * @file: file pointer - * @buf: data to write - * @count: number of bytes - * @ppos: starting offset - * - * Similarly to driverfs_read_file, we act essentially as a bit pipe. - * We check for a "write" callback in file->private_data, and pass - * @buffer, @count, @ppos, and the file entry's data to the callback. - * The number of bytes written is returned, and we handle updating - * @ppos properly. - */ -static ssize_t -driverfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos) -{ - struct attribute * attr = file->f_dentry->d_fsdata; - struct driver_dir_entry * dir; - ssize_t retval = 0; - char * page; - - dir = file->f_dentry->d_parent->d_fsdata; - - page = (char *)__get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - if (count >= PAGE_SIZE) - count = PAGE_SIZE - 1; - if (copy_from_user(page,buf,count)) - goto done; - *(page + count) = '\0'; - - while (count > 0) { - ssize_t len; - - len = dir->ops->store(dir,attr,page + retval,count,*ppos); - - if (len <= 0) { - if (len < 0) - retval = len; - break; - } - retval += len; - count -= len; - *ppos += len; - buf += len; - } - done: - free_page((unsigned long)page); - return retval; -} - -static loff_t -driverfs_file_lseek(struct file *file, loff_t offset, int orig) -{ - loff_t retval = -EINVAL; - - down(&file->f_dentry->d_inode->i_sem); - switch(orig) { - case 0: - if (offset > 0) { - file->f_pos = offset; - retval = file->f_pos; - } - break; - case 1: - if ((offset + file->f_pos) > 0) { - file->f_pos += offset; - retval = file->f_pos; - } - break; - default: - break; - } - up(&file->f_dentry->d_inode->i_sem); - return retval; -} - -static int driverfs_open_file(struct inode * inode, struct file * filp) -{ - struct driver_dir_entry * dir; - int error = 0; - - dir = (struct driver_dir_entry *)filp->f_dentry->d_parent->d_fsdata; - if (dir) { - struct attribute * attr = filp->f_dentry->d_fsdata; - if (attr && dir->ops) { - if (dir->ops->open) - error = dir->ops->open(dir); - goto Done; - } - } - error = -EINVAL; - Done: - return error; -} - -static int driverfs_release(struct inode * inode, struct file * filp) -{ - struct driver_dir_entry * dir; - dir = (struct driver_dir_entry *)filp->f_dentry->d_parent->d_fsdata; - if (dir->ops->close) - dir->ops->close(dir); - return 0; -} - -static struct file_operations driverfs_file_operations = { - .read = driverfs_read_file, - .write = driverfs_write_file, - .llseek = driverfs_file_lseek, - .open = driverfs_open_file, - .release = driverfs_release, -}; - -static struct inode_operations driverfs_dir_inode_operations = { - .lookup = simple_lookup, -}; - -static struct address_space_operations driverfs_aops = { - .readpage = driverfs_readpage, - .writepage = fail_writepage, - .prepare_write = driverfs_prepare_write, - .commit_write = driverfs_commit_write -}; - -static struct super_operations driverfs_ops = { - .statfs = simple_statfs, - .drop_inode = generic_delete_inode, -}; - -static int driverfs_fill_super(struct super_block *sb, void *data, int silent) -{ - struct inode *inode; - struct dentry *root; - - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - sb->s_magic = DRIVERFS_MAGIC; - sb->s_op = &driverfs_ops; - inode = driverfs_get_inode(sb, S_IFDIR | 0755, 0); - - if (!inode) { - DBG("%s: could not get inode!\n",__FUNCTION__); - return -ENOMEM; - } - - root = d_alloc_root(inode); - if (!root) { - DBG("%s: could not get root dentry!\n",__FUNCTION__); - iput(inode); - return -ENOMEM; - } - sb->s_root = root; - return 0; -} - -static struct super_block *driverfs_get_sb(struct file_system_type *fs_type, - int flags, char *dev_name, void *data) -{ - return get_sb_single(fs_type, flags, data, driverfs_fill_super); -} - -static struct file_system_type driverfs_fs_type = { - .owner = THIS_MODULE, - .name = "driverfs", - .get_sb = driverfs_get_sb, - .kill_sb = kill_litter_super, -}; - -static int get_mount(void) -{ - struct vfsmount * mnt; - - spin_lock(&mount_lock); - if (driverfs_mount) { - mntget(driverfs_mount); - ++mount_count; - spin_unlock(&mount_lock); - goto go_ahead; - } - - spin_unlock(&mount_lock); - mnt = kern_mount(&driverfs_fs_type); - - if (IS_ERR(mnt)) { - printk(KERN_ERR "driverfs: could not mount!\n"); - return -ENODEV; - } - - spin_lock(&mount_lock); - if (!driverfs_mount) { - driverfs_mount = mnt; - ++mount_count; - spin_unlock(&mount_lock); - goto go_ahead; - } - - mntget(driverfs_mount); - ++mount_count; - spin_unlock(&mount_lock); - - go_ahead: - DBG("driverfs: mount_count = %d\n",mount_count); - return 0; -} - -static void put_mount(void) -{ - struct vfsmount * mnt; - - spin_lock(&mount_lock); - mnt = driverfs_mount; - --mount_count; - if (!mount_count) - driverfs_mount = NULL; - spin_unlock(&mount_lock); - mntput(mnt); - DBG("driverfs: mount_count = %d\n",mount_count); -} - -static int __init driverfs_init(void) -{ - return register_filesystem(&driverfs_fs_type); -} - -core_initcall(driverfs_init); - -static struct dentry * get_dentry(struct dentry * parent, const char * name) -{ - struct qstr qstr; - - qstr.name = name; - qstr.len = strlen(name); - qstr.hash = full_name_hash(name,qstr.len); - return lookup_hash(&qstr,parent); -} - -/** - * driverfs_create_dir - create a directory in the filesystem - * @entry: directory entry - * @parent: parent directory entry - */ -int -driverfs_create_dir(struct driver_dir_entry * entry, - struct driver_dir_entry * parent) -{ - struct dentry * dentry = NULL; - struct dentry * parent_dentry; - int error = 0; - - if (!entry) - return -EINVAL; - - get_mount(); - - parent_dentry = parent ? parent->dentry : NULL; - - if (!parent_dentry) - if (driverfs_mount && driverfs_mount->mnt_sb) - parent_dentry = driverfs_mount->mnt_sb->s_root; - - if (!parent_dentry) { - put_mount(); - return -EFAULT; - } - - down(&parent_dentry->d_inode->i_sem); - dentry = get_dentry(parent_dentry,entry->name); - if (!IS_ERR(dentry)) { - dentry->d_fsdata = (void *) entry; - entry->dentry = dentry; - error = driverfs_mkdir(parent_dentry->d_inode,dentry,entry->mode); - } else - error = PTR_ERR(dentry); - up(&parent_dentry->d_inode->i_sem); - - if (error) - put_mount(); - return error; -} - -/** - * driverfs_create_file - create a file - * @entry: structure describing the file - * @parent: directory to create it in - */ -int -driverfs_create_file(struct attribute * entry, - struct driver_dir_entry * parent) -{ - struct dentry * dentry; - int error = 0; - - if (!entry || !parent) - return -EINVAL; - - if (!parent->dentry) { - put_mount(); - return -EINVAL; - } - - down(&parent->dentry->d_inode->i_sem); - dentry = get_dentry(parent->dentry,entry->name); - if (!IS_ERR(dentry)) { - dentry->d_fsdata = (void *)entry; - error = driverfs_create(parent->dentry->d_inode,dentry,entry->mode); - } else - error = PTR_ERR(dentry); - up(&parent->dentry->d_inode->i_sem); - return error; -} - -/** - * driverfs_create_symlink - make a symlink - * @parent: directory we're creating in - * @entry: entry describing link - * @target: place we're symlinking to - * - */ -int driverfs_create_symlink(struct driver_dir_entry * parent, - char * name, char * target) -{ - struct dentry * dentry; - int error = 0; - - if (!parent) - return -EINVAL; - - if (!parent->dentry) { - put_mount(); - return -EINVAL; - } - down(&parent->dentry->d_inode->i_sem); - dentry = get_dentry(parent->dentry,name); - if (!IS_ERR(dentry)) - error = driverfs_symlink(parent->dentry->d_inode,dentry,target); - else - error = PTR_ERR(dentry); - up(&parent->dentry->d_inode->i_sem); - return error; -} - -/** - * driverfs_remove_file - exported file removal - * @dir: directory the file supposedly resides in - * @name: name of the file - * - * Try and find the file in the dir's list. - * If it's there, call __remove_file() (above) for the dentry. - */ -void driverfs_remove_file(struct driver_dir_entry * dir, const char * name) -{ - struct dentry * dentry; - - if (!dir->dentry) - return; - - down(&dir->dentry->d_inode->i_sem); - dentry = get_dentry(dir->dentry,name); - if (!IS_ERR(dentry)) { - /* make sure dentry is really there */ - if (dentry->d_inode && - (dentry->d_parent->d_inode == dir->dentry->d_inode)) { - driverfs_unlink(dir->dentry->d_inode,dentry); - } - } - up(&dir->dentry->d_inode->i_sem); -} - -/** - * driverfs_remove_dir - exportable directory removal - * @dir: directory to remove - * - * To make sure we don't orphan anyone, first remove - * all the children in the list, then do clean up the directory. - */ -void driverfs_remove_dir(struct driver_dir_entry * dir) -{ - struct list_head * node, * next; - struct dentry * dentry = dir->dentry; - struct dentry * parent; - - if (!dentry) - goto done; - - parent = dget(dentry->d_parent); - down(&parent->d_inode->i_sem); - down(&dentry->d_inode->i_sem); - - list_for_each_safe(node,next,&dentry->d_subdirs) { - struct dentry * d = list_entry(node,struct dentry,d_child); - /* make sure dentry is still there */ - if (d->d_inode) - driverfs_unlink(dentry->d_inode,d); - } - - d_invalidate(dentry); - if (driverfs_empty(dentry)) { - dentry->d_inode->i_nlink -= 2; - dentry->d_inode->i_flags |= S_DEAD; - parent->d_inode->i_nlink--; - } - up(&dentry->d_inode->i_sem); - dput(dentry); - - up(&parent->d_inode->i_sem); - dput(parent); - done: - put_mount(); -} - -EXPORT_SYMBOL(driverfs_create_file); -EXPORT_SYMBOL(driverfs_create_symlink); -EXPORT_SYMBOL(driverfs_create_dir); -EXPORT_SYMBOL(driverfs_remove_file); -EXPORT_SYMBOL(driverfs_remove_dir); -MODULE_LICENSE("GPL"); diff -Nru a/fs/eventpoll.c b/fs/eventpoll.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/eventpoll.c Mon Nov 4 14:31:01 2002 @@ -0,0 +1,1293 @@ +/* + * drivers/char/eventpoll.c ( Efficent event polling implementation ) + * Copyright (C) 2001,...,2002 Davide Libenzi + * + * 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. + * + * Davide Libenzi + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +#define EVENTPOLLFS_MAGIC 0x03111965 /* My birthday should work for this :) */ + +#define DEBUG_EPOLL 0 + +#if DEBUG_EPOLL > 0 +#define DPRINTK(x) printk x +#define DNPRINTK(n, x) do { if ((n) <= DEBUG_EPOLL) printk x; } while (0) +#else /* #if DEBUG_EPOLL > 0 */ +#define DPRINTK(x) (void) 0 +#define DNPRINTK(n, x) (void) 0 +#endif /* #if DEBUG_EPOLL > 0 */ + +#define DEBUG_DPI 0 + +#if DEBUG_DPI != 0 +#define DPI_SLAB_DEBUG (SLAB_DEBUG_FREE | SLAB_RED_ZONE /* | SLAB_POISON */) +#else /* #if DEBUG_DPI != 0 */ +#define DPI_SLAB_DEBUG 0 +#endif /* #if DEBUG_DPI != 0 */ + + +/* Maximum storage for the eventpoll interest set */ +#define EP_MAX_FDS_SIZE (1024 * 128) + +/* We don't want the hash to be smaller than this */ +#define EP_MIN_HASH_SIZE 101 +/* + * Event buffer dimension used to cache events before sending them in + * userspace with a __copy_to_user(). The event buffer is in stack, + * so keep this size fairly small. + */ +#define EP_EVENT_BUFF_SIZE 32 + +/* Maximum number of wait queue we can attach to */ +#define EP_MAX_POLL_QUEUE 2 + +/* Number of hash entries ( "struct list_head" ) inside a page */ +#define EP_HENTRY_X_PAGE (PAGE_SIZE / sizeof(struct list_head)) + +/* Maximum size of the hash in pages */ +#define EP_MAX_HPAGES (EP_MAX_FDS_SIZE / EP_HENTRY_X_PAGE + 1) + +/* Macro to allocate a "struct epitem" from the slab cache */ +#define DPI_MEM_ALLOC() (struct epitem *) kmem_cache_alloc(dpi_cache, SLAB_KERNEL) + +/* Macro to free a "struct epitem" to the slab cache */ +#define DPI_MEM_FREE(p) kmem_cache_free(dpi_cache, p) + +/* Fast test to see if the file is an evenpoll file */ +#define IS_FILE_EPOLL(f) ((f)->f_op == &eventpoll_fops) + +/* + * Remove the item from the list and perform its initialization. + * This is usefull for us because we can test if the item is linked + * using "EP_IS_LINKED(p)". + */ +#define EP_LIST_DEL(p) do { list_del(p); INIT_LIST_HEAD(p); } while (0) + +/* Tells us if the item is currently linked */ +#define EP_IS_LINKED(p) (!list_empty(p)) + +/* Get the "struct epitem" from a wait queue pointer */ +#define EP_ITEM_FROM_WAIT(p) ((struct epitem *) container_of(p, struct eppoll_entry, wait)->base) + + + + + +/* + * This structure is stored inside the "private_data" member of the file + * structure and rapresent the main data sructure for the eventpoll + * interface. + */ +struct eventpoll { + /* Used to link to the "struct eventpoll" list ( eplist ) */ + struct list_head llink; + + /* Protect the this structure access */ + rwlock_t lock; + + /* Wait queue used by sys_epoll_wait() */ + wait_queue_head_t wq; + + /* Wait queue used by file->poll() */ + wait_queue_head_t poll_wait; + + /* List of ready file descriptors */ + struct list_head rdllist; + + /* Size of the hash */ + int hsize; + + /* Number of pages currently allocated for the hash */ + int nhpages; + + /* Pages for the "struct epitem" hash */ + char *hpages[EP_MAX_HPAGES]; +}; + +/* Wait structure used by the poll hooks */ +struct eppoll_entry { + /* The "base" pointer is set to the container "struct epitem" */ + void *base; + + /* + * Wait queue item that will be linked to the target file wait + * queue head. + */ + wait_queue_t wait; + + /* The wait queue head that linked the "wait" wait queue item */ + wait_queue_head_t *whead; +}; + +/* + * Each file descriptor added to the eventpoll interface will + * have an entry of this type linked to the hash. + */ +struct epitem { + /* List header used to link this structure to the eventpoll hash */ + struct list_head llink; + + /* List header used to link this structure to the eventpoll ready list */ + struct list_head rdllink; + + /* Number of active wait queue attached to poll operations */ + int nwait; + + /* Wait queue used to attach poll operations */ + struct eppoll_entry wait[EP_MAX_POLL_QUEUE]; + + /* The "container" of this item */ + struct eventpoll *ep; + + /* The file this item refers to */ + struct file *file; + + /* The structure that describe the interested events and the source fd */ + struct pollfd pfd; + + /* + * Used to keep track of the usage count of the structure. This avoids + * that the structure will desappear from underneath our processing. + */ + atomic_t usecnt; +}; + + + + +static int ep_is_prime(int n); +static int ep_getfd(int *efd, struct inode **einode, struct file **efile); +static int ep_alloc_pages(char **pages, int numpages); +static int ep_free_pages(char **pages, int numpages); +static int ep_file_init(struct file *file, int hsize); +static int ep_hash_index(struct eventpoll *ep, struct file *file); +static struct list_head *ep_hash_entry(struct eventpoll *ep, int index); +static int ep_init(struct eventpoll *ep, int hsize); +static void ep_free(struct eventpoll *ep); +static struct epitem *ep_find(struct eventpoll *ep, struct file *file); +static void ep_use_epitem(struct epitem *dpi); +static void ep_release_epitem(struct epitem *dpi); +static void ep_ptable_queue_proc(void *priv, wait_queue_head_t *whead); +static int ep_insert(struct eventpoll *ep, struct pollfd *pfd, struct file *tfile); +static unsigned int ep_get_file_events(struct file *file); +static int ep_modify(struct eventpoll *ep, struct epitem *dpi, unsigned int events); +static int ep_unlink(struct eventpoll *ep, struct epitem *dpi); +static int ep_remove(struct eventpoll *ep, struct epitem *dpi); +static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync); +static int ep_eventpoll_close(struct inode *inode, struct file *file); +static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait); +static int ep_events_transfer(struct eventpoll *ep, struct pollfd *events, int maxevents); +static int ep_poll(struct eventpoll *ep, struct pollfd *events, int maxevents, + int timeout); +static int eventpollfs_delete_dentry(struct dentry *dentry); +static struct inode *ep_eventpoll_inode(void); +static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type, + int flags, char *dev_name, void *data); + + +/* Use to link togheter all the "struct eventpoll" */ +static struct list_head eplist; + +/* Serialize the access to "eplist" */ +static rwlock_t eplock; + +/* Slab cache used to allocate "struct epitem" */ +static kmem_cache_t *dpi_cache; + +/* Virtual fs used to allocate inodes for eventpoll files */ +static struct vfsmount *eventpoll_mnt; + +/* File callbacks that implement the eventpoll file behaviour */ +static struct file_operations eventpoll_fops = { + .release = ep_eventpoll_close, + .poll = ep_eventpoll_poll +}; + +/* + * This is used to register the virtual file system from where + * eventpoll inodes are allocated. + */ +static struct file_system_type eventpoll_fs_type = { + .name = "eventpollfs", + .get_sb = eventpollfs_get_sb, + .kill_sb = kill_anon_super, +}; + +/* Very basic directory entry operations for the eventpoll virtual file system */ +static struct dentry_operations eventpollfs_dentry_operations = { + .d_delete = eventpollfs_delete_dentry, +}; + + + +/* Report if the number is prime. Needed to correctly size the hash */ +static int ep_is_prime(int n) +{ + + if (n > 3) { + if (n & 1) { + int i, hn = n / 2; + + for (i = 3; i < hn; i += 2) + if (!(n % i)) + return 0; + } else + return 0; + } + return 1; +} + + +/* + * This is called from inside fs/file_table.c:__fput() to unlink files + * from the eventpoll interface. We need to have this facility to cleanup + * correctly files that are closed without being removed from the eventpoll + * interface. + */ +void ep_notify_file_close(struct file *file) +{ + unsigned long flags; + struct list_head *lnk; + struct eventpoll *ep; + struct epitem *dpi; + + read_lock_irqsave(&eplock, flags); + list_for_each(lnk, &eplist) { + ep = list_entry(lnk, struct eventpoll, llink); + + while ((dpi = ep_find(ep, file))) { + ep_remove(ep, dpi); + ep_release_epitem(dpi); + } + } + read_unlock_irqrestore(&eplock, flags); +} + + +/* + * It opens an eventpoll file descriptor by suggesting a storage of "size" + * file descriptors. It is the kernel part of the userspace epoll_create(2). + */ +asmlinkage int sys_epoll_create(int size) +{ + int error, fd; + struct inode *inode; + struct file *file; + + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n", + current, size)); + + /* Search the nearest prime number higher than "size" */ + for (; !ep_is_prime(size); size++); + if (size < EP_MIN_HASH_SIZE) + size = EP_MIN_HASH_SIZE; + + /* + * Creates all the items needed to setup an eventpoll file. That is, + * a file structure, and inode and a free file descriptor. + */ + error = ep_getfd(&fd, &inode, &file); + if (error) + goto eexit_1; + + /* Setup the file internal data structure ( "struct eventpoll" ) */ + error = ep_file_init(file, size); + if (error) + goto eexit_2; + + + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", + current, size, fd)); + + return fd; + +eexit_2: + sys_close(fd); +eexit_1: + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", + current, size, error)); + return error; +} + + +/* + * The following function implement the controller interface for the eventpoll + * file that enable the insertion/removal/change of file descriptors inside + * the interest set. It rapresents the kernel part of the user spcae epoll_ctl(2). + */ +asmlinkage int sys_epoll_ctl(int epfd, int op, int fd, unsigned int events) +{ + int error; + struct file *file, *tfile; + struct eventpoll *ep; + struct epitem *dpi; + struct pollfd pfd; + + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %u)\n", + current, epfd, op, fd, events)); + + /* Get the "struct file *" for the eventpoll file */ + error = -EBADF; + file = fget(epfd); + if (!file) + goto eexit_1; + + /* Get the "struct file *" for the target file */ + tfile = fget(fd); + if (!tfile) + goto eexit_2; + + /* The target file descriptor must support poll */ + error = -EPERM; + if (!tfile->f_op || !tfile->f_op->poll) + goto eexit_3; + + /* + * We have to check that the file structure underneath the file descriptor + * the user passed to us _is_ an eventpoll file. + */ + error = -EINVAL; + if (!IS_FILE_EPOLL(file)) + goto eexit_3; + + /* + * At this point it is safe to assume that the "private_data" contains + * our own data structure. + */ + ep = file->private_data; + + /* + * Try to lookup the file inside our hash table. When an item is found + * ep_find() increases the usage count of the item so that it won't + * desappear underneath us. The only thing that might happen, if someone + * tries very hard, is a double insertion of the same file descriptor. + * This does not rapresent a problem though and we don't really want + * to put an extra syncronization object to deal with this harmless condition. + */ + dpi = ep_find(ep, tfile); + + error = -EINVAL; + switch (op) { + case EP_CTL_ADD: + if (!dpi) { + pfd.fd = fd; + pfd.events = events | POLLERR | POLLHUP; + pfd.revents = 0; + + error = ep_insert(ep, &pfd, tfile); + } else + error = -EEXIST; + break; + case EP_CTL_DEL: + if (dpi) + error = ep_remove(ep, dpi); + else + error = -ENOENT; + break; + case EP_CTL_MOD: + if (dpi) + error = ep_modify(ep, dpi, events | POLLERR | POLLHUP); + else + error = -ENOENT; + break; + } + + /* + * The function ep_find() increments the usage count of the structure + * so, if this is not NULL, we need to release it. + */ + if (dpi) + ep_release_epitem(dpi); + + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %u) = %d\n", + current, epfd, op, fd, events, error)); + +eexit_3: + fput(tfile); +eexit_2: + fput(file); +eexit_1: + return error; +} + + +/* + * Implement the event wait interface for the eventpoll file. It is the kernel + * part of the user space epoll_wait(2). + */ +asmlinkage int sys_epoll_wait(int epfd, struct pollfd *events, int maxevents, + int timeout) +{ + int error; + struct file *file; + struct eventpoll *ep; + + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d)\n", + current, epfd, events, maxevents, timeout)); + + /* Verify that the area passed by the user is writeable */ + if ((error = verify_area(VERIFY_WRITE, events, maxevents * sizeof(struct pollfd)))) + goto eexit_1; + + /* Get the "struct file *" for the eventpoll file */ + error = -EBADF; + file = fget(epfd); + if (!file) + goto eexit_1; + + /* + * We have to check that the file structure underneath the file descriptor + * the user passed to us _is_ an eventpoll file. + */ + error = -EINVAL; + if (!IS_FILE_EPOLL(file)) + goto eexit_2; + + /* + * At this point it is safe to assume that the "private_data" contains + * our own data structure. + */ + ep = file->private_data; + + /* Time to fish for events ... */ + error = ep_poll(ep, events, maxevents, timeout); + + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d) = %d\n", + current, epfd, events, maxevents, timeout, error)); + +eexit_2: + fput(file); +eexit_1: + return error; +} + + +/* + * Creates the file descriptor to be used by the epoll interface. + */ +static int ep_getfd(int *efd, struct inode **einode, struct file **efile) +{ + struct qstr this; + char name[32]; + struct dentry *dentry; + struct inode *inode; + struct file *file; + int error, fd; + + /* Get an ready to use file */ + error = -ENFILE; + file = get_empty_filp(); + if (!file) + goto eexit_1; + + /* Allocates an inode from the eventpoll file system */ + inode = ep_eventpoll_inode(); + error = PTR_ERR(inode); + if (IS_ERR(inode)) + goto eexit_2; + + /* Allocates a free descriptor to plug the file onto */ + error = get_unused_fd(); + if (error < 0) + goto eexit_3; + fd = error; + + /* + * Link the inode to a directory entry by creating a unique name + * using the inode number. + */ + error = -ENOMEM; + sprintf(name, "[%lu]", inode->i_ino); + this.name = name; + this.len = strlen(name); + this.hash = inode->i_ino; + dentry = d_alloc(eventpoll_mnt->mnt_sb->s_root, &this); + if (!dentry) + goto eexit_4; + dentry->d_op = &eventpollfs_dentry_operations; + d_add(dentry, inode); + file->f_vfsmnt = mntget(eventpoll_mnt); + file->f_dentry = dget(dentry); + + /* + * Initialize the file as read/write because it could be used + * with write() to add/remove/change interest sets. + */ + file->f_pos = 0; + file->f_flags = O_RDONLY; + file->f_op = &eventpoll_fops; + file->f_mode = FMODE_READ; + file->f_version = 0; + file->private_data = NULL; + + /* Install the new setup file into the allocated fd. */ + fd_install(fd, file); + + *efd = fd; + *einode = inode; + *efile = file; + return 0; + +eexit_4: + put_unused_fd(fd); +eexit_3: + iput(inode); +eexit_2: + put_filp(file); +eexit_1: + return error; +} + + +static int ep_alloc_pages(char **pages, int numpages) +{ + int i; + + for (i = 0; i < numpages; i++) { + pages[i] = (char *) __get_free_pages(GFP_KERNEL, 0); + if (!pages[i]) { + for (--i; i >= 0; i--) { + ClearPageReserved(virt_to_page(pages[i])); + free_pages((unsigned long) pages[i], 0); + } + return -ENOMEM; + } + SetPageReserved(virt_to_page(pages[i])); + } + return 0; +} + + +static int ep_free_pages(char **pages, int numpages) +{ + int i; + + for (i = 0; i < numpages; i++) { + ClearPageReserved(virt_to_page(pages[i])); + free_pages((unsigned long) pages[i], 0); + } + return 0; +} + + +static int ep_file_init(struct file *file, int hsize) +{ + int error; + unsigned long flags; + struct eventpoll *ep; + + if (!(ep = kmalloc(sizeof(struct eventpoll), GFP_KERNEL))) + return -ENOMEM; + + memset(ep, 0, sizeof(*ep)); + + error = ep_init(ep, hsize); + if (error) { + kfree(ep); + return error; + } + + file->private_data = ep; + + /* Add the structure to the linked list that links "struct eventpoll" */ + write_lock_irqsave(&eplock, flags); + list_add(&ep->llink, &eplist); + write_unlock_irqrestore(&eplock, flags); + + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_file_init() ep=%p\n", + current, ep)); + return 0; +} + + +/* + * Calculate the index of the hash relative to "file". + */ +static int ep_hash_index(struct eventpoll *ep, struct file *file) +{ + + return (int) ((((unsigned long) file) / sizeof(struct file)) % ep->hsize); +} + + +/* + * Returns the hash entry ( struct list_head * ) of the passed index. + */ +static struct list_head *ep_hash_entry(struct eventpoll *ep, int index) +{ + + return (struct list_head *) (ep->hpages[index / EP_HENTRY_X_PAGE] + + (index % EP_HENTRY_X_PAGE) * sizeof(struct list_head)); +} + + +static int ep_init(struct eventpoll *ep, int hsize) +{ + int error, i; + + INIT_LIST_HEAD(&ep->llink); + rwlock_init(&ep->lock); + init_waitqueue_head(&ep->wq); + init_waitqueue_head(&ep->poll_wait); + INIT_LIST_HEAD(&ep->rdllist); + + /* Hash allocation and setup */ + ep->hsize = hsize; + ep->nhpages = hsize / EP_HENTRY_X_PAGE + (hsize % EP_HENTRY_X_PAGE ? 1: 0); + error = ep_alloc_pages(ep->hpages, ep->nhpages); + if (error) + goto eexit_1; + + /* Initialize hash buckets */ + for (i = 0; i < ep->hsize; i++) + INIT_LIST_HEAD(ep_hash_entry(ep, i)); + + return 0; +eexit_1: + return error; +} + + +static void ep_free(struct eventpoll *ep) +{ + int i; + unsigned long flags; + struct list_head *lsthead; + + /* + * Walks through the whole hash by unregistering file callbacks and + * freeing each "struct epitem". + */ + for (i = 0; i < ep->hsize; i++) { + lsthead = ep_hash_entry(ep, i); + + /* + * We need to lock this because we could be hit by + * ep_notify_file_close() while we're freeing this. + */ + write_lock_irqsave(&ep->lock, flags); + + while (!list_empty(lsthead)) { + struct epitem *dpi = list_entry(lsthead->next, struct epitem, llink); + + /* The function ep_unlink() must be called with held lock */ + ep_unlink(ep, dpi); + + /* We release the lock before releasing the "struct epitem" */ + write_unlock_irqrestore(&ep->lock, flags); + + ep_release_epitem(dpi); + + /* And then we reaquire the lock ... */ + write_lock_irqsave(&ep->lock, flags); + } + + write_unlock_irqrestore(&ep->lock, flags); + } + + /* Remove the structure to the linked list that links "struct eventpoll" */ + write_lock_irqsave(&eplock, flags); + EP_LIST_DEL(&ep->llink); + write_unlock_irqrestore(&eplock, flags); + + /* Free hash pages */ + if (ep->nhpages > 0) + ep_free_pages(ep->hpages, ep->nhpages); +} + + +/* + * Search the file inside the eventpoll hash. It add usage count to + * the returned item, so the caller must call ep_release_epitem() + * after finished using the "struct epitem". + */ +static struct epitem *ep_find(struct eventpoll *ep, struct file *file) +{ + unsigned long flags; + struct list_head *lsthead, *lnk; + struct epitem *dpi = NULL; + + read_lock_irqsave(&ep->lock, flags); + + lsthead = ep_hash_entry(ep, ep_hash_index(ep, file)); + list_for_each(lnk, lsthead) { + dpi = list_entry(lnk, struct epitem, llink); + + if (dpi->file == file) { + ep_use_epitem(dpi); + break; + } + dpi = NULL; + } + + read_unlock_irqrestore(&ep->lock, flags); + + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_find(%p) -> %p\n", + current, file, dpi)); + + return dpi; +} + + +/* + * Increment the usage count of the "struct epitem" making it sure + * that the user will have a valid pointer to reference. + */ +static void ep_use_epitem(struct epitem *dpi) +{ + + atomic_inc(&dpi->usecnt); +} + + +/* + * Decrement ( release ) the usage count by signaling that the user + * has finished using the structure. It might lead to freeing the + * structure itself if the count goes to zero. + */ +static void ep_release_epitem(struct epitem *dpi) +{ + + if (atomic_dec_and_test(&dpi->usecnt)) + DPI_MEM_FREE(dpi); +} + + +/* + * This is the callback that is used to add our wait queue to the + * target file wakeup lists. + */ +static void ep_ptable_queue_proc(void *priv, wait_queue_head_t *whead) +{ + struct epitem *dpi = priv; + + /* No more than EP_MAX_POLL_QUEUE wait queue are supported */ + if (dpi->nwait < EP_MAX_POLL_QUEUE) { + add_wait_queue(whead, &dpi->wait[dpi->nwait].wait); + dpi->wait[dpi->nwait].whead = whead; + dpi->nwait++; + } +} + + +static int ep_insert(struct eventpoll *ep, struct pollfd *pfd, struct file *tfile) +{ + int error, i, revents; + unsigned long flags; + struct epitem *dpi; + poll_table pt; + + error = -ENOMEM; + if (!(dpi = DPI_MEM_ALLOC())) + goto eexit_1; + + /* Item initialization follow here ... */ + INIT_LIST_HEAD(&dpi->llink); + INIT_LIST_HEAD(&dpi->rdllink); + dpi->ep = ep; + dpi->file = tfile; + dpi->pfd = *pfd; + atomic_set(&dpi->usecnt, 1); + dpi->nwait = 0; + for (i = 0; i < EP_MAX_POLL_QUEUE; i++) { + init_waitqueue_func_entry(&dpi->wait[i].wait, ep_poll_callback); + dpi->wait[i].whead = NULL; + dpi->wait[i].base = dpi; + } + + /* Attach the item to the poll hooks */ + poll_initwait_ex(&pt, 1, ep_ptable_queue_proc, dpi); + revents = tfile->f_op->poll(tfile, &pt); + poll_freewait(&pt); + + /* We have to drop the new item inside our item list to keep track of it */ + write_lock_irqsave(&ep->lock, flags); + + list_add(&dpi->llink, ep_hash_entry(ep, ep_hash_index(ep, tfile))); + + /* If the file is already "ready" we drop it inside the ready list */ + if ((revents & pfd->events) && !EP_IS_LINKED(&dpi->rdllink)) + list_add(&dpi->rdllink, &ep->rdllist); + + write_unlock_irqrestore(&ep->lock, flags); + + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_insert(%p, %d)\n", + current, ep, pfd->fd)); + + return 0; + +eexit_1: + return error; +} + + +/* + * Returns the current events of the given file. It uses the special + * poll table initialization to avoid any poll queue insertion. + */ +static unsigned int ep_get_file_events(struct file *file) +{ + unsigned int revents; + poll_table pt; + + /* + * This is a special poll table initialization that will + * make poll_wait() to not perform any wait queue insertion when + * called by file->f_op->poll(). This is a fast way to retrieve + * file events with perform any queue insertion, hence saving CPU cycles. + */ + poll_initwait_ex(&pt, 0, NULL, NULL); + + revents = file->f_op->poll(file, &pt); + + poll_freewait(&pt); + return revents; +} + + +/* + * Modify the interest event mask by dropping an event if the new mask + * has a match in the current file status. + */ +static int ep_modify(struct eventpoll *ep, struct epitem *dpi, unsigned int events) +{ + unsigned int revents; + unsigned long flags; + + revents = ep_get_file_events(dpi->file); + + write_lock_irqsave(&ep->lock, flags); + + dpi->pfd.events = events; + + /* If the file is already "ready" we drop it inside the ready list */ + if ((revents & events) && EP_IS_LINKED(&dpi->llink) && !EP_IS_LINKED(&dpi->rdllink)) + list_add(&dpi->rdllink, &ep->rdllist); + + write_unlock_irqrestore(&ep->lock, flags); + + return 0; +} + + +/* + * Unlink the "struct epitem" from all places it might have been hooked up. + * This function must be called with write IRQ lock on "ep->lock". + */ +static int ep_unlink(struct eventpoll *ep, struct epitem *dpi) +{ + int i; + + /* + * It can happen that this one is called for an item already unlinked. + * The check protect us from doing a double unlink ( crash ). + */ + if (!EP_IS_LINKED(&dpi->llink)) + goto not_linked; + + /* + * At this point is safe to do the job, unlink the item from our list. + * This operation togheter with the above check closes the door to + * double unlinks. + */ + EP_LIST_DEL(&dpi->llink); + + /* Removes poll wait queue hooks */ + for (i = 0; i < dpi->nwait; i++) + remove_wait_queue(dpi->wait[i].whead, &dpi->wait[i].wait); + + /* + * If the item we are going to remove is inside the ready file descriptors + * we want to remove it from this list to avoid stale events. + */ + if (EP_IS_LINKED(&dpi->rdllink)) + EP_LIST_DEL(&dpi->rdllink); + +not_linked: + + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_unlink(%p, %d)\n", + current, ep, dpi->pfd.fd)); + + return 0; +} + + +/* + * Removes a "struct epitem" from the eventpoll hash and deallocates + * all the associated resources. + */ +static int ep_remove(struct eventpoll *ep, struct epitem *dpi) +{ + int error; + unsigned long flags; + + /* We need to acquire the write IRQ lock before calling ep_unlink() */ + write_lock_irqsave(&ep->lock, flags); + + /* Really unlink the item from the hash */ + error = ep_unlink(ep, dpi); + + write_unlock_irqrestore(&ep->lock, flags); + + if (error) + goto eexit_1; + + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %d)\n", + current, ep, dpi->pfd.fd)); + + /* At this point it is safe to free the eventpoll item */ + ep_release_epitem(dpi); + + error = 0; +eexit_1: + return error; +} + + +/* + * This is the callback that is passed to the wait queue wakeup + * machanism. It is called by the stored file descriptors when they + * have events to report. + */ +static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync) +{ + unsigned long flags; + struct epitem *dpi = EP_ITEM_FROM_WAIT(wait); + struct eventpoll *ep = dpi->ep; + + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) dpi=%p ep=%p\n", + current, dpi->file, dpi, ep)); + + write_lock_irqsave(&ep->lock, flags); + + /* If this file is already in the ready list we exit soon */ + if (EP_IS_LINKED(&dpi->rdllink)) + goto is_linked; + + list_add(&dpi->rdllink, &ep->rdllist); + +is_linked: + /* + * Wake up ( if active ) both the eventpoll wait list and the ->poll() + * wait list. + */ + if (waitqueue_active(&ep->wq)) + wake_up(&ep->wq); + if (waitqueue_active(&ep->poll_wait)) + wake_up(&ep->poll_wait); + + write_unlock_irqrestore(&ep->lock, flags); + return 1; +} + + +static int ep_eventpoll_close(struct inode *inode, struct file *file) +{ + struct eventpoll *ep = file->private_data; + + if (ep) { + ep_free(ep); + kfree(ep); + } + + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: close() ep=%p\n", current, ep)); + return 0; +} + + +static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait) +{ + unsigned int pollflags = 0; + unsigned long flags; + struct eventpoll *ep = file->private_data; + + /* Insert inside our poll wait queue */ + poll_wait(file, &ep->poll_wait, wait); + + /* Check our condition */ + read_lock_irqsave(&ep->lock, flags); + if (!list_empty(&ep->rdllist)) + pollflags = POLLIN | POLLRDNORM; + read_unlock_irqrestore(&ep->lock, flags); + + return pollflags; +} + + +/* + * Perform the transfer of events to user space. Optimize the copy by + * caching EP_EVENT_BUFF_SIZE events at a time and then copying it to user space. + */ +static int ep_events_transfer(struct eventpoll *ep, struct pollfd *events, int maxevents) +{ + int eventcnt, ebufcnt, revents; + unsigned long flags; + struct list_head *lsthead = &ep->rdllist; + struct pollfd eventbuf[EP_EVENT_BUFF_SIZE]; + poll_table pt; + + /* + * This is a special poll table initialization that will + * make poll_wait() to not perform any wait queue insertion when + * called by file->f_op->poll(). This is a fast way to retrieve + * file events with perform any queue insertion, hence saving CPU cycles. + */ + poll_initwait_ex(&pt, 0, NULL, NULL); + + write_lock_irqsave(&ep->lock, flags); + + for (eventcnt = 0, ebufcnt = 0; eventcnt < maxevents && !list_empty(lsthead);) { + struct epitem *dpi = list_entry(lsthead->next, struct epitem, rdllink); + + /* Remove the item from the ready list */ + EP_LIST_DEL(&dpi->rdllink); + + /* Fetch event bits from the signaled file */ + revents = dpi->file->f_op->poll(dpi->file, &pt); + + if (revents & dpi->pfd.events) { + eventbuf[ebufcnt] = dpi->pfd; + eventbuf[ebufcnt].revents = revents & eventbuf[ebufcnt].events; + ebufcnt++; + + /* If our buffer page is full we need to flush it to user space */ + if (ebufcnt == EP_EVENT_BUFF_SIZE) { + /* + * We need to drop the irqlock before using the function + * __copy_to_user() because it might fault. + */ + write_unlock_irqrestore(&ep->lock, flags); + if (__copy_to_user(&events[eventcnt], eventbuf, + ebufcnt * sizeof(struct pollfd))) { + poll_freewait(&pt); + return -EFAULT; + } + eventcnt += ebufcnt; + ebufcnt = 0; + write_lock_irqsave(&ep->lock, flags); + } + } + } + write_unlock_irqrestore(&ep->lock, flags); + + /* There might be still something inside our event buffer */ + if (ebufcnt) { + if (__copy_to_user(&events[eventcnt], eventbuf, + ebufcnt * sizeof(struct pollfd))) + eventcnt = -EFAULT; + else + eventcnt += ebufcnt; + } + + poll_freewait(&pt); + + return eventcnt; +} + + +static int ep_poll(struct eventpoll *ep, struct pollfd *events, int maxevents, + int timeout) +{ + int res = 0, eavail; + unsigned long flags; + long jtimeout; + wait_queue_t wait; + + /* + * Calculate the timeout by checking for the "infinite" value ( -1 ) + * and the overflow condition ( > MAX_SCHEDULE_TIMEOUT / HZ ). The + * passed timeout is in milliseconds, that why (t * HZ) / 1000. + */ + jtimeout = timeout == -1 || timeout > MAX_SCHEDULE_TIMEOUT / HZ ? + MAX_SCHEDULE_TIMEOUT: (timeout * HZ) / 1000; + +retry: + write_lock_irqsave(&ep->lock, flags); + + res = 0; + if (list_empty(&ep->rdllist)) { + /* + * We don't have any available event to return to the caller. + * We need to sleep here, and we will be wake up by + * ep_poll_callback() when events will become available. + */ + init_waitqueue_entry(&wait, current); + add_wait_queue(&ep->wq, &wait); + + for (;;) { + /* + * We don't want to sleep if the ep_poll_callback() sends us + * a wakeup in between. That's why we set the task state + * to TASK_INTERRUPTIBLE before doing the checks. + */ + set_current_state(TASK_INTERRUPTIBLE); + if (!list_empty(&ep->rdllist) || !jtimeout) + break; + if (signal_pending(current)) { + res = -EINTR; + break; + } + + write_unlock_irqrestore(&ep->lock, flags); + jtimeout = schedule_timeout(jtimeout); + write_lock_irqsave(&ep->lock, flags); + } + remove_wait_queue(&ep->wq, &wait); + + set_current_state(TASK_RUNNING); + } + + /* Is it worth to try to dig for events ? */ + eavail = !list_empty(&ep->rdllist); + + write_unlock_irqrestore(&ep->lock, flags); + + /* + * Try to transfer events to user space. In case we get 0 events and + * there's still timeout left over, we go trying again in search of + * more luck. + */ + if (!res && eavail && + !(res = ep_events_transfer(ep, events, maxevents)) && jtimeout) + goto retry; + + return res; +} + + +static int eventpollfs_delete_dentry(struct dentry *dentry) +{ + + return 1; +} + + +static struct inode *ep_eventpoll_inode(void) +{ + int error = -ENOMEM; + struct inode *inode = new_inode(eventpoll_mnt->mnt_sb); + + if (!inode) + goto eexit_1; + + inode->i_fop = &eventpoll_fops; + + /* + * Mark the inode dirty from the very beginning, + * that way it will never be moved to the dirty + * list because mark_inode_dirty() will think + * that it already _is_ on the dirty list. + */ + inode->i_state = I_DIRTY; + inode->i_mode = S_IRUSR | S_IWUSR; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_blksize = PAGE_SIZE; + return inode; + +eexit_1: + return ERR_PTR(error); +} + + +static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type, + int flags, char *dev_name, void *data) +{ + + return get_sb_pseudo(fs_type, "eventpoll:", NULL, EVENTPOLLFS_MAGIC); +} + + +static int __init eventpoll_init(void) +{ + int error; + + /* Initialize the list that will link "struct eventpoll" */ + INIT_LIST_HEAD(&eplist); + + /* Initialize the rwlock used to access "eplist" */ + rwlock_init(&eplock); + + /* Allocates slab cache used to allocate "struct epitem" items */ + error = -ENOMEM; + dpi_cache = kmem_cache_create("eventpoll", + sizeof(struct epitem), + 0, + DPI_SLAB_DEBUG, NULL, NULL); + if (!dpi_cache) + goto eexit_1; + + /* + * Register the virtual file system that will be the source of inodes + * for the eventpoll files + */ + error = register_filesystem(&eventpoll_fs_type); + if (error) + goto eexit_2; + + /* Mount the above commented virtual file system */ + eventpoll_mnt = kern_mount(&eventpoll_fs_type); + error = PTR_ERR(eventpoll_mnt); + if (IS_ERR(eventpoll_mnt)) + goto eexit_3; + + printk(KERN_INFO "[%p] eventpoll: driver installed.\n", current); + + return 0; + +eexit_3: + unregister_filesystem(&eventpoll_fs_type); +eexit_2: + kmem_cache_destroy(dpi_cache); +eexit_1: + + return error; +} + + +static void __exit eventpoll_exit(void) +{ + /* Undo all operations done inside eventpoll_init() */ + unregister_filesystem(&eventpoll_fs_type); + mntput(eventpoll_mnt); + kmem_cache_destroy(dpi_cache); +} + +module_init(eventpoll_init); +module_exit(eventpoll_exit); + +MODULE_LICENSE("GPL"); + diff -Nru a/fs/exec.c b/fs/exec.c --- a/fs/exec.c Mon Nov 4 14:31:01 2002 +++ b/fs/exec.c Mon Nov 4 14:31:01 2002 @@ -306,7 +306,7 @@ pte_unmap(pte); goto out; } - lru_cache_add(page); + lru_cache_add_active(page); flush_dcache_page(page); flush_page_to_ram(page); set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY)))); diff -Nru a/fs/ext2/Makefile b/fs/ext2/Makefile --- a/fs/ext2/Makefile Mon Nov 4 14:31:02 2002 +++ b/fs/ext2/Makefile Mon Nov 4 14:31:02 2002 @@ -7,4 +7,14 @@ ext2-objs := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ ioctl.o namei.o super.o symlink.o +export-objs += xattr.o + +ifeq ($(CONFIG_EXT2_FS_XATTR),y) +ext2-objs += xattr.o xattr_user.o +endif + +ifeq ($(CONFIG_EXT2_FS_POSIX_ACL),y) +ext2-objs += acl.o +endif + include $(TOPDIR)/Rules.make diff -Nru a/fs/ext2/acl.c b/fs/ext2/acl.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/ext2/acl.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,573 @@ +/* + * linux/fs/ext2/acl.c + * + * Copyright (C) 2001 by Andreas Gruenbacher, + */ + +#include +#include +#include +#include +#include "ext2.h" +#include "xattr.h" +#include "acl.h" + +/* + * Convert from filesystem to in-memory representation. + */ +static struct posix_acl * +ext2_acl_from_disk(const void *value, size_t size) +{ + const char *end = (char *)value + size; + int n, count; + struct posix_acl *acl; + + if (!value) + return NULL; + if (size < sizeof(ext2_acl_header)) + return ERR_PTR(-EINVAL); + if (((ext2_acl_header *)value)->a_version != + cpu_to_le32(EXT2_ACL_VERSION)) + return ERR_PTR(-EINVAL); + value = (char *)value + sizeof(ext2_acl_header); + count = ext2_acl_count(size); + if (count < 0) + return ERR_PTR(-EINVAL); + if (count == 0) + return NULL; + acl = posix_acl_alloc(count, GFP_KERNEL); + if (!acl) + return ERR_PTR(-ENOMEM); + for (n=0; n < count; n++) { + ext2_acl_entry *entry = + (ext2_acl_entry *)value; + if ((char *)value + sizeof(ext2_acl_entry_short) > end) + goto fail; + acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag); + acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm); + switch(acl->a_entries[n].e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + value = (char *)value + + sizeof(ext2_acl_entry_short); + acl->a_entries[n].e_id = ACL_UNDEFINED_ID; + break; + + case ACL_USER: + case ACL_GROUP: + value = (char *)value + sizeof(ext2_acl_entry); + if ((char *)value > end) + goto fail; + acl->a_entries[n].e_id = + le32_to_cpu(entry->e_id); + break; + + default: + goto fail; + } + } + if (value != end) + goto fail; + return acl; + +fail: + posix_acl_release(acl); + return ERR_PTR(-EINVAL); +} + +/* + * Convert from in-memory to filesystem representation. + */ +static void * +ext2_acl_to_disk(const struct posix_acl *acl, size_t *size) +{ + ext2_acl_header *ext_acl; + char *e; + int n; + + *size = ext2_acl_size(acl->a_count); + ext_acl = (ext2_acl_header *)kmalloc(sizeof(ext2_acl_header) + + acl->a_count * sizeof(ext2_acl_entry), GFP_KERNEL); + if (!ext_acl) + return ERR_PTR(-ENOMEM); + ext_acl->a_version = cpu_to_le32(EXT2_ACL_VERSION); + e = (char *)ext_acl + sizeof(ext2_acl_header); + for (n=0; n < acl->a_count; n++) { + ext2_acl_entry *entry = (ext2_acl_entry *)e; + entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag); + entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm); + switch(acl->a_entries[n].e_tag) { + case ACL_USER: + case ACL_GROUP: + entry->e_id = + cpu_to_le32(acl->a_entries[n].e_id); + e += sizeof(ext2_acl_entry); + break; + + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + e += sizeof(ext2_acl_entry_short); + break; + + default: + goto fail; + } + } + return (char *)ext_acl; + +fail: + kfree(ext_acl); + return ERR_PTR(-EINVAL); +} + +/* + * inode->i_sem: down + */ +static struct posix_acl * +ext2_get_acl(struct inode *inode, int type) +{ + int name_index; + char *value; + struct posix_acl *acl, **p_acl; + const size_t size = ext2_acl_size(EXT2_ACL_MAX_ENTRIES); + int retval; + + if (!test_opt(inode->i_sb, POSIX_ACL)) + return 0; + + switch(type) { + case ACL_TYPE_ACCESS: + p_acl = &EXT2_I(inode)->i_acl; + name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; + break; + + case ACL_TYPE_DEFAULT: + p_acl = &EXT2_I(inode)->i_default_acl; + name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT; + break; + + default: + return ERR_PTR(-EINVAL); + } + if (*p_acl != EXT2_ACL_NOT_CACHED) + return posix_acl_dup(*p_acl); + value = kmalloc(size, GFP_KERNEL); + if (!value) + return ERR_PTR(-ENOMEM); + + retval = ext2_xattr_get(inode, name_index, "", value, size); + + if (retval == -ENODATA || retval == -ENOSYS) + *p_acl = acl = NULL; + else if (retval < 0) + acl = ERR_PTR(retval); + else { + acl = ext2_acl_from_disk(value, retval); + if (!IS_ERR(acl)) + *p_acl = posix_acl_dup(acl); + } + kfree(value); + return acl; +} + +/* + * inode->i_sem: down + */ +static int +ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) +{ + int name_index; + void *value = NULL; + struct posix_acl **p_acl; + size_t size; + int error; + + if (S_ISLNK(inode->i_mode)) + return -EOPNOTSUPP; + if (!test_opt(inode->i_sb, POSIX_ACL)) + return 0; + + switch(type) { + case ACL_TYPE_ACCESS: + name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; + p_acl = &EXT2_I(inode)->i_acl; + if (acl) { + mode_t mode = inode->i_mode; + error = posix_acl_equiv_mode(acl, &mode); + if (error < 0) + return error; + else { + inode->i_mode = mode; + mark_inode_dirty(inode); + if (error == 0) + acl = NULL; + } + } + break; + + case ACL_TYPE_DEFAULT: + name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT; + p_acl = &EXT2_I(inode)->i_default_acl; + if (!S_ISDIR(inode->i_mode)) + return acl ? -EACCES : 0; + break; + + default: + return -EINVAL; + } + if (acl) { + if (acl->a_count > EXT2_ACL_MAX_ENTRIES) + return -EINVAL; + value = ext2_acl_to_disk(acl, &size); + if (IS_ERR(value)) + return (int)PTR_ERR(value); + } + + error = ext2_xattr_set(inode, name_index, "", value, size, 0); + + if (value) + kfree(value); + if (!error) { + if (*p_acl && *p_acl != EXT2_ACL_NOT_CACHED) + posix_acl_release(*p_acl); + *p_acl = posix_acl_dup(acl); + } + return error; +} + +static int +__ext2_permission(struct inode *inode, int mask, int lock) +{ + int mode = inode->i_mode; + + /* Nobody gets write access to a read-only fs */ + if ((mask & MAY_WRITE) && IS_RDONLY(inode) && + (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) + return -EROFS; + /* Nobody gets write access to an immutable file */ + if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode)) + return -EACCES; + if (current->fsuid == inode->i_uid) { + mode >>= 6; + } else if (test_opt(inode->i_sb, POSIX_ACL)) { + /* ACL can't contain additional permissions if + the ACL_MASK entry is 0 */ + if (!(mode & S_IRWXG)) + goto check_groups; + if (EXT2_I(inode)->i_acl == EXT2_ACL_NOT_CACHED) { + struct posix_acl *acl; + + if (lock) { + down(&inode->i_sem); + acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); + up(&inode->i_sem); + } else + acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); + + if (IS_ERR(acl)) + return PTR_ERR(acl); + posix_acl_release(acl); + if (EXT2_I(inode)->i_acl == EXT2_ACL_NOT_CACHED) + return -EIO; + } + if (EXT2_I(inode)->i_acl) { + int error = posix_acl_permission(inode, + EXT2_I(inode)->i_acl, mask); + if (error == -EACCES) + goto check_capabilities; + return error; + } else + goto check_groups; + } else { +check_groups: + if (in_group_p(inode->i_gid)) + mode >>= 3; + } + if ((mode & mask & S_IRWXO) == mask) + return 0; + +check_capabilities: + /* Allowed to override Discretionary Access Control? */ + if ((mask & (MAY_READ|MAY_WRITE)) || (inode->i_mode & S_IXUGO)) + if (capable(CAP_DAC_OVERRIDE)) + return 0; + /* Read and search granted if capable(CAP_DAC_READ_SEARCH) */ + if (capable(CAP_DAC_READ_SEARCH) && ((mask == MAY_READ) || + (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE)))) + return 0; + return -EACCES; +} + +/* + * Inode operation permission(). + * + * inode->i_sem: up + * BKL held [before 2.5.x] + */ +int +ext2_permission(struct inode *inode, int mask) +{ + return __ext2_permission(inode, mask, 1); +} + +/* + * Used internally if i_sem is already down. + */ +int +ext2_permission_locked(struct inode *inode, int mask) +{ + return __ext2_permission(inode, mask, 0); +} + +/* + * Initialize the ACLs of a new inode. Called from ext2_new_inode. + * + * dir->i_sem: down + * inode->i_sem: up (access to inode is still exclusive) + * BKL held [before 2.5.x] + */ +int +ext2_init_acl(struct inode *inode, struct inode *dir) +{ + struct posix_acl *acl = NULL; + int error = 0; + + if (!S_ISLNK(inode->i_mode)) { + if (test_opt(dir->i_sb, POSIX_ACL)) { + acl = ext2_get_acl(dir, ACL_TYPE_DEFAULT); + if (IS_ERR(acl)) + return PTR_ERR(acl); + } + if (!acl) + inode->i_mode &= ~current->fs->umask; + } + if (test_opt(inode->i_sb, POSIX_ACL) && acl) { + struct posix_acl *clone; + mode_t mode; + + if (S_ISDIR(inode->i_mode)) { + error = ext2_set_acl(inode, ACL_TYPE_DEFAULT, acl); + if (error) + goto cleanup; + } + clone = posix_acl_clone(acl, GFP_KERNEL); + error = -ENOMEM; + if (!clone) + goto cleanup; + mode = inode->i_mode; + error = posix_acl_create_masq(clone, &mode); + if (error >= 0) { + inode->i_mode = mode; + if (error > 0) { + /* This is an extended ACL */ + error = ext2_set_acl(inode, + ACL_TYPE_ACCESS, clone); + } + } + posix_acl_release(clone); + } +cleanup: + posix_acl_release(acl); + return error; +} + +/* + * Does chmod for an inode that may have an Access Control List. The + * inode->i_mode field must be updated to the desired value by the caller + * before calling this function. + * Returns 0 on success, or a negative error number. + * + * We change the ACL rather than storing some ACL entries in the file + * mode permission bits (which would be more efficient), because that + * would break once additional permissions (like ACL_APPEND, ACL_DELETE + * for directories) are added. There are no more bits available in the + * file mode. + * + * inode->i_sem: down + * BKL held [before 2.5.x] + */ +int +ext2_acl_chmod(struct inode *inode) +{ + struct posix_acl *acl, *clone; + int error; + + if (!test_opt(inode->i_sb, POSIX_ACL)) + return 0; + if (S_ISLNK(inode->i_mode)) + return -EOPNOTSUPP; + acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); + if (IS_ERR(acl) || !acl) + return PTR_ERR(acl); + clone = posix_acl_clone(acl, GFP_KERNEL); + posix_acl_release(acl); + if (!clone) + return -ENOMEM; + error = posix_acl_chmod_masq(clone, inode->i_mode); + if (!error) + error = ext2_set_acl(inode, ACL_TYPE_ACCESS, clone); + posix_acl_release(clone); + return error; +} + +/* + * Extended attribut handlers + */ +static size_t +ext2_xattr_list_acl_access(char *list, struct inode *inode, + const char *name, int name_len) +{ + const size_t len = sizeof(XATTR_NAME_ACL_ACCESS)-1; + + if (!test_opt(inode->i_sb, POSIX_ACL)) + return 0; + if (list) + memcpy(list, XATTR_NAME_ACL_ACCESS, len); + return len; +} + +static size_t +ext2_xattr_list_acl_default(char *list, struct inode *inode, + const char *name, int name_len) +{ + const size_t len = sizeof(XATTR_NAME_ACL_DEFAULT)-1; + + if (!test_opt(inode->i_sb, POSIX_ACL)) + return 0; + if (list) + memcpy(list, XATTR_NAME_ACL_DEFAULT, len); + return len; +} + +static int +ext2_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size) +{ + struct posix_acl *acl; + int error; + + if (!test_opt(inode->i_sb, POSIX_ACL)) + return -EOPNOTSUPP; + + acl = ext2_get_acl(inode, type); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl == NULL) + return -ENODATA; + error = posix_acl_to_xattr(acl, buffer, size); + posix_acl_release(acl); + + return error; +} + +static int +ext2_xattr_get_acl_access(struct inode *inode, const char *name, + void *buffer, size_t size) +{ + if (strcmp(name, "") != 0) + return -EINVAL; + return ext2_xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size); +} + +static int +ext2_xattr_get_acl_default(struct inode *inode, const char *name, + void *buffer, size_t size) +{ + if (strcmp(name, "") != 0) + return -EINVAL; + return ext2_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size); +} + +static int +ext2_xattr_set_acl(struct inode *inode, int type, const void *value, size_t size) +{ + struct posix_acl *acl; + int error; + + if (!test_opt(inode->i_sb, POSIX_ACL)) + return -EOPNOTSUPP; + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EPERM; + + if (value) { + acl = posix_acl_from_xattr(value, size); + if (IS_ERR(acl)) + return PTR_ERR(acl); + else if (acl) { + error = posix_acl_valid(acl); + if (error) + goto release_and_out; + } + } else + acl = NULL; + + error = ext2_set_acl(inode, type, acl); + +release_and_out: + posix_acl_release(acl); + return error; +} + +static int +ext2_xattr_set_acl_access(struct inode *inode, const char *name, + const void *value, size_t size, int flags) +{ + if (strcmp(name, "") != 0) + return -EINVAL; + return ext2_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size); +} + +static int +ext2_xattr_set_acl_default(struct inode *inode, const char *name, + const void *value, size_t size, int flags) +{ + if (strcmp(name, "") != 0) + return -EINVAL; + return ext2_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); +} + +struct ext2_xattr_handler ext2_xattr_acl_access_handler = { + prefix: XATTR_NAME_ACL_ACCESS, + list: ext2_xattr_list_acl_access, + get: ext2_xattr_get_acl_access, + set: ext2_xattr_set_acl_access, +}; + +struct ext2_xattr_handler ext2_xattr_acl_default_handler = { + prefix: XATTR_NAME_ACL_DEFAULT, + list: ext2_xattr_list_acl_default, + get: ext2_xattr_get_acl_default, + set: ext2_xattr_set_acl_default, +}; + +void +exit_ext2_acl(void) +{ + ext2_xattr_unregister(EXT2_XATTR_INDEX_POSIX_ACL_ACCESS, + &ext2_xattr_acl_access_handler); + ext2_xattr_unregister(EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT, + &ext2_xattr_acl_default_handler); +} + +int __init +init_ext2_acl(void) +{ + int error; + + error = ext2_xattr_register(EXT2_XATTR_INDEX_POSIX_ACL_ACCESS, + &ext2_xattr_acl_access_handler); + if (error) + goto fail; + error = ext2_xattr_register(EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT, + &ext2_xattr_acl_default_handler); + if (error) + goto fail; + return 0; + +fail: + exit_ext2_acl(); + return error; +} diff -Nru a/fs/ext2/acl.h b/fs/ext2/acl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/ext2/acl.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,88 @@ +/* + File: fs/ext2/acl.h + + (C) 2001 Andreas Gruenbacher, +*/ + +#include + +#define EXT2_ACL_VERSION 0x0001 +#define EXT2_ACL_MAX_ENTRIES 32 + +typedef struct { + __u16 e_tag; + __u16 e_perm; + __u32 e_id; +} ext2_acl_entry; + +typedef struct { + __u16 e_tag; + __u16 e_perm; +} ext2_acl_entry_short; + +typedef struct { + __u32 a_version; +} ext2_acl_header; + +static inline size_t ext2_acl_size(int count) +{ + if (count <= 4) { + return sizeof(ext2_acl_header) + + count * sizeof(ext2_acl_entry_short); + } else { + return sizeof(ext2_acl_header) + + 4 * sizeof(ext2_acl_entry_short) + + (count - 4) * sizeof(ext2_acl_entry); + } +} + +static inline int ext2_acl_count(size_t size) +{ + ssize_t s; + size -= sizeof(ext2_acl_header); + s = size - 4 * sizeof(ext2_acl_entry_short); + if (s < 0) { + if (size % sizeof(ext2_acl_entry_short)) + return -1; + return size / sizeof(ext2_acl_entry_short); + } else { + if (s % sizeof(ext2_acl_entry)) + return -1; + return s / sizeof(ext2_acl_entry) + 4; + } +} + +#ifdef CONFIG_EXT2_FS_POSIX_ACL + +/* Value for inode->u.ext2_i.i_acl and inode->u.ext2_i.i_default_acl + if the ACL has not been cached */ +#define EXT2_ACL_NOT_CACHED ((void *)-1) + +/* acl.c */ +extern int ext2_permission (struct inode *, int); +extern int ext2_permission_locked (struct inode *, int); +extern int ext2_acl_chmod (struct inode *); +extern int ext2_init_acl (struct inode *, struct inode *); + +extern int init_ext2_acl(void); +extern void exit_ext2_acl(void); + +#else +#include +#define ext2_permission NULL +#define ext2_get_acl NULL +#define ext2_set_acl NULL + +static inline int +ext2_acl_chmod (struct inode *inode) +{ + return 0; +} + +static inline int ext2_init_acl (struct inode *inode, struct inode *dir) +{ + inode->i_mode &= ~current->fs->umask; + return 0; +} +#endif + diff -Nru a/fs/ext2/ext2.h b/fs/ext2/ext2.h --- a/fs/ext2/ext2.h Mon Nov 4 14:31:03 2002 +++ b/fs/ext2/ext2.h Mon Nov 4 14:31:03 2002 @@ -10,6 +10,7 @@ __u32 i_faddr; __u8 i_frag_no; __u8 i_frag_size; + __u16 i_state; __u32 i_file_acl; __u32 i_dir_acl; __u32 i_dtime; @@ -19,11 +20,21 @@ __u32 i_prealloc_block; __u32 i_prealloc_count; __u32 i_dir_start_lookup; +#ifdef CONFIG_EXT2_FS_POSIX_ACL + struct posix_acl *i_acl; + struct posix_acl *i_default_acl; +#endif rwlock_t i_meta_lock; struct inode vfs_inode; }; /* + * Inode dynamic state flags + */ +#define EXT2_STATE_NEW 0x00000001 /* inode is newly created */ + + +/* * Function prototypes */ @@ -45,6 +56,7 @@ extern void ext2_free_blocks (struct inode *, unsigned long, unsigned long); extern unsigned long ext2_count_free_blocks (struct super_block *); +extern unsigned long ext2_count_dirs (struct super_block *); extern void ext2_check_blocks_bitmap (struct super_block *); extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb, unsigned int block_group, @@ -78,6 +90,7 @@ extern int ext2_sync_inode (struct inode *); extern void ext2_discard_prealloc (struct inode *); extern void ext2_truncate (struct inode *); +extern int ext2_setattr (struct dentry *, struct iattr *); /* ioctl.c */ extern int ext2_ioctl (struct inode *, struct file *, unsigned int, @@ -110,6 +123,8 @@ /* namei.c */ extern struct inode_operations ext2_dir_inode_operations; +extern struct inode_operations ext2_special_inode_operations; /* symlink.c */ extern struct inode_operations ext2_fast_symlink_inode_operations; +extern struct inode_operations ext2_symlink_inode_operations; diff -Nru a/fs/ext2/file.c b/fs/ext2/file.c --- a/fs/ext2/file.c Mon Nov 4 14:31:01 2002 +++ b/fs/ext2/file.c Mon Nov 4 14:31:01 2002 @@ -18,8 +18,10 @@ * (jj@sunsite.ms.mff.cuni.cz) */ -#include "ext2.h" #include +#include "ext2.h" +#include "xattr.h" +#include "acl.h" /* * Called when an inode is released. Note that this is different @@ -55,4 +57,10 @@ struct inode_operations ext2_file_inode_operations = { .truncate = ext2_truncate, + .setxattr = ext2_setxattr, + .getxattr = ext2_getxattr, + .listxattr = ext2_listxattr, + .removexattr = ext2_removexattr, + .setattr = ext2_setattr, + .permission = ext2_permission, }; diff -Nru a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c --- a/fs/ext2/ialloc.c Mon Nov 4 14:31:02 2002 +++ b/fs/ext2/ialloc.c Mon Nov 4 14:31:02 2002 @@ -13,11 +13,14 @@ */ #include -#include "ext2.h" #include #include #include #include +#include +#include "ext2.h" +#include "xattr.h" +#include "acl.h" /* * ialloc.c contains the inodes allocation and deallocation routines @@ -97,6 +100,7 @@ */ if (!is_bad_inode(inode)) { /* Quota is already initialized in iput() */ + ext2_xattr_delete_inode(inode); DQUOT_FREE_INODE(inode); DQUOT_DROP(inode); } @@ -205,8 +209,7 @@ * For other inodes, search forward from the parent directory\'s block * group to find a free inode. */ - -static int find_group_dir(struct super_block *sb, int parent_group) +static int find_group_dir(struct super_block *sb, struct inode *parent) { struct ext2_super_block * es = EXT2_SB(sb)->s_es; int ngroups = EXT2_SB(sb)->s_groups_count; @@ -239,8 +242,140 @@ return best_group; } -static int find_group_other(struct super_block *sb, int parent_group) +/* + * Orlov's allocator for directories. + * + * We always try to spread first-level directories. + * + * If there are blockgroups with both free inodes and free blocks counts + * not worse than average we return one with smallest directory count. + * Otherwise we simply return a random group. + * + * For the rest rules look so: + * + * It's OK to put directory into a group unless + * it has too many directories already (max_dirs) or + * it has too few free inodes left (min_inodes) or + * it has too few free blocks left (min_blocks) or + * it's already running too large debt (max_debt). + * Parent's group is prefered, if it doesn't satisfy these + * conditions we search cyclically through the rest. If none + * of the groups look good we just look for a group with more + * free inodes than average (starting at parent's group). + * + * Debt is incremented each time we allocate a directory and decremented + * when we allocate an inode, within 0--255. + */ + +#define INODE_COST 64 +#define BLOCK_COST 256 + +static int find_group_orlov(struct super_block *sb, struct inode *parent) +{ + int parent_group = EXT2_I(parent)->i_block_group; + struct ext2_sb_info *sbi = EXT2_SB(sb); + struct ext2_super_block *es = sbi->s_es; + int ngroups = sbi->s_groups_count; + int inodes_per_group = EXT2_INODES_PER_GROUP(sb); + int avefreei = le32_to_cpu(es->s_free_inodes_count) / ngroups; + int avefreeb = le32_to_cpu(es->s_free_blocks_count) / ngroups; + int blocks_per_dir; + int ndirs = sbi->s_dir_count; + int max_debt, max_dirs, min_blocks, min_inodes; + int group = -1, i; + struct ext2_group_desc *desc; + struct buffer_head *bh; + + if ((parent == sb->s_root->d_inode) || + (parent->i_flags & EXT2_TOPDIR_FL)) { + struct ext2_group_desc *best_desc = NULL; + struct buffer_head *best_bh = NULL; + int best_ndir = inodes_per_group; + int best_group = -1; + + get_random_bytes(&group, sizeof(group)); + parent_group = (unsigned)group % ngroups; + for (i = 0; i < ngroups; i++) { + group = (parent_group + i) % ngroups; + desc = ext2_get_group_desc (sb, group, &bh); + if (!desc || !desc->bg_free_inodes_count) + continue; + if (le16_to_cpu(desc->bg_used_dirs_count) >= best_ndir) + continue; + if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) + continue; + if (le16_to_cpu(desc->bg_free_blocks_count) < avefreeb) + continue; + best_group = group; + best_ndir = le16_to_cpu(desc->bg_used_dirs_count); + best_desc = desc; + best_bh = bh; + } + if (best_group >= 0) { + desc = best_desc; + bh = best_bh; + group = best_group; + goto found; + } + goto fallback; + } + + blocks_per_dir = (le32_to_cpu(es->s_blocks_count) - + le32_to_cpu(es->s_free_blocks_count)) / ndirs; + + max_dirs = ndirs / ngroups + inodes_per_group / 16; + min_inodes = avefreei - inodes_per_group / 4; + min_blocks = avefreeb - EXT2_BLOCKS_PER_GROUP(sb) / 4; + + max_debt = EXT2_BLOCKS_PER_GROUP(sb) / max(blocks_per_dir, BLOCK_COST); + if (max_debt * INODE_COST > inodes_per_group) + max_debt = inodes_per_group / INODE_COST; + if (max_debt > 255) + max_debt = 255; + if (max_debt == 0) + max_debt = 1; + + for (i = 0; i < ngroups; i++) { + group = (parent_group + i) % ngroups; + desc = ext2_get_group_desc (sb, group, &bh); + if (!desc || !desc->bg_free_inodes_count) + continue; + if (sbi->s_debts[group] >= max_debt) + continue; + if (le16_to_cpu(desc->bg_used_dirs_count) >= max_dirs) + continue; + if (le16_to_cpu(desc->bg_free_inodes_count) < min_inodes) + continue; + if (le16_to_cpu(desc->bg_free_blocks_count) < min_blocks) + continue; + goto found; + } + +fallback: + for (i = 0; i < ngroups; i++) { + group = (parent_group + i) % ngroups; + desc = ext2_get_group_desc (sb, group, &bh); + if (!desc || !desc->bg_free_inodes_count) + continue; + if (le16_to_cpu(desc->bg_free_inodes_count) >= avefreei) + goto found; + } + + return -1; + +found: + desc->bg_free_inodes_count = + cpu_to_le16(le16_to_cpu(desc->bg_free_inodes_count) - 1); + desc->bg_used_dirs_count = + cpu_to_le16(le16_to_cpu(desc->bg_used_dirs_count) + 1); + sbi->s_dir_count++; + mark_buffer_dirty(bh); + return group; +} + +static int find_group_other(struct super_block *sb, struct inode *parent) { + int parent_group = EXT2_I(parent)->i_block_group; int ngroups = EXT2_SB(sb)->s_groups_count; struct ext2_group_desc *desc; struct buffer_head *bh; @@ -300,7 +435,6 @@ struct ext2_super_block * es; struct ext2_inode_info *ei; int err; - struct inode *ret; sb = dir->i_sb; inode = new_inode(sb); @@ -311,17 +445,19 @@ lock_super (sb); es = EXT2_SB(sb)->s_es; repeat: - if (S_ISDIR(mode)) - group = find_group_dir(sb, EXT2_I(dir)->i_block_group); - else - group = find_group_other(sb, EXT2_I(dir)->i_block_group); + if (S_ISDIR(mode)) { + if (test_opt (sb, OLDALLOC)) + group = find_group_dir(sb, dir); + else + group = find_group_orlov(sb, dir); + } else + group = find_group_other(sb, dir); err = -ENOSPC; if (group == -1) goto fail; err = -EIO; - brelse(bitmap_bh); bitmap_bh = read_inode_bitmap(sb, group); if (!bitmap_bh) goto fail2; @@ -337,6 +473,7 @@ ll_rw_block(WRITE, 1, &bitmap_bh); wait_on_buffer(bitmap_bh); } + brelse(bitmap_bh); ino = group * EXT2_INODES_PER_GROUP(sb) + i + 1; if (ino < EXT2_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { @@ -350,6 +487,15 @@ es->s_free_inodes_count = cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) - 1); + + if (S_ISDIR(mode)) { + if (EXT2_SB(sb)->s_debts[group] < 255) + EXT2_SB(sb)->s_debts[group]++; + } else { + if (EXT2_SB(sb)->s_debts[group]) + EXT2_SB(sb)->s_debts[group]--; + } + mark_buffer_dirty(EXT2_SB(sb)->s_sbh); sb->s_dirt = 1; inode->i_uid = current->fsuid; @@ -386,27 +532,34 @@ ei->i_prealloc_block = 0; ei->i_prealloc_count = 0; ei->i_dir_start_lookup = 0; + ei->i_state = EXT2_STATE_NEW; if (ei->i_flags & EXT2_SYNC_FL) inode->i_flags |= S_SYNC; if (ei->i_flags & EXT2_DIRSYNC_FL) inode->i_flags |= S_DIRSYNC; inode->i_generation = EXT2_SB(sb)->s_next_generation++; insert_inode_hash(inode); - mark_inode_dirty(inode); unlock_super(sb); - ret = inode; if(DQUOT_ALLOC_INODE(inode)) { DQUOT_DROP(inode); - inode->i_flags |= S_NOQUOTA; - inode->i_nlink = 0; - iput(inode); - ret = ERR_PTR(-EDQUOT); - } else { - ext2_debug("allocating inode %lu\n", inode->i_ino); - ext2_preread_inode(inode); + goto fail3; + } + err = ext2_init_acl(inode, dir); + if (err) { + DQUOT_FREE_INODE(inode); + goto fail3; } - goto out; + mark_inode_dirty(inode); + ext2_debug("allocating inode %lu\n", inode->i_ino); + ext2_preread_inode(inode); + return inode; + +fail3: + inode->i_flags |= S_NOQUOTA; + inode->i_nlink = 0; + iput(inode); + return ERR_PTR(err); fail2: desc = ext2_get_group_desc (sb, group, &bh2); @@ -420,10 +573,10 @@ unlock_super(sb); make_bad_inode(inode); iput(inode); - ret = ERR_PTR(err); - goto out; + return ERR_PTR(err); bad_count: + brelse(bitmap_bh); ext2_error (sb, "ext2_new_inode", "Free inodes count corrupted in group %d", group); @@ -436,9 +589,6 @@ desc->bg_free_inodes_count = 0; mark_buffer_dirty(bh2); goto repeat; -out: - brelse(bitmap_bh); - return ret; } unsigned long ext2_count_free_inodes (struct super_block * sb) @@ -477,6 +627,21 @@ #else return le32_to_cpu(EXT2_SB(sb)->s_es->s_free_inodes_count); #endif +} + +/* Called at mount-time, super-block is locked */ +unsigned long ext2_count_dirs (struct super_block * sb) +{ + unsigned long count = 0; + int i; + + for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) { + struct ext2_group_desc *gdp = ext2_get_group_desc (sb, i, NULL); + if (!gdp) + continue; + count += le16_to_cpu(gdp->bg_used_dirs_count); + } + return count; } #ifdef CONFIG_EXT2_CHECK diff -Nru a/fs/ext2/inode.c b/fs/ext2/inode.c --- a/fs/ext2/inode.c Mon Nov 4 14:31:00 2002 +++ b/fs/ext2/inode.c Mon Nov 4 14:31:00 2002 @@ -22,7 +22,6 @@ * Assorted race fixes, rewrite of ext2_get_block() by Al Viro, 2000 */ -#include "ext2.h" #include #include #include @@ -31,6 +30,8 @@ #include #include #include +#include "ext2.h" +#include "acl.h" MODULE_AUTHOR("Remy Card and others"); MODULE_DESCRIPTION("Second Extended Filesystem"); @@ -39,6 +40,18 @@ static int ext2_update_inode(struct inode * inode, int do_sync); /* + * Test whether an inode is a fast symlink. + */ +static inline int ext2_inode_is_fast_symlink(struct inode *inode) +{ + int ea_blocks = EXT2_I(inode)->i_file_acl ? + (inode->i_sb->s_blocksize >> 9) : 0; + + return (S_ISLNK(inode->i_mode) && + inode->i_blocks - ea_blocks == 0); +} + +/* * Called at each iput() */ void ext2_put_inode (struct inode * inode) @@ -51,9 +64,7 @@ */ void ext2_delete_inode (struct inode * inode) { - if (is_bad_inode(inode) || - inode->i_ino == EXT2_ACL_IDX_INO || - inode->i_ino == EXT2_ACL_DATA_INO) + if (is_bad_inode(inode)) goto no_delete; EXT2_I(inode)->i_dtime = CURRENT_TIME; mark_inode_dirty(inode); @@ -843,6 +854,8 @@ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) return; + if (ext2_inode_is_fast_symlink(inode)) + return; if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return; @@ -929,8 +942,7 @@ struct ext2_group_desc * gdp; *p = NULL; - if ((ino != EXT2_ROOT_INO && ino != EXT2_ACL_IDX_INO && - ino != EXT2_ACL_DATA_INO && ino < EXT2_FIRST_INO(sb)) || + if ((ino != EXT2_ROOT_INO && ino < EXT2_FIRST_INO(sb)) || ino > le32_to_cpu(EXT2_SB(sb)->s_es->s_inodes_count)) goto Einval; @@ -971,6 +983,10 @@ struct ext2_inode * raw_inode = ext2_get_inode(inode->i_sb, ino, &bh); int n; +#ifdef CONFIG_EXT2_FS_POSIX_ACL + ei->i_acl = EXT2_ACL_NOT_CACHED; + ei->i_default_acl = EXT2_ACL_NOT_CACHED; +#endif if (IS_ERR(raw_inode)) goto bad_inode; @@ -1012,6 +1028,7 @@ ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl); ei->i_dtime = 0; inode->i_generation = le32_to_cpu(raw_inode->i_generation); + ei->i_state = 0; ei->i_next_alloc_block = 0; ei->i_next_alloc_goal = 0; ei->i_prealloc_count = 0; @@ -1025,9 +1042,7 @@ for (n = 0; n < EXT2_N_BLOCKS; n++) ei->i_data[n] = raw_inode->i_block[n]; - if (ino == EXT2_ACL_IDX_INO || ino == EXT2_ACL_DATA_INO) - /* Nothing to do */ ; - else if (S_ISREG(inode->i_mode)) { + if (S_ISREG(inode->i_mode)) { inode->i_op = &ext2_file_inode_operations; inode->i_fop = &ext2_file_operations; inode->i_mapping->a_ops = &ext2_aops; @@ -1036,15 +1051,17 @@ inode->i_fop = &ext2_dir_operations; inode->i_mapping->a_ops = &ext2_aops; } else if (S_ISLNK(inode->i_mode)) { - if (!inode->i_blocks) + if (ext2_inode_is_fast_symlink(inode)) inode->i_op = &ext2_fast_symlink_inode_operations; else { - inode->i_op = &page_symlink_inode_operations; + inode->i_op = &ext2_symlink_inode_operations; inode->i_mapping->a_ops = &ext2_aops; } - } else + } else { + inode->i_op = &ext2_special_inode_operations; init_special_inode(inode, inode->i_mode, le32_to_cpu(raw_inode->i_block[0])); + } brelse (bh); if (ei->i_flags & EXT2_SYNC_FL) inode->i_flags |= S_SYNC; @@ -1076,12 +1093,11 @@ if (IS_ERR(raw_inode)) return -EIO; - if (ino == EXT2_ACL_IDX_INO || ino == EXT2_ACL_DATA_INO) { - ext2_error (sb, "ext2_write_inode", "bad inode number: %lu", - (unsigned long) ino); - brelse(bh); - return -EIO; - } + /* For fields not not tracking in the in-memory inode, + * initialise them to zero for new inodes. */ + if (ei->i_state & EXT2_STATE_NEW) + memset(raw_inode, 0, EXT2_SB(sb)->s_inode_size); + raw_inode->i_mode = cpu_to_le16(inode->i_mode); if (!(test_opt(sb, NO_UID32))) { raw_inode->i_uid_low = cpu_to_le16(low_16_bits(uid)); @@ -1152,6 +1168,7 @@ err = -EIO; } } + ei->i_state &= ~EXT2_STATE_NEW; brelse (bh); return err; } @@ -1165,3 +1182,18 @@ { return ext2_update_inode (inode, 1); } + +int ext2_setattr(struct dentry *dentry, struct iattr *iattr) +{ + struct inode *inode = dentry->d_inode; + int error; + + error = inode_change_ok(inode, iattr); + if (error) + return error; + inode_setattr(inode, iattr); + if (iattr->ia_valid & ATTR_MODE) + error = ext2_acl_chmod(inode); + return error; +} + diff -Nru a/fs/ext2/namei.c b/fs/ext2/namei.c --- a/fs/ext2/namei.c Mon Nov 4 14:31:02 2002 +++ b/fs/ext2/namei.c Mon Nov 4 14:31:02 2002 @@ -29,8 +29,10 @@ * David S. Miller (davem@caip.rutgers.edu), 1995 */ -#include "ext2.h" #include +#include "ext2.h" +#include "xattr.h" +#include "acl.h" /* * Couple of helper functions - make the code slightly cleaner. @@ -137,7 +139,10 @@ struct inode * inode = ext2_new_inode (dir, mode); int err = PTR_ERR(inode); if (!IS_ERR(inode)) { - init_special_inode(inode, mode, rdev); + init_special_inode(inode, inode->i_mode, rdev); +#ifdef CONFIG_EXT2_FS_EXT_ATTR + inode->i_op = &ext2_special_inode_operations; +#endif mark_inode_dirty(inode); err = ext2_add_nondir(dentry, inode); } @@ -162,7 +167,7 @@ if (l > sizeof (EXT2_I(inode)->i_data)) { /* slow symlink */ - inode->i_op = &page_symlink_inode_operations; + inode->i_op = &ext2_symlink_inode_operations; inode->i_mapping->a_ops = &ext2_aops; err = page_symlink(inode, symname, l); if (err) @@ -368,4 +373,19 @@ .rmdir = ext2_rmdir, .mknod = ext2_mknod, .rename = ext2_rename, + .setxattr = ext2_setxattr, + .getxattr = ext2_getxattr, + .listxattr = ext2_listxattr, + .removexattr = ext2_removexattr, + .setattr = ext2_setattr, + .permission = ext2_permission, +}; + +struct inode_operations ext2_special_inode_operations = { + .setxattr = ext2_setxattr, + .getxattr = ext2_getxattr, + .listxattr = ext2_listxattr, + .removexattr = ext2_removexattr, + .setattr = ext2_setattr, + .permission = ext2_permission, }; diff -Nru a/fs/ext2/super.c b/fs/ext2/super.c --- a/fs/ext2/super.c Mon Nov 4 14:31:02 2002 +++ b/fs/ext2/super.c Mon Nov 4 14:31:02 2002 @@ -19,7 +19,6 @@ #include #include #include -#include "ext2.h" #include #include #include @@ -27,7 +26,9 @@ #include #include #include - +#include "ext2.h" +#include "xattr.h" +#include "acl.h" static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es); @@ -52,16 +53,12 @@ va_start (args, fmt); vsprintf (error_buf, fmt, args); va_end (args); - if (test_opt (sb, ERRORS_PANIC) || - (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC && - !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_RO))) + if (test_opt (sb, ERRORS_PANIC)) panic ("EXT2-fs panic (device %s): %s: %s\n", sb->s_id, function, error_buf); printk (KERN_CRIT "EXT2-fs error (device %s): %s: %s\n", sb->s_id, function, error_buf); - if (test_opt (sb, ERRORS_RO) || - (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_RO && - !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_PANIC))) { + if (test_opt (sb, ERRORS_RO)) { printk ("Remounting filesystem read-only\n"); sb->s_flags |= MS_RDONLY; } @@ -131,6 +128,7 @@ int i; struct ext2_sb_info *sbi = EXT2_SB(sb); + ext2_xattr_put_super(sb); if (!(sb->s_flags & MS_RDONLY)) { struct ext2_super_block *es = sbi->s_es; @@ -142,6 +140,7 @@ if (sbi->s_group_desc[i]) brelse (sbi->s_group_desc[i]); kfree(sbi->s_group_desc); + kfree(sbi->s_debts); brelse (sbi->s_sbh); sb->s_fs_info = NULL; kfree(sbi); @@ -157,6 +156,10 @@ ei = (struct ext2_inode_info *)kmem_cache_alloc(ext2_inode_cachep, SLAB_KERNEL); if (!ei) return NULL; +#ifdef CONFIG_EXT2_FS_POSIX_ACL + ei->i_acl = EXT2_ACL_NOT_CACHED; + ei->i_default_acl = EXT2_ACL_NOT_CACHED; +#endif return &ei->vfs_inode; } @@ -193,6 +196,26 @@ printk(KERN_INFO "ext2_inode_cache: not all structures were freed\n"); } +#ifdef CONFIG_EXT2_FS_POSIX_ACL + +static void ext2_clear_inode(struct inode *inode) +{ + struct ext2_inode_info *ei = EXT2_I(inode); + + if (ei->i_acl && ei->i_acl != EXT2_ACL_NOT_CACHED) { + posix_acl_release(ei->i_acl); + ei->i_acl = EXT2_ACL_NOT_CACHED; + } + if (ei->i_default_acl && ei->i_default_acl != EXT2_ACL_NOT_CACHED) { + posix_acl_release(ei->i_default_acl); + ei->i_default_acl = EXT2_ACL_NOT_CACHED; + } +} + +#else +# define ext2_clear_inode NULL +#endif + static struct super_operations ext2_sops = { .alloc_inode = ext2_alloc_inode, .destroy_inode = ext2_destroy_inode, @@ -204,6 +227,7 @@ .write_super = ext2_write_super, .statfs = ext2_statfs, .remount_fs = ext2_remount, + .clear_inode = ext2_clear_inode, }; /* Yes, most of these are left as NULL!! @@ -216,12 +240,61 @@ .get_parent = ext2_get_parent, }; +static unsigned long get_sb_block(void **data) +{ + unsigned long sb_block; + char *options = (char *) *data; + + if (!options || strncmp(options, "sb=", 3) != 0) + return 1; /* Default location */ + options += 3; + sb_block = simple_strtoul(options, &options, 0); + if (*options && *options != ',') { + printk("EXT2-fs: Invalid sb specification: %s\n", + (char *) *data); + return 1; + } + if (*options == ',') + options++; + *data = (void *) options; + return sb_block; +} + +static int want_value(char *value, char *option) +{ + if (!value || !*value) { + printk(KERN_NOTICE "EXT2-fs: the %s option needs an argument\n", + option); + return -1; + } + return 0; +} + +static int want_null_value(char *value, char *option) +{ + if (*value) { + printk(KERN_NOTICE "EXT2-fs: Invalid %s argument: %s\n", + option, value); + return -1; + } + return 0; +} + +static int want_numeric(char *value, char *option, unsigned long *number) +{ + if (want_value(value, option)) + return -1; + *number = simple_strtoul(value, &value, 0); + if (want_null_value(value, option)) + return -1; + return 0; +} + /* * This function has been shamelessly adapted from the msdos fs */ -static int parse_options (char * options, unsigned long * sb_block, - unsigned short *resuid, unsigned short * resgid, - unsigned long * mount_options) +static int parse_options (char * options, + struct ext2_sb_info *sbi) { char * this_char; char * value; @@ -233,23 +306,37 @@ continue; if ((value = strchr (this_char, '=')) != NULL) *value++ = 0; +#ifdef CONFIG_EXT2_FS_XATTR + if (!strcmp (this_char, "user_xattr")) + set_opt (sbi->s_mount_opt, XATTR_USER); + else if (!strcmp (this_char, "nouser_xattr")) + clear_opt (sbi->s_mount_opt, XATTR_USER); + else +#endif +#ifdef CONFIG_EXT2_FS_POSIX_ACL + if (!strcmp(this_char, "acl")) + set_opt(sbi->s_mount_opt, POSIX_ACL); + else if (!strcmp(this_char, "noacl")) + clear_opt(sbi->s_mount_opt, POSIX_ACL); + else +#endif if (!strcmp (this_char, "bsddf")) - clear_opt (*mount_options, MINIX_DF); + clear_opt (sbi->s_mount_opt, MINIX_DF); else if (!strcmp (this_char, "nouid32")) { - set_opt (*mount_options, NO_UID32); + set_opt (sbi->s_mount_opt, NO_UID32); } else if (!strcmp (this_char, "check")) { if (!value || !*value || !strcmp (value, "none")) - clear_opt (*mount_options, CHECK); + clear_opt (sbi->s_mount_opt, CHECK); else #ifdef CONFIG_EXT2_CHECK - set_opt (*mount_options, CHECK); + set_opt (sbi->s_mount_opt, CHECK); #else printk("EXT2 Check option not supported\n"); #endif } else if (!strcmp (this_char, "debug")) - set_opt (*mount_options, DEBUG); + set_opt (sbi->s_mount_opt, DEBUG); else if (!strcmp (this_char, "errors")) { if (!value || !*value) { printk ("EXT2-fs: the errors option requires " @@ -257,19 +344,19 @@ return 0; } if (!strcmp (value, "continue")) { - clear_opt (*mount_options, ERRORS_RO); - clear_opt (*mount_options, ERRORS_PANIC); - set_opt (*mount_options, ERRORS_CONT); + clear_opt (sbi->s_mount_opt, ERRORS_RO); + clear_opt (sbi->s_mount_opt, ERRORS_PANIC); + set_opt (sbi->s_mount_opt, ERRORS_CONT); } else if (!strcmp (value, "remount-ro")) { - clear_opt (*mount_options, ERRORS_CONT); - clear_opt (*mount_options, ERRORS_PANIC); - set_opt (*mount_options, ERRORS_RO); + clear_opt (sbi->s_mount_opt, ERRORS_CONT); + clear_opt (sbi->s_mount_opt, ERRORS_PANIC); + set_opt (sbi->s_mount_opt, ERRORS_RO); } else if (!strcmp (value, "panic")) { - clear_opt (*mount_options, ERRORS_CONT); - clear_opt (*mount_options, ERRORS_RO); - set_opt (*mount_options, ERRORS_PANIC); + clear_opt (sbi->s_mount_opt, ERRORS_CONT); + clear_opt (sbi->s_mount_opt, ERRORS_RO); + set_opt (sbi->s_mount_opt, ERRORS_PANIC); } else { printk ("EXT2-fs: Invalid errors option: %s\n", @@ -279,53 +366,30 @@ } else if (!strcmp (this_char, "grpid") || !strcmp (this_char, "bsdgroups")) - set_opt (*mount_options, GRPID); + set_opt (sbi->s_mount_opt, GRPID); else if (!strcmp (this_char, "minixdf")) - set_opt (*mount_options, MINIX_DF); + set_opt (sbi->s_mount_opt, MINIX_DF); else if (!strcmp (this_char, "nocheck")) - clear_opt (*mount_options, CHECK); + clear_opt (sbi->s_mount_opt, CHECK); else if (!strcmp (this_char, "nogrpid") || !strcmp (this_char, "sysvgroups")) - clear_opt (*mount_options, GRPID); + clear_opt (sbi->s_mount_opt, GRPID); else if (!strcmp (this_char, "resgid")) { - if (!value || !*value) { - printk ("EXT2-fs: the resgid option requires " - "an argument\n"); + unsigned long v; + if (want_numeric(value, "resgid", &v)) return 0; - } - *resgid = simple_strtoul (value, &value, 0); - if (*value) { - printk ("EXT2-fs: Invalid resgid option: %s\n", - value); - return 0; - } + sbi->s_resgid = v; } else if (!strcmp (this_char, "resuid")) { - if (!value || !*value) { - printk ("EXT2-fs: the resuid option requires " - "an argument"); - return 0; - } - *resuid = simple_strtoul (value, &value, 0); - if (*value) { - printk ("EXT2-fs: Invalid resuid option: %s\n", - value); + unsigned long v; + if (want_numeric(value, "resuid", &v)) return 0; - } - } - else if (!strcmp (this_char, "sb")) { - if (!value || !*value) { - printk ("EXT2-fs: the sb option requires " - "an argument"); - return 0; - } - *sb_block = simple_strtoul (value, &value, 0); - if (*value) { - printk ("EXT2-fs: Invalid sb option: %s\n", - value); - return 0; - } + sbi->s_resuid = v; } + else if (!strcmp (this_char, "oldalloc")) + set_opt (sbi->s_mount_opt, OLDALLOC); + else if (!strcmp (this_char, "orlov")) + clear_opt (sbi->s_mount_opt, OLDALLOC); /* Silently ignore the quota options */ else if (!strcmp (this_char, "grpquota") || !strcmp (this_char, "noquota") @@ -458,16 +522,32 @@ return res; } +static unsigned long descriptor_loc(struct super_block *sb, + unsigned long logic_sb_block, + int nr) +{ + struct ext2_sb_info *sbi = EXT2_SB(sb); + unsigned long bg, first_data_block, first_meta_bg; + + first_data_block = le32_to_cpu(sbi->s_es->s_first_data_block); + first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg); + + if (!EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_META_BG) || + nr < first_meta_bg) + return (logic_sb_block + nr + 1); + bg = sbi->s_desc_per_block * nr; + return (first_data_block + 1 + (bg * sbi->s_blocks_per_group)); +} + static int ext2_fill_super(struct super_block *sb, void *data, int silent) { struct buffer_head * bh; struct ext2_sb_info * sbi; struct ext2_super_block * es; - unsigned long sb_block = 1; - unsigned short resuid = EXT2_DEF_RESUID; - unsigned short resgid = EXT2_DEF_RESGID; - unsigned long logic_sb_block = 1; + unsigned long block, sb_block = 1; + unsigned long logic_sb_block = get_sb_block(&data); unsigned long offset = 0; + unsigned long def_mount_opts; int blocksize = BLOCK_SIZE; int db_count; int i, j; @@ -485,12 +565,6 @@ * This is important for devices that have a hardware * sectorsize that is larger than the default. */ - - sbi->s_mount_opt = 0; - if (!parse_options ((char *) data, &sb_block, &resuid, &resgid, - &sbi->s_mount_opt)) - goto failed_sbi; - blocksize = sb_min_blocksize(sb, BLOCK_SIZE); if (!blocksize) { printk ("EXT2-fs: unable to set blocksize\n"); @@ -498,9 +572,8 @@ } /* - * If the superblock doesn't start on a sector boundary, - * calculate the offset. FIXME(eric) this doesn't make sense - * that we would have to do this. + * If the superblock doesn't start on a hardware sector boundary, + * calculate the offset. */ if (blocksize != BLOCK_SIZE) { logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize; @@ -524,6 +597,35 @@ sb->s_id); goto failed_mount; } + + /* Set defaults before we parse the mount options */ + def_mount_opts = le32_to_cpu(es->s_default_mount_opts); + if (def_mount_opts & EXT2_DEFM_DEBUG) + set_opt(sbi->s_mount_opt, DEBUG); + if (def_mount_opts & EXT2_DEFM_BSDGROUPS) + set_opt(sbi->s_mount_opt, GRPID); + if (def_mount_opts & EXT2_DEFM_UID16) + set_opt(sbi->s_mount_opt, NO_UID32); + if (def_mount_opts & EXT2_DEFM_XATTR_USER) + set_opt(sbi->s_mount_opt, XATTR_USER); + if (def_mount_opts & EXT2_DEFM_ACL) + set_opt(sbi->s_mount_opt, POSIX_ACL); + + if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC) + set_opt(sbi->s_mount_opt, ERRORS_PANIC); + else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_RO) + set_opt(sbi->s_mount_opt, ERRORS_RO); + + sbi->s_resuid = le16_to_cpu(es->s_def_resuid); + sbi->s_resgid = le16_to_cpu(es->s_def_resgid); + + if (!parse_options ((char *) data, sbi)) + goto failed_mount; + + sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | + ((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? + MS_POSIXACL : 0); + if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV && (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) || EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) || @@ -582,7 +684,9 @@ } else { sbi->s_inode_size = le16_to_cpu(es->s_inode_size); sbi->s_first_ino = le32_to_cpu(es->s_first_ino); - if (sbi->s_inode_size != EXT2_GOOD_OLD_INODE_SIZE) { + if ((sbi->s_inode_size < EXT2_GOOD_OLD_INODE_SIZE) || + (sbi->s_inode_size & (sbi->s_inode_size - 1)) || + (sbi->s_inode_size > blocksize)) { printk ("EXT2-fs: unsupported inode size: %d\n", sbi->s_inode_size); goto failed_mount; @@ -605,14 +709,6 @@ sbi->s_desc_per_block = sb->s_blocksize / sizeof (struct ext2_group_desc); sbi->s_sbh = bh; - if (resuid != EXT2_DEF_RESUID) - sbi->s_resuid = resuid; - else - sbi->s_resuid = le16_to_cpu(es->s_def_resuid); - if (resgid != EXT2_DEF_RESGID) - sbi->s_resgid = resgid; - else - sbi->s_resgid = le16_to_cpu(es->s_def_resgid); sbi->s_mount_state = le16_to_cpu(es->s_state); sbi->s_addr_per_block_bits = log2 (EXT2_ADDR_PER_BLOCK(sb)); @@ -665,14 +761,22 @@ printk ("EXT2-fs: not enough memory\n"); goto failed_mount; } + sbi->s_debts = kmalloc(sbi->s_groups_count * sizeof(*sbi->s_debts), + GFP_KERNEL); + if (!sbi->s_debts) { + printk ("EXT2-fs: not enough memory\n"); + goto failed_mount_group_desc; + } + memset(sbi->s_debts, 0, sbi->s_groups_count * sizeof(*sbi->s_debts)); for (i = 0; i < db_count; i++) { - sbi->s_group_desc[i] = sb_bread(sb, logic_sb_block + i + 1); + block = descriptor_loc(sb, logic_sb_block, i); + sbi->s_group_desc[i] = sb_bread(sb, block); if (!sbi->s_group_desc[i]) { for (j = 0; j < i; j++) brelse (sbi->s_group_desc[j]); kfree(sbi->s_group_desc); printk ("EXT2-fs: unable to read group descriptors\n"); - goto failed_mount; + goto failed_mount_group_desc; } } if (!ext2_check_descriptors (sb)) { @@ -681,6 +785,7 @@ goto failed_mount2; } sbi->s_gdb_count = db_count; + sbi->s_dir_count = ext2_count_dirs(sb); get_random_bytes(&sbi->s_next_generation, sizeof(u32)); /* * set up enough so that it can read an inode @@ -706,7 +811,10 @@ failed_mount2: for (i = 0; i < db_count; i++) brelse(sbi->s_group_desc[i]); +failed_mount_group_desc: kfree(sbi->s_group_desc); + if (sbi->s_debts) + kfree(sbi->s_debts); failed_mount: brelse(bh); failed_sbi: @@ -767,22 +875,16 @@ { struct ext2_sb_info * sbi = EXT2_SB(sb); struct ext2_super_block * es; - unsigned short resuid = sbi->s_resuid; - unsigned short resgid = sbi->s_resgid; - unsigned long new_mount_opt; - unsigned long tmp; /* * Allow the "check" option to be passed as a remount option. */ - new_mount_opt = sbi->s_mount_opt; - if (!parse_options (data, &tmp, &resuid, &resgid, - &new_mount_opt)) + if (!parse_options (data, sbi)) return -EINVAL; - sbi->s_mount_opt = new_mount_opt; - sbi->s_resuid = resuid; - sbi->s_resgid = resgid; + sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | + ((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); + es = sbi->s_es; if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) return 0; @@ -883,7 +985,10 @@ static int __init init_ext2_fs(void) { - int err = init_inodecache(); + int err = init_ext2_xattr(); + if (err) + return err; + err = init_inodecache(); if (err) goto out1; err = register_filesystem(&ext2_fs_type); @@ -893,6 +998,7 @@ out: destroy_inodecache(); out1: + exit_ext2_xattr(); return err; } @@ -900,6 +1006,7 @@ { unregister_filesystem(&ext2_fs_type); destroy_inodecache(); + exit_ext2_xattr(); } module_init(init_ext2_fs) diff -Nru a/fs/ext2/symlink.c b/fs/ext2/symlink.c --- a/fs/ext2/symlink.c Mon Nov 4 14:31:01 2002 +++ b/fs/ext2/symlink.c Mon Nov 4 14:31:01 2002 @@ -18,6 +18,7 @@ */ #include "ext2.h" +#include "xattr.h" static int ext2_readlink(struct dentry *dentry, char *buffer, int buflen) { @@ -31,7 +32,20 @@ return vfs_follow_link(nd, (char *)ei->i_data); } +struct inode_operations ext2_symlink_inode_operations = { + .readlink = page_readlink, + .follow_link = page_follow_link, + .setxattr = ext2_setxattr, + .getxattr = ext2_getxattr, + .listxattr = ext2_listxattr, + .removexattr = ext2_removexattr, +}; + struct inode_operations ext2_fast_symlink_inode_operations = { .readlink = ext2_readlink, .follow_link = ext2_follow_link, + .setxattr = ext2_setxattr, + .getxattr = ext2_getxattr, + .listxattr = ext2_listxattr, + .removexattr = ext2_removexattr, }; diff -Nru a/fs/ext2/xattr.c b/fs/ext2/xattr.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/ext2/xattr.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,1135 @@ +/* + * linux/fs/ext2/xattr.c + * + * Copyright (C) 2001 by Andreas Gruenbacher, + * + * Fix by Harrison Xing . + * Extended attributes for symlinks and special files added per + * suggestion of Luka Renko . + */ + +/* + * Extended attributes are stored on disk blocks allocated outside of + * any inode. The i_file_acl field is then made to point to this allocated + * block. If all extended attributes of an inode are identical, these + * inodes may share the same extended attribute block. Such situations + * are automatically detected by keeping a cache of recent attribute block + * numbers and hashes over the block's contents in memory. + * + * + * Extended attribute block layout: + * + * +------------------+ + * | header | + * ¦ entry 1 | | + * | entry 2 | | growing downwards + * | entry 3 | v + * | four null bytes | + * | . . . | + * | value 1 | ^ + * | value 3 | | growing upwards + * | value 2 | | + * +------------------+ + * + * The block header is followed by multiple entry descriptors. These entry + * descriptors are variable in size, and alligned to EXT2_XATTR_PAD + * byte boundaries. The entry descriptors are sorted by attribute name, + * so that two extended attribute blocks can be compared efficiently. + * + * Attribute values are aligned to the end of the block, stored in + * no specific order. They are also padded to EXT2_XATTR_PAD byte + * boundaries. No additional gaps are left between them. + * + * Locking strategy + * ---------------- + * The VFS already holds the BKL and the inode->i_sem semaphore when any of + * the xattr inode operations are called, so we are guaranteed that only one + * processes accesses extended attributes of an inode at any time. + * + * For writing we also grab the ext2_xattr_sem semaphore. This ensures that + * only a single process is modifying an extended attribute block, even + * if the block is shared among inodes. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "ext2.h" +#include "xattr.h" +#include "acl.h" + +/* These symbols may be needed by a module. */ +EXPORT_SYMBOL(ext2_xattr_register); +EXPORT_SYMBOL(ext2_xattr_unregister); +EXPORT_SYMBOL(ext2_xattr_get); +EXPORT_SYMBOL(ext2_xattr_list); +EXPORT_SYMBOL(ext2_xattr_set); + +#define HDR(bh) ((struct ext2_xattr_header *)((bh)->b_data)) +#define ENTRY(ptr) ((struct ext2_xattr_entry *)(ptr)) +#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1) +#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) + +#ifdef EXT2_XATTR_DEBUG +# define ea_idebug(inode, f...) do { \ + printk(KERN_DEBUG "inode %s:%ld: ", \ + kdevname(inode->i_dev), inode->i_ino); \ + printk(f); \ + printk("\n"); \ + } while (0) +# define ea_bdebug(bh, f...) do { \ + printk(KERN_DEBUG "block %s:%ld: ", \ + kdevname(bh->b_dev), bh->b_blocknr); \ + printk(f); \ + printk("\n"); \ + } while (0) +#else +# define ea_idebug(f...) +# define ea_bdebug(f...) +#endif + +static int ext2_xattr_set2(struct inode *, struct buffer_head *, + struct ext2_xattr_header *); + +static int ext2_xattr_cache_insert(struct buffer_head *); +static struct buffer_head *ext2_xattr_cache_find(struct inode *, + struct ext2_xattr_header *); +static void ext2_xattr_cache_remove(struct buffer_head *); +static void ext2_xattr_rehash(struct ext2_xattr_header *, + struct ext2_xattr_entry *); + +static struct mb_cache *ext2_xattr_cache; + +/* + * If a file system does not share extended attributes among inodes, + * we should not need the ext2_xattr_sem semaphore. However, the + * filesystem may still contain shared blocks, so we always take + * the lock. + */ + +static DECLARE_MUTEX(ext2_xattr_sem); +static struct ext2_xattr_handler *ext2_xattr_handlers[EXT2_XATTR_INDEX_MAX]; +static rwlock_t ext2_handler_lock = RW_LOCK_UNLOCKED; + +int +ext2_xattr_register(int name_index, struct ext2_xattr_handler *handler) +{ + int error = -EINVAL; + + if (name_index > 0 && name_index <= EXT2_XATTR_INDEX_MAX) { + write_lock(&ext2_handler_lock); + if (!ext2_xattr_handlers[name_index-1]) { + ext2_xattr_handlers[name_index-1] = handler; + error = 0; + } + write_unlock(&ext2_handler_lock); + } + return error; +} + +void +ext2_xattr_unregister(int name_index, struct ext2_xattr_handler *handler) +{ + if (name_index > 0 || name_index <= EXT2_XATTR_INDEX_MAX) { + write_lock(&ext2_handler_lock); + ext2_xattr_handlers[name_index-1] = NULL; + write_unlock(&ext2_handler_lock); + } +} + +static inline const char * +strcmp_prefix(const char *a, const char *a_prefix) +{ + while (*a_prefix && *a == *a_prefix) { + a++; + a_prefix++; + } + return *a_prefix ? NULL : a; +} + +/* + * Decode the extended attribute name, and translate it into + * the name_index and name suffix. + */ +static struct ext2_xattr_handler * +ext2_xattr_resolve_name(const char **name) +{ + struct ext2_xattr_handler *handler = NULL; + int i; + + if (!*name) + return NULL; + read_lock(&ext2_handler_lock); + for (i=0; iprefix); + if (n) { + handler = ext2_xattr_handlers[i]; + *name = n; + break; + } + } + } + read_unlock(&ext2_handler_lock); + return handler; +} + +static inline struct ext2_xattr_handler * +ext2_xattr_handler(int name_index) +{ + struct ext2_xattr_handler *handler = NULL; + if (name_index > 0 && name_index <= EXT2_XATTR_INDEX_MAX) { + read_lock(&ext2_handler_lock); + handler = ext2_xattr_handlers[name_index-1]; + read_unlock(&ext2_handler_lock); + } + return handler; +} + +/* + * Inode operation getxattr() + * + * dentry->d_inode->i_sem down + * BKL held [before 2.5.x] + */ +ssize_t +ext2_getxattr(struct dentry *dentry, const char *name, + void *buffer, size_t size) +{ + struct ext2_xattr_handler *handler; + struct inode *inode = dentry->d_inode; + + handler = ext2_xattr_resolve_name(&name); + if (!handler) + return -EOPNOTSUPP; + return handler->get(inode, name, buffer, size); +} + +/* + * Inode operation listxattr() + * + * dentry->d_inode->i_sem down + * BKL held [before 2.5.x] + */ +ssize_t +ext2_listxattr(struct dentry *dentry, char *buffer, size_t size) +{ + return ext2_xattr_list(dentry->d_inode, buffer, size); +} + +/* + * Inode operation setxattr() + * + * dentry->d_inode->i_sem down + * BKL held [before 2.5.x] + */ +int +ext2_setxattr(struct dentry *dentry, const char *name, + void *value, size_t size, int flags) +{ + struct ext2_xattr_handler *handler; + struct inode *inode = dentry->d_inode; + + if (size == 0) + value = ""; /* empty EA, do not remove */ + handler = ext2_xattr_resolve_name(&name); + if (!handler) + return -EOPNOTSUPP; + return handler->set(inode, name, value, size, flags); +} + +/* + * Inode operation removexattr() + * + * dentry->d_inode->i_sem down + * BKL held [before 2.5.x] + */ +int +ext2_removexattr(struct dentry *dentry, const char *name) +{ + struct ext2_xattr_handler *handler; + struct inode *inode = dentry->d_inode; + + handler = ext2_xattr_resolve_name(&name); + if (!handler) + return -EOPNOTSUPP; + return handler->set(inode, name, NULL, 0, XATTR_REPLACE); +} + +/* + * ext2_xattr_get() + * + * Copy an extended attribute into the buffer + * provided, or compute the buffer size required. + * Buffer is NULL to compute the size of the buffer required. + * + * Returns a negative error number on failure, or the number of bytes + * used / required on success. + */ +int +ext2_xattr_get(struct inode *inode, int name_index, const char *name, + void *buffer, size_t buffer_size) +{ + struct buffer_head *bh = NULL; + struct ext2_xattr_entry *entry; + unsigned int size; + char *end; + int name_len, error; + + ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", + name_index, name, buffer, (long)buffer_size); + + if (name == NULL) + return -EINVAL; + if (!EXT2_I(inode)->i_file_acl) + return -ENODATA; + ea_idebug(inode, "reading block %d", EXT2_I(inode)->i_file_acl); + bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl); + if (!bh) + return -EIO; + ea_bdebug(bh, "b_count=%d, refcount=%d", + atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); + end = bh->b_data + bh->b_size; + if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || + HDR(bh)->h_blocks != cpu_to_le32(1)) { +bad_block: ext2_error(inode->i_sb, "ext2_xattr_get", + "inode %ld: bad block %d", inode->i_ino, + EXT2_I(inode)->i_file_acl); + error = -EIO; + goto cleanup; + } + /* find named attribute */ + name_len = strlen(name); + + error = -ERANGE; + if (name_len > 255) + goto cleanup; + entry = FIRST_ENTRY(bh); + while (!IS_LAST_ENTRY(entry)) { + struct ext2_xattr_entry *next = + EXT2_XATTR_NEXT(entry); + if ((char *)next >= end) + goto bad_block; + if (name_index == entry->e_name_index && + name_len == entry->e_name_len && + memcmp(name, entry->e_name, name_len) == 0) + goto found; + entry = next; + } + /* Check the remaining name entries */ + while (!IS_LAST_ENTRY(entry)) { + struct ext2_xattr_entry *next = + EXT2_XATTR_NEXT(entry); + if ((char *)next >= end) + goto bad_block; + entry = next; + } + if (ext2_xattr_cache_insert(bh)) + ea_idebug(inode, "cache insert failed"); + error = -ENODATA; + goto cleanup; +found: + /* check the buffer size */ + if (entry->e_value_block != 0) + goto bad_block; + size = le32_to_cpu(entry->e_value_size); + if (size > inode->i_sb->s_blocksize || + le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize) + goto bad_block; + + if (ext2_xattr_cache_insert(bh)) + ea_idebug(inode, "cache insert failed"); + if (buffer) { + error = -ERANGE; + if (size > buffer_size) + goto cleanup; + /* return value of attribute */ + memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs), + size); + } + error = size; + +cleanup: + brelse(bh); + + return error; +} + +/* + * ext2_xattr_list() + * + * Copy a list of attribute names into the buffer + * provided, or compute the buffer size required. + * Buffer is NULL to compute the size of the buffer required. + * + * Returns a negative error number on failure, or the number of bytes + * used / required on success. + */ +int +ext2_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) +{ + struct buffer_head *bh = NULL; + struct ext2_xattr_entry *entry; + unsigned int size = 0; + char *buf, *end; + int error; + + ea_idebug(inode, "buffer=%p, buffer_size=%ld", + buffer, (long)buffer_size); + + if (!EXT2_I(inode)->i_file_acl) + return 0; + ea_idebug(inode, "reading block %d", EXT2_I(inode)->i_file_acl); + bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl); + if (!bh) + return -EIO; + ea_bdebug(bh, "b_count=%d, refcount=%d", + atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); + end = bh->b_data + bh->b_size; + if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || + HDR(bh)->h_blocks != cpu_to_le32(1)) { +bad_block: ext2_error(inode->i_sb, "ext2_xattr_list", + "inode %ld: bad block %d", inode->i_ino, + EXT2_I(inode)->i_file_acl); + error = -EIO; + goto cleanup; + } + /* compute the size required for the list of attribute names */ + for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry); + entry = EXT2_XATTR_NEXT(entry)) { + struct ext2_xattr_handler *handler; + struct ext2_xattr_entry *next = + EXT2_XATTR_NEXT(entry); + if ((char *)next >= end) + goto bad_block; + + handler = ext2_xattr_handler(entry->e_name_index); + if (handler) { + size += handler->list(NULL, inode, entry->e_name, + entry->e_name_len) + 1; + } + } + + if (ext2_xattr_cache_insert(bh)) + ea_idebug(inode, "cache insert failed"); + if (!buffer) { + error = size; + goto cleanup; + } else { + error = -ERANGE; + if (size > buffer_size) + goto cleanup; + } + + /* list the attribute names */ + buf = buffer; + for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry); + entry = EXT2_XATTR_NEXT(entry)) { + struct ext2_xattr_handler *handler; + + handler = ext2_xattr_handler(entry->e_name_index); + if (handler) { + buf += handler->list(buf, inode, entry->e_name, + entry->e_name_len); + *buf++ = '\0'; + } + } + error = size; + +cleanup: + brelse(bh); + + return error; +} + +/* + * If the EXT2_FEATURE_COMPAT_EXT_ATTR feature of this file system is + * not set, set it. + */ +static void ext2_xattr_update_super_block(struct super_block *sb) +{ + if (EXT2_HAS_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_EXT_ATTR)) + return; + + lock_super(sb); + EXT2_SB(sb)->s_es->s_feature_compat |= + cpu_to_le32(EXT2_FEATURE_COMPAT_EXT_ATTR); + sb->s_dirt = 1; + mark_buffer_dirty(EXT2_SB(sb)->s_sbh); + unlock_super(sb); +} + +/* + * ext2_xattr_set() + * + * Create, replace or remove an extended attribute for this inode. Buffer + * is NULL to remove an existing extended attribute, and non-NULL to + * either replace an existing extended attribute, or create a new extended + * attribute. The flags XATTR_REPLACE and XATTR_CREATE + * specify that an extended attribute must exist and must not exist + * previous to the call, respectively. + * + * Returns 0, or a negative error number on failure. + */ +int +ext2_xattr_set(struct inode *inode, int name_index, const char *name, + const void *value, size_t value_len, int flags) +{ + struct super_block *sb = inode->i_sb; + struct buffer_head *bh = NULL; + struct ext2_xattr_header *header = NULL; + struct ext2_xattr_entry *here, *last; + unsigned int name_len; + int min_offs = sb->s_blocksize, not_found = 1, free, error; + char *end; + + /* + * header -- Points either into bh, or to a temporarily + * allocated buffer. + * here -- The named entry found, or the place for inserting, within + * the block pointed to by header. + * last -- Points right after the last named entry within the block + * pointed to by header. + * min_offs -- The offset of the first value (values are aligned + * towards the end of the block). + * end -- Points right after the block pointed to by header. + */ + + ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", + name_index, name, value, (long)value_len); + + if (IS_RDONLY(inode)) + return -EROFS; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + return -EPERM; + if (value == NULL) + value_len = 0; + if (name == NULL) + return -EINVAL; + name_len = strlen(name); + if (name_len > 255 || value_len > sb->s_blocksize) + return -ERANGE; + down(&ext2_xattr_sem); + + if (EXT2_I(inode)->i_file_acl) { + /* The inode already has an extended attribute block. */ + bh = sb_bread(sb, EXT2_I(inode)->i_file_acl); + error = -EIO; + if (!bh) + goto cleanup; + ea_bdebug(bh, "b_count=%d, refcount=%d", + atomic_read(&(bh->b_count)), + le32_to_cpu(HDR(bh)->h_refcount)); + header = HDR(bh); + end = bh->b_data + bh->b_size; + if (header->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || + header->h_blocks != cpu_to_le32(1)) { +bad_block: ext2_error(sb, "ext2_xattr_set", + "inode %ld: bad block %d", inode->i_ino, + EXT2_I(inode)->i_file_acl); + error = -EIO; + goto cleanup; + } + /* Find the named attribute. */ + here = FIRST_ENTRY(bh); + while (!IS_LAST_ENTRY(here)) { + struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(here); + if ((char *)next >= end) + goto bad_block; + if (!here->e_value_block && here->e_value_size) { + int offs = le16_to_cpu(here->e_value_offs); + if (offs < min_offs) + min_offs = offs; + } + not_found = name_index - here->e_name_index; + if (!not_found) + not_found = name_len - here->e_name_len; + if (!not_found) + not_found = memcmp(name, here->e_name,name_len); + if (not_found <= 0) + break; + here = next; + } + last = here; + /* We still need to compute min_offs and last. */ + while (!IS_LAST_ENTRY(last)) { + struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(last); + if ((char *)next >= end) + goto bad_block; + if (!last->e_value_block && last->e_value_size) { + int offs = le16_to_cpu(last->e_value_offs); + if (offs < min_offs) + min_offs = offs; + } + last = next; + } + + /* Check whether we have enough space left. */ + free = min_offs - ((char*)last - (char*)header) - sizeof(__u32); + } else { + /* We will use a new extended attribute block. */ + free = sb->s_blocksize - + sizeof(struct ext2_xattr_header) - sizeof(__u32); + here = last = NULL; /* avoid gcc uninitialized warning. */ + } + + if (not_found) { + /* Request to remove a nonexistent attribute? */ + error = -ENODATA; + if (flags & XATTR_REPLACE) + goto cleanup; + error = 0; + if (value == NULL) + goto cleanup; + else + free -= EXT2_XATTR_LEN(name_len); + } else { + /* Request to create an existing attribute? */ + error = -EEXIST; + if (flags & XATTR_CREATE) + goto cleanup; + if (!here->e_value_block && here->e_value_size) { + unsigned int size = le32_to_cpu(here->e_value_size); + + if (le16_to_cpu(here->e_value_offs) + size > + sb->s_blocksize || size > sb->s_blocksize) + goto bad_block; + free += EXT2_XATTR_SIZE(size); + } + } + free -= EXT2_XATTR_SIZE(value_len); + error = -ENOSPC; + if (free < 0) + goto cleanup; + + /* Here we know that we can set the new attribute. */ + + if (header) { + if (header->h_refcount == cpu_to_le32(1)) { + ea_bdebug(bh, "modifying in-place"); + ext2_xattr_cache_remove(bh); + } else { + int offset; + + ea_bdebug(bh, "cloning"); + header = kmalloc(bh->b_size, GFP_KERNEL); + error = -ENOMEM; + if (header == NULL) + goto cleanup; + memcpy(header, HDR(bh), bh->b_size); + header->h_refcount = cpu_to_le32(1); + offset = (char *)header - bh->b_data; + here = ENTRY((char *)here + offset); + last = ENTRY((char *)last + offset); + } + } else { + /* Allocate a buffer where we construct the new block. */ + header = kmalloc(sb->s_blocksize, GFP_KERNEL); + error = -ENOMEM; + if (header == NULL) + goto cleanup; + memset(header, 0, sb->s_blocksize); + end = (char *)header + sb->s_blocksize; + header->h_magic = cpu_to_le32(EXT2_XATTR_MAGIC); + header->h_blocks = header->h_refcount = cpu_to_le32(1); + last = here = ENTRY(header+1); + } + + if (not_found) { + /* Insert the new name. */ + int size = EXT2_XATTR_LEN(name_len); + int rest = (char *)last - (char *)here; + memmove((char *)here + size, here, rest); + memset(here, 0, size); + here->e_name_index = name_index; + here->e_name_len = name_len; + memcpy(here->e_name, name, name_len); + } else { + /* Remove the old value. */ + if (!here->e_value_block && here->e_value_size) { + char *first_val = (char *)header + min_offs; + int offs = le16_to_cpu(here->e_value_offs); + char *val = (char *)header + offs; + size_t size = EXT2_XATTR_SIZE( + le32_to_cpu(here->e_value_size)); + memmove(first_val + size, first_val, val - first_val); + memset(first_val, 0, size); + here->e_value_offs = 0; + min_offs += size; + + /* Adjust all value offsets. */ + last = ENTRY(header+1); + while (!IS_LAST_ENTRY(last)) { + int o = le16_to_cpu(last->e_value_offs); + if (!last->e_value_block && o < offs) + last->e_value_offs = + cpu_to_le16(o + size); + last = EXT2_XATTR_NEXT(last); + } + } + if (value == NULL) { + /* Remove this attribute. */ + if (EXT2_XATTR_NEXT(ENTRY(header+1)) == last) { + /* This block is now empty. */ + error = ext2_xattr_set2(inode, bh, NULL); + goto cleanup; + } else { + /* Remove the old name. */ + int size = EXT2_XATTR_LEN(name_len); + last = ENTRY((char *)last - size); + memmove(here, (char*)here + size, + (char*)last - (char*)here); + memset(last, 0, size); + } + } + } + + if (value != NULL) { + /* Insert the new value. */ + here->e_value_size = cpu_to_le32(value_len); + if (value_len) { + size_t size = EXT2_XATTR_SIZE(value_len); + char *val = (char *)header + min_offs - size; + here->e_value_offs = + cpu_to_le16((char *)val - (char *)header); + memset(val + size - EXT2_XATTR_PAD, 0, + EXT2_XATTR_PAD); /* Clear the pad bytes. */ + memcpy(val, value, value_len); + } + } + ext2_xattr_rehash(header, here); + + error = ext2_xattr_set2(inode, bh, header); + +cleanup: + brelse(bh); + if (!(bh && header == HDR(bh))) + kfree(header); + up(&ext2_xattr_sem); + + return error; +} + +/* + * Second half of ext2_xattr_set(): Update the file system. + */ +static int +ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, + struct ext2_xattr_header *header) +{ + struct super_block *sb = inode->i_sb; + struct buffer_head *new_bh = NULL; + int error; + + if (header) { + new_bh = ext2_xattr_cache_find(inode, header); + if (new_bh) { + /* + * We found an identical block in the cache. + * The old block will be released after updating + * the inode. + */ + ea_bdebug(old_bh, "reusing block %ld", + new_bh->b_blocknr); + + error = -EDQUOT; + if (DQUOT_ALLOC_BLOCK(inode, 1)) + goto cleanup; + + HDR(new_bh)->h_refcount = cpu_to_le32( + le32_to_cpu(HDR(new_bh)->h_refcount) + 1); + ea_bdebug(new_bh, "refcount now=%d", + le32_to_cpu(HDR(new_bh)->h_refcount)); + } else if (old_bh && header == HDR(old_bh)) { + /* Keep this block. */ + new_bh = old_bh; + ext2_xattr_cache_insert(new_bh); + } else { + /* We need to allocate a new block */ + int goal = le32_to_cpu(EXT2_SB(sb)->s_es->s_first_data_block) + + EXT2_I(inode)->i_block_group * EXT2_BLOCKS_PER_GROUP(sb); + int block = ext2_new_block(inode, goal, 0, 0, &error); + if (error) + goto cleanup; + ea_idebug(inode, "creating block %d", block); + + new_bh = sb_getblk(sb, block); + if (!new_bh) { + ext2_free_blocks(inode, block, 1); + error = -EIO; + goto cleanup; + } + lock_buffer(new_bh); + memcpy(new_bh->b_data, header, new_bh->b_size); + set_buffer_uptodate(new_bh); + unlock_buffer(new_bh); + ext2_xattr_cache_insert(new_bh); + + ext2_xattr_update_super_block(sb); + } + mark_buffer_dirty(new_bh); + if (IS_SYNC(inode)) { + ll_rw_block(WRITE, 1, &new_bh); + wait_on_buffer(new_bh); + error = -EIO; + if (buffer_req(new_bh) && !buffer_uptodate(new_bh)) + goto cleanup; + } + } + + /* Update the inode. */ + EXT2_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0; + inode->i_ctime = CURRENT_TIME; + if (IS_SYNC(inode)) { + error = ext2_sync_inode (inode); + if (error) + goto cleanup; + } else + mark_inode_dirty(inode); + + error = 0; + if (old_bh && old_bh != new_bh) { + /* + * If there was an old block, and we are not still using it, + * we now release the old block. + */ + unsigned int refcount = le32_to_cpu(HDR(old_bh)->h_refcount); + + if (refcount == 1) { + /* Free the old block. */ + ea_bdebug(old_bh, "freeing"); + ext2_free_blocks(inode, old_bh->b_blocknr, 1); + /* We let our caller release old_bh, so we + * need to duplicate the buffer before. */ + get_bh(old_bh); + bforget(old_bh); + } else { + /* Decrement the refcount only. */ + refcount--; + HDR(old_bh)->h_refcount = cpu_to_le32(refcount); + DQUOT_FREE_BLOCK(inode, 1); + mark_buffer_dirty(old_bh); + ea_bdebug(old_bh, "refcount now=%d", refcount); + } + } + +cleanup: + if (old_bh != new_bh) + brelse(new_bh); + + return error; +} + +/* + * ext2_xattr_delete_inode() + * + * Free extended attribute resources associated with this inode. This + * is called immediately before an inode is freed. + */ +void +ext2_xattr_delete_inode(struct inode *inode) +{ + struct buffer_head *bh; + + if (!EXT2_I(inode)->i_file_acl) + return; + down(&ext2_xattr_sem); + + bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl); + if (!bh) { + ext2_error(inode->i_sb, "ext2_xattr_delete_inode", + "inode %ld: block %d read error", inode->i_ino, + EXT2_I(inode)->i_file_acl); + goto cleanup; + } + ea_bdebug(bh, "b_count=%d", atomic_read(&(bh->b_count))); + if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || + HDR(bh)->h_blocks != cpu_to_le32(1)) { + ext2_error(inode->i_sb, "ext2_xattr_delete_inode", + "inode %ld: bad block %d", inode->i_ino, + EXT2_I(inode)->i_file_acl); + goto cleanup; + } + ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1); + if (HDR(bh)->h_refcount == cpu_to_le32(1)) { + ext2_xattr_cache_remove(bh); + ext2_free_blocks(inode, EXT2_I(inode)->i_file_acl, 1); + bforget(bh); + bh = NULL; + } else { + HDR(bh)->h_refcount = cpu_to_le32( + le32_to_cpu(HDR(bh)->h_refcount) - 1); + mark_buffer_dirty(bh); + if (IS_SYNC(inode)) { + ll_rw_block(WRITE, 1, &bh); + wait_on_buffer(bh); + } + DQUOT_FREE_BLOCK(inode, 1); + } + EXT2_I(inode)->i_file_acl = 0; + +cleanup: + brelse(bh); + up(&ext2_xattr_sem); +} + +/* + * ext2_xattr_put_super() + * + * This is called when a file system is unmounted. + */ +void +ext2_xattr_put_super(struct super_block *sb) +{ + mb_cache_shrink(ext2_xattr_cache, sb->s_bdev); +} + + +/* + * ext2_xattr_cache_insert() + * + * Create a new entry in the extended attribute cache, and insert + * it unless such an entry is already in the cache. + * + * Returns 0, or a negative error number on failure. + */ +static int +ext2_xattr_cache_insert(struct buffer_head *bh) +{ + __u32 hash = le32_to_cpu(HDR(bh)->h_hash); + struct mb_cache_entry *ce; + int error; + + ce = mb_cache_entry_alloc(ext2_xattr_cache); + if (!ce) + return -ENOMEM; + error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash); + if (error) { + mb_cache_entry_free(ce); + if (error == -EBUSY) { + ea_bdebug(bh, "already in cache (%d cache entries)", + atomic_read(&ext2_xattr_cache->c_entry_count)); + error = 0; + } + } else { + ea_bdebug(bh, "inserting [%x] (%d cache entries)", (int)hash, + atomic_read(&ext2_xattr_cache->c_entry_count)); + mb_cache_entry_release(ce); + } + return error; +} + +/* + * ext2_xattr_cmp() + * + * Compare two extended attribute blocks for equality. + * + * Returns 0 if the blocks are equal, 1 if they differ, and + * a negative error number on errors. + */ +static int +ext2_xattr_cmp(struct ext2_xattr_header *header1, + struct ext2_xattr_header *header2) +{ + struct ext2_xattr_entry *entry1, *entry2; + + entry1 = ENTRY(header1+1); + entry2 = ENTRY(header2+1); + while (!IS_LAST_ENTRY(entry1)) { + if (IS_LAST_ENTRY(entry2)) + return 1; + if (entry1->e_hash != entry2->e_hash || + entry1->e_name_len != entry2->e_name_len || + entry1->e_value_size != entry2->e_value_size || + memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len)) + return 1; + if (entry1->e_value_block != 0 || entry2->e_value_block != 0) + return -EIO; + if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs), + (char *)header2 + le16_to_cpu(entry2->e_value_offs), + le32_to_cpu(entry1->e_value_size))) + return 1; + + entry1 = EXT2_XATTR_NEXT(entry1); + entry2 = EXT2_XATTR_NEXT(entry2); + } + if (!IS_LAST_ENTRY(entry2)) + return 1; + return 0; +} + +/* + * ext2_xattr_cache_find() + * + * Find an identical extended attribute block. + * + * Returns a pointer to the block found, or NULL if such a block was + * not found or an error occurred. + */ +static struct buffer_head * +ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header) +{ + __u32 hash = le32_to_cpu(header->h_hash); + struct mb_cache_entry *ce; + + if (!header->h_hash) + return NULL; /* never share */ + ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); + ce = mb_cache_entry_find_first(ext2_xattr_cache, 0, inode->i_bdev, hash); + while (ce) { + struct buffer_head *bh = sb_bread(inode->i_sb, ce->e_block); + + if (!bh) { + ext2_error(inode->i_sb, "ext2_xattr_cache_find", + "inode %ld: block %ld read error", + inode->i_ino, (unsigned long) ce->e_block); + } else if (le32_to_cpu(HDR(bh)->h_refcount) > + EXT2_XATTR_REFCOUNT_MAX) { + ea_idebug(inode, "block %ld refcount %d>%d", + (unsigned long) ce->e_block, + le32_to_cpu(HDR(bh)->h_refcount), + EXT2_XATTR_REFCOUNT_MAX); + } else if (!ext2_xattr_cmp(header, HDR(bh))) { + ea_bdebug(bh, "b_count=%d",atomic_read(&(bh->b_count))); + mb_cache_entry_release(ce); + return bh; + } + brelse(bh); + ce = mb_cache_entry_find_next(ce, 0, inode->i_bdev, hash); + } + return NULL; +} + +/* + * ext2_xattr_cache_remove() + * + * Remove the cache entry of a block from the cache. Called when a + * block becomes invalid. + */ +static void +ext2_xattr_cache_remove(struct buffer_head *bh) +{ + struct mb_cache_entry *ce; + + ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev, bh->b_blocknr); + if (ce) { + ea_bdebug(bh, "removing (%d cache entries remaining)", + atomic_read(&ext2_xattr_cache->c_entry_count)-1); + mb_cache_entry_free(ce); + } else + ea_bdebug(bh, "no cache entry"); +} + +#define NAME_HASH_SHIFT 5 +#define VALUE_HASH_SHIFT 16 + +/* + * ext2_xattr_hash_entry() + * + * Compute the hash of an extended attribute. + */ +static inline void ext2_xattr_hash_entry(struct ext2_xattr_header *header, + struct ext2_xattr_entry *entry) +{ + __u32 hash = 0; + char *name = entry->e_name; + int n; + + for (n=0; n < entry->e_name_len; n++) { + hash = (hash << NAME_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^ + *name++; + } + + if (entry->e_value_block == 0 && entry->e_value_size != 0) { + __u32 *value = (__u32 *)((char *)header + + le16_to_cpu(entry->e_value_offs)); + for (n = (le32_to_cpu(entry->e_value_size) + + EXT2_XATTR_ROUND) >> EXT2_XATTR_PAD_BITS; n; n--) { + hash = (hash << VALUE_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^ + le32_to_cpu(*value++); + } + } + entry->e_hash = cpu_to_le32(hash); +} + +#undef NAME_HASH_SHIFT +#undef VALUE_HASH_SHIFT + +#define BLOCK_HASH_SHIFT 16 + +/* + * ext2_xattr_rehash() + * + * Re-compute the extended attribute hash value after an entry has changed. + */ +static void ext2_xattr_rehash(struct ext2_xattr_header *header, + struct ext2_xattr_entry *entry) +{ + struct ext2_xattr_entry *here; + __u32 hash = 0; + + ext2_xattr_hash_entry(header, entry); + here = ENTRY(header+1); + while (!IS_LAST_ENTRY(here)) { + if (!here->e_hash) { + /* Block is not shared if an entry's hash value == 0 */ + hash = 0; + break; + } + hash = (hash << BLOCK_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^ + le32_to_cpu(here->e_hash); + here = EXT2_XATTR_NEXT(here); + } + header->h_hash = cpu_to_le32(hash); +} + +#undef BLOCK_HASH_SHIFT + +int __init +init_ext2_xattr(void) +{ + int err; + + err = ext2_xattr_register(EXT2_XATTR_INDEX_USER, &ext2_xattr_user_handler); + if (err) + return err; +#ifdef CONFIG_EXT2_FS_POSIX_ACL + err = init_ext2_acl(); + if (err) + goto out; +#endif + ext2_xattr_cache = mb_cache_create("ext2_xattr", NULL, + sizeof(struct mb_cache_entry) + + sizeof(struct mb_cache_entry_index), 1, 6); + if (!ext2_xattr_cache) { + err = -ENOMEM; + goto out1; + } + return 0; +out1: +#ifdef CONFIG_EXT2_FS_POSIX_ACL + exit_ext2_acl(); +out: +#endif + ext2_xattr_unregister(EXT2_XATTR_INDEX_USER, + &ext2_xattr_user_handler); + return err; +} + +void +exit_ext2_xattr(void) +{ + mb_cache_destroy(ext2_xattr_cache); +#ifdef CONFIG_EXT2_FS_POSIX_ACL + exit_ext2_acl(); +#endif + ext2_xattr_unregister(EXT2_XATTR_INDEX_USER, &ext2_xattr_user_handler); +} diff -Nru a/fs/ext2/xattr.h b/fs/ext2/xattr.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/ext2/xattr.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,135 @@ +/* + File: linux/ext2_xattr.h + + On-disk format of extended attributes for the ext2 filesystem. + + (C) 2001 Andreas Gruenbacher, +*/ + +#include +#include +#include + +/* Magic value in attribute blocks */ +#define EXT2_XATTR_MAGIC 0xEA020000 + +/* Maximum number of references to one attribute block */ +#define EXT2_XATTR_REFCOUNT_MAX 1024 + +/* Name indexes */ +#define EXT2_XATTR_INDEX_MAX 10 +#define EXT2_XATTR_INDEX_USER 1 +#define EXT2_XATTR_INDEX_POSIX_ACL_ACCESS 2 +#define EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT 3 + +struct ext2_xattr_header { + __u32 h_magic; /* magic number for identification */ + __u32 h_refcount; /* reference count */ + __u32 h_blocks; /* number of disk blocks used */ + __u32 h_hash; /* hash value of all attributes */ + __u32 h_reserved[4]; /* zero right now */ +}; + +struct ext2_xattr_entry { + __u8 e_name_len; /* length of name */ + __u8 e_name_index; /* attribute name index */ + __u16 e_value_offs; /* offset in disk block of value */ + __u32 e_value_block; /* disk block attribute is stored on (n/i) */ + __u32 e_value_size; /* size of attribute value */ + __u32 e_hash; /* hash value of name and value */ + char e_name[0]; /* attribute name */ +}; + +#define EXT2_XATTR_PAD_BITS 2 +#define EXT2_XATTR_PAD (1<e_name_len)) ) +#define EXT2_XATTR_SIZE(size) \ + (((size) + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND) + +# ifdef CONFIG_EXT2_FS_XATTR + +struct ext2_xattr_handler { + char *prefix; + size_t (*list)(char *list, struct inode *inode, const char *name, + int name_len); + int (*get)(struct inode *inode, const char *name, void *buffer, + size_t size); + int (*set)(struct inode *inode, const char *name, const void *buffer, + size_t size, int flags); +}; + +extern int ext2_xattr_register(int, struct ext2_xattr_handler *); +extern void ext2_xattr_unregister(int, struct ext2_xattr_handler *); + +extern int ext2_setxattr(struct dentry *, const char *, void *, size_t, int); +extern ssize_t ext2_getxattr(struct dentry *, const char *, void *, size_t); +extern ssize_t ext2_listxattr(struct dentry *, char *, size_t); +extern int ext2_removexattr(struct dentry *, const char *); + +extern int ext2_xattr_get(struct inode *, int, const char *, void *, size_t); +extern int ext2_xattr_list(struct inode *, char *, size_t); +extern int ext2_xattr_set(struct inode *, int, const char *, const void *, size_t, int); + +extern void ext2_xattr_delete_inode(struct inode *); +extern void ext2_xattr_put_super(struct super_block *); + +extern int init_ext2_xattr(void); +extern void exit_ext2_xattr(void); + +# else /* CONFIG_EXT2_FS_XATTR */ +# define ext2_setxattr NULL +# define ext2_getxattr NULL +# define ext2_listxattr NULL +# define ext2_removexattr NULL + +static inline int +ext2_xattr_get(struct inode *inode, int name_index, + const char *name, void *buffer, size_t size) +{ + return -EOPNOTSUPP; +} + +static inline int +ext2_xattr_list(struct inode *inode, char *buffer, size_t size) +{ + return -EOPNOTSUPP; +} + +static inline int +ext2_xattr_set(struct inode *inode, int name_index, const char *name, + const void *value, size_t size, int flags) +{ + return -EOPNOTSUPP; +} + +static inline void +ext2_xattr_delete_inode(struct inode *inode) +{ +} + +static inline void +ext2_xattr_put_super(struct super_block *sb) +{ +} + +static inline int +init_ext2_xattr(void) +{ + return 0; +} + +static inline void +exit_ext2_xattr(void) +{ +} + +# endif /* CONFIG_EXT2_FS_XATTR */ + +extern struct ext2_xattr_handler ext2_xattr_user_handler; + diff -Nru a/fs/ext2/xattr_user.c b/fs/ext2/xattr_user.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/ext2/xattr_user.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,102 @@ +/* + * linux/fs/ext2/xattr_user.c + * Handler for extended user attributes. + * + * Copyright (C) 2001 by Andreas Gruenbacher, + */ + +#include +#include +#include +#include "ext2.h" +#include "xattr.h" + +#ifdef CONFIG_EXT2_FS_POSIX_ACL +# include "acl.h" +#endif + +#define XATTR_USER_PREFIX "user." + +static size_t +ext2_xattr_user_list(char *list, struct inode *inode, + const char *name, int name_len) +{ + const int prefix_len = sizeof(XATTR_USER_PREFIX)-1; + + if (!test_opt(inode->i_sb, XATTR_USER)) + return 0; + + if (list) { + memcpy(list, XATTR_USER_PREFIX, prefix_len); + memcpy(list+prefix_len, name, name_len); + } + return prefix_len + name_len; +} + +static int +ext2_xattr_user_get(struct inode *inode, const char *name, + void *buffer, size_t size) +{ + int error; + + if (strcmp(name, "") == 0) + return -EINVAL; + if (!test_opt(inode->i_sb, XATTR_USER)) + return -EOPNOTSUPP; +#ifdef CONFIG_EXT2_FS_POSIX_ACL + error = ext2_permission_locked(inode, MAY_READ); +#else + error = permission(inode, MAY_READ); +#endif + if (error) + return error; + + return ext2_xattr_get(inode, EXT2_XATTR_INDEX_USER, name, + buffer, size); +} + +static int +ext2_xattr_user_set(struct inode *inode, const char *name, + const void *value, size_t size, int flags) +{ + int error; + + if (strcmp(name, "") == 0) + return -EINVAL; + if (!test_opt(inode->i_sb, XATTR_USER)) + return -EOPNOTSUPP; + if ( !S_ISREG(inode->i_mode) && + (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX)) + return -EPERM; +#ifdef CONFIG_EXT2_FS_POSIX_ACL + error = ext2_permission_locked(inode, MAY_WRITE); +#else + error = permission(inode, MAY_WRITE); +#endif + if (error) + return error; + + return ext2_xattr_set(inode, EXT2_XATTR_INDEX_USER, name, + value, size, flags); +} + +struct ext2_xattr_handler ext2_xattr_user_handler = { + prefix: XATTR_USER_PREFIX, + list: ext2_xattr_user_list, + get: ext2_xattr_user_get, + set: ext2_xattr_user_set, +}; + +int __init +init_ext2_xattr_user(void) +{ + return ext2_xattr_register(EXT2_XATTR_INDEX_USER, + &ext2_xattr_user_handler); +} + +void +exit_ext2_xattr_user(void) +{ + ext2_xattr_unregister(EXT2_XATTR_INDEX_USER, + &ext2_xattr_user_handler); +} diff -Nru a/fs/ext3/Makefile b/fs/ext3/Makefile --- a/fs/ext3/Makefile Mon Nov 4 14:31:00 2002 +++ b/fs/ext3/Makefile Mon Nov 4 14:31:00 2002 @@ -7,4 +7,14 @@ ext3-objs := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ ioctl.o namei.o super.o symlink.o hash.o +export-objs += xattr.o + +ifeq ($(CONFIG_EXT3_FS_XATTR),y) +ext3-objs += xattr.o xattr_user.o +endif + +ifeq ($(CONFIG_EXT3_FS_POSIX_ACL),y) +ext3-objs += acl.o +endif + include $(TOPDIR)/Rules.make diff -Nru a/fs/ext3/acl.c b/fs/ext3/acl.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/ext3/acl.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,590 @@ +/* + * linux/fs/ext3/acl.c + * + * Copyright (C) 2001 by Andreas Gruenbacher, + */ + +#include +#include +#include +#include +#include +#include +#include "xattr.h" +#include "acl.h" + +/* + * Convert from filesystem to in-memory representation. + */ +static struct posix_acl * +ext3_acl_from_disk(const void *value, size_t size) +{ + const char *end = (char *)value + size; + int n, count; + struct posix_acl *acl; + + if (!value) + return NULL; + if (size < sizeof(ext3_acl_header)) + return ERR_PTR(-EINVAL); + if (((ext3_acl_header *)value)->a_version != + cpu_to_le32(EXT3_ACL_VERSION)) + return ERR_PTR(-EINVAL); + value = (char *)value + sizeof(ext3_acl_header); + count = ext3_acl_count(size); + if (count < 0) + return ERR_PTR(-EINVAL); + if (count == 0) + return NULL; + acl = posix_acl_alloc(count, GFP_KERNEL); + if (!acl) + return ERR_PTR(-ENOMEM); + for (n=0; n < count; n++) { + ext3_acl_entry *entry = + (ext3_acl_entry *)value; + if ((char *)value + sizeof(ext3_acl_entry_short) > end) + goto fail; + acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag); + acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm); + switch(acl->a_entries[n].e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + value = (char *)value + + sizeof(ext3_acl_entry_short); + acl->a_entries[n].e_id = ACL_UNDEFINED_ID; + break; + + case ACL_USER: + case ACL_GROUP: + value = (char *)value + sizeof(ext3_acl_entry); + if ((char *)value > end) + goto fail; + acl->a_entries[n].e_id = + le32_to_cpu(entry->e_id); + break; + + default: + goto fail; + } + } + if (value != end) + goto fail; + return acl; + +fail: + posix_acl_release(acl); + return ERR_PTR(-EINVAL); +} + +/* + * Convert from in-memory to filesystem representation. + */ +static void * +ext3_acl_to_disk(const struct posix_acl *acl, size_t *size) +{ + ext3_acl_header *ext_acl; + char *e; + int n; + + *size = ext3_acl_size(acl->a_count); + ext_acl = (ext3_acl_header *)kmalloc(sizeof(ext3_acl_header) + + acl->a_count * sizeof(ext3_acl_entry), GFP_KERNEL); + if (!ext_acl) + return ERR_PTR(-ENOMEM); + ext_acl->a_version = cpu_to_le32(EXT3_ACL_VERSION); + e = (char *)ext_acl + sizeof(ext3_acl_header); + for (n=0; n < acl->a_count; n++) { + ext3_acl_entry *entry = (ext3_acl_entry *)e; + entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag); + entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm); + switch(acl->a_entries[n].e_tag) { + case ACL_USER: + case ACL_GROUP: + entry->e_id = + cpu_to_le32(acl->a_entries[n].e_id); + e += sizeof(ext3_acl_entry); + break; + + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + e += sizeof(ext3_acl_entry_short); + break; + + default: + goto fail; + } + } + return (char *)ext_acl; + +fail: + kfree(ext_acl); + return ERR_PTR(-EINVAL); +} + +/* + * Inode operation get_posix_acl(). + * + * inode->i_sem: down + */ +static struct posix_acl * +ext3_get_acl(struct inode *inode, int type) +{ + int name_index; + char *value; + struct posix_acl *acl, **p_acl; + const size_t size = ext3_acl_size(EXT3_ACL_MAX_ENTRIES); + int retval; + + if (!test_opt(inode->i_sb, POSIX_ACL)) + return 0; + + switch(type) { + case ACL_TYPE_ACCESS: + p_acl = &EXT3_I(inode)->i_acl; + name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; + break; + + case ACL_TYPE_DEFAULT: + p_acl = &EXT3_I(inode)->i_default_acl; + name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; + break; + + default: + return ERR_PTR(-EINVAL); + } + if (*p_acl != EXT3_ACL_NOT_CACHED) + return posix_acl_dup(*p_acl); + value = kmalloc(size, GFP_KERNEL); + if (!value) + return ERR_PTR(-ENOMEM); + + retval = ext3_xattr_get(inode, name_index, "", value, size); + + if (retval == -ENODATA || retval == -ENOSYS) + *p_acl = acl = NULL; + else if (retval < 0) + acl = ERR_PTR(retval); + else { + acl = ext3_acl_from_disk(value, retval); + if (!IS_ERR(acl)) + *p_acl = posix_acl_dup(acl); + } + kfree(value); + return acl; +} + +/* + * Set the access or default ACL of an inode. + * + * inode->i_sem: down unless called from ext3_new_inode + */ +static int +ext3_set_acl(handle_t *handle, struct inode *inode, int type, + struct posix_acl *acl) +{ + int name_index; + void *value = NULL; + struct posix_acl **p_acl; + size_t size; + int error; + + if (S_ISLNK(inode->i_mode)) + return -EOPNOTSUPP; + + switch(type) { + case ACL_TYPE_ACCESS: + name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; + p_acl = &EXT3_I(inode)->i_acl; + if (acl) { + mode_t mode = inode->i_mode; + error = posix_acl_equiv_mode(acl, &mode); + if (error < 0) + return error; + else { + inode->i_mode = mode; + ext3_mark_inode_dirty(handle, inode); + if (error == 0) + acl = NULL; + } + } + break; + + case ACL_TYPE_DEFAULT: + name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; + p_acl = &EXT3_I(inode)->i_default_acl; + if (!S_ISDIR(inode->i_mode)) + return acl ? -EACCES : 0; + break; + + default: + return -EINVAL; + } + if (acl) { + if (acl->a_count > EXT3_ACL_MAX_ENTRIES) + return -EINVAL; + value = ext3_acl_to_disk(acl, &size); + if (IS_ERR(value)) + return (int)PTR_ERR(value); + } + + error = ext3_xattr_set(handle, inode, name_index, "", value, size, 0); + + if (value) + kfree(value); + if (!error) { + if (*p_acl && *p_acl != EXT3_ACL_NOT_CACHED) + posix_acl_release(*p_acl); + *p_acl = posix_acl_dup(acl); + } + return error; +} + +static int +__ext3_permission(struct inode *inode, int mask, int lock) +{ + int mode = inode->i_mode; + + /* Nobody gets write access to a read-only fs */ + if ((mask & MAY_WRITE) && IS_RDONLY(inode) && + (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) + return -EROFS; + /* Nobody gets write access to an immutable file */ + if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode)) + return -EACCES; + if (current->fsuid == inode->i_uid) { + mode >>= 6; + } else if (test_opt(inode->i_sb, POSIX_ACL)) { + /* ACL can't contain additional permissions if + the ACL_MASK entry is 0 */ + if (!(mode & S_IRWXG)) + goto check_groups; + if (EXT3_I(inode)->i_acl == EXT3_ACL_NOT_CACHED) { + struct posix_acl *acl; + + if (lock) { + down(&inode->i_sem); + acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); + up(&inode->i_sem); + } else + acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); + + if (IS_ERR(acl)) + return PTR_ERR(acl); + posix_acl_release(acl); + if (EXT3_I(inode)->i_acl == EXT3_ACL_NOT_CACHED) + return -EIO; + } + if (EXT3_I(inode)->i_acl) { + int error = posix_acl_permission(inode, + EXT3_I(inode)->i_acl, mask); + if (error == -EACCES) + goto check_capabilities; + return error; + } else + goto check_groups; + } else { +check_groups: + if (in_group_p(inode->i_gid)) + mode >>= 3; + } + if ((mode & mask & S_IRWXO) == mask) + return 0; + +check_capabilities: + /* Allowed to override Discretionary Access Control? */ + if ((mask & (MAY_READ|MAY_WRITE)) || (inode->i_mode & S_IXUGO)) + if (capable(CAP_DAC_OVERRIDE)) + return 0; + /* Read and search granted if capable(CAP_DAC_READ_SEARCH) */ + if (capable(CAP_DAC_READ_SEARCH) && ((mask == MAY_READ) || + (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE)))) + return 0; + return -EACCES; +} + +/* + * Inode operation permission(). + * + * inode->i_sem: up + */ +int +ext3_permission(struct inode *inode, int mask) +{ + return __ext3_permission(inode, mask, 1); +} + +/* + * Used internally if i_sem is already down. + */ +int +ext3_permission_locked(struct inode *inode, int mask) +{ + return __ext3_permission(inode, mask, 0); +} + +/* + * Initialize the ACLs of a new inode. Called from ext3_new_inode. + * + * dir->i_sem: down + * inode->i_sem: up (access to inode is still exclusive) + */ +int +ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) +{ + struct posix_acl *acl = NULL; + int error = 0; + + if (!S_ISLNK(inode->i_mode)) { + if (test_opt(dir->i_sb, POSIX_ACL)) { + acl = ext3_get_acl(dir, ACL_TYPE_DEFAULT); + if (IS_ERR(acl)) + return PTR_ERR(acl); + } + if (!acl) + inode->i_mode &= ~current->fs->umask; + } + if (test_opt(inode->i_sb, POSIX_ACL) && acl) { + struct posix_acl *clone; + mode_t mode; + + if (S_ISDIR(inode->i_mode)) { + error = ext3_set_acl(handle, inode, + ACL_TYPE_DEFAULT, acl); + if (error) + goto cleanup; + } + clone = posix_acl_clone(acl, GFP_KERNEL); + error = -ENOMEM; + if (!clone) + goto cleanup; + + mode = inode->i_mode; + error = posix_acl_create_masq(clone, &mode); + if (error >= 0) { + inode->i_mode = mode; + if (error > 0) { + /* This is an extended ACL */ + error = ext3_set_acl(handle, inode, + ACL_TYPE_ACCESS, clone); + } + } + posix_acl_release(clone); + } +cleanup: + posix_acl_release(acl); + return error; +} + +/* + * Does chmod for an inode that may have an Access Control List. The + * inode->i_mode field must be updated to the desired value by the caller + * before calling this function. + * Returns 0 on success, or a negative error number. + * + * We change the ACL rather than storing some ACL entries in the file + * mode permission bits (which would be more efficient), because that + * would break once additional permissions (like ACL_APPEND, ACL_DELETE + * for directories) are added. There are no more bits available in the + * file mode. + * + * inode->i_sem: down + */ +int +ext3_acl_chmod(struct inode *inode) +{ + struct posix_acl *acl, *clone; + int error; + + if (S_ISLNK(inode->i_mode)) + return -EOPNOTSUPP; + if (!test_opt(inode->i_sb, POSIX_ACL)) + return 0; + acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); + if (IS_ERR(acl) || !acl) + return PTR_ERR(acl); + clone = posix_acl_clone(acl, GFP_KERNEL); + posix_acl_release(acl); + if (!clone) + return -ENOMEM; + error = posix_acl_chmod_masq(clone, inode->i_mode); + if (!error) { + handle_t *handle; + + handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS); + if (IS_ERR(handle)) { + ext3_std_error(inode->i_sb, error); + return PTR_ERR(handle); + } + error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, clone); + ext3_journal_stop(handle, inode); + } + posix_acl_release(clone); + return error; +} + +/* + * Extended attribute handlers + */ +static size_t +ext3_xattr_list_acl_access(char *list, struct inode *inode, + const char *name, int name_len) +{ + const size_t len = sizeof(XATTR_NAME_ACL_ACCESS)-1; + + if (!test_opt(inode->i_sb, POSIX_ACL)) + return 0; + if (list) + memcpy(list, XATTR_NAME_ACL_ACCESS, len); + return len; +} + +static size_t +ext3_xattr_list_acl_default(char *list, struct inode *inode, + const char *name, int name_len) +{ + const size_t len = sizeof(XATTR_NAME_ACL_DEFAULT)-1; + + if (!test_opt(inode->i_sb, POSIX_ACL)) + return 0; + if (list) + memcpy(list, XATTR_NAME_ACL_DEFAULT, len); + return len; +} + +static int +ext3_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size) +{ + struct posix_acl *acl; + int error; + + if (!test_opt(inode->i_sb, POSIX_ACL)) + return -EOPNOTSUPP; + + acl = ext3_get_acl(inode, type); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl == NULL) + return -ENODATA; + error = posix_acl_to_xattr(acl, buffer, size); + posix_acl_release(acl); + + return error; +} + +static int +ext3_xattr_get_acl_access(struct inode *inode, const char *name, + void *buffer, size_t size) +{ + if (strcmp(name, "") != 0) + return -EINVAL; + return ext3_xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size); +} + +static int +ext3_xattr_get_acl_default(struct inode *inode, const char *name, + void *buffer, size_t size) +{ + if (strcmp(name, "") != 0) + return -EINVAL; + return ext3_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size); +} + +static int +ext3_xattr_set_acl(struct inode *inode, int type, const void *value, size_t size) +{ + handle_t *handle; + struct posix_acl *acl; + int error; + + if (!test_opt(inode->i_sb, POSIX_ACL)) + return -EOPNOTSUPP; + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EPERM; + + if (value) { + acl = posix_acl_from_xattr(value, size); + if (IS_ERR(acl)) + return PTR_ERR(acl); + else if (acl) { + error = posix_acl_valid(acl); + if (error) + goto release_and_out; + } + } else + acl = NULL; + + handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS); + if (IS_ERR(handle)) + return PTR_ERR(handle); + error = ext3_set_acl(handle, inode, type, acl); + ext3_journal_stop(handle, inode); + +release_and_out: + posix_acl_release(acl); + return error; +} + +static int +ext3_xattr_set_acl_access(struct inode *inode, const char *name, + const void *value, size_t size, int flags) +{ + if (strcmp(name, "") != 0) + return -EINVAL; + return ext3_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size); +} + +static int +ext3_xattr_set_acl_default(struct inode *inode, const char *name, + const void *value, size_t size, int flags) +{ + if (strcmp(name, "") != 0) + return -EINVAL; + return ext3_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size); +} + +struct ext3_xattr_handler ext3_xattr_acl_access_handler = { + prefix: XATTR_NAME_ACL_ACCESS, + list: ext3_xattr_list_acl_access, + get: ext3_xattr_get_acl_access, + set: ext3_xattr_set_acl_access, +}; + +struct ext3_xattr_handler ext3_xattr_acl_default_handler = { + prefix: XATTR_NAME_ACL_DEFAULT, + list: ext3_xattr_list_acl_default, + get: ext3_xattr_get_acl_default, + set: ext3_xattr_set_acl_default, +}; + +void +exit_ext3_acl(void) +{ + ext3_xattr_unregister(EXT3_XATTR_INDEX_POSIX_ACL_ACCESS, + &ext3_xattr_acl_access_handler); + ext3_xattr_unregister(EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT, + &ext3_xattr_acl_default_handler); +} + +int __init +init_ext3_acl(void) +{ + int error; + + error = ext3_xattr_register(EXT3_XATTR_INDEX_POSIX_ACL_ACCESS, + &ext3_xattr_acl_access_handler); + if (error) + goto fail; + error = ext3_xattr_register(EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT, + &ext3_xattr_acl_default_handler); + if (error) + goto fail; + return 0; + +fail: + exit_ext3_acl(); + return error; +} diff -Nru a/fs/ext3/acl.h b/fs/ext3/acl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/ext3/acl.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,87 @@ +/* + File: fs/ext3/acl.h + + (C) 2001 Andreas Gruenbacher, +*/ + +#include + +#define EXT3_ACL_VERSION 0x0001 +#define EXT3_ACL_MAX_ENTRIES 32 + +typedef struct { + __u16 e_tag; + __u16 e_perm; + __u32 e_id; +} ext3_acl_entry; + +typedef struct { + __u16 e_tag; + __u16 e_perm; +} ext3_acl_entry_short; + +typedef struct { + __u32 a_version; +} ext3_acl_header; + +static inline size_t ext3_acl_size(int count) +{ + if (count <= 4) { + return sizeof(ext3_acl_header) + + count * sizeof(ext3_acl_entry_short); + } else { + return sizeof(ext3_acl_header) + + 4 * sizeof(ext3_acl_entry_short) + + (count - 4) * sizeof(ext3_acl_entry); + } +} + +static inline int ext3_acl_count(size_t size) +{ + ssize_t s; + size -= sizeof(ext3_acl_header); + s = size - 4 * sizeof(ext3_acl_entry_short); + if (s < 0) { + if (size % sizeof(ext3_acl_entry_short)) + return -1; + return size / sizeof(ext3_acl_entry_short); + } else { + if (s % sizeof(ext3_acl_entry)) + return -1; + return s / sizeof(ext3_acl_entry) + 4; + } +} + +#ifdef CONFIG_EXT3_FS_POSIX_ACL + +/* Value for inode->u.ext3_i.i_acl and inode->u.ext3_i.i_default_acl + if the ACL has not been cached */ +#define EXT3_ACL_NOT_CACHED ((void *)-1) + +/* acl.c */ +extern int ext3_permission (struct inode *, int); +extern int ext3_permission_locked (struct inode *, int); +extern int ext3_acl_chmod (struct inode *); +extern int ext3_init_acl (handle_t *, struct inode *, struct inode *); + +extern int init_ext3_acl(void); +extern void exit_ext3_acl(void); + +#else /* CONFIG_EXT3_FS_POSIX_ACL */ +#include +#define ext3_permission NULL + +static inline int +ext3_acl_chmod(struct inode *inode) +{ + return 0; +} + +static inline int +ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) +{ + inode->i_mode &= ~current->fs->umask; + return 0; +} +#endif /* CONFIG_EXT3_FS_POSIX_ACL */ + diff -Nru a/fs/ext3/file.c b/fs/ext3/file.c --- a/fs/ext3/file.c Mon Nov 4 14:31:02 2002 +++ b/fs/ext3/file.c Mon Nov 4 14:31:02 2002 @@ -23,7 +23,8 @@ #include #include #include -#include +#include "xattr.h" +#include "acl.h" /* * Called when an inode is released. Note that this is different @@ -98,5 +99,10 @@ struct inode_operations ext3_file_inode_operations = { .truncate = ext3_truncate, .setattr = ext3_setattr, + .setxattr = ext3_setxattr, + .getxattr = ext3_getxattr, + .listxattr = ext3_listxattr, + .removexattr = ext3_removexattr, + .permission = ext3_permission, }; diff -Nru a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c --- a/fs/ext3/ialloc.c Mon Nov 4 14:31:02 2002 +++ b/fs/ext3/ialloc.c Mon Nov 4 14:31:02 2002 @@ -21,10 +21,14 @@ #include #include #include +#include #include #include +#include "xattr.h" +#include "acl.h" + /* * ialloc.c contains the inodes allocation and deallocation routines */ @@ -118,6 +122,7 @@ * as writing the quota to disk may need the lock as well. */ DQUOT_INIT(inode); + ext3_xattr_delete_inode(handle, inode); DQUOT_FREE_INODE(inode); DQUOT_DROP(inode); @@ -194,6 +199,230 @@ * the groups with above-average free space, that group with the fewest * directories already is chosen. * + * For other inodes, search forward from the parent directory\'s block + * group to find a free inode. + */ +static int find_group_dir(struct super_block *sb, struct inode *parent) +{ + struct ext3_super_block * es = EXT3_SB(sb)->s_es; + int ngroups = EXT3_SB(sb)->s_groups_count; + int avefreei = le32_to_cpu(es->s_free_inodes_count) / ngroups; + struct ext3_group_desc *desc, *best_desc = NULL; + struct buffer_head *bh, *best_bh = NULL; + int group, best_group = -1; + + for (group = 0; group < ngroups; group++) { + desc = ext3_get_group_desc (sb, group, &bh); + if (!desc || !desc->bg_free_inodes_count) + continue; + if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) + continue; + if (!best_desc || + (le16_to_cpu(desc->bg_free_blocks_count) > + le16_to_cpu(best_desc->bg_free_blocks_count))) { + best_group = group; + best_desc = desc; + best_bh = bh; + } + } + if (!best_desc) + return -1; + best_desc->bg_free_inodes_count = + cpu_to_le16(le16_to_cpu(best_desc->bg_free_inodes_count) - 1); + best_desc->bg_used_dirs_count = + cpu_to_le16(le16_to_cpu(best_desc->bg_used_dirs_count) + 1); + mark_buffer_dirty(best_bh); + return best_group; +} + +/* + * Orlov's allocator for directories. + * + * We always try to spread first-level directories. + * + * If there are blockgroups with both free inodes and free blocks counts + * not worse than average we return one with smallest directory count. + * Otherwise we simply return a random group. + * + * For the rest rules look so: + * + * It's OK to put directory into a group unless + * it has too many directories already (max_dirs) or + * it has too few free inodes left (min_inodes) or + * it has too few free blocks left (min_blocks) or + * it's already running too large debt (max_debt). + * Parent's group is prefered, if it doesn't satisfy these + * conditions we search cyclically through the rest. If none + * of the groups look good we just look for a group with more + * free inodes than average (starting at parent's group). + * + * Debt is incremented each time we allocate a directory and decremented + * when we allocate an inode, within 0--255. + */ + +#define INODE_COST 64 +#define BLOCK_COST 256 + +static int find_group_orlov(struct super_block *sb, struct inode *parent) +{ + int parent_group = EXT3_I(parent)->i_block_group; + struct ext3_sb_info *sbi = EXT3_SB(sb); + struct ext3_super_block *es = sbi->s_es; + int ngroups = sbi->s_groups_count; + int inodes_per_group = EXT3_INODES_PER_GROUP(sb); + int avefreei = le32_to_cpu(es->s_free_inodes_count) / ngroups; + int avefreeb = le32_to_cpu(es->s_free_blocks_count) / ngroups; + int blocks_per_dir; + int ndirs = sbi->s_dir_count; + int max_debt, max_dirs, min_blocks, min_inodes; + int group = -1, i; + struct ext3_group_desc *desc; + struct buffer_head *bh; + + if ((parent == sb->s_root->d_inode) || + (parent->i_flags & EXT3_TOPDIR_FL)) { + struct ext3_group_desc *best_desc = NULL; + struct buffer_head *best_bh = NULL; + int best_ndir = inodes_per_group; + int best_group = -1; + + get_random_bytes(&group, sizeof(group)); + parent_group = (unsigned)group % ngroups; + for (i = 0; i < ngroups; i++) { + group = (parent_group + i) % ngroups; + desc = ext3_get_group_desc (sb, group, &bh); + if (!desc || !desc->bg_free_inodes_count) + continue; + if (le16_to_cpu(desc->bg_used_dirs_count) >= best_ndir) + continue; + if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) + continue; + if (le16_to_cpu(desc->bg_free_blocks_count) < avefreeb) + continue; + best_group = group; + best_ndir = le16_to_cpu(desc->bg_used_dirs_count); + best_desc = desc; + best_bh = bh; + } + if (best_group >= 0) { + desc = best_desc; + bh = best_bh; + group = best_group; + goto found; + } + goto fallback; + } + + blocks_per_dir = (le32_to_cpu(es->s_blocks_count) - + le32_to_cpu(es->s_free_blocks_count)) / ndirs; + + max_dirs = ndirs / ngroups + inodes_per_group / 16; + min_inodes = avefreei - inodes_per_group / 4; + min_blocks = avefreeb - EXT3_BLOCKS_PER_GROUP(sb) / 4; + + max_debt = EXT3_BLOCKS_PER_GROUP(sb) / max(blocks_per_dir, BLOCK_COST); + if (max_debt * INODE_COST > inodes_per_group) + max_debt = inodes_per_group / INODE_COST; + if (max_debt > 255) + max_debt = 255; + if (max_debt == 0) + max_debt = 1; + + for (i = 0; i < ngroups; i++) { + group = (parent_group + i) % ngroups; + desc = ext3_get_group_desc (sb, group, &bh); + if (!desc || !desc->bg_free_inodes_count) + continue; + if (sbi->s_debts[group] >= max_debt) + continue; + if (le16_to_cpu(desc->bg_used_dirs_count) >= max_dirs) + continue; + if (le16_to_cpu(desc->bg_free_inodes_count) < min_inodes) + continue; + if (le16_to_cpu(desc->bg_free_blocks_count) < min_blocks) + continue; + goto found; + } + +fallback: + for (i = 0; i < ngroups; i++) { + group = (parent_group + i) % ngroups; + desc = ext3_get_group_desc (sb, group, &bh); + if (!desc || !desc->bg_free_inodes_count) + continue; + if (le16_to_cpu(desc->bg_free_inodes_count) >= avefreei) + goto found; + } + + return -1; + +found: + desc->bg_free_inodes_count = + cpu_to_le16(le16_to_cpu(desc->bg_free_inodes_count) - 1); + desc->bg_used_dirs_count = + cpu_to_le16(le16_to_cpu(desc->bg_used_dirs_count) + 1); + sbi->s_dir_count++; + mark_buffer_dirty(bh); + return group; +} + +static int find_group_other(struct super_block *sb, struct inode *parent) +{ + int parent_group = EXT3_I(parent)->i_block_group; + int ngroups = EXT3_SB(sb)->s_groups_count; + struct ext3_group_desc *desc; + struct buffer_head *bh; + int group, i; + + /* + * Try to place the inode in its parent directory + */ + group = parent_group; + desc = ext3_get_group_desc (sb, group, &bh); + if (desc && le16_to_cpu(desc->bg_free_inodes_count)) + goto found; + + /* + * Use a quadratic hash to find a group with a + * free inode + */ + for (i = 1; i < ngroups; i <<= 1) { + group += i; + if (group >= ngroups) + group -= ngroups; + desc = ext3_get_group_desc (sb, group, &bh); + if (desc && le16_to_cpu(desc->bg_free_inodes_count)) + goto found; + } + + /* + * That failed: try linear search for a free inode + */ + group = parent_group + 1; + for (i = 2; i < ngroups; i++) { + if (++group >= ngroups) + group = 0; + desc = ext3_get_group_desc (sb, group, &bh); + if (desc && le16_to_cpu(desc->bg_free_inodes_count)) + goto found; + } + + return -1; + +found: + desc->bg_free_inodes_count = + cpu_to_le16(le16_to_cpu(desc->bg_free_inodes_count) - 1); + mark_buffer_dirty(bh); + return group; +} + +/* + * There are two policies for allocating an inode. If the new inode is + * a directory, then a forward search is made for a block group with both + * free space and a low directory-to-inode ratio; if that fails, then of + * the groups with above-average free space, that group with the fewest + * directories already is chosen. + * * For other inodes, search forward from the parent directory's block * group to find a free inode. */ @@ -202,10 +431,10 @@ struct super_block *sb; struct buffer_head *bitmap_bh = NULL; struct buffer_head *bh2; - int i, j, avefreei; + int group; + ino_t ino; struct inode * inode; struct ext3_group_desc * gdp; - struct ext3_group_desc * tmp; struct ext3_super_block * es; struct ext3_inode_info *ei; int err = 0; @@ -224,93 +453,35 @@ lock_super (sb); es = EXT3_SB(sb)->s_es; repeat: - gdp = NULL; - i = 0; - if (S_ISDIR(mode)) { - avefreei = le32_to_cpu(es->s_free_inodes_count) / - EXT3_SB(sb)->s_groups_count; - if (!gdp) { - for (j = 0; j < EXT3_SB(sb)->s_groups_count; j++) { - struct buffer_head *temp_buffer; - tmp = ext3_get_group_desc (sb, j, &temp_buffer); - if (tmp && - le16_to_cpu(tmp->bg_free_inodes_count) && - le16_to_cpu(tmp->bg_free_inodes_count) >= - avefreei) { - if (!gdp || (le16_to_cpu(tmp->bg_free_blocks_count) > - le16_to_cpu(gdp->bg_free_blocks_count))) { - i = j; - gdp = tmp; - bh2 = temp_buffer; - } - } - } - } - } else { - /* - * Try to place the inode in its parent directory - */ - i = EXT3_I(dir)->i_block_group; - tmp = ext3_get_group_desc (sb, i, &bh2); - if (tmp && le16_to_cpu(tmp->bg_free_inodes_count)) - gdp = tmp; + if (test_opt (sb, OLDALLOC)) + group = find_group_dir(sb, dir); else - { - /* - * Use a quadratic hash to find a group with a - * free inode - */ - for (j = 1; j < EXT3_SB(sb)->s_groups_count; j <<= 1) { - i += j; - if (i >= EXT3_SB(sb)->s_groups_count) - i -= EXT3_SB(sb)->s_groups_count; - tmp = ext3_get_group_desc (sb, i, &bh2); - if (tmp && - le16_to_cpu(tmp->bg_free_inodes_count)) { - gdp = tmp; - break; - } - } - } - if (!gdp) { - /* - * That failed: try linear search for a free inode - */ - i = EXT3_I(dir)->i_block_group + 1; - for (j = 2; j < EXT3_SB(sb)->s_groups_count; j++) { - if (++i >= EXT3_SB(sb)->s_groups_count) - i = 0; - tmp = ext3_get_group_desc (sb, i, &bh2); - if (tmp && - le16_to_cpu(tmp->bg_free_inodes_count)) { - gdp = tmp; - break; - } - } - } - } + group = find_group_orlov(sb, dir); + } else + group = find_group_other(sb, dir); err = -ENOSPC; - if (!gdp) + if (group == -1) goto out; err = -EIO; brelse(bitmap_bh); - bitmap_bh = read_inode_bitmap(sb, i); + bitmap_bh = read_inode_bitmap(sb, group); if (!bitmap_bh) goto fail; + gdp = ext3_get_group_desc (sb, group, &bh2); - if ((j = ext3_find_first_zero_bit((unsigned long *)bitmap_bh->b_data, + if ((ino = ext3_find_first_zero_bit((unsigned long *)bitmap_bh->b_data, EXT3_INODES_PER_GROUP(sb))) < EXT3_INODES_PER_GROUP(sb)) { BUFFER_TRACE(bitmap_bh, "get_write_access"); err = ext3_journal_get_write_access(handle, bitmap_bh); if (err) goto fail; - if (ext3_set_bit(j, bitmap_bh->b_data)) { + if (ext3_set_bit(ino, bitmap_bh->b_data)) { ext3_error (sb, "ext3_new_inode", - "bit already set for inode %d", j); + "bit already set for inode %lu", ino); goto repeat; } BUFFER_TRACE(bitmap_bh, "call ext3_journal_dirty_metadata"); @@ -320,7 +491,7 @@ if (le16_to_cpu(gdp->bg_free_inodes_count) != 0) { ext3_error (sb, "ext3_new_inode", "Free inodes count corrupted in group %d", - i); + group); /* Is it really ENOSPC? */ err = -ENOSPC; if (sb->s_flags & MS_RDONLY) @@ -336,11 +507,11 @@ } goto repeat; } - j += i * EXT3_INODES_PER_GROUP(sb) + 1; - if (j < EXT3_FIRST_INO(sb) || j > le32_to_cpu(es->s_inodes_count)) { + ino += group * EXT3_INODES_PER_GROUP(sb) + 1; + if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { ext3_error (sb, "ext3_new_inode", "reserved inode or inode > inodes count - " - "block_group = %d,inode=%d", i, j); + "block_group = %d, inode=%lu", group, ino); err = -EIO; goto fail; } @@ -378,7 +549,7 @@ inode->i_gid = current->fsgid; inode->i_mode = mode; - inode->i_ino = j; + inode->i_ino = ino; /* This is the optimal IO size (for stat), not the fs block size */ inode->i_blksize = PAGE_SIZE; inode->i_blocks = 0; @@ -408,7 +579,7 @@ ei->i_prealloc_block = 0; ei->i_prealloc_count = 0; #endif - ei->i_block_group = i; + ei->i_block_group = group; if (ei->i_flags & EXT3_SYNC_FL) inode->i_flags |= S_SYNC; @@ -420,20 +591,27 @@ inode->i_generation = EXT3_SB(sb)->s_next_generation++; ei->i_state = EXT3_STATE_NEW; - err = ext3_mark_inode_dirty(handle, inode); - if (err) goto fail; - + unlock_super(sb); ret = inode; if(DQUOT_ALLOC_INODE(inode)) { DQUOT_DROP(inode); - inode->i_flags |= S_NOQUOTA; - inode->i_nlink = 0; - iput(inode); - ret = ERR_PTR(-EDQUOT); - } else { - ext3_debug("allocating inode %lu\n", inode->i_ino); + err = -EDQUOT; + goto fail2; + } + err = ext3_init_acl(handle, inode, dir); + if (err) { + DQUOT_FREE_INODE(inode); + goto fail2; + } + err = ext3_mark_inode_dirty(handle, inode); + if (err) { + ext3_std_error(sb, err); + DQUOT_FREE_INODE(inode); + goto fail2; } + + ext3_debug("allocating inode %lu\n", inode->i_ino); goto really_out; fail: ext3_std_error(sb, err); @@ -444,6 +622,12 @@ really_out: brelse(bitmap_bh); return ret; + +fail2: + inode->i_flags |= S_NOQUOTA; + inode->i_nlink = 0; + iput(inode); + return ERR_PTR(err); } /* Verify that we are loading a valid orphan from disk */ @@ -543,6 +727,21 @@ #else return le32_to_cpu(EXT3_SB(sb)->s_es->s_free_inodes_count); #endif +} + +/* Called at mount-time, super-block is locked */ +unsigned long ext3_count_dirs (struct super_block * sb) +{ + unsigned long count = 0; + int i; + + for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { + struct ext3_group_desc *gdp = ext3_get_group_desc (sb, i, NULL); + if (!gdp) + continue; + count += le16_to_cpu(gdp->bg_used_dirs_count); + } + return count; } #ifdef CONFIG_EXT3_CHECK diff -Nru a/fs/ext3/inode.c b/fs/ext3/inode.c --- a/fs/ext3/inode.c Mon Nov 4 14:31:02 2002 +++ b/fs/ext3/inode.c Mon Nov 4 14:31:02 2002 @@ -34,6 +34,8 @@ #include #include #include +#include "xattr.h" +#include "acl.h" /* * SEARCH_FROM_ZERO forces each block allocation to search from the start @@ -42,6 +44,18 @@ */ #undef SEARCH_FROM_ZERO +/* + * Test whether an inode is a fast symlink. + */ +static inline int ext3_inode_is_fast_symlink(struct inode *inode) +{ + int ea_blocks = EXT3_I(inode)->i_file_acl ? + (inode->i_sb->s_blocksize >> 9) : 0; + + return (S_ISLNK(inode->i_mode) && + inode->i_blocks - ea_blocks == 0); +} + /* The ext3 forget function must perform a revoke if we are freeing data * which has been journaled. Metadata (eg. indirect blocks) must be * revoked in all cases. @@ -51,7 +65,7 @@ * still needs to be revoked. */ -static int ext3_forget(handle_t *handle, int is_metadata, +int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode, struct buffer_head *bh, int blocknr) { @@ -167,9 +181,7 @@ { handle_t *handle; - if (is_bad_inode(inode) || - inode->i_ino == EXT3_ACL_IDX_INO || - inode->i_ino == EXT3_ACL_DATA_INO) + if (is_bad_inode(inode)) goto no_delete; lock_kernel(); @@ -1979,6 +1991,8 @@ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) return; + if (ext3_inode_is_fast_symlink(inode)) + return; if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return; @@ -2130,8 +2144,6 @@ struct ext3_group_desc * gdp; if ((inode->i_ino != EXT3_ROOT_INO && - inode->i_ino != EXT3_ACL_IDX_INO && - inode->i_ino != EXT3_ACL_DATA_INO && inode->i_ino != EXT3_JOURNAL_INO && inode->i_ino < EXT3_FIRST_INO(inode->i_sb)) || inode->i_ino > le32_to_cpu( @@ -2189,7 +2201,11 @@ struct buffer_head *bh; int block; - if(ext3_get_inode_loc(inode, &iloc)) +#ifdef CONFIG_EXT3_FS_POSIX_ACL + ei->i_acl = EXT3_ACL_NOT_CACHED; + ei->i_default_acl = EXT3_ACL_NOT_CACHED; +#endif + if (ext3_get_inode_loc(inode, &iloc)) goto bad_inode; bh = iloc.bh; raw_inode = iloc.raw_inode; @@ -2263,10 +2279,7 @@ brelse (iloc.bh); - if (inode->i_ino == EXT3_ACL_IDX_INO || - inode->i_ino == EXT3_ACL_DATA_INO) - /* Nothing to do */ ; - else if (S_ISREG(inode->i_mode)) { + if (S_ISREG(inode->i_mode)) { inode->i_op = &ext3_file_inode_operations; inode->i_fop = &ext3_file_operations; if (ext3_should_writeback_data(inode)) @@ -2277,18 +2290,20 @@ inode->i_op = &ext3_dir_inode_operations; inode->i_fop = &ext3_dir_operations; } else if (S_ISLNK(inode->i_mode)) { - if (!inode->i_blocks) + if (ext3_inode_is_fast_symlink(inode)) inode->i_op = &ext3_fast_symlink_inode_operations; else { - inode->i_op = &page_symlink_inode_operations; + inode->i_op = &ext3_symlink_inode_operations; if (ext3_should_writeback_data(inode)) inode->i_mapping->a_ops = &ext3_writeback_aops; else inode->i_mapping->a_ops = &ext3_aops; } - } else + } else { + inode->i_op = &ext3_special_inode_operations; init_special_inode(inode, inode->i_mode, le32_to_cpu(iloc.raw_inode->i_block[0])); + } if (ei->i_flags & EXT3_SYNC_FL) inode->i_flags |= S_SYNC; if (ei->i_flags & EXT3_APPEND_FL) @@ -2325,6 +2340,11 @@ if (err) goto out_brelse; } + /* For fields not not tracking in the in-memory inode, + * initialise them to zero for new inodes. */ + if (ei->i_state & EXT3_STATE_NEW) + memset(raw_inode, 0, EXT3_SB(inode->i_sb)->s_inode_size); + raw_inode->i_mode = cpu_to_le16(inode->i_mode); if(!(test_opt(inode->i_sb, NO_UID32))) { raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid)); @@ -2362,15 +2382,6 @@ raw_inode->i_faddr = cpu_to_le32(ei->i_faddr); raw_inode->i_frag = ei->i_frag_no; raw_inode->i_fsize = ei->i_frag_size; -#else - /* If we are not tracking these fields in the in-memory inode, - * then preserve them on disk, but still initialise them to zero - * for new inodes. */ - if (ei->i_state & EXT3_STATE_NEW) { - raw_inode->i_faddr = 0; - raw_inode->i_frag = 0; - raw_inode->i_fsize = 0; - } #endif raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl); if (!S_ISREG(inode->i_mode)) { @@ -2486,13 +2497,8 @@ * be freed, so we have a strong guarantee that no future commit will * leave these blocks visible to the user.) * - * This is only needed for regular files. rmdir() has its own path, and - * we can never truncate a direcory except on final unlink (at which - * point i_nlink is zero so recovery is easy.) - * - * Called with the BKL. + * Called with inode->sem down. */ - int ext3_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; @@ -2512,7 +2518,8 @@ lock_kernel(); - if (attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) { + if (S_ISREG(inode->i_mode) && + attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) { handle_t *handle; handle = ext3_journal_start(inode, 3); @@ -2536,6 +2543,9 @@ * orphan list manually. */ if (inode->i_nlink) ext3_orphan_del(NULL, inode); + + if (!rc && (ia_valid & ATTR_MODE)) + rc = ext3_acl_chmod(inode); err_out: ext3_std_error(inode->i_sb, error); diff -Nru a/fs/ext3/namei.c b/fs/ext3/namei.c --- a/fs/ext3/namei.c Mon Nov 4 14:31:02 2002 +++ b/fs/ext3/namei.c Mon Nov 4 14:31:02 2002 @@ -36,7 +36,8 @@ #include #include #include - +#include "xattr.h" +#include "acl.h" /* * define how far ahead to read directories while searching them. @@ -1623,7 +1624,10 @@ inode = ext3_new_inode (handle, dir, mode); err = PTR_ERR(inode); if (!IS_ERR(inode)) { - init_special_inode(inode, mode, rdev); + init_special_inode(inode, inode->i_mode, rdev); +#ifdef CONFIG_EXT3_FS_XATTR + inode->i_op = &ext3_special_inode_operations; +#endif err = ext3_add_nondir(handle, dentry, inode); ext3_mark_inode_dirty(handle, inode); } @@ -1654,7 +1658,7 @@ if (IS_DIRSYNC(dir)) handle->h_sync = 1; - inode = ext3_new_inode (handle, dir, S_IFDIR); + inode = ext3_new_inode (handle, dir, S_IFDIR | mode); err = PTR_ERR(inode); if (IS_ERR(inode)) goto out_stop; @@ -1662,7 +1666,6 @@ inode->i_op = &ext3_dir_inode_operations; inode->i_fop = &ext3_dir_operations; inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize; - inode->i_blocks = 0; dir_block = ext3_bread (handle, inode, 0, 1, &err); if (!dir_block) { inode->i_nlink--; /* is this nlink == 0? */ @@ -1689,9 +1692,6 @@ BUFFER_TRACE(dir_block, "call ext3_journal_dirty_metadata"); ext3_journal_dirty_metadata(handle, dir_block); brelse (dir_block); - inode->i_mode = S_IFDIR | mode; - if (dir->i_mode & S_ISGID) - inode->i_mode |= S_ISGID; ext3_mark_inode_dirty(handle, inode); err = ext3_add_entry (handle, dentry, inode); if (err) { @@ -2068,7 +2068,7 @@ goto out_stop; if (l > sizeof (EXT3_I(inode)->i_data)) { - inode->i_op = &page_symlink_inode_operations; + inode->i_op = &ext3_symlink_inode_operations; if (ext3_should_writeback_data(inode)) inode->i_mapping->a_ops = &ext3_writeback_aops; else @@ -2284,4 +2284,21 @@ .rmdir = ext3_rmdir, .mknod = ext3_mknod, .rename = ext3_rename, + .setattr = ext3_setattr, + .setxattr = ext3_setxattr, + .getxattr = ext3_getxattr, + .listxattr = ext3_listxattr, + .removexattr = ext3_removexattr, + .permission = ext3_permission, }; + +struct inode_operations ext3_special_inode_operations = { + .setattr = ext3_setattr, + .setxattr = ext3_setxattr, + .getxattr = ext3_getxattr, + .listxattr = ext3_listxattr, + .removexattr = ext3_removexattr, + .permission = ext3_permission, +}; + + diff -Nru a/fs/ext3/super.c b/fs/ext3/super.c --- a/fs/ext3/super.c Mon Nov 4 14:31:02 2002 +++ b/fs/ext3/super.c Mon Nov 4 14:31:02 2002 @@ -30,6 +30,8 @@ #include #include #include +#include "xattr.h" +#include "acl.h" #ifdef CONFIG_JBD_DEBUG static int ext3_ro_after; /* Make fs read-only after this many jiffies */ @@ -105,32 +107,6 @@ static char error_buf[1024]; -/* Determine the appropriate response to ext3_error on a given filesystem */ - -static int ext3_error_behaviour(struct super_block *sb) -{ - /* First check for mount-time options */ - if (test_opt (sb, ERRORS_PANIC)) - return EXT3_ERRORS_PANIC; - if (test_opt (sb, ERRORS_RO)) - return EXT3_ERRORS_RO; - if (test_opt (sb, ERRORS_CONT)) - return EXT3_ERRORS_CONTINUE; - - /* If no overrides were specified on the mount, then fall back - * to the default behaviour set in the filesystem's superblock - * on disk. */ - switch (le16_to_cpu(EXT3_SB(sb)->s_es->s_errors)) { - case EXT3_ERRORS_PANIC: - return EXT3_ERRORS_PANIC; - case EXT3_ERRORS_RO: - return EXT3_ERRORS_RO; - default: - break; - } - return EXT3_ERRORS_CONTINUE; -} - /* Deal with the reporting of failure conditions on a filesystem such as * inconsistencies detected or read IO failures. * @@ -156,20 +132,16 @@ if (sb->s_flags & MS_RDONLY) return; - if (ext3_error_behaviour(sb) != EXT3_ERRORS_CONTINUE) { - EXT3_SB(sb)->s_mount_opt |= EXT3_MOUNT_ABORT; - journal_abort(EXT3_SB(sb)->s_journal, -EIO); - } - - if (ext3_error_behaviour(sb) == EXT3_ERRORS_PANIC) + if (test_opt (sb, ERRORS_PANIC)) panic ("EXT3-fs (device %s): panic forced after error\n", sb->s_id); - - if (ext3_error_behaviour(sb) == EXT3_ERRORS_RO) { + if (test_opt (sb, ERRORS_RO)) { printk (KERN_CRIT "Remounting filesystem read-only\n"); sb->s_flags |= MS_RDONLY; + } else { + EXT3_SB(sb)->s_mount_opt |= EXT3_MOUNT_ABORT; + journal_abort(EXT3_SB(sb)->s_journal, -EIO); } - ext3_commit_super(sb, es, 1); } @@ -257,7 +229,7 @@ vsprintf (error_buf, fmt, args); va_end (args); - if (ext3_error_behaviour(sb) == EXT3_ERRORS_PANIC) + if (test_opt (sb, ERRORS_PANIC)) panic ("EXT3-fs panic (device %s): %s: %s\n", sb->s_id, function, error_buf); @@ -405,6 +377,7 @@ struct ext3_super_block *es = sbi->s_es; int i; + ext3_xattr_put_super(sb); journal_destroy(sbi->s_journal); if (!(sb->s_flags & MS_RDONLY)) { EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); @@ -417,6 +390,7 @@ for (i = 0; i < sbi->s_gdb_count; i++) brelse(sbi->s_group_desc[i]); kfree(sbi->s_group_desc); + kfree(sbi->s_debts); brelse(sbi->s_sbh); /* Debugging code just in case the in-memory inode orphan list @@ -456,6 +430,10 @@ ei = kmem_cache_alloc(ext3_inode_cachep, SLAB_NOFS); if (!ei) return NULL; +#ifdef CONFIG_EXT3_FS_POSIX_ACL + ei->i_acl = EXT3_ACL_NOT_CACHED; + ei->i_default_acl = EXT3_ACL_NOT_CACHED; +#endif return &ei->vfs_inode; } @@ -493,6 +471,26 @@ printk(KERN_INFO "ext3_inode_cache: not all structures were freed\n"); } +#ifdef CONFIG_EXT3_FS_POSIX_ACL + +static void ext3_clear_inode(struct inode *inode) +{ + if (EXT3_I(inode)->i_acl && + EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) { + posix_acl_release(EXT3_I(inode)->i_acl); + EXT3_I(inode)->i_acl = EXT3_ACL_NOT_CACHED; + } + if (EXT3_I(inode)->i_default_acl && + EXT3_I(inode)->i_default_acl != EXT3_ACL_NOT_CACHED) { + posix_acl_release(EXT3_I(inode)->i_default_acl); + EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED; + } +} + +#else +# define ext3_clear_inode NULL +#endif + static struct super_operations ext3_sops = { .alloc_inode = ext3_alloc_inode, .destroy_inode = ext3_destroy_inode, @@ -507,6 +505,7 @@ .unlockfs = ext3_unlockfs, /* BKL not held. We take it */ .statfs = ext3_statfs, /* BKL not held. */ .remount_fs = ext3_remount, /* BKL held */ + .clear_inode = ext3_clear_inode, /* BKL not needed. */ }; struct dentry *ext3_get_parent(struct dentry *child); @@ -545,17 +544,32 @@ return 0; } +static unsigned long get_sb_block(void **data) +{ + unsigned long sb_block; + char *options = (char *) *data; + + if (!options || strncmp(options, "sb=", 3) != 0) + return 1; /* Default location */ + options += 3; + sb_block = simple_strtoul(options, &options, 0); + if (*options && *options != ',') { + printk("EXT3-fs: Invalid sb specification: %s\n", + (char *) *data); + return 1; + } + if (*options == ',') + options++; + *data = (void *) options; + return sb_block; +} + /* * This function has been shamelessly adapted from the msdos fs */ -static int parse_options (char * options, unsigned long * sb_block, - struct ext3_sb_info *sbi, - unsigned long * inum, - int is_remount) -{ - unsigned long *mount_options = &sbi->s_mount_opt; - uid_t *resuid = &sbi->s_resuid; - gid_t *resgid = &sbi->s_resgid; +static int parse_options (char * options, struct ext3_sb_info *sbi, + unsigned long * inum, int is_remount) +{ char * this_char; char * value; @@ -566,43 +580,57 @@ continue; if ((value = strchr (this_char, '=')) != NULL) *value++ = 0; +#ifdef CONFIG_EXT3_FS_XATTR + if (!strcmp (this_char, "user_xattr")) + set_opt (sbi->s_mount_opt, XATTR_USER); + else if (!strcmp (this_char, "nouser_xattr")) + clear_opt (sbi->s_mount_opt, XATTR_USER); + else +#endif +#ifdef CONFIG_EXT3_FS_POSIX_ACL + if (!strcmp(this_char, "acl")) + set_opt (sbi->s_mount_opt, POSIX_ACL); + else if (!strcmp(this_char, "noacl")) + clear_opt (sbi->s_mount_opt, POSIX_ACL); + else +#endif if (!strcmp (this_char, "bsddf")) - clear_opt (*mount_options, MINIX_DF); + clear_opt (sbi->s_mount_opt, MINIX_DF); else if (!strcmp (this_char, "nouid32")) { - set_opt (*mount_options, NO_UID32); + set_opt (sbi->s_mount_opt, NO_UID32); } else if (!strcmp (this_char, "abort")) - set_opt (*mount_options, ABORT); + set_opt (sbi->s_mount_opt, ABORT); else if (!strcmp (this_char, "check")) { if (!value || !*value || !strcmp (value, "none")) - clear_opt (*mount_options, CHECK); + clear_opt (sbi->s_mount_opt, CHECK); else #ifdef CONFIG_EXT3_CHECK - set_opt (*mount_options, CHECK); + set_opt (sbi->s_mount_opt, CHECK); #else printk(KERN_ERR "EXT3 Check option not supported\n"); #endif } else if (!strcmp (this_char, "debug")) - set_opt (*mount_options, DEBUG); + set_opt (sbi->s_mount_opt, DEBUG); else if (!strcmp (this_char, "errors")) { if (want_value(value, "errors")) return 0; if (!strcmp (value, "continue")) { - clear_opt (*mount_options, ERRORS_RO); - clear_opt (*mount_options, ERRORS_PANIC); - set_opt (*mount_options, ERRORS_CONT); + clear_opt (sbi->s_mount_opt, ERRORS_RO); + clear_opt (sbi->s_mount_opt, ERRORS_PANIC); + set_opt (sbi->s_mount_opt, ERRORS_CONT); } else if (!strcmp (value, "remount-ro")) { - clear_opt (*mount_options, ERRORS_CONT); - clear_opt (*mount_options, ERRORS_PANIC); - set_opt (*mount_options, ERRORS_RO); + clear_opt (sbi->s_mount_opt, ERRORS_CONT); + clear_opt (sbi->s_mount_opt, ERRORS_PANIC); + set_opt (sbi->s_mount_opt, ERRORS_RO); } else if (!strcmp (value, "panic")) { - clear_opt (*mount_options, ERRORS_CONT); - clear_opt (*mount_options, ERRORS_RO); - set_opt (*mount_options, ERRORS_PANIC); + clear_opt (sbi->s_mount_opt, ERRORS_CONT); + clear_opt (sbi->s_mount_opt, ERRORS_RO); + set_opt (sbi->s_mount_opt, ERRORS_PANIC); } else { printk (KERN_ERR @@ -613,29 +641,25 @@ } else if (!strcmp (this_char, "grpid") || !strcmp (this_char, "bsdgroups")) - set_opt (*mount_options, GRPID); + set_opt (sbi->s_mount_opt, GRPID); else if (!strcmp (this_char, "minixdf")) - set_opt (*mount_options, MINIX_DF); + set_opt (sbi->s_mount_opt, MINIX_DF); else if (!strcmp (this_char, "nocheck")) - clear_opt (*mount_options, CHECK); + clear_opt (sbi->s_mount_opt, CHECK); else if (!strcmp (this_char, "nogrpid") || !strcmp (this_char, "sysvgroups")) - clear_opt (*mount_options, GRPID); + clear_opt (sbi->s_mount_opt, GRPID); else if (!strcmp (this_char, "resgid")) { unsigned long v; if (want_numeric(value, "resgid", &v)) return 0; - *resgid = v; + sbi->s_resgid = v; } else if (!strcmp (this_char, "resuid")) { unsigned long v; if (want_numeric(value, "resuid", &v)) return 0; - *resuid = v; - } - else if (!strcmp (this_char, "sb")) { - if (want_numeric(value, "sb", sb_block)) - return 0; + sbi->s_resuid = v; } #ifdef CONFIG_JBD_DEBUG else if (!strcmp (this_char, "ro-after")) { @@ -666,12 +690,12 @@ if (want_value(value, "journal")) return 0; if (!strcmp (value, "update")) - set_opt (*mount_options, UPDATE_JOURNAL); + set_opt (sbi->s_mount_opt, UPDATE_JOURNAL); else if (want_numeric(value, "journal", inum)) return 0; } else if (!strcmp (this_char, "noload")) - set_opt (*mount_options, NOLOAD); + set_opt (sbi->s_mount_opt, NOLOAD); else if (!strcmp (this_char, "data")) { int data_opt = 0; @@ -690,7 +714,7 @@ return 0; } if (is_remount) { - if ((*mount_options & EXT3_MOUNT_DATA_FLAGS) != + if ((sbi->s_mount_opt & EXT3_MOUNT_DATA_FLAGS) != data_opt) { printk(KERN_ERR "EXT3-fs: cannot change data " @@ -698,8 +722,8 @@ return 0; } } else { - *mount_options &= ~EXT3_MOUNT_DATA_FLAGS; - *mount_options |= data_opt; + sbi->s_mount_opt &= ~EXT3_MOUNT_DATA_FLAGS; + sbi->s_mount_opt |= data_opt; } } else if (!strcmp (this_char, "commit")) { unsigned long v; @@ -948,16 +972,34 @@ return res; } +static unsigned long descriptor_loc(struct super_block *sb, + unsigned long logic_sb_block, + int nr) +{ + struct ext3_sb_info *sbi = EXT3_SB(sb); + unsigned long bg, first_data_block, first_meta_bg; + + first_data_block = le32_to_cpu(sbi->s_es->s_first_data_block); + first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg); + + if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_META_BG) || + nr < first_meta_bg) + return (logic_sb_block + nr + 1); + bg = sbi->s_desc_per_block * nr; + return (first_data_block + 1 + (bg * sbi->s_blocks_per_group)); +} + static int ext3_fill_super (struct super_block *sb, void *data, int silent) { struct buffer_head * bh; struct ext3_super_block *es = 0; struct ext3_sb_info *sbi; - unsigned long sb_block = 1; - unsigned long logic_sb_block = 1; + unsigned long sb_block = get_sb_block(&data); + unsigned long block, logic_sb_block = 1; unsigned long offset = 0; unsigned long journal_inum = 0; + unsigned long def_mount_opts; int blocksize; int hblock; int db_count; @@ -967,13 +1009,6 @@ #ifdef CONFIG_JBD_DEBUG ext3_ro_after = 0; #endif - /* - * See what the current blocksize for the device is, and - * use that as the blocksize. Otherwise (or if the blocksize - * is smaller than the default) use the default. - * This is important for devices that have a hardware - * sectorsize that is larger than the default. - */ sbi = kmalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) return -ENOMEM; @@ -982,8 +1017,6 @@ sbi->s_mount_opt = 0; sbi->s_resuid = EXT3_DEF_RESUID; sbi->s_resgid = EXT3_DEF_RESGID; - if (!parse_options ((char *) data, &sb_block, sbi, &journal_inum, 0)) - goto out_fail; blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE); if (!blocksize) { @@ -1018,6 +1051,40 @@ sb->s_id); goto failed_mount; } + + /* Set defaults before we parse the mount options */ + def_mount_opts = le32_to_cpu(es->s_default_mount_opts); + if (def_mount_opts & EXT3_DEFM_DEBUG) + set_opt(sbi->s_mount_opt, DEBUG); + if (def_mount_opts & EXT3_DEFM_BSDGROUPS) + set_opt(sbi->s_mount_opt, GRPID); + if (def_mount_opts & EXT3_DEFM_UID16) + set_opt(sbi->s_mount_opt, NO_UID32); + if (def_mount_opts & EXT3_DEFM_XATTR_USER) + set_opt(sbi->s_mount_opt, XATTR_USER); + if (def_mount_opts & EXT3_DEFM_ACL) + set_opt(sbi->s_mount_opt, POSIX_ACL); + if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_DATA) + sbi->s_mount_opt |= EXT3_MOUNT_JOURNAL_DATA; + else if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_ORDERED) + sbi->s_mount_opt |= EXT3_MOUNT_ORDERED_DATA; + else if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_WBACK) + sbi->s_mount_opt |= EXT3_MOUNT_WRITEBACK_DATA; + + if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_PANIC) + set_opt(sbi->s_mount_opt, ERRORS_PANIC); + else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_RO) + set_opt(sbi->s_mount_opt, ERRORS_RO); + + sbi->s_resuid = le16_to_cpu(es->s_def_resuid); + sbi->s_resgid = le16_to_cpu(es->s_def_resgid); + + if (!parse_options ((char *) data, sbi, &journal_inum, 0)) + goto failed_mount; + + sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | + ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); + if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV && (EXT3_HAS_COMPAT_FEATURE(sb, ~0U) || EXT3_HAS_RO_COMPAT_FEATURE(sb, ~0U) || @@ -1092,7 +1159,9 @@ } else { sbi->s_inode_size = le16_to_cpu(es->s_inode_size); sbi->s_first_ino = le32_to_cpu(es->s_first_ino); - if (sbi->s_inode_size != EXT3_GOOD_OLD_INODE_SIZE) { + if ((sbi->s_inode_size < EXT3_GOOD_OLD_INODE_SIZE) || + (sbi->s_inode_size & (sbi->s_inode_size - 1)) || + (sbi->s_inode_size > blocksize)) { printk (KERN_ERR "EXT3-fs: unsupported inode size: %d\n", sbi->s_inode_size); @@ -1115,10 +1184,6 @@ sbi->s_itb_per_group = sbi->s_inodes_per_group /sbi->s_inodes_per_block; sbi->s_desc_per_block = blocksize / sizeof(struct ext3_group_desc); sbi->s_sbh = bh; - if (sbi->s_resuid == EXT3_DEF_RESUID) - sbi->s_resuid = le16_to_cpu(es->s_def_resuid); - if (sbi->s_resgid == EXT3_DEF_RESGID) - sbi->s_resgid = le16_to_cpu(es->s_def_resgid); sbi->s_mount_state = le16_to_cpu(es->s_state); sbi->s_addr_per_block_bits = log2(EXT3_ADDR_PER_BLOCK(sb)); sbi->s_desc_per_block_bits = log2(EXT3_DESC_PER_BLOCK(sb)); @@ -1157,8 +1222,16 @@ printk (KERN_ERR "EXT3-fs: not enough memory\n"); goto failed_mount; } + sbi->s_debts = kmalloc(sbi->s_groups_count * sizeof(*sbi->s_debts), + GFP_KERNEL); + if (!sbi->s_debts) { + printk ("EXT3-fs: not enough memory\n"); + goto failed_mount2; + } + memset(sbi->s_debts, 0, sbi->s_groups_count * sizeof(*sbi->s_debts)); for (i = 0; i < db_count; i++) { - sbi->s_group_desc[i] = sb_bread(sb, logic_sb_block + i + 1); + block = descriptor_loc(sb, logic_sb_block, i); + sbi->s_group_desc[i] = sb_bread(sb, block); if (!sbi->s_group_desc[i]) { printk (KERN_ERR "EXT3-fs: " "can't read group descriptor %d\n", i); @@ -1171,6 +1244,7 @@ goto failed_mount2; } sbi->s_gdb_count = db_count; + sbi->s_dir_count = ext3_count_dirs(sb); /* * set up enough so that it can read an inode */ @@ -1274,6 +1348,8 @@ failed_mount3: journal_destroy(sbi->s_journal); failed_mount2: + if (sbi->s_debts) + kfree(sbi->s_debts); for (i = 0; i < db_count; i++) brelse(sbi->s_group_desc[i]); kfree(sbi->s_group_desc); @@ -1702,12 +1778,15 @@ /* * Allow the "check" option to be passed as a remount option. */ - if (!parse_options(data, &tmp, sbi, &tmp, 1)) + if (!parse_options(data, sbi, &tmp, 1)) return -EINVAL; if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) ext3_abort(sb, __FUNCTION__, "Abort forced by user"); + sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | + ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); + es = sbi->s_es; ext3_init_journal_params(sbi, sbi->s_journal); @@ -1824,7 +1903,10 @@ static int __init init_ext3_fs(void) { - int err = init_inodecache(); + int err = init_ext3_xattr(); + if (err) + return err; + err = init_inodecache(); if (err) goto out1; err = register_filesystem(&ext3_fs_type); @@ -1834,6 +1916,7 @@ out: destroy_inodecache(); out1: + exit_ext3_xattr(); return err; } @@ -1841,6 +1924,7 @@ { unregister_filesystem(&ext3_fs_type); destroy_inodecache(); + exit_ext3_xattr(); } MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); diff -Nru a/fs/ext3/symlink.c b/fs/ext3/symlink.c --- a/fs/ext3/symlink.c Mon Nov 4 14:31:02 2002 +++ b/fs/ext3/symlink.c Mon Nov 4 14:31:02 2002 @@ -20,6 +20,7 @@ #include #include #include +#include "xattr.h" static int ext3_readlink(struct dentry *dentry, char *buffer, int buflen) { @@ -33,7 +34,20 @@ return vfs_follow_link(nd, (char*)ei->i_data); } +struct inode_operations ext3_symlink_inode_operations = { + .readlink = page_readlink, + .follow_link = page_follow_link, + .setxattr = ext3_setxattr, + .getxattr = ext3_getxattr, + .listxattr = ext3_listxattr, + .removexattr = ext3_removexattr, +}; + struct inode_operations ext3_fast_symlink_inode_operations = { - .readlink = ext3_readlink, /* BKL not held. Don't need */ + .readlink = ext3_readlink, /* BKL not held. Don't need */ .follow_link = ext3_follow_link, /* BKL not held. Don't need */ + .setxattr = ext3_setxattr, + .getxattr = ext3_getxattr, + .listxattr = ext3_listxattr, + .removexattr = ext3_removexattr, }; diff -Nru a/fs/ext3/xattr.c b/fs/ext3/xattr.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/ext3/xattr.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,1142 @@ +/* + * linux/fs/ext3/xattr.c + * + * Copyright (C) 2001 by Andreas Gruenbacher, + * + * Fix by Harrison Xing . + * Ext3 code with a lot of help from Eric Jarman . + * Extended attributes for symlinks and special files added per + * suggestion of Luka Renko . + */ + +/* + * Extended attributes are stored on disk blocks allocated outside of + * any inode. The i_file_acl field is then made to point to this allocated + * block. If all extended attributes of an inode are identical, these + * inodes may share the same extended attribute block. Such situations + * are automatically detected by keeping a cache of recent attribute block + * numbers and hashes over the block's contents in memory. + * + * + * Extended attribute block layout: + * + * +------------------+ + * | header | + * ¦ entry 1 | | + * | entry 2 | | growing downwards + * | entry 3 | v + * | four null bytes | + * | . . . | + * | value 1 | ^ + * | value 3 | | growing upwards + * | value 2 | | + * +------------------+ + * + * The block header is followed by multiple entry descriptors. These entry + * descriptors are variable in size, and alligned to EXT3_XATTR_PAD + * byte boundaries. The entry descriptors are sorted by attribute name, + * so that two extended attribute blocks can be compared efficiently. + * + * Attribute values are aligned to the end of the block, stored in + * no specific order. They are also padded to EXT3_XATTR_PAD byte + * boundaries. No additional gaps are left between them. + * + * Locking strategy + * ---------------- + * The VFS holdsinode->i_sem semaphore when any of the xattr inode + * operations are called, so we are guaranteed that only one + * processes accesses extended attributes of an inode at any time. + * + * For writing we also grab the ext3_xattr_sem semaphore. This ensures that + * only a single process is modifying an extended attribute block, even + * if the block is shared among inodes. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "xattr.h" +#include "acl.h" + +#define EXT3_EA_USER "user." + +#define HDR(bh) ((struct ext3_xattr_header *)((bh)->b_data)) +#define ENTRY(ptr) ((struct ext3_xattr_entry *)(ptr)) +#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1) +#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) + +#ifdef EXT3_XATTR_DEBUG +# define ea_idebug(inode, f...) do { \ + printk(KERN_DEBUG "inode %s:%ld: ", \ + kdevname(inode->i_dev), inode->i_ino); \ + printk(f); \ + printk("\n"); \ + } while (0) +# define ea_bdebug(bh, f...) do { \ + printk(KERN_DEBUG "block %s:%ld: ", \ + kdevname(bh->b_dev), bh->b_blocknr); \ + printk(f); \ + printk("\n"); \ + } while (0) +#else +# define ea_idebug(f...) +# define ea_bdebug(f...) +#endif + +static int ext3_xattr_set2(handle_t *, struct inode *, struct buffer_head *, + struct ext3_xattr_header *); + +static int ext3_xattr_cache_insert(struct buffer_head *); +static struct buffer_head *ext3_xattr_cache_find(struct inode *, + struct ext3_xattr_header *); +static void ext3_xattr_cache_remove(struct buffer_head *); +static void ext3_xattr_rehash(struct ext3_xattr_header *, + struct ext3_xattr_entry *); + +static struct mb_cache *ext3_xattr_cache; + +/* + * If a file system does not share extended attributes among inodes, + * we should not need the ext3_xattr_sem semaphore. However, the + * filesystem may still contain shared blocks, so we always take + * the lock. + */ + +static DECLARE_MUTEX(ext3_xattr_sem); +static struct ext3_xattr_handler *ext3_xattr_handlers[EXT3_XATTR_INDEX_MAX]; +static rwlock_t ext3_handler_lock = RW_LOCK_UNLOCKED; + +int +ext3_xattr_register(int name_index, struct ext3_xattr_handler *handler) +{ + int error = -EINVAL; + + if (name_index > 0 && name_index <= EXT3_XATTR_INDEX_MAX) { + write_lock(&ext3_handler_lock); + if (!ext3_xattr_handlers[name_index-1]) { + ext3_xattr_handlers[name_index-1] = handler; + error = 0; + } + write_unlock(&ext3_handler_lock); + } + return error; +} + +void +ext3_xattr_unregister(int name_index, struct ext3_xattr_handler *handler) +{ + if (name_index > 0 || name_index <= EXT3_XATTR_INDEX_MAX) { + write_lock(&ext3_handler_lock); + ext3_xattr_handlers[name_index-1] = NULL; + write_unlock(&ext3_handler_lock); + } +} + +static inline const char * +strcmp_prefix(const char *a, const char *a_prefix) +{ + while (*a_prefix && *a == *a_prefix) { + a++; + a_prefix++; + } + return *a_prefix ? NULL : a; +} + +/* + * Decode the extended attribute name, and translate it into + * the name_index and name suffix. + */ +static inline struct ext3_xattr_handler * +ext3_xattr_resolve_name(const char **name) +{ + struct ext3_xattr_handler *handler = NULL; + int i; + + if (!*name) + return NULL; + read_lock(&ext3_handler_lock); + for (i=0; iprefix); + if (n) { + handler = ext3_xattr_handlers[i]; + *name = n; + break; + } + } + } + read_unlock(&ext3_handler_lock); + return handler; +} + +static inline struct ext3_xattr_handler * +ext3_xattr_handler(int name_index) +{ + struct ext3_xattr_handler *handler = NULL; + if (name_index > 0 && name_index <= EXT3_XATTR_INDEX_MAX) { + read_lock(&ext3_handler_lock); + handler = ext3_xattr_handlers[name_index-1]; + read_unlock(&ext3_handler_lock); + } + return handler; +} + +/* + * Inode operation getxattr() + * + * dentry->d_inode->i_sem down + */ +ssize_t +ext3_getxattr(struct dentry *dentry, const char *name, + void *buffer, size_t size) +{ + struct ext3_xattr_handler *handler; + struct inode *inode = dentry->d_inode; + + handler = ext3_xattr_resolve_name(&name); + if (!handler) + return -EOPNOTSUPP; + return handler->get(inode, name, buffer, size); +} + +/* + * Inode operation listxattr() + * + * dentry->d_inode->i_sem down + */ +ssize_t +ext3_listxattr(struct dentry *dentry, char *buffer, size_t size) +{ + return ext3_xattr_list(dentry->d_inode, buffer, size); +} + +/* + * Inode operation setxattr() + * + * dentry->d_inode->i_sem down + */ +int +ext3_setxattr(struct dentry *dentry, const char *name, + void *value, size_t size, int flags) +{ + struct ext3_xattr_handler *handler; + struct inode *inode = dentry->d_inode; + + if (size == 0) + value = ""; /* empty EA, do not remove */ + handler = ext3_xattr_resolve_name(&name); + if (!handler) + return -EOPNOTSUPP; + return handler->set(inode, name, value, size, flags); +} + +/* + * Inode operation removexattr() + * + * dentry->d_inode->i_sem down + */ +int +ext3_removexattr(struct dentry *dentry, const char *name) +{ + struct ext3_xattr_handler *handler; + struct inode *inode = dentry->d_inode; + + handler = ext3_xattr_resolve_name(&name); + if (!handler) + return -EOPNOTSUPP; + return handler->set(inode, name, NULL, 0, XATTR_REPLACE); +} + +/* + * ext3_xattr_get() + * + * Copy an extended attribute into the buffer + * provided, or compute the buffer size required. + * Buffer is NULL to compute the size of the buffer required. + * + * Returns a negative error number on failure, or the number of bytes + * used / required on success. + */ +int +ext3_xattr_get(struct inode *inode, int name_index, const char *name, + void *buffer, size_t buffer_size) +{ + struct buffer_head *bh = NULL; + struct ext3_xattr_entry *entry; + unsigned int size; + char *end; + int name_len, error; + + ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", + name_index, name, buffer, (long)buffer_size); + + if (name == NULL) + return -EINVAL; + if (!EXT3_I(inode)->i_file_acl) + return -ENODATA; + ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl); + bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); + if (!bh) + return -EIO; + ea_bdebug(bh, "b_count=%d, refcount=%d", + atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); + end = bh->b_data + bh->b_size; + if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || + HDR(bh)->h_blocks != cpu_to_le32(1)) { +bad_block: ext3_error(inode->i_sb, "ext3_xattr_get", + "inode %ld: bad block %d", inode->i_ino, + EXT3_I(inode)->i_file_acl); + error = -EIO; + goto cleanup; + } + /* find named attribute */ + name_len = strlen(name); + + error = -ERANGE; + if (name_len > 255) + goto cleanup; + entry = FIRST_ENTRY(bh); + while (!IS_LAST_ENTRY(entry)) { + struct ext3_xattr_entry *next = + EXT3_XATTR_NEXT(entry); + if ((char *)next >= end) + goto bad_block; + if (name_index == entry->e_name_index && + name_len == entry->e_name_len && + memcmp(name, entry->e_name, name_len) == 0) + goto found; + entry = next; + } + /* Check the remaining name entries */ + while (!IS_LAST_ENTRY(entry)) { + struct ext3_xattr_entry *next = + EXT3_XATTR_NEXT(entry); + if ((char *)next >= end) + goto bad_block; + entry = next; + } + if (ext3_xattr_cache_insert(bh)) + ea_idebug(inode, "cache insert failed"); + error = -ENODATA; + goto cleanup; +found: + /* check the buffer size */ + if (entry->e_value_block != 0) + goto bad_block; + size = le32_to_cpu(entry->e_value_size); + if (size > inode->i_sb->s_blocksize || + le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize) + goto bad_block; + + if (ext3_xattr_cache_insert(bh)) + ea_idebug(inode, "cache insert failed"); + if (buffer) { + error = -ERANGE; + if (size > buffer_size) + goto cleanup; + /* return value of attribute */ + memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs), + size); + } + error = size; + +cleanup: + brelse(bh); + + return error; +} + +/* + * ext3_xattr_list() + * + * Copy a list of attribute names into the buffer + * provided, or compute the buffer size required. + * Buffer is NULL to compute the size of the buffer required. + * + * Returns a negative error number on failure, or the number of bytes + * used / required on success. + */ +int +ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) +{ + struct buffer_head *bh = NULL; + struct ext3_xattr_entry *entry; + unsigned int size = 0; + char *buf, *end; + int error; + + ea_idebug(inode, "buffer=%p, buffer_size=%ld", + buffer, (long)buffer_size); + + if (!EXT3_I(inode)->i_file_acl) + return 0; + ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl); + bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); + if (!bh) + return -EIO; + ea_bdebug(bh, "b_count=%d, refcount=%d", + atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); + end = bh->b_data + bh->b_size; + if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || + HDR(bh)->h_blocks != cpu_to_le32(1)) { +bad_block: ext3_error(inode->i_sb, "ext3_xattr_list", + "inode %ld: bad block %d", inode->i_ino, + EXT3_I(inode)->i_file_acl); + error = -EIO; + goto cleanup; + } + /* compute the size required for the list of attribute names */ + for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry); + entry = EXT3_XATTR_NEXT(entry)) { + struct ext3_xattr_handler *handler; + struct ext3_xattr_entry *next = + EXT3_XATTR_NEXT(entry); + if ((char *)next >= end) + goto bad_block; + + handler = ext3_xattr_handler(entry->e_name_index); + if (handler) { + size += handler->list(NULL, inode, entry->e_name, + entry->e_name_len) + 1; + } + } + + if (ext3_xattr_cache_insert(bh)) + ea_idebug(inode, "cache insert failed"); + if (!buffer) { + error = size; + goto cleanup; + } else { + error = -ERANGE; + if (size > buffer_size) + goto cleanup; + } + + /* list the attribute names */ + buf = buffer; + for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry); + entry = EXT3_XATTR_NEXT(entry)) { + struct ext3_xattr_handler *handler; + + handler = ext3_xattr_handler(entry->e_name_index); + if (handler) { + buf += handler->list(buf, inode, entry->e_name, + entry->e_name_len); + *buf++ = '\0'; + } + } + error = size; + +cleanup: + brelse(bh); + + return error; +} + +/* + * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is + * not set, set it. + */ +static void ext3_xattr_update_super_block(handle_t *handle, + struct super_block *sb) +{ + if (EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_EXT_ATTR)) + return; + + lock_super(sb); + ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); + EXT3_SB(sb)->s_es->s_feature_compat |= + cpu_to_le32(EXT3_FEATURE_COMPAT_EXT_ATTR); + sb->s_dirt = 1; + ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); + unlock_super(sb); +} + +/* + * ext3_xattr_set() + * + * Create, replace or remove an extended attribute for this inode. Buffer + * is NULL to remove an existing extended attribute, and non-NULL to + * either replace an existing extended attribute, or create a new extended + * attribute. The flags XATTR_REPLACE and XATTR_CREATE + * specify that an extended attribute must exist and must not exist + * previous to the call, respectively. + * + * Returns 0, or a negative error number on failure. + */ +int +ext3_xattr_set(handle_t *handle, struct inode *inode, int name_index, + const char *name, const void *value, size_t value_len, int flags) +{ + struct super_block *sb = inode->i_sb; + struct buffer_head *bh = NULL; + struct ext3_xattr_header *header = NULL; + struct ext3_xattr_entry *here, *last; + unsigned int name_len; + int min_offs = sb->s_blocksize, not_found = 1, free, error; + char *end; + + /* + * header -- Points either into bh, or to a temporarily + * allocated buffer. + * here -- The named entry found, or the place for inserting, within + * the block pointed to by header. + * last -- Points right after the last named entry within the block + * pointed to by header. + * min_offs -- The offset of the first value (values are aligned + * towards the end of the block). + * end -- Points right after the block pointed to by header. + */ + + ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", + name_index, name, value, (long)value_len); + + if (IS_RDONLY(inode)) + return -EROFS; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + return -EPERM; + if (value == NULL) + value_len = 0; + if (name == NULL) + return -EINVAL; + name_len = strlen(name); + if (name_len > 255 || value_len > sb->s_blocksize) + return -ERANGE; + down(&ext3_xattr_sem); + + if (EXT3_I(inode)->i_file_acl) { + /* The inode already has an extended attribute block. */ + bh = sb_bread(sb, EXT3_I(inode)->i_file_acl); + error = -EIO; + if (!bh) + goto cleanup; + ea_bdebug(bh, "b_count=%d, refcount=%d", + atomic_read(&(bh->b_count)), + le32_to_cpu(HDR(bh)->h_refcount)); + header = HDR(bh); + end = bh->b_data + bh->b_size; + if (header->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || + header->h_blocks != cpu_to_le32(1)) { +bad_block: ext3_error(sb, "ext3_xattr_set", + "inode %ld: bad block %d", inode->i_ino, + EXT3_I(inode)->i_file_acl); + error = -EIO; + goto cleanup; + } + /* Find the named attribute. */ + here = FIRST_ENTRY(bh); + while (!IS_LAST_ENTRY(here)) { + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(here); + if ((char *)next >= end) + goto bad_block; + if (!here->e_value_block && here->e_value_size) { + int offs = le16_to_cpu(here->e_value_offs); + if (offs < min_offs) + min_offs = offs; + } + not_found = name_index - here->e_name_index; + if (!not_found) + not_found = name_len - here->e_name_len; + if (!not_found) + not_found = memcmp(name, here->e_name,name_len); + if (not_found <= 0) + break; + here = next; + } + last = here; + /* We still need to compute min_offs and last. */ + while (!IS_LAST_ENTRY(last)) { + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last); + if ((char *)next >= end) + goto bad_block; + if (!last->e_value_block && last->e_value_size) { + int offs = le16_to_cpu(last->e_value_offs); + if (offs < min_offs) + min_offs = offs; + } + last = next; + } + + /* Check whether we have enough space left. */ + free = min_offs - ((char*)last - (char*)header) - sizeof(__u32); + } else { + /* We will use a new extended attribute block. */ + free = sb->s_blocksize - + sizeof(struct ext3_xattr_header) - sizeof(__u32); + here = last = NULL; /* avoid gcc uninitialized warning. */ + } + + if (not_found) { + /* Request to remove a nonexistent attribute? */ + error = -ENODATA; + if (flags & XATTR_REPLACE) + goto cleanup; + error = 0; + if (value == NULL) + goto cleanup; + else + free -= EXT3_XATTR_LEN(name_len); + } else { + /* Request to create an existing attribute? */ + error = -EEXIST; + if (flags & XATTR_CREATE) + goto cleanup; + if (!here->e_value_block && here->e_value_size) { + unsigned int size = le32_to_cpu(here->e_value_size); + + if (le16_to_cpu(here->e_value_offs) + size > + sb->s_blocksize || size > sb->s_blocksize) + goto bad_block; + free += EXT3_XATTR_SIZE(size); + } + } + free -= EXT3_XATTR_SIZE(value_len); + error = -ENOSPC; + if (free < 0) + goto cleanup; + + /* Here we know that we can set the new attribute. */ + + if (header) { + if (header->h_refcount == cpu_to_le32(1)) { + ea_bdebug(bh, "modifying in-place"); + ext3_xattr_cache_remove(bh); + error = ext3_journal_get_write_access(handle, bh); + if (error) + goto cleanup; + } else { + int offset; + + ea_bdebug(bh, "cloning"); + header = kmalloc(bh->b_size, GFP_KERNEL); + error = -ENOMEM; + if (header == NULL) + goto cleanup; + memcpy(header, HDR(bh), bh->b_size); + header->h_refcount = cpu_to_le32(1); + offset = (char *)header - bh->b_data; + here = ENTRY((char *)here + offset); + last = ENTRY((char *)last + offset); + } + } else { + /* Allocate a buffer where we construct the new block. */ + header = kmalloc(sb->s_blocksize, GFP_KERNEL); + error = -ENOMEM; + if (header == NULL) + goto cleanup; + memset(header, 0, sb->s_blocksize); + end = (char *)header + sb->s_blocksize; + header->h_magic = cpu_to_le32(EXT3_XATTR_MAGIC); + header->h_blocks = header->h_refcount = cpu_to_le32(1); + last = here = ENTRY(header+1); + } + + if (not_found) { + /* Insert the new name. */ + int size = EXT3_XATTR_LEN(name_len); + int rest = (char *)last - (char *)here; + memmove((char *)here + size, here, rest); + memset(here, 0, size); + here->e_name_index = name_index; + here->e_name_len = name_len; + memcpy(here->e_name, name, name_len); + } else { + /* Remove the old value. */ + if (!here->e_value_block && here->e_value_size) { + char *first_val = (char *)header + min_offs; + int offs = le16_to_cpu(here->e_value_offs); + char *val = (char *)header + offs; + size_t size = EXT3_XATTR_SIZE( + le32_to_cpu(here->e_value_size)); + memmove(first_val + size, first_val, val - first_val); + memset(first_val, 0, size); + here->e_value_offs = 0; + min_offs += size; + + /* Adjust all value offsets. */ + last = ENTRY(header+1); + while (!IS_LAST_ENTRY(last)) { + int o = le16_to_cpu(last->e_value_offs); + if (!last->e_value_block && o < offs) + last->e_value_offs = + cpu_to_le16(o + size); + last = EXT3_XATTR_NEXT(last); + } + } + if (value == NULL) { + /* Remove this attribute. */ + if (EXT3_XATTR_NEXT(ENTRY(header+1)) == last) { + /* This block is now empty. */ + error = ext3_xattr_set2(handle, inode, bh,NULL); + goto cleanup; + } else { + /* Remove the old name. */ + int size = EXT3_XATTR_LEN(name_len); + last = ENTRY((char *)last - size); + memmove(here, (char*)here + size, + (char*)last - (char*)here); + memset(last, 0, size); + } + } + } + + if (value != NULL) { + /* Insert the new value. */ + here->e_value_size = cpu_to_le32(value_len); + if (value_len) { + size_t size = EXT3_XATTR_SIZE(value_len); + char *val = (char *)header + min_offs - size; + here->e_value_offs = + cpu_to_le16((char *)val - (char *)header); + memset(val + size - EXT3_XATTR_PAD, 0, + EXT3_XATTR_PAD); /* Clear the pad bytes. */ + memcpy(val, value, value_len); + } + } + ext3_xattr_rehash(header, here); + + error = ext3_xattr_set2(handle, inode, bh, header); + +cleanup: + brelse(bh); + if (!(bh && header == HDR(bh))) + kfree(header); + up(&ext3_xattr_sem); + + return error; +} + +/* + * Second half of ext3_xattr_set(): Update the file system. + */ +static int +ext3_xattr_set2(handle_t *handle, struct inode *inode, + struct buffer_head *old_bh, struct ext3_xattr_header *header) +{ + struct super_block *sb = inode->i_sb; + struct buffer_head *new_bh = NULL; + int error; + + if (header) { + new_bh = ext3_xattr_cache_find(inode, header); + if (new_bh) { + /* + * We found an identical block in the cache. + * The old block will be released after updating + * the inode. + */ + ea_bdebug(old_bh, "reusing block %ld", + new_bh->b_blocknr); + + error = -EDQUOT; + if (DQUOT_ALLOC_BLOCK(inode, 1)) + goto cleanup; + + error = ext3_journal_get_write_access(handle, new_bh); + if (error) + goto cleanup; + HDR(new_bh)->h_refcount = cpu_to_le32( + le32_to_cpu(HDR(new_bh)->h_refcount) + 1); + ea_bdebug(new_bh, "refcount now=%d", + le32_to_cpu(HDR(new_bh)->h_refcount)); + } else if (old_bh && header == HDR(old_bh)) { + /* Keep this block. */ + new_bh = old_bh; + ext3_xattr_cache_insert(new_bh); + } else { + /* We need to allocate a new block */ + int goal = le32_to_cpu( + EXT3_SB(sb)->s_es->s_first_data_block) + + EXT3_I(inode)->i_block_group * + EXT3_BLOCKS_PER_GROUP(sb); + int block = ext3_new_block(handle, + inode, goal, 0, 0, &error); + if (error) + goto cleanup; + ea_idebug(inode, "creating block %d", block); + + new_bh = sb_getblk(sb, block); + if (!new_bh) { +getblk_failed: + ext3_free_blocks(handle, inode, block, 1); + error = -EIO; + goto cleanup; + } + lock_buffer(new_bh); + error = ext3_journal_get_create_access(handle, new_bh); + if (error) { + unlock_buffer(new_bh); + goto getblk_failed; + } + memcpy(new_bh->b_data, header, new_bh->b_size); + set_buffer_uptodate(new_bh); + unlock_buffer(new_bh); + ext3_xattr_cache_insert(new_bh); + + ext3_xattr_update_super_block(handle, sb); + } + error = ext3_journal_dirty_metadata(handle, new_bh); + if (error) + goto cleanup; + } + + /* Update the inode. */ + EXT3_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0; + inode->i_ctime = CURRENT_TIME; + ext3_mark_inode_dirty(handle, inode); + if (IS_SYNC(inode)) + handle->h_sync = 1; + + error = 0; + if (old_bh && old_bh != new_bh) { + /* + * If there was an old block, and we are not still using it, + * we now release the old block. + */ + unsigned int refcount = le32_to_cpu(HDR(old_bh)->h_refcount); + + error = ext3_journal_get_write_access(handle, old_bh); + if (error) + goto cleanup; + if (refcount == 1) { + /* Free the old block. */ + ea_bdebug(old_bh, "freeing"); + ext3_free_blocks(handle, inode, old_bh->b_blocknr, 1); + + /* ext3_forget() calls bforget() for us, but we + let our caller release old_bh, so we need to + duplicate the handle before. */ + get_bh(old_bh); + ext3_forget(handle, 1, inode, old_bh,old_bh->b_blocknr); + } else { + /* Decrement the refcount only. */ + refcount--; + HDR(old_bh)->h_refcount = cpu_to_le32(refcount); + DQUOT_FREE_BLOCK(inode, 1); + ext3_journal_dirty_metadata(handle, old_bh); + ea_bdebug(old_bh, "refcount now=%d", refcount); + } + } + +cleanup: + if (old_bh != new_bh) + brelse(new_bh); + + return error; +} + +/* + * ext3_xattr_delete_inode() + * + * Free extended attribute resources associated with this inode. This + * is called immediately before an inode is freed. + */ +void +ext3_xattr_delete_inode(handle_t *handle, struct inode *inode) +{ + struct buffer_head *bh; + + if (!EXT3_I(inode)->i_file_acl) + return; + down(&ext3_xattr_sem); + + bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); + if (!bh) { + ext3_error(inode->i_sb, "ext3_xattr_delete_inode", + "inode %ld: block %d read error", inode->i_ino, + EXT3_I(inode)->i_file_acl); + goto cleanup; + } + ea_bdebug(bh, "b_count=%d", atomic_read(&(bh->b_count))); + if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || + HDR(bh)->h_blocks != cpu_to_le32(1)) { + ext3_error(inode->i_sb, "ext3_xattr_delete_inode", + "inode %ld: bad block %d", inode->i_ino, + EXT3_I(inode)->i_file_acl); + goto cleanup; + } + ext3_journal_get_write_access(handle, bh); + ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1); + if (HDR(bh)->h_refcount == cpu_to_le32(1)) { + ext3_xattr_cache_remove(bh); + ext3_free_blocks(handle, inode, EXT3_I(inode)->i_file_acl, 1); + ext3_forget(handle, 1, inode, bh, EXT3_I(inode)->i_file_acl); + bh = NULL; + } else { + HDR(bh)->h_refcount = cpu_to_le32( + le32_to_cpu(HDR(bh)->h_refcount) - 1); + ext3_journal_dirty_metadata(handle, bh); + if (IS_SYNC(inode)) + handle->h_sync = 1; + DQUOT_FREE_BLOCK(inode, 1); + } + EXT3_I(inode)->i_file_acl = 0; + +cleanup: + brelse(bh); + up(&ext3_xattr_sem); +} + +/* + * ext3_xattr_put_super() + * + * This is called when a file system is unmounted. + */ +void +ext3_xattr_put_super(struct super_block *sb) +{ + mb_cache_shrink(ext3_xattr_cache, sb->s_bdev); +} + +/* + * ext3_xattr_cache_insert() + * + * Create a new entry in the extended attribute cache, and insert + * it unless such an entry is already in the cache. + * + * Returns 0, or a negative error number on failure. + */ +static int +ext3_xattr_cache_insert(struct buffer_head *bh) +{ + __u32 hash = le32_to_cpu(HDR(bh)->h_hash); + struct mb_cache_entry *ce; + int error; + + ce = mb_cache_entry_alloc(ext3_xattr_cache); + if (!ce) + return -ENOMEM; + error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash); + if (error) { + mb_cache_entry_free(ce); + if (error == -EBUSY) { + ea_bdebug(bh, "already in cache (%d cache entries)", + atomic_read(&ext3_xattr_cache->c_entry_count)); + error = 0; + } + } else { + ea_bdebug(bh, "inserting [%x] (%d cache entries)", (int)hash, + atomic_read(&ext3_xattr_cache->c_entry_count)); + mb_cache_entry_release(ce); + } + return error; +} + +/* + * ext3_xattr_cmp() + * + * Compare two extended attribute blocks for equality. + * + * Returns 0 if the blocks are equal, 1 if they differ, and + * a negative error number on errors. + */ +static int +ext3_xattr_cmp(struct ext3_xattr_header *header1, + struct ext3_xattr_header *header2) +{ + struct ext3_xattr_entry *entry1, *entry2; + + entry1 = ENTRY(header1+1); + entry2 = ENTRY(header2+1); + while (!IS_LAST_ENTRY(entry1)) { + if (IS_LAST_ENTRY(entry2)) + return 1; + if (entry1->e_hash != entry2->e_hash || + entry1->e_name_len != entry2->e_name_len || + entry1->e_value_size != entry2->e_value_size || + memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len)) + return 1; + if (entry1->e_value_block != 0 || entry2->e_value_block != 0) + return -EIO; + if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs), + (char *)header2 + le16_to_cpu(entry2->e_value_offs), + le32_to_cpu(entry1->e_value_size))) + return 1; + + entry1 = EXT3_XATTR_NEXT(entry1); + entry2 = EXT3_XATTR_NEXT(entry2); + } + if (!IS_LAST_ENTRY(entry2)) + return 1; + return 0; +} + +/* + * ext3_xattr_cache_find() + * + * Find an identical extended attribute block. + * + * Returns a pointer to the block found, or NULL if such a block was + * not found or an error occurred. + */ +static struct buffer_head * +ext3_xattr_cache_find(struct inode *inode, struct ext3_xattr_header *header) +{ + __u32 hash = le32_to_cpu(header->h_hash); + struct mb_cache_entry *ce; + + if (!header->h_hash) + return NULL; /* never share */ + ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); + ce = mb_cache_entry_find_first(ext3_xattr_cache, 0, inode->i_bdev, hash); + while (ce) { + struct buffer_head *bh = sb_bread(inode->i_sb, ce->e_block); + + if (!bh) { + ext3_error(inode->i_sb, "ext3_xattr_cache_find", + "inode %ld: block %ld read error", + inode->i_ino, (unsigned long) ce->e_block); + } else if (le32_to_cpu(HDR(bh)->h_refcount) > + EXT3_XATTR_REFCOUNT_MAX) { + ea_idebug(inode, "block %ld refcount %d>%d", + (unsigned long) ce->e_block, + le32_to_cpu(HDR(bh)->h_refcount), + EXT3_XATTR_REFCOUNT_MAX); + } else if (!ext3_xattr_cmp(header, HDR(bh))) { + ea_bdebug(bh, "b_count=%d",atomic_read(&(bh->b_count))); + mb_cache_entry_release(ce); + return bh; + } + brelse(bh); + ce = mb_cache_entry_find_next(ce, 0, inode->i_bdev, hash); + } + return NULL; +} + +/* + * ext3_xattr_cache_remove() + * + * Remove the cache entry of a block from the cache. Called when a + * block becomes invalid. + */ +static void +ext3_xattr_cache_remove(struct buffer_head *bh) +{ + struct mb_cache_entry *ce; + + ce = mb_cache_entry_get(ext3_xattr_cache, bh->b_bdev, + bh->b_blocknr); + if (ce) { + ea_bdebug(bh, "removing (%d cache entries remaining)", + atomic_read(&ext3_xattr_cache->c_entry_count)-1); + mb_cache_entry_free(ce); + } else + ea_bdebug(bh, "no cache entry"); +} + +#define NAME_HASH_SHIFT 5 +#define VALUE_HASH_SHIFT 16 + +/* + * ext3_xattr_hash_entry() + * + * Compute the hash of an extended attribute. + */ +static inline void ext3_xattr_hash_entry(struct ext3_xattr_header *header, + struct ext3_xattr_entry *entry) +{ + __u32 hash = 0; + char *name = entry->e_name; + int n; + + for (n=0; n < entry->e_name_len; n++) { + hash = (hash << NAME_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^ + *name++; + } + + if (entry->e_value_block == 0 && entry->e_value_size != 0) { + __u32 *value = (__u32 *)((char *)header + + le16_to_cpu(entry->e_value_offs)); + for (n = (le32_to_cpu(entry->e_value_size) + + EXT3_XATTR_ROUND) >> EXT3_XATTR_PAD_BITS; n; n--) { + hash = (hash << VALUE_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^ + le32_to_cpu(*value++); + } + } + entry->e_hash = cpu_to_le32(hash); +} + +#undef NAME_HASH_SHIFT +#undef VALUE_HASH_SHIFT + +#define BLOCK_HASH_SHIFT 16 + +/* + * ext3_xattr_rehash() + * + * Re-compute the extended attribute hash value after an entry has changed. + */ +static void ext3_xattr_rehash(struct ext3_xattr_header *header, + struct ext3_xattr_entry *entry) +{ + struct ext3_xattr_entry *here; + __u32 hash = 0; + + ext3_xattr_hash_entry(header, entry); + here = ENTRY(header+1); + while (!IS_LAST_ENTRY(here)) { + if (!here->e_hash) { + /* Block is not shared if an entry's hash value == 0 */ + hash = 0; + break; + } + hash = (hash << BLOCK_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^ + le32_to_cpu(here->e_hash); + here = EXT3_XATTR_NEXT(here); + } + header->h_hash = cpu_to_le32(hash); +} + +#undef BLOCK_HASH_SHIFT + +int __init +init_ext3_xattr(void) +{ + int err; + + err = ext3_xattr_register(EXT3_XATTR_INDEX_USER, &ext3_xattr_user_handler); + if (err) + return err; +#ifdef CONFIG_EXT3_FS_POSIX_ACL + err = init_ext3_acl(); + if (err) + goto out; +#endif + ext3_xattr_cache = mb_cache_create("ext3_xattr", NULL, + sizeof(struct mb_cache_entry) + + sizeof(struct mb_cache_entry_index), 1, 6); + if (!ext3_xattr_cache) { + err = -ENOMEM; + goto out1; + } + return 0; +out1: +#ifdef CONFIG_EXT3_FS_POSIX_ACL + exit_ext3_acl(); +out: +#endif + ext3_xattr_unregister(EXT3_XATTR_INDEX_USER, + &ext3_xattr_user_handler); + return err; +} + +void +exit_ext3_xattr(void) +{ + if (ext3_xattr_cache) + mb_cache_destroy(ext3_xattr_cache); + ext3_xattr_cache = NULL; +#ifdef CONFIG_EXT3_FS_POSIX_ACL + exit_ext3_acl(); +#endif + ext3_xattr_unregister(EXT3_XATTR_INDEX_USER, &ext3_xattr_user_handler); +} diff -Nru a/fs/ext3/xattr.h b/fs/ext3/xattr.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/ext3/xattr.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,133 @@ +/* + File: fs/ext3/xattr.h + + On-disk format of extended attributes for the ext3 filesystem. + + (C) 2001 Andreas Gruenbacher, +*/ + +#include +#include + +/* Magic value in attribute blocks */ +#define EXT3_XATTR_MAGIC 0xEA020000 + +/* Maximum number of references to one attribute block */ +#define EXT3_XATTR_REFCOUNT_MAX 1024 + +/* Name indexes */ +#define EXT3_XATTR_INDEX_MAX 10 +#define EXT3_XATTR_INDEX_USER 1 +#define EXT3_XATTR_INDEX_POSIX_ACL_ACCESS 2 +#define EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT 3 + +struct ext3_xattr_header { + __u32 h_magic; /* magic number for identification */ + __u32 h_refcount; /* reference count */ + __u32 h_blocks; /* number of disk blocks used */ + __u32 h_hash; /* hash value of all attributes */ + __u32 h_reserved[4]; /* zero right now */ +}; + +struct ext3_xattr_entry { + __u8 e_name_len; /* length of name */ + __u8 e_name_index; /* attribute name index */ + __u16 e_value_offs; /* offset in disk block of value */ + __u32 e_value_block; /* disk block attribute is stored on (n/i) */ + __u32 e_value_size; /* size of attribute value */ + __u32 e_hash; /* hash value of name and value */ + char e_name[0]; /* attribute name */ +}; + +#define EXT3_XATTR_PAD_BITS 2 +#define EXT3_XATTR_PAD (1<e_name_len)) ) +#define EXT3_XATTR_SIZE(size) \ + (((size) + EXT3_XATTR_ROUND) & ~EXT3_XATTR_ROUND) + +# ifdef CONFIG_EXT3_FS_XATTR + +struct ext3_xattr_handler { + char *prefix; + size_t (*list)(char *list, struct inode *inode, const char *name, + int name_len); + int (*get)(struct inode *inode, const char *name, void *buffer, + size_t size); + int (*set)(struct inode *inode, const char *name, const void *buffer, + size_t size, int flags); +}; + +extern int ext3_xattr_register(int, struct ext3_xattr_handler *); +extern void ext3_xattr_unregister(int, struct ext3_xattr_handler *); + +extern int ext3_setxattr(struct dentry *, const char *, void *, size_t, int); +extern ssize_t ext3_getxattr(struct dentry *, const char *, void *, size_t); +extern ssize_t ext3_listxattr(struct dentry *, char *, size_t); +extern int ext3_removexattr(struct dentry *, const char *); + +extern int ext3_xattr_get(struct inode *, int, const char *, void *, size_t); +extern int ext3_xattr_list(struct inode *, char *, size_t); +extern int ext3_xattr_set(handle_t *handle, struct inode *, int, const char *, const void *, size_t, int); + +extern void ext3_xattr_delete_inode(handle_t *, struct inode *); +extern void ext3_xattr_put_super(struct super_block *); + +extern int init_ext3_xattr(void); +extern void exit_ext3_xattr(void); + +# else /* CONFIG_EXT3_FS_XATTR */ +# define ext3_setxattr NULL +# define ext3_getxattr NULL +# define ext3_listxattr NULL +# define ext3_removexattr NULL + +static inline int +ext3_xattr_get(struct inode *inode, int name_index, const char *name, + void *buffer, size_t size, int flags) +{ + return -EOPNOTSUPP; +} + +static inline int +ext3_xattr_list(struct inode *inode, void *buffer, size_t size, int flags) +{ + return -EOPNOTSUPP; +} + +static inline int +ext3_xattr_set(handle_t *handle, struct inode *inode, int name_index, + const char *name, const void *value, size_t size, int flags) +{ + return -EOPNOTSUPP; +} + +static inline void +ext3_xattr_delete_inode(handle_t *handle, struct inode *inode) +{ +} + +static inline void +ext3_xattr_put_super(struct super_block *sb) +{ +} + +static inline int +init_ext3_xattr(void) +{ + return 0; +} + +static inline void +exit_ext3_xattr(void) +{ +} + +# endif /* CONFIG_EXT3_FS_XATTR */ + +extern struct ext3_xattr_handler ext3_xattr_user_handler; diff -Nru a/fs/ext3/xattr_user.c b/fs/ext3/xattr_user.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/ext3/xattr_user.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,99 @@ +/* + * linux/fs/ext3/xattr_user.c + * Handler for extended user attributes. + * + * Copyright (C) 2001 by Andreas Gruenbacher, + */ + +#include +#include +#include +#include +#include +#include +#include "xattr.h" + +#ifdef CONFIG_EXT3_FS_POSIX_ACL +# include "acl.h" +#endif + +#define XATTR_USER_PREFIX "user." + +static size_t +ext3_xattr_user_list(char *list, struct inode *inode, + const char *name, int name_len) +{ + const int prefix_len = sizeof(XATTR_USER_PREFIX)-1; + + if (!test_opt(inode->i_sb, XATTR_USER)) + return 0; + + if (list) { + memcpy(list, XATTR_USER_PREFIX, prefix_len); + memcpy(list+prefix_len, name, name_len); + } + return prefix_len + name_len; +} + +static int +ext3_xattr_user_get(struct inode *inode, const char *name, + void *buffer, size_t size) +{ + int error; + + if (strcmp(name, "") == 0) + return -EINVAL; + if (!test_opt(inode->i_sb, XATTR_USER)) + return -EOPNOTSUPP; +#ifdef CONFIG_EXT3_FS_POSIX_ACL + error = ext3_permission_locked(inode, MAY_READ); +#else + error = permission(inode, MAY_READ); +#endif + if (error) + return error; + + return ext3_xattr_get(inode, EXT3_XATTR_INDEX_USER, name, + buffer, size); +} + +static int +ext3_xattr_user_set(struct inode *inode, const char *name, + const void *value, size_t size, int flags) +{ + handle_t *handle; + int error; + + if (strcmp(name, "") == 0) + return -EINVAL; + if (!test_opt(inode->i_sb, XATTR_USER)) + return -EOPNOTSUPP; + if ( !S_ISREG(inode->i_mode) && + (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX)) + return -EPERM; +#ifdef CONFIG_EXT3_FS_POSIX_ACL + error = ext3_permission_locked(inode, MAY_WRITE); +#else + error = permission(inode, MAY_WRITE); +#endif + if (error) + return error; + + lock_kernel(); + handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS); + if (IS_ERR(handle)) + return PTR_ERR(handle); + error = ext3_xattr_set(handle, inode, EXT3_XATTR_INDEX_USER, name, + value, size, flags); + ext3_journal_stop(handle, inode); + unlock_kernel(); + + return error; +} + +struct ext3_xattr_handler ext3_xattr_user_handler = { + prefix: XATTR_USER_PREFIX, + list: ext3_xattr_user_list, + get: ext3_xattr_user_get, + set: ext3_xattr_user_set, +}; diff -Nru a/fs/fcblist.c b/fs/fcblist.c --- a/fs/fcblist.c Mon Nov 4 14:31:02 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,146 +0,0 @@ -/* - * linux/fs/fcblist.c ( File event callbacks handling ) - * Copyright (C) 2001,...,2002 Davide Libenzi - * - * 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. - * - * Davide Libenzi - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -long ion_band_table[NSIGPOLL] = { - ION_IN, /* POLL_IN */ - ION_OUT, /* POLL_OUT */ - ION_IN, /* POLL_MSG */ - ION_ERR, /* POLL_ERR */ - 0, /* POLL_PRI */ - ION_HUP /* POLL_HUP */ -}; - -long poll_band_table[NSIGPOLL] = { - POLLIN | POLLRDNORM, /* POLL_IN */ - POLLOUT | POLLWRNORM | POLLWRBAND, /* POLL_OUT */ - POLLIN | POLLRDNORM | POLLMSG, /* POLL_MSG */ - POLLERR, /* POLL_ERR */ - POLLPRI | POLLRDBAND, /* POLL_PRI */ - POLLHUP | POLLERR /* POLL_HUP */ -}; - - - -/* - * Walk through the file callback list by calling each registered callback - * with the event that happened on the "filep" file. Callbacks are called - * by holding a read lock on the callback list lock, and also by keeping - * local IRQs disabled. - */ -void file_notify_event(struct file *filep, long *event) -{ - unsigned long flags; - struct list_head *lnk, *lsthead; - - read_lock_irqsave(&filep->f_cblock, flags); - - lsthead = &filep->f_cblist; - list_for_each(lnk, lsthead) { - struct fcb_struct *fcbp = list_entry(lnk, struct fcb_struct, llink); - - fcbp->cbproc(filep, fcbp->data, fcbp->local, event); - } - - read_unlock_irqrestore(&filep->f_cblock, flags); -} - - -/* - * Add a new callback to the list of file callbacks. - */ -int file_notify_addcb(struct file *filep, - void (*cbproc)(struct file *, void *, unsigned long *, long *), - void *data) -{ - unsigned long flags; - struct fcb_struct *fcbp; - - if (!(fcbp = (struct fcb_struct *) kmalloc(sizeof(struct fcb_struct), GFP_KERNEL))) - return -ENOMEM; - - memset(fcbp, 0, sizeof(struct fcb_struct)); - fcbp->cbproc = cbproc; - fcbp->data = data; - - write_lock_irqsave(&filep->f_cblock, flags); - list_add_tail(&fcbp->llink, &filep->f_cblist); - write_unlock_irqrestore(&filep->f_cblock, flags); - - return 0; -} - - -/* - * Removes the callback "cbproc" from the file callback list. - */ -int file_notify_delcb(struct file *filep, - void (*cbproc)(struct file *, void *, unsigned long *, long *)) -{ - unsigned long flags; - struct list_head *lnk, *lsthead; - - write_lock_irqsave(&filep->f_cblock, flags); - - lsthead = &filep->f_cblist; - list_for_each(lnk, lsthead) { - struct fcb_struct *fcbp = list_entry(lnk, struct fcb_struct, llink); - - if (fcbp->cbproc == cbproc) { - list_del(lnk); - write_unlock_irqrestore(&filep->f_cblock, flags); - kfree(fcbp); - return 0; - } - } - - write_unlock_irqrestore(&filep->f_cblock, flags); - - return -ENOENT; -} - - -/* - * It is called at file cleanup time and removes all the registered callbacks. - */ -void file_notify_cleanup(struct file *filep) -{ - unsigned long flags; - struct list_head *lsthead; - - write_lock_irqsave(&filep->f_cblock, flags); - - lsthead = &filep->f_cblist; - while (!list_empty(lsthead)) { - struct fcb_struct *fcbp = list_entry(lsthead->next, struct fcb_struct, llink); - - list_del(lsthead->next); - write_unlock_irqrestore(&filep->f_cblock, flags); - kfree(fcbp); - write_lock_irqsave(&filep->f_cblock, flags); - } - - write_unlock_irqrestore(&filep->f_cblock, flags); -} - diff -Nru a/fs/file_table.c b/fs/file_table.c --- a/fs/file_table.c Mon Nov 4 14:31:00 2002 +++ b/fs/file_table.c Mon Nov 4 14:31:00 2002 @@ -8,12 +8,12 @@ #include #include #include -#include #include #include #include #include #include +#include /* sysctl tunables... */ struct files_stat_struct files_stat = {0, 0, NR_FILE}; @@ -59,7 +59,6 @@ f->f_gid = current->fsgid; f->f_owner.lock = RW_LOCK_UNLOCKED; list_add(&f->f_list, &anon_list); - file_notify_init(f); file_list_unlock(); return f; } @@ -104,7 +103,6 @@ filp->f_uid = current->fsuid; filp->f_gid = current->fsgid; filp->f_op = dentry->d_inode->i_fop; - file_notify_init(filp); if (filp->f_op->open) return filp->f_op->open(dentry->d_inode, filp); else @@ -126,7 +124,7 @@ struct vfsmount * mnt = file->f_vfsmnt; struct inode * inode = dentry->d_inode; - file_notify_cleanup(file); + ep_notify_file_close(file); locks_remove_flock(file); if (file->f_op && file->f_op->release) diff -Nru a/fs/hugetlbfs/Makefile b/fs/hugetlbfs/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/hugetlbfs/Makefile Mon Nov 4 14:31:04 2002 @@ -0,0 +1,9 @@ +# +# Makefile for the linux ramfs routines. +# + +obj-$(CONFIG_HUGETLBFS) += hugetlbfs.o + +hugetlbfs-objs := inode.o + +include $(TOPDIR)/Rules.make diff -Nru a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/hugetlbfs/inode.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,594 @@ +/* + * hugetlbpage-backed filesystem. Based on ramfs. + * + * William Irwin, 2002 + * + * Copyright (C) 2002 Linus Torvalds. + */ + +#include +#include +#include +#include /* remove ASAP */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* some random number */ +#define HUGETLBFS_MAGIC 0x958458f6 + +static struct super_operations hugetlbfs_ops; +static struct address_space_operations hugetlbfs_aops; +struct file_operations hugetlbfs_file_operations; +static struct inode_operations hugetlbfs_dir_inode_operations; + +static struct backing_dev_info hugetlbfs_backing_dev_info = { + .ra_pages = 0, /* No readahead */ + .memory_backed = 1, /* Does not contribute to dirty memory */ +}; + +static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct inode *inode =file->f_dentry->d_inode; + struct address_space *mapping = inode->i_mapping; + int ret; + + if (!capable(CAP_IPC_LOCK)) + return -EPERM; + + if (vma->vm_start & ~HPAGE_MASK) + return -EINVAL; + + if (vma->vm_end & ~HPAGE_MASK) + return -EINVAL; + + if (vma->vm_end - vma->vm_start < HPAGE_SIZE) + return -EINVAL; + + down(&inode->i_sem); + + UPDATE_ATIME(inode); + vma->vm_flags |= VM_HUGETLB | VM_RESERVED; + vma->vm_ops = &hugetlb_vm_ops; + ret = hugetlb_prefault(mapping, vma); + + up(&inode->i_sem); + + return ret; +} + +/* + * Read a page. Again trivial. If it didn't already exist + * in the page cache, it is zero-filled. + */ +static int hugetlbfs_readpage(struct file *file, struct page * page) +{ + return -EINVAL; +} + +static int hugetlbfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) +{ + return -EINVAL; +} + +static int hugetlbfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) +{ + return -EINVAL; +} + +void huge_pagevec_release(struct pagevec *pvec) +{ + int i; + + for (i = 0; i < pagevec_count(pvec); ++i) + huge_page_release(pvec->pages[i]); + + pagevec_reinit(pvec); +} + +void truncate_partial_hugepage(struct page *page, unsigned partial) +{ + int i; + const unsigned piece = partial & (PAGE_SIZE - 1); + const unsigned tailstart = PAGE_SIZE - piece; + const unsigned whole_pages = partial / PAGE_SIZE; + const unsigned last_page_offset = HPAGE_SIZE/PAGE_SIZE - whole_pages; + + for (i = HPAGE_SIZE/PAGE_SIZE - 1; i >= last_page_offset; ++i) + memclear_highpage_flush(&page[i], 0, PAGE_SIZE); + + if (!piece) + return; + + memclear_highpage_flush(&page[last_page_offset - 1], tailstart, piece); +} + +void truncate_huge_page(struct address_space *mapping, struct page *page) +{ + if (page->mapping != mapping) + return; + + clear_page_dirty(page); + ClearPageUptodate(page); + remove_from_page_cache(page); + huge_page_release(page); +} + +void truncate_hugepages(struct address_space *mapping, loff_t lstart) +{ + const pgoff_t start = (lstart + HPAGE_SIZE - 1) >> HPAGE_SHIFT; + const unsigned partial = lstart & (HPAGE_SIZE - 1); + struct pagevec pvec; + pgoff_t next; + int i; + + pagevec_init(&pvec, 0); + next = start; + + while (pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { + for (i = 0; i < pagevec_count(&pvec); ++i) { + struct page *page = pvec.pages[i]; + pgoff_t page_index = page->index; + + if (page_index > next) + next = page_index; + + ++next; + + if (TestSetPageLocked(page)) + continue; + + if (PageWriteback(page)) { + unlock_page(page); + continue; + } + + truncate_huge_page(mapping, page); + unlock_page(page); + } + huge_pagevec_release(&pvec); + cond_resched(); + } + + if (partial) { + struct page *page = find_lock_page(mapping, start - 1); + if (page) { + wait_on_page_writeback(page); + truncate_partial_hugepage(page, partial); + unlock_page(page); + huge_page_release(page); + } + } + + next = start; + + while (1) { + if (!pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { + if (next == start) + break; + next = start; + continue; + } + + for (i = 0; i < pagevec_count(&pvec); ++i) { + struct page *page = pvec.pages[i]; + + lock_page(page); + wait_on_page_writeback(page); + if (page->index > next) + next = page->index; + ++next; + truncate_huge_page(mapping, page); + unlock_page(page); + } + huge_pagevec_release(&pvec); + } + BUG_ON(!lstart && mapping->nrpages); +} + +static void hugetlbfs_delete_inode(struct inode *inode) +{ + list_del_init(&inode->i_hash); + list_del_init(&inode->i_list); + inode->i_state |= I_FREEING; + inodes_stat.nr_inodes--; + spin_unlock(&inode_lock); + + if (inode->i_data.nrpages) + truncate_hugepages(&inode->i_data, 0); + + security_ops->inode_delete(inode); + + clear_inode(inode); + destroy_inode(inode); +} + +static void hugetlbfs_forget_inode(struct inode *inode) +{ + struct super_block *super_block = inode->i_sb; + + if (list_empty(&inode->i_hash)) + goto out_truncate; + + if (!(inode->i_state & (I_DIRTY|I_LOCK))) { + list_del(&inode->i_list); + list_add(&inode->i_list, &inode_unused); + } + inodes_stat.nr_unused++; + if (!super_block | (super_block->s_flags & MS_ACTIVE)) { + spin_unlock(&inode_lock); + return; + } + + /* write_inode_now() ? */ + inodes_stat.nr_unused--; + list_del_init(&inode->i_hash); +out_truncate: + list_del_init(&inode->i_list); + inode->i_state |= I_FREEING; + inodes_stat.nr_inodes--; + spin_unlock(&inode_lock); + if (inode->i_data.nrpages) + truncate_hugepages(&inode->i_data, 0); + clear_inode(inode); + destroy_inode(inode); +} + +static void hugetlbfs_drop_inode(struct inode *inode) +{ + if (!inode->i_nlink) + hugetlbfs_delete_inode(inode); + else + hugetlbfs_forget_inode(inode); +} + +static void hugetlb_vmtruncate_list(struct list_head *list, unsigned long pgoff) +{ + unsigned long start, end, length, delta; + struct vm_area_struct *vma; + + list_for_each_entry(vma, list, shared) { + start = vma->vm_start; + end = vma->vm_end; + length = end - start; + + if (vma->vm_pgoff >= pgoff) { + zap_hugepage_range(vma, start, length); + continue; + } + + length >>= PAGE_SHIFT; + delta = pgoff = vma->vm_pgoff; + if (delta >= length) + continue; + + start += delta << PAGE_SHIFT; + length = (length - delta) << PAGE_SHIFT; + zap_hugepage_range(vma, start, length); + } +} + +static int hugetlb_vmtruncate(struct inode *inode, loff_t offset) +{ + unsigned long pgoff; + struct address_space *mapping = inode->i_mapping; + unsigned long limit; + + pgoff = (offset + HPAGE_SIZE - 1) >> HPAGE_SHIFT; + + if (inode->i_size < offset) + goto do_expand; + + inode->i_size = offset; + spin_lock(&mapping->i_shared_lock); + if (list_empty(&mapping->i_mmap) && list_empty(&mapping->i_mmap_shared)) + goto out_unlock; + if (!list_empty(&mapping->i_mmap)) + hugetlb_vmtruncate_list(&mapping->i_mmap, pgoff); + if (!list_empty(&mapping->i_mmap_shared)) + hugetlb_vmtruncate_list(&mapping->i_mmap_shared, pgoff); + +out_unlock: + spin_unlock(&mapping->i_shared_lock); + truncate_hugepages(mapping, offset); + return 0; + +do_expand: + limit = current->rlim[RLIMIT_FSIZE].rlim_cur; + if (limit != RLIM_INFINITY && offset > limit) + goto out_sig; + if (offset > inode->i_sb->s_maxbytes) + goto out; + inode->i_size = offset; + return 0; + +out_sig: + send_sig(SIGXFSZ, current, 0); +out: + return -EFBIG; +} + +static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + int error; + unsigned int ia_valid = attr->ia_valid; + unsigned long dn_mask; + + BUG_ON(!inode); + + error = inode_change_ok(inode, attr); + if (error) + goto out; + + error = security_ops->inode_setattr(dentry, attr); + if (error) + goto out; + + if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || + (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) + error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; + if (error) + goto out; + + if (ia_valid & ATTR_SIZE) { + error = hugetlb_vmtruncate(inode, attr->ia_size); + if (error) + goto out; + attr->ia_valid &= ~ATTR_SIZE; + error = inode_setattr(inode, attr); + } + if (error) + goto out; + dn_mask = setattr_mask(ia_valid); + if (dn_mask) + dnotify_parent(dentry, dn_mask); +out: + return error; +} + +struct inode *hugetlbfs_get_inode(struct super_block *sb, int mode, int dev) +{ + struct inode * inode = new_inode(sb); + + if (inode) { + inode->i_mode = mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_rdev = NODEV; + inode->i_mapping->a_ops = &hugetlbfs_aops; + inode->i_mapping->backing_dev_info = &hugetlbfs_backing_dev_info; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + switch (mode & S_IFMT) { + default: + init_special_inode(inode, mode, dev); + break; + case S_IFREG: + inode->i_fop = &hugetlbfs_file_operations; + break; + case S_IFDIR: + inode->i_op = &hugetlbfs_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + + /* directory inodes start off with i_nlink == 2 (for "." entry) */ + inode->i_nlink++; + break; + case S_IFLNK: + inode->i_op = &page_symlink_inode_operations; + break; + } + } + return inode; +} + +/* + * File creation. Allocate an inode, and we're done.. + */ +/* SMP-safe */ +static int hugetlbfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev) +{ + struct inode * inode = hugetlbfs_get_inode(dir->i_sb, mode, dev); + int error = -ENOSPC; + + if (inode) { + d_instantiate(dentry, inode); + dget(dentry); /* Extra count - pin the dentry in core */ + error = 0; + } + return error; +} + +static int hugetlbfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) +{ + int retval = hugetlbfs_mknod(dir, dentry, mode | S_IFDIR, 0); + if (!retval) + dir->i_nlink++; + return retval; +} + +static int hugetlbfs_create(struct inode *dir, struct dentry *dentry, int mode) +{ + return hugetlbfs_mknod(dir, dentry, mode | S_IFREG, 0); +} + +static int hugetlbfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname) +{ + struct inode *inode; + int error = -ENOSPC; + + inode = hugetlbfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0); + if (inode) { + int l = strlen(symname)+1; + error = page_symlink(inode, symname, l); + if (!error) { + d_instantiate(dentry, inode); + dget(dentry); + } else + iput(inode); + } + return error; +} + +static struct address_space_operations hugetlbfs_aops = { + readpage: hugetlbfs_readpage, + writepage: fail_writepage, + prepare_write: hugetlbfs_prepare_write, + commit_write: hugetlbfs_commit_write +}; + +struct file_operations hugetlbfs_file_operations = { + read: generic_file_read, + write: generic_file_write, + mmap: hugetlbfs_file_mmap, + fsync: simple_sync_file, + sendfile: generic_file_sendfile, +}; + +static struct inode_operations hugetlbfs_dir_inode_operations = { + create: hugetlbfs_create, + lookup: simple_lookup, + link: simple_link, + unlink: simple_unlink, + symlink: hugetlbfs_symlink, + mkdir: hugetlbfs_mkdir, + rmdir: simple_rmdir, + mknod: hugetlbfs_mknod, + rename: simple_rename, + setattr: hugetlbfs_setattr, +}; + +static struct super_operations hugetlbfs_ops = { + statfs: simple_statfs, + drop_inode: hugetlbfs_drop_inode, +}; + +static int hugetlbfs_fill_super(struct super_block * sb, void * data, int silent) +{ + struct inode * inode; + struct dentry * root; + + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = HUGETLBFS_MAGIC; + sb->s_op = &hugetlbfs_ops; + inode = hugetlbfs_get_inode(sb, S_IFDIR | 0755, 0); + if (!inode) + return -ENOMEM; + + root = d_alloc_root(inode); + if (!root) { + iput(inode); + return -ENOMEM; + } + sb->s_root = root; + return 0; +} + +static struct super_block *hugetlbfs_get_sb(struct file_system_type *fs_type, + int flags, char *dev_name, void *data) +{ + return get_sb_nodev(fs_type, flags, data, hugetlbfs_fill_super); +} + +static struct file_system_type hugetlbfs_fs_type = { + name: "hugetlbfs", + get_sb: hugetlbfs_get_sb, + kill_sb: kill_litter_super, +}; + +static struct vfsmount *hugetlbfs_vfsmount; + +static atomic_t hugetlbfs_counter = ATOMIC_INIT(0); + +struct file *hugetlb_zero_setup(size_t size) +{ + int error, n; + struct file *file; + struct inode *inode; + struct dentry *dentry, *root; + struct qstr quick_string; + char buf[16]; + + if (!capable(CAP_IPC_LOCK)) + return ERR_PTR(-EPERM); + + n = atomic_read(&hugetlbfs_counter); + atomic_inc(&hugetlbfs_counter); + + root = hugetlbfs_vfsmount->mnt_root; + snprintf(buf, 16, "%d", n); + quick_string.name = buf; + quick_string.len = strlen(quick_string.name); + quick_string.hash = 0; + dentry = d_alloc(root, &quick_string); + if (!dentry) + return ERR_PTR(-ENOMEM); + + error = -ENFILE; + file = get_empty_filp(); + if (!file) + goto out_dentry; + + error = -ENOSPC; + inode = hugetlbfs_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0); + if (!inode) + goto out_file; + + d_instantiate(dentry, inode); + inode->i_size = size; + inode->i_nlink = 0; + file->f_vfsmnt = mntget(hugetlbfs_vfsmount); + file->f_dentry = dentry; + file->f_op = &hugetlbfs_file_operations; + file->f_mode = FMODE_WRITE | FMODE_READ; + return file; + +out_file: + put_filp(file); +out_dentry: + dput(dentry); + return ERR_PTR(error); +} + +static int __init init_hugetlbfs_fs(void) +{ + int error; + struct vfsmount *vfsmount; + + error = register_filesystem(&hugetlbfs_fs_type); + if (error) + return error; + + vfsmount = kern_mount(&hugetlbfs_fs_type); + + if (!IS_ERR(vfsmount)) { + hugetlbfs_vfsmount = vfsmount; + return 0; + } + + error = PTR_ERR(vfsmount); + return error; +} + +static void __exit exit_hugetlbfs_fs(void) +{ + unregister_filesystem(&hugetlbfs_fs_type); +} + +module_init(init_hugetlbfs_fs) +module_exit(exit_hugetlbfs_fs) + +MODULE_LICENSE("GPL"); diff -Nru a/fs/inode.c b/fs/inode.c --- a/fs/inode.c Mon Nov 4 14:31:03 2002 +++ b/fs/inode.c Mon Nov 4 14:31:03 2002 @@ -142,7 +142,7 @@ return inode; } -static void destroy_inode(struct inode *inode) +void destroy_inode(struct inode *inode) { if (inode_has_buffers(inode)) BUG(); @@ -363,57 +363,69 @@ return res; } +static int can_unuse(struct inode *inode) +{ + if (inode->i_state) + return 0; + if (inode_has_buffers(inode)) + return 0; + if (atomic_read(&inode->i_count)) + return 0; + return 1; +} /* - * This is called with the inode lock held. It searches - * the in-use for freeable inodes, which are moved to a - * temporary list and then placed on the unused list by - * dispose_list. - * - * We don't expect to have to call this very often. + * Scan `goal' inodes on the unused list for freeable ones. They are moved to + * a temporary list and then are freed outside inode_lock by dispose_list(). * - * N.B. The spinlock is released during the call to - * dispose_list. + * Any inodes which are pinned purely because of attached pagecache have their + * pagecache removed. We expect the final iput() on that inode to add it to + * the front of the inode_unused list. So look for it there and if the + * inode is still freeable, proceed. The right inode is found 99.9% of the + * time in testing on a 4-way. */ -#define CAN_UNUSE(inode) \ - ((((inode)->i_state | (inode)->i_data.nrpages) == 0) && \ - !inode_has_buffers(inode)) -#define INODE(entry) (list_entry(entry, struct inode, i_list)) - -static inline void prune_icache(int goal) -{ - LIST_HEAD(list); - struct list_head *entry, *freeable = &list; - int count; - struct inode * inode; +static void prune_icache(int nr_to_scan) +{ + LIST_HEAD(freeable); + int nr_pruned = 0; + int nr_scanned; spin_lock(&inode_lock); + for (nr_scanned = 0; nr_scanned < nr_to_scan; nr_scanned++) { + struct inode *inode; - count = 0; - entry = inode_unused.prev; - for(; goal; goal--) { - struct list_head *tmp = entry; - - if (entry == &inode_unused) + if (list_empty(&inode_unused)) break; - entry = entry->prev; - inode = INODE(tmp); - if (inode->i_state & (I_FREEING|I_CLEAR|I_LOCK)) - continue; - if (!CAN_UNUSE(inode)) - continue; - if (atomic_read(&inode->i_count)) + + inode = list_entry(inode_unused.prev, struct inode, i_list); + + if (!can_unuse(inode)) { + list_move(&inode->i_list, &inode_unused); continue; - list_del(tmp); + } + if (inode->i_data.nrpages) { + __iget(inode); + spin_unlock(&inode_lock); + invalidate_inode_pages(&inode->i_data); + iput(inode); + spin_lock(&inode_lock); + + if (inode != list_entry(inode_unused.next, + struct inode, i_list)) + continue; /* wrong inode or list_empty */ + if (!can_unuse(inode)) + continue; + if (inode->i_data.nrpages) + continue; + } list_del_init(&inode->i_hash); - list_add(tmp, freeable); + list_move(&inode->i_list, &freeable); inode->i_state |= I_FREEING; - count++; + nr_pruned++; } - inodes_stat.nr_unused -= count; + inodes_stat.nr_unused -= nr_pruned; spin_unlock(&inode_lock); - - dispose_list(freeable); + dispose_list(&freeable); } /* diff -Nru a/fs/jfs/Makefile b/fs/jfs/Makefile --- a/fs/jfs/Makefile Mon Nov 4 14:31:02 2002 +++ b/fs/jfs/Makefile Mon Nov 4 14:31:02 2002 @@ -10,6 +10,10 @@ jfs_extent.o symlink.o jfs_metapage.o \ jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o resize.o xattr.o +ifeq ($(CONFIG_JFS_POSIX_ACL),y) +jfs-objs += acl.o +endif + EXTRA_CFLAGS += -D_JFS_4K include $(TOPDIR)/Rules.make diff -Nru a/fs/jfs/file.c b/fs/jfs/file.c --- a/fs/jfs/file.c Mon Nov 4 14:31:01 2002 +++ b/fs/jfs/file.c Mon Nov 4 14:31:01 2002 @@ -22,6 +22,7 @@ #include "jfs_dmap.h" #include "jfs_txnmgr.h" #include "jfs_xattr.h" +#include "jfs_acl.h" #include "jfs_debug.h" @@ -142,6 +143,10 @@ .getxattr = jfs_getxattr, .listxattr = jfs_listxattr, .removexattr = jfs_removexattr, +#ifdef CONFIG_JFS_POSIX_ACL + .setattr = jfs_setattr, + .permission = jfs_permission, +#endif }; struct file_operations jfs_file_operations = { diff -Nru a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h --- a/fs/jfs/jfs_incore.h Mon Nov 4 14:31:00 2002 +++ b/fs/jfs/jfs_incore.h Mon Nov 4 14:31:00 2002 @@ -69,6 +69,10 @@ */ struct semaphore commit_sem; lid_t xtlid; /* lid of xtree lock on directory */ +#ifdef CONFIG_JFS_POSIX_ACL + struct posix_acl *i_acl; + struct posix_acl *i_default_acl; +#endif union { struct { xtpage_t _xtroot; /* 288: xtree root */ @@ -97,6 +101,7 @@ #define i_inline u.link._inline #define i_inline_ea u.link._inline_ea +#define JFS_ACL_NOT_CACHED ((void *)-1) #define IREAD_LOCK(ip) down_read(&JFS_IP(ip)->rdwrlock) #define IREAD_UNLOCK(ip) up_read(&JFS_IP(ip)->rdwrlock) diff -Nru a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c --- a/fs/jfs/jfs_txnmgr.c Mon Nov 4 14:31:02 2002 +++ b/fs/jfs/jfs_txnmgr.c Mon Nov 4 14:31:02 2002 @@ -2209,9 +2209,21 @@ tlck->flag &= ~tlckWRITEPAGE; /* do not release page to freelist */ + + /* + * The "right" thing to do here is to + * synchronously write the metadata. + * With the current implementation this + * is hard since write_metapage requires + * us to kunmap & remap the page. If we + * have tlocks pointing into the metadata + * pages, we don't want to do this. I think + * we can get by with synchronously writing + * the pages when they are released. + */ assert(atomic_read(&mp->nohomeok)); - hold_metapage(mp, 0); - write_metapage(mp); + set_bit(META_dirty, &mp->flag); + set_bit(META_sync, &mp->flag); } } } diff -Nru a/fs/jfs/namei.c b/fs/jfs/namei.c --- a/fs/jfs/namei.c Mon Nov 4 14:31:02 2002 +++ b/fs/jfs/namei.c Mon Nov 4 14:31:02 2002 @@ -25,6 +25,7 @@ #include "jfs_unicode.h" #include "jfs_metapage.h" #include "jfs_xattr.h" +#include "jfs_acl.h" #include "jfs_debug.h" extern struct inode_operations jfs_file_inode_operations; @@ -35,6 +36,7 @@ extern int jfs_fsync(struct file *, struct dentry *, int); extern void jfs_truncate_nolock(struct inode *, loff_t); extern struct inode *jfs_iget(struct super_block *, ino_t); +extern int jfs_init_acl(struct inode *, struct inode *); /* * forward references @@ -150,6 +152,11 @@ out2: free_UCSname(&dname); +#ifdef CONFIG_JFS_POSIX_ACL + if (rc == 0) + jfs_init_acl(ip, dip); +#endif + out1: jFYI(1, ("jfs_create: rc:%d\n", -rc)); @@ -275,6 +282,11 @@ out2: free_UCSname(&dname); +#ifdef CONFIG_JFS_POSIX_ACL + if (rc == 0) + jfs_init_acl(ip, dip); +#endif + out1: jFYI(1, ("jfs_mkdir: rc:%d\n", -rc)); @@ -1016,6 +1028,11 @@ out2: free_UCSname(&dname); +#ifdef CONFIG_JFS_POSIX_ACL + if (rc == 0) + jfs_init_acl(ip, dip); +#endif + out1: jFYI(1, ("jfs_symlink: rc:%d\n", -rc)); return -rc; @@ -1364,6 +1381,11 @@ out1: free_UCSname(&dname); +#ifdef CONFIG_JFS_POSIX_ACL + if (rc == 0) + jfs_init_acl(ip, dir); +#endif + out: jFYI(1, ("jfs_mknod: returning %d\n", rc)); return -rc; @@ -1445,6 +1467,10 @@ .getxattr = jfs_getxattr, .listxattr = jfs_listxattr, .removexattr = jfs_removexattr, +#ifdef CONFIG_JFS_POSIX_ACL + .setattr = jfs_setattr, + .permission = jfs_permission, +#endif }; struct file_operations jfs_dir_operations = { diff -Nru a/fs/jfs/super.c b/fs/jfs/super.c --- a/fs/jfs/super.c Mon Nov 4 14:31:01 2002 +++ b/fs/jfs/super.c Mon Nov 4 14:31:01 2002 @@ -28,6 +28,7 @@ #include "jfs_superblock.h" #include "jfs_dmap.h" #include "jfs_imap.h" +#include "jfs_acl.h" #include "jfs_debug.h" MODULE_DESCRIPTION("The Journaled Filesystem (JFS)"); @@ -94,7 +95,16 @@ static void jfs_destroy_inode(struct inode *inode) { - kmem_cache_free(jfs_inode_cachep, JFS_IP(inode)); + struct jfs_inode_info *ji = JFS_IP(inode); + +#ifdef CONFIG_JFS_POSIX_ACL + if (ji->i_acl && (ji->i_acl != JFS_ACL_NOT_CACHED)) + posix_acl_release(ji->i_acl); + if (ji->i_default_acl && (ji->i_default_acl != JFS_ACL_NOT_CACHED)) + posix_acl_release(ji->i_default_acl); +#endif + + kmem_cache_free(jfs_inode_cachep, ji); } static int jfs_statfs(struct super_block *sb, struct statfs *buf) @@ -407,6 +417,10 @@ init_MUTEX(&jfs_ip->commit_sem); jfs_ip->atlhead = 0; jfs_ip->active_ag = -1; +#ifdef CONFIG_JFS_POSIX_ACL + jfs_ip->i_acl = JFS_ACL_NOT_CACHED; + jfs_ip->i_default_acl = JFS_ACL_NOT_CACHED; +#endif inode_init_once(&jfs_ip->vfs_inode); } } diff -Nru a/fs/jfs/xattr.c b/fs/jfs/xattr.c --- a/fs/jfs/xattr.c Mon Nov 4 14:31:01 2002 +++ b/fs/jfs/xattr.c Mon Nov 4 14:31:01 2002 @@ -26,6 +26,7 @@ #include "jfs_extent.h" #include "jfs_metapage.h" #include "jfs_xattr.h" +#include "jfs_acl.h" /* * jfs_xattr.c: extended attribute service @@ -201,7 +202,6 @@ ji->mode2 |= INLINEEA; } - mark_inode_dirty(ip); return 0; } @@ -640,6 +640,71 @@ return rc; } +/* + * can_set_system_xattr + * + * This code is specific to the system.* namespace. It contains policy + * which doesn't belong in the main xattr codepath. + */ +static int can_set_system_xattr(struct inode *inode, const char *name, + const void *value, size_t value_len) +{ +#ifdef CONFIG_JFS_POSIX_ACL + struct posix_acl *acl; + int rc; + + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EPERM; + + /* + * XATTR_NAME_ACL_ACCESS is tied to i_mode + */ + if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0) { + acl = posix_acl_from_xattr(value, value_len); + if (acl < 0) { + printk(KERN_ERR "posix_acl_from_xattr returned %d\n", + rc); + return rc; + } + if (acl > 0) { + mode_t mode = inode->i_mode; + rc = posix_acl_equiv_mode(acl, &mode); + posix_acl_release(acl); + if (rc < 0) { + printk(KERN_ERR + "posix_acl_equiv_mode returned %d\n", + rc); + return rc; + } + inode->i_mode = mode; + mark_inode_dirty(inode); + if (rc == 0) + value = NULL; + } + /* + * We're changing the ACL. Get rid of the cached one + */ + acl =JFS_IP(inode)->i_acl; + if (acl && (acl != JFS_ACL_NOT_CACHED)) + posix_acl_release(acl); + JFS_IP(inode)->i_acl = JFS_ACL_NOT_CACHED; + } else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0) { + /* + * We're changing the default ACL. Get rid of the cached one + */ + acl =JFS_IP(inode)->i_default_acl; + if (acl && (acl != JFS_ACL_NOT_CACHED)) + posix_acl_release(acl); + JFS_IP(inode)->i_default_acl = JFS_ACL_NOT_CACHED; + } else + /* Invalid xattr name */ + return -EINVAL; + return 0; +#else /* CONFIG_JFS_POSIX_ACL */ + return -EOPNOTSUPP; +#endif /* CONFIG_JFS_POSIX_ACL */ +} + static int can_set_xattr(struct inode *inode, const char *name, void *value, size_t value_len) { @@ -649,6 +714,12 @@ if (IS_IMMUTABLE(inode) || IS_APPEND(inode) || S_ISLNK(inode->i_mode)) return -EPERM; + if(strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) == 0) + /* + * "system.*" + */ + return can_set_system_xattr(inode, name, value, value_len); + if((strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) != 0) && (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) != 0)) return -EOPNOTSUPP; @@ -657,7 +728,11 @@ (!S_ISDIR(inode->i_mode) || inode->i_mode &S_ISVTX)) return -EPERM; +#ifdef CONFIG_JFS_POSIX_ACL + return jfs_permission_have_sem(inode, MAY_WRITE); +#else return permission(inode, MAY_WRITE); +#endif } int __jfs_setxattr(struct inode *inode, const char *name, void *value, @@ -810,9 +885,16 @@ return __jfs_setxattr(dentry->d_inode, name, value, value_len, flags); } -static inline int can_get_xattr(struct inode *inode, const char *name) +static int can_get_xattr(struct inode *inode, const char *name) { +#ifdef CONFIG_JFS_POSIX_ACL + if(strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) == 0) + return 0; + else + return jfs_permission_have_sem(inode, MAY_READ); +#else return permission(inode, MAY_READ); +#endif } ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data, diff -Nru a/fs/mbcache.c b/fs/mbcache.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/mbcache.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,702 @@ +/* + * linux/fs/mbcache.c + * (C) 2001-2002 Andreas Gruenbacher, + */ + +/* + * Filesystem Meta Information Block Cache (mbcache) + * + * The mbcache caches blocks of block devices that need to be located + * by their device/block number, as well as by other criteria (such + * as the block's contents). + * + * There can only be one cache entry in a cache per device and block number. + * Additional indexes need not be unique in this sense. The number of + * additional indexes (=other criteria) can be hardwired (at compile time) + * or specified at cache create time. + * + * Each cache entry is of fixed size. An entry may be `valid' or `invalid' + * in the cache. A valid entry is in the main hash tables of the cache, + * and may also be in the lru list. An invalid entry is not in any hashes + * or lists. + * + * A valid cache entry is only in the lru list if no handles refer to it. + * Invalid cache entries will be freed when the last handle to the cache + * entry is released. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#ifdef MB_CACHE_DEBUG +# define mb_debug(f...) do { \ + printk(KERN_DEBUG f); \ + printk("\n"); \ + } while (0) +#define mb_assert(c) do { if (!(c)) \ + printk(KERN_ERR "assertion " #c " failed\n"); \ + } while(0) +#else +# define mb_debug(f...) do { } while(0) +# define mb_assert(c) do { } while(0) +#endif +#define mb_error(f...) do { \ + printk(KERN_ERR f); \ + printk("\n"); \ + } while(0) + +MODULE_AUTHOR("Andreas Gruenbacher "); +MODULE_DESCRIPTION("Meta block cache (for extended attributes)"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(mb_cache_create); +EXPORT_SYMBOL(mb_cache_shrink); +EXPORT_SYMBOL(mb_cache_destroy); +EXPORT_SYMBOL(mb_cache_entry_alloc); +EXPORT_SYMBOL(mb_cache_entry_insert); +EXPORT_SYMBOL(mb_cache_entry_release); +EXPORT_SYMBOL(mb_cache_entry_takeout); +EXPORT_SYMBOL(mb_cache_entry_free); +EXPORT_SYMBOL(mb_cache_entry_dup); +EXPORT_SYMBOL(mb_cache_entry_get); +#if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) +EXPORT_SYMBOL(mb_cache_entry_find_first); +EXPORT_SYMBOL(mb_cache_entry_find_next); +#endif + + +/* + * Global data: list of all mbcache's, lru list, and a spinlock for + * accessing cache data structures on SMP machines. (The lru list is + * global across all mbcaches.) + */ + +static LIST_HEAD(mb_cache_list); +static LIST_HEAD(mb_cache_lru_list); +static spinlock_t mb_cache_spinlock = SPIN_LOCK_UNLOCKED; +static struct shrinker *mb_shrinker; + +static inline int +mb_cache_indexes(struct mb_cache *cache) +{ +#ifdef MB_CACHE_INDEXES_COUNT + return MB_CACHE_INDEXES_COUNT; +#else + return cache->c_indexes_count; +#endif +} + +/* + * What the mbcache registers as to get shrunk dynamically. + */ + +static int mb_cache_shrink_fn(int nr_to_scan, unsigned int gfp_mask); + +static inline void +__mb_cache_entry_takeout_lru(struct mb_cache_entry *ce) +{ + if (!list_empty(&ce->e_lru_list)) + list_del_init(&ce->e_lru_list); +} + + +static inline void +__mb_cache_entry_into_lru(struct mb_cache_entry *ce) +{ + list_add(&ce->e_lru_list, &mb_cache_lru_list); +} + + +static inline int +__mb_cache_entry_in_lru(struct mb_cache_entry *ce) +{ + return (!list_empty(&ce->e_lru_list)); +} + + +/* + * Insert the cache entry into all hashes. + */ +static inline void +__mb_cache_entry_link(struct mb_cache_entry *ce) +{ + struct mb_cache *cache = ce->e_cache; + unsigned int bucket; + int n; + + bucket = hash_long((unsigned long)ce->e_bdev + + (ce->e_block & 0xffffff), cache->c_bucket_bits); + list_add(&ce->e_block_list, &cache->c_block_hash[bucket]); + for (n=0; ne_indexes[n].o_key, + cache->c_bucket_bits); + list_add(&ce->e_indexes[n].o_list, + &cache->c_indexes_hash[n][bucket]); + } +} + + +/* + * Remove the cache entry from all hashes. + */ +static inline void +__mb_cache_entry_unlink(struct mb_cache_entry *ce) +{ + int n; + + list_del_init(&ce->e_block_list); + for (n = 0; n < mb_cache_indexes(ce->e_cache); n++) + list_del(&ce->e_indexes[n].o_list); +} + + +static inline int +__mb_cache_entry_is_linked(struct mb_cache_entry *ce) +{ + return (!list_empty(&ce->e_block_list)); +} + + +static inline struct mb_cache_entry * +__mb_cache_entry_read(struct mb_cache_entry *ce) +{ + __mb_cache_entry_takeout_lru(ce); + atomic_inc(&ce->e_used); + return ce; +} + + +static inline void +__mb_cache_entry_forget(struct mb_cache_entry *ce) +{ + struct mb_cache *cache = ce->e_cache; + + mb_assert(atomic_read(&ce->e_used) == 0); + atomic_dec(&cache->c_entry_count); + if (cache->c_op.free) + cache->c_op.free(ce); + kmem_cache_free(cache->c_entry_cache, ce); +} + + +static inline void +__mb_cache_entry_release_unlock(struct mb_cache_entry *ce) +{ + if (atomic_dec_and_test(&ce->e_used)) { + if (!__mb_cache_entry_is_linked(ce)) + goto forget; + __mb_cache_entry_into_lru(ce); + } + spin_unlock(&mb_cache_spinlock); + return; +forget: + spin_unlock(&mb_cache_spinlock); + __mb_cache_entry_forget(ce); +} + + +/* + * mb_cache_shrink_fn() memory pressure callback + * + * This function is called by the kernel memory management when memory + * gets low. + * + * @nr_to_scan: Number of objects to scan + * @gfp_mask: (ignored) + * + * Returns the number of objects which are present in the cache. + */ +static int +mb_cache_shrink_fn(int nr_to_scan, unsigned int gfp_mask) +{ + LIST_HEAD(free_list); + struct list_head *l; + int count = 0; + + spin_lock(&mb_cache_spinlock); + list_for_each_prev(l, &mb_cache_list) { + struct mb_cache *cache = + list_entry(l, struct mb_cache, c_cache_list); + mb_debug("cache %s (%d)", cache->c_name, + atomic_read(&cache->c_entry_count)); + count += atomic_read(&cache->c_entry_count); + } + mb_debug("trying to free %d entries", nr_to_scan); + if (nr_to_scan == 0) { + spin_unlock(&mb_cache_spinlock); + goto out; + } + while (nr_to_scan && !list_empty(&mb_cache_lru_list)) { + struct mb_cache_entry *ce = + list_entry(mb_cache_lru_list.prev, + struct mb_cache_entry, e_lru_list); + list_move(&ce->e_lru_list, &free_list); + if (__mb_cache_entry_is_linked(ce)) + __mb_cache_entry_unlink(ce); + nr_to_scan--; + } + spin_unlock(&mb_cache_spinlock); + l = free_list.prev; + while (l != &free_list) { + struct mb_cache_entry *ce = list_entry(l, + struct mb_cache_entry, e_lru_list); + l = l->prev; + __mb_cache_entry_forget(ce); + count--; + } +out: + mb_debug("%d remaining entries ", count); + return count; +} + + +/* + * mb_cache_create() create a new cache + * + * All entries in one cache are equal size. Cache entries may be from + * multiple devices. If this is the first mbcache created, registers + * the cache with kernel memory management. Returns NULL if no more + * memory was available. + * + * @name: name of the cache (informal) + * @cache_op: contains the callback called when freeing a cache entry + * @entry_size: The size of a cache entry, including + * struct mb_cache_entry + * @indexes_count: number of additional indexes in the cache. Must equal + * MB_CACHE_INDEXES_COUNT if the number of indexes is + * hardwired. + * @bucket_bits: log2(number of hash buckets) + */ +struct mb_cache * +mb_cache_create(const char *name, struct mb_cache_op *cache_op, + size_t entry_size, int indexes_count, int bucket_bits) +{ + int m=0, n, bucket_count = 1 << bucket_bits; + struct mb_cache *cache = NULL; + + if(entry_size < sizeof(struct mb_cache_entry) + + indexes_count * sizeof(struct mb_cache_entry_index)) + return NULL; + + cache = kmalloc(sizeof(struct mb_cache) + + indexes_count * sizeof(struct list_head), GFP_KERNEL); + if (!cache) + goto fail; + cache->c_name = name; + if (cache_op) + cache->c_op.free = cache_op->free; + else + cache->c_op.free = NULL; + atomic_set(&cache->c_entry_count, 0); + cache->c_bucket_bits = bucket_bits; +#ifdef MB_CACHE_INDEXES_COUNT + mb_assert(indexes_count == MB_CACHE_INDEXES_COUNT); +#else + cache->c_indexes_count = indexes_count; +#endif + cache->c_block_hash = kmalloc(bucket_count * sizeof(struct list_head), + GFP_KERNEL); + if (!cache->c_block_hash) + goto fail; + for (n=0; nc_block_hash[n]); + for (m=0; mc_indexes_hash[m] = kmalloc(bucket_count * + sizeof(struct list_head), + GFP_KERNEL); + if (!cache->c_indexes_hash[m]) + goto fail; + for (n=0; nc_indexes_hash[m][n]); + } + cache->c_entry_cache = kmem_cache_create(name, entry_size, 0, + 0 /*SLAB_POISON | SLAB_RED_ZONE*/, NULL, NULL); + if (!cache->c_entry_cache) + goto fail; + + spin_lock(&mb_cache_spinlock); + if (list_empty(&mb_cache_list)) { + if (mb_shrinker) { + printk(KERN_ERR "%s: already have a shrinker!\n", + __FUNCTION__); + remove_shrinker(mb_shrinker); + } + mb_shrinker = set_shrinker(DEFAULT_SEEKS, mb_cache_shrink_fn); + } + list_add(&cache->c_cache_list, &mb_cache_list); + spin_unlock(&mb_cache_spinlock); + return cache; + +fail: + if (cache) { + while (--m >= 0) + kfree(cache->c_indexes_hash[m]); + if (cache->c_block_hash) + kfree(cache->c_block_hash); + kfree(cache); + } + return NULL; +} + + +/* + * mb_cache_shrink() + * + * Removes all cache entires of a device from the cache. All cache entries + * currently in use cannot be freed, and thus remain in the cache. All others + * are freed. + * + * @cache: which cache to shrink + * @bdev: which device's cache entries to shrink + */ +void +mb_cache_shrink(struct mb_cache *cache, struct block_device *bdev) +{ + LIST_HEAD(free_list); + struct list_head *l; + + spin_lock(&mb_cache_spinlock); + l = mb_cache_lru_list.prev; + while (l != &mb_cache_lru_list) { + struct mb_cache_entry *ce = + list_entry(l, struct mb_cache_entry, e_lru_list); + l = l->prev; + if (ce->e_bdev == bdev) { + list_move(&ce->e_lru_list, &free_list); + if (__mb_cache_entry_is_linked(ce)) + __mb_cache_entry_unlink(ce); + } + } + spin_unlock(&mb_cache_spinlock); + l = free_list.prev; + while (l != &free_list) { + struct mb_cache_entry *ce = + list_entry(l, struct mb_cache_entry, e_lru_list); + l = l->prev; + __mb_cache_entry_forget(ce); + } +} + + +/* + * mb_cache_destroy() + * + * Shrinks the cache to its minimum possible size (hopefully 0 entries), + * and then destroys it. If this was the last mbcache, un-registers the + * mbcache from kernel memory management. + */ +void +mb_cache_destroy(struct mb_cache *cache) +{ + LIST_HEAD(free_list); + struct list_head *l; + int n; + + spin_lock(&mb_cache_spinlock); + l = mb_cache_lru_list.prev; + while (l != &mb_cache_lru_list) { + struct mb_cache_entry *ce = + list_entry(l, struct mb_cache_entry, e_lru_list); + l = l->prev; + if (ce->e_cache == cache) { + list_move(&ce->e_lru_list, &free_list); + if (__mb_cache_entry_is_linked(ce)) + __mb_cache_entry_unlink(ce); + } + } + list_del(&cache->c_cache_list); + if (list_empty(&mb_cache_list) && mb_shrinker) { + remove_shrinker(mb_shrinker); + mb_shrinker = 0; + } + spin_unlock(&mb_cache_spinlock); + + l = free_list.prev; + while (l != &free_list) { + struct mb_cache_entry *ce = + list_entry(l, struct mb_cache_entry, e_lru_list); + l = l->prev; + __mb_cache_entry_forget(ce); + } + + if (atomic_read(&cache->c_entry_count) > 0) { + mb_error("cache %s: %d orphaned entries", + cache->c_name, + atomic_read(&cache->c_entry_count)); + } + + kmem_cache_destroy(cache->c_entry_cache); + + for (n=0; n < mb_cache_indexes(cache); n++) + kfree(cache->c_indexes_hash[n]); + kfree(cache->c_block_hash); + + kfree(cache); +} + + +/* + * mb_cache_entry_alloc() + * + * Allocates a new cache entry. The new entry will not be valid initially, + * and thus cannot be looked up yet. It should be filled with data, and + * then inserted into the cache using mb_cache_entry_insert(). Returns NULL + * if no more memory was available. + */ +struct mb_cache_entry * +mb_cache_entry_alloc(struct mb_cache *cache) +{ + struct mb_cache_entry *ce; + + atomic_inc(&cache->c_entry_count); + ce = kmem_cache_alloc(cache->c_entry_cache, GFP_KERNEL); + if (ce) { + INIT_LIST_HEAD(&ce->e_lru_list); + INIT_LIST_HEAD(&ce->e_block_list); + ce->e_cache = cache; + atomic_set(&ce->e_used, 1); + } + return ce; +} + + +/* + * mb_cache_entry_insert() + * + * Inserts an entry that was allocated using mb_cache_entry_alloc() into + * the cache. After this, the cache entry can be looked up, but is not yet + * in the lru list as the caller still holds a handle to it. Returns 0 on + * success, or -EBUSY if a cache entry for that device + inode exists + * already (this may happen after a failed lookup, but when another process + * has inserted the same cache entry in the meantime). + * + * @bdev: device the cache entry belongs to + * @block: block number + * @keys: array of additional keys. There must be indexes_count entries + * in the array (as specified when creating the cache). + */ +int +mb_cache_entry_insert(struct mb_cache_entry *ce, struct block_device *bdev, + sector_t block, unsigned int keys[]) +{ + struct mb_cache *cache = ce->e_cache; + unsigned int bucket; + struct list_head *l; + int error = -EBUSY, n; + + bucket = hash_long((unsigned long)bdev + (block & 0xffffffff), + cache->c_bucket_bits); + spin_lock(&mb_cache_spinlock); + list_for_each_prev(l, &cache->c_block_hash[bucket]) { + struct mb_cache_entry *ce = + list_entry(l, struct mb_cache_entry, e_block_list); + if (ce->e_bdev == bdev && ce->e_block == block) + goto out; + } + mb_assert(!__mb_cache_entry_is_linked(ce)); + ce->e_bdev = bdev; + ce->e_block = block; + for (n=0; ne_indexes[n].o_key = keys[n]; + __mb_cache_entry_link(ce); +out: + spin_unlock(&mb_cache_spinlock); + return error; +} + + +/* + * mb_cache_entry_release() + * + * Release a handle to a cache entry. When the last handle to a cache entry + * is released it is either freed (if it is invalid) or otherwise inserted + * in to the lru list. + */ +void +mb_cache_entry_release(struct mb_cache_entry *ce) +{ + spin_lock(&mb_cache_spinlock); + __mb_cache_entry_release_unlock(ce); +} + + +/* + * mb_cache_entry_takeout() + * + * Take a cache entry out of the cache, making it invalid. The entry can later + * be re-inserted using mb_cache_entry_insert(), or released using + * mb_cache_entry_release(). + */ +void +mb_cache_entry_takeout(struct mb_cache_entry *ce) +{ + spin_lock(&mb_cache_spinlock); + mb_assert(!__mb_cache_entry_in_lru(ce)); + if (__mb_cache_entry_is_linked(ce)) + __mb_cache_entry_unlink(ce); + spin_unlock(&mb_cache_spinlock); +} + + +/* + * mb_cache_entry_free() + * + * This is equivalent to the sequence mb_cache_entry_takeout() -- + * mb_cache_entry_release(). + */ +void +mb_cache_entry_free(struct mb_cache_entry *ce) +{ + spin_lock(&mb_cache_spinlock); + mb_assert(!__mb_cache_entry_in_lru(ce)); + if (__mb_cache_entry_is_linked(ce)) + __mb_cache_entry_unlink(ce); + __mb_cache_entry_release_unlock(ce); +} + + +/* + * mb_cache_entry_dup() + * + * Duplicate a handle to a cache entry (does not duplicate the cache entry + * itself). After the call, both the old and the new handle must be released. + */ +struct mb_cache_entry * +mb_cache_entry_dup(struct mb_cache_entry *ce) +{ + atomic_inc(&ce->e_used); + return ce; +} + + +/* + * mb_cache_entry_get() + * + * Get a cache entry by device / block number. (There can only be one entry + * in the cache per device and block.) Returns NULL if no such cache entry + * exists. + */ +struct mb_cache_entry * +mb_cache_entry_get(struct mb_cache *cache, struct block_device *bdev, + sector_t block) +{ + unsigned int bucket; + struct list_head *l; + struct mb_cache_entry *ce; + + bucket = hash_long((unsigned long)bdev + (block & 0xffffffff), + cache->c_bucket_bits); + spin_lock(&mb_cache_spinlock); + list_for_each(l, &cache->c_block_hash[bucket]) { + ce = list_entry(l, struct mb_cache_entry, e_block_list); + if (ce->e_bdev == bdev && ce->e_block == block) { + ce = __mb_cache_entry_read(ce); + goto cleanup; + } + } + ce = NULL; + +cleanup: + spin_unlock(&mb_cache_spinlock); + return ce; +} + +#if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) + +static struct mb_cache_entry * +__mb_cache_entry_find(struct list_head *l, struct list_head *head, + int index, struct block_device *bdev, unsigned int key) +{ + while (l != head) { + struct mb_cache_entry *ce = + list_entry(l, struct mb_cache_entry, + e_indexes[index].o_list); + if (ce->e_bdev == bdev && + ce->e_indexes[index].o_key == key) { + ce = __mb_cache_entry_read(ce); + if (ce) + return ce; + } + l = l->next; + } + return NULL; +} + + +/* + * mb_cache_entry_find_first() + * + * Find the first cache entry on a given device with a certain key in + * an additional index. Additonal matches can be found with + * mb_cache_entry_find_next(). Returns NULL if no match was found. + * + * @cache: the cache to search + * @index: the number of the additonal index to search (0<=indexc_bucket_bits); + struct list_head *l; + struct mb_cache_entry *ce; + + mb_assert(index < mb_cache_indexes(cache)); + spin_lock(&mb_cache_spinlock); + l = cache->c_indexes_hash[index][bucket].next; + ce = __mb_cache_entry_find(l, &cache->c_indexes_hash[index][bucket], + index, bdev, key); + spin_unlock(&mb_cache_spinlock); + return ce; +} + + +/* + * mb_cache_entry_find_next() + * + * Find the next cache entry on a given device with a certain key in an + * additional index. Returns NULL if no match could be found. The previous + * entry is atomatically released, so that mb_cache_entry_find_next() can + * be called like this: + * + * entry = mb_cache_entry_find_first(); + * while (entry) { + * ... + * entry = mb_cache_entry_find_next(entry, ...); + * } + * + * @prev: The previous match + * @index: the number of the additonal index to search (0<=indexe_cache; + unsigned int bucket = hash_long(key, cache->c_bucket_bits); + struct list_head *l; + struct mb_cache_entry *ce; + + mb_assert(index < mb_cache_indexes(cache)); + spin_lock(&mb_cache_spinlock); + l = prev->e_indexes[index].o_list.next; + ce = __mb_cache_entry_find(l, &cache->c_indexes_hash[index][bucket], + index, bdev, key); + __mb_cache_entry_release_unlock(prev); + return ce; +} + +#endif /* !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) */ diff -Nru a/fs/namei.c b/fs/namei.c --- a/fs/namei.c Mon Nov 4 14:31:01 2002 +++ b/fs/namei.c Mon Nov 4 14:31:01 2002 @@ -1279,8 +1279,9 @@ /* Negative dentry, just create the file */ if (!dentry->d_inode) { - error = vfs_create(dir->d_inode, dentry, - mode & ~current->fs->umask); + if (!IS_POSIXACL(dir->d_inode)) + mode &= ~current->fs->umask; + error = vfs_create(dir->d_inode, dentry, mode); up(&dir->d_inode->i_sem); dput(nd->dentry); nd->dentry = dentry; @@ -1442,7 +1443,8 @@ dentry = lookup_create(&nd, 0); error = PTR_ERR(dentry); - mode &= ~current->fs->umask; + if (!IS_POSIXACL(nd.dentry->d_inode)) + mode &= ~current->fs->umask; if (!IS_ERR(dentry)) { switch (mode & S_IFMT) { case 0: case S_IFREG: @@ -1508,8 +1510,9 @@ dentry = lookup_create(&nd, 1); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { - error = vfs_mkdir(nd.dentry->d_inode, dentry, - mode & ~current->fs->umask); + if (!IS_POSIXACL(nd.dentry->d_inode)) + mode &= ~current->fs->umask; + error = vfs_mkdir(nd.dentry->d_inode, dentry, mode); dput(dentry); } up(&nd.dentry->d_inode->i_sem); diff -Nru a/fs/partitions/check.c b/fs/partitions/check.c --- a/fs/partitions/check.c Mon Nov 4 14:31:02 2002 +++ b/fs/partitions/check.c Mon Nov 4 14:31:02 2002 @@ -277,231 +277,146 @@ #endif } -static ssize_t part_dev_read(struct device *dev, - char *page, size_t count, loff_t off) + +/* + * sysfs bindings for partitions + */ + +struct part_attribute { + struct attribute attr; + ssize_t (*show)(struct hd_struct *,char *,size_t,loff_t); +}; + +static ssize_t part_attr_show(struct kobject * kobj, struct attribute * attr, + char * page, size_t count, loff_t off) +{ + struct hd_struct * p = container_of(kobj,struct hd_struct,kobj); + struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr); + ssize_t ret = 0; + if (part_attr->show) + part_attr->show(p,page,count,off); + return ret; +} + +static struct sysfs_ops part_sysfs_ops = { + .show = part_attr_show, +}; + +static ssize_t part_dev_read(struct hd_struct * p, + char *page, size_t count, loff_t off) { - struct gendisk *disk = dev->parent->driver_data; - struct hd_struct *p = dev->driver_data; + struct gendisk *disk = container_of(p->kobj.parent,struct gendisk,kobj); int part = p - disk->part + 1; dev_t base = MKDEV(disk->major, disk->first_minor); return off ? 0 : sprintf(page, "%04x\n",base + part); } -static ssize_t part_start_read(struct device *dev, - char *page, size_t count, loff_t off) +static ssize_t part_start_read(struct hd_struct * p, + char *page, size_t count, loff_t off) { - struct hd_struct *p = dev->driver_data; return off ? 0 : sprintf(page, "%llu\n",(unsigned long long)p->start_sect); } -static ssize_t part_size_read(struct device *dev, - char *page, size_t count, loff_t off) +static ssize_t part_size_read(struct hd_struct * p, + char *page, size_t count, loff_t off) { - struct hd_struct *p = dev->driver_data; return off ? 0 : sprintf(page, "%llu\n",(unsigned long long)p->nr_sects); } -static ssize_t part_stat_read(struct device *dev, - char *page, size_t count, loff_t off) +static ssize_t part_stat_read(struct hd_struct * p, + char *page, size_t count, loff_t off) { - struct hd_struct *p = dev->driver_data; return off ? 0 : sprintf(page, "%8u %8llu %8u %8llu\n", p->reads, (u64)p->read_sectors, p->writes, (u64)p->write_sectors); } -static struct device_attribute part_attr_dev = { +static struct part_attribute part_attr_dev = { .attr = {.name = "dev", .mode = S_IRUGO }, .show = part_dev_read }; -static struct device_attribute part_attr_start = { +static struct part_attribute part_attr_start = { .attr = {.name = "start", .mode = S_IRUGO }, .show = part_start_read }; -static struct device_attribute part_attr_size = { +static struct part_attribute part_attr_size = { .attr = {.name = "size", .mode = S_IRUGO }, .show = part_size_read }; -static struct device_attribute part_attr_stat = { +static struct part_attribute part_attr_stat = { .attr = {.name = "stat", .mode = S_IRUGO }, .show = part_stat_read }; +static struct attribute * default_attrs[] = { + &part_attr_dev.attr, + &part_attr_start.attr, + &part_attr_size.attr, + &part_attr_stat.attr, + NULL, +}; + +extern struct subsystem block_subsys; + +static struct subsystem part_subsys = { + .parent = &block_subsys, + .default_attrs = default_attrs, + .sysfs_ops = &part_sysfs_ops, +}; + +static int __init part_subsys_init(void) +{ + return subsystem_register(&part_subsys); +} + +__initcall(part_subsys_init); + void delete_partition(struct gendisk *disk, int part) { struct hd_struct *p = disk->part + part - 1; - struct device *dev; if (!p->nr_sects) return; p->start_sect = 0; p->nr_sects = 0; p->reads = p->writes = p->read_sectors = p->write_sectors = 0; devfs_unregister(p->de); - dev = p->hd_driverfs_dev; - p->hd_driverfs_dev = NULL; - if (dev) { - device_remove_file(dev, &part_attr_stat); - device_remove_file(dev, &part_attr_size); - device_remove_file(dev, &part_attr_start); - device_remove_file(dev, &part_attr_dev); - device_unregister(dev); - } -} - -static void part_release(struct device *dev) -{ - kfree(dev); + kobject_unregister(&p->kobj); } void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) { struct hd_struct *p = disk->part + part - 1; - struct device *parent = &disk->disk_dev; - struct device *dev; p->start_sect = start; p->nr_sects = len; devfs_register_partition(disk, part); - dev = kmalloc(sizeof(struct device), GFP_KERNEL); - if (!dev) - return; - memset(dev, 0, sizeof(struct device)); - dev->parent = parent; - sprintf(dev->bus_id, "p%d", part); - dev->release = part_release; - dev->driver_data = p; - device_register(dev); - device_create_file(dev, &part_attr_dev); - device_create_file(dev, &part_attr_start); - device_create_file(dev, &part_attr_size); - device_create_file(dev, &part_attr_stat); - p->hd_driverfs_dev = dev; + kobject_init(&p->kobj); + snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->disk_name,part); + p->kobj.parent = &disk->kobj; + p->kobj.subsys = &part_subsys; + kobject_register(&p->kobj); } -static ssize_t disk_dev_read(struct device *dev, - char *page, size_t count, loff_t off) -{ - struct gendisk *disk = dev->driver_data; - dev_t base = MKDEV(disk->major, disk->first_minor); - return off ? 0 : sprintf(page, "%04x\n",base); -} -static ssize_t disk_range_read(struct device *dev, - char *page, size_t count, loff_t off) -{ - struct gendisk *disk = dev->driver_data; - return off ? 0 : sprintf(page, "%d\n",disk->minors); -} -static ssize_t disk_size_read(struct device *dev, - char *page, size_t count, loff_t off) -{ - struct gendisk *disk = dev->driver_data; - return off ? 0 : sprintf(page, "%llu\n",(unsigned long long)get_capacity(disk)); -} -static inline unsigned MSEC(unsigned x) -{ - return x * 1000 / HZ; -} -static ssize_t disk_stat_read(struct device *dev, - char *page, size_t count, loff_t off) -{ - struct gendisk *disk = dev->driver_data; - disk_round_stats(disk); - return off ? 0 : sprintf(page, - "%8u %8u %8llu %8u " - "%8u %8u %8llu %8u " - "%8u %8u %8u" - "\n", - disk->reads, disk->read_merges, (u64)disk->read_sectors, - MSEC(disk->read_ticks), - disk->writes, disk->write_merges, (u64)disk->write_sectors, - MSEC(disk->write_ticks), - disk->in_flight, MSEC(disk->io_ticks), - MSEC(disk->time_in_queue)); -} -static struct device_attribute disk_attr_dev = { - .attr = {.name = "dev", .mode = S_IRUGO }, - .show = disk_dev_read -}; -static struct device_attribute disk_attr_range = { - .attr = {.name = "range", .mode = S_IRUGO }, - .show = disk_range_read -}; -static struct device_attribute disk_attr_size = { - .attr = {.name = "size", .mode = S_IRUGO }, - .show = disk_size_read -}; -static struct device_attribute disk_attr_stat = { - .attr = {.name = "stat", .mode = S_IRUGO }, - .show = disk_stat_read -}; - -static void disk_driverfs_symlinks(struct gendisk *disk) -{ - struct device *target = disk->driverfs_dev; - struct device *dev = &disk->disk_dev; - struct device *p; - char *path; - char *s; - int length; - int depth; - - if (!target) - return; - - get_device(target); - - length = get_devpath_length(target); - length += strlen(".."); - - if (length > PATH_MAX) - return; - - if (!(path = kmalloc(length,GFP_KERNEL))) - return; - memset(path,0,length); - - /* our relative position */ - strcpy(path,".."); - - fill_devpath(target, path, length); - driverfs_create_symlink(&dev->dir, "device", path); - kfree(path); - - for (p = target, depth = 0; p; p = p->parent, depth++) - ; - length = get_devpath_length(dev); - length += 3 * depth - 1; - - if (length > PATH_MAX) - return; - - if (!(path = kmalloc(length,GFP_KERNEL))) - return; - memset(path,0,length); - for (s = path; depth--; s += 3) - strcpy(s, "../"); - - fill_devpath(dev, path, length); - driverfs_create_symlink(&target->dir, "block", path); - kfree(path); +static void disk_sysfs_symlinks(struct gendisk *disk) +{ + struct device *target = get_device(disk->driverfs_dev); + if (target) { + sysfs_create_link(&disk->kobj,&target->kobj,"device"); + sysfs_create_link(&target->kobj,&disk->kobj,"block"); + } } /* Not exported, helper to add_disk(). */ void register_disk(struct gendisk *disk) { - struct device *dev = &disk->disk_dev; struct parsed_partitions *state; struct block_device *bdev; char *s; int j; - strcpy(dev->bus_id, disk->disk_name); + strncpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN); /* ewww... some of these buggers have / in name... */ - s = strchr(dev->bus_id, '/'); + s = strchr(disk->kobj.name, '/'); if (s) *s = '!'; - device_add(dev); - device_create_file(dev, &disk_attr_dev); - device_create_file(dev, &disk_attr_range); - device_create_file(dev, &disk_attr_size); - device_create_file(dev, &disk_attr_stat); - disk_driverfs_symlinks(disk); + kobject_register(&disk->kobj); + disk_sysfs_symlinks(disk); if (disk->flags & GENHD_FL_CD) devfs_create_cdrom(disk); @@ -620,16 +535,13 @@ disk->time_in_queue = 0; disk->stamp = disk->stamp_idle = 0; devfs_remove_partitions(disk); - device_remove_file(&disk->disk_dev, &disk_attr_dev); - device_remove_file(&disk->disk_dev, &disk_attr_range); - device_remove_file(&disk->disk_dev, &disk_attr_size); - device_remove_file(&disk->disk_dev, &disk_attr_stat); - driverfs_remove_file(&disk->disk_dev.dir, "device"); if (disk->driverfs_dev) { - driverfs_remove_file(&disk->driverfs_dev->dir, "block"); + sysfs_remove_link(&disk->kobj, "device"); + sysfs_remove_link(&disk->driverfs_dev->kobj, "block"); put_device(disk->driverfs_dev); } - device_del(&disk->disk_dev); + kobject_get(&disk->kobj); /* kobject model is fucked in head */ + kobject_unregister(&disk->kobj); } struct dev_name { @@ -680,3 +592,4 @@ return dname->name; } + diff -Nru a/fs/pipe.c b/fs/pipe.c --- a/fs/pipe.c Mon Nov 4 14:31:02 2002 +++ b/fs/pipe.c Mon Nov 4 14:31:02 2002 @@ -11,7 +11,6 @@ #include #include #include -#include #include #include @@ -34,13 +33,12 @@ /* Drop the inode semaphore and wait for a pipe event, atomically */ void pipe_wait(struct inode * inode) { - DECLARE_WAITQUEUE(wait, current); - current->state = TASK_INTERRUPTIBLE; - add_wait_queue(PIPE_WAIT(*inode), &wait); + DEFINE_WAIT(wait); + + prepare_to_wait(PIPE_WAIT(*inode), &wait, TASK_INTERRUPTIBLE); up(PIPE_SEM(*inode)); schedule(); - remove_wait_queue(PIPE_WAIT(*inode), &wait); - current->state = TASK_RUNNING; + finish_wait(PIPE_WAIT(*inode), &wait); down(PIPE_SEM(*inode)); } @@ -48,7 +46,7 @@ pipe_read(struct file *filp, char *buf, size_t count, loff_t *ppos) { struct inode *inode = filp->f_dentry->d_inode; - int do_wakeup, pfull; + int do_wakeup; ssize_t ret; /* pread is not allowed on pipes. */ @@ -64,7 +62,6 @@ down(PIPE_SEM(*inode)); for (;;) { int size = PIPE_LEN(*inode); - pfull = PIPE_FULL(*inode); if (size) { char *pipebuf = PIPE_BASE(*inode) + PIPE_START(*inode); ssize_t chars = PIPE_MAX_RCHUNK(*inode); @@ -110,18 +107,12 @@ if (!ret) ret = -ERESTARTSYS; break; } - /* Send notification message */ - if (pfull && !PIPE_FULL(*inode) && PIPE_WRITEFILE(*inode)) - file_send_notify(PIPE_WRITEFILE(*inode), ION_OUT, POLLOUT | POLLWRNORM | POLLWRBAND); if (do_wakeup) { wake_up_interruptible_sync(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT); } pipe_wait(inode); } - /* Send notification message */ - if (pfull && !PIPE_FULL(*inode) && PIPE_WRITEFILE(*inode)) - file_send_notify(PIPE_WRITEFILE(*inode), ION_OUT, POLLOUT | POLLWRNORM | POLLWRBAND); up(PIPE_SEM(*inode)); /* Signal writers asynchronously that there is more room. */ if (do_wakeup) { @@ -139,7 +130,7 @@ struct inode *inode = filp->f_dentry->d_inode; ssize_t ret; size_t min; - int do_wakeup, pempty; + int do_wakeup; /* pwrite is not allowed on pipes. */ if (unlikely(ppos != &filp->f_pos)) @@ -157,7 +148,6 @@ down(PIPE_SEM(*inode)); for (;;) { int free; - pempty = PIPE_EMPTY(*inode); if (!PIPE_READERS(*inode)) { send_sig(SIGPIPE, current, 0); if (!ret) ret = -EPIPE; @@ -203,9 +193,6 @@ if (!ret) ret = -ERESTARTSYS; break; } - /* Send notification message */ - if (pempty && !PIPE_EMPTY(*inode) && PIPE_READFILE(*inode)) - file_send_notify(PIPE_READFILE(*inode), ION_IN, POLLIN | POLLRDNORM); if (do_wakeup) { wake_up_interruptible_sync(PIPE_WAIT(*inode)); kill_fasync(PIPE_FASYNC_READERS(*inode), SIGIO, POLL_IN); @@ -215,9 +202,6 @@ pipe_wait(inode); PIPE_WAITING_WRITERS(*inode)--; } - /* Send notification message */ - if (pempty && !PIPE_EMPTY(*inode) && PIPE_READFILE(*inode)) - file_send_notify(PIPE_READFILE(*inode), ION_IN, POLLIN | POLLRDNORM); up(PIPE_SEM(*inode)); if (do_wakeup) { wake_up_interruptible(PIPE_WAIT(*inode)); @@ -281,22 +265,9 @@ static int pipe_release(struct inode *inode, int decr, int decw) { - struct file *rdfile, *wrfile; down(PIPE_SEM(*inode)); PIPE_READERS(*inode) -= decr; PIPE_WRITERS(*inode) -= decw; - rdfile = PIPE_READFILE(*inode); - wrfile = PIPE_WRITEFILE(*inode); - if (decr && !PIPE_READERS(*inode)) { - PIPE_READFILE(*inode) = NULL; - if (wrfile) - file_send_notify(wrfile, ION_HUP, POLLHUP); - } - if (decw && !PIPE_WRITERS(*inode)) { - PIPE_WRITEFILE(*inode) = NULL; - if (rdfile) - file_send_notify(rdfile, ION_HUP, POLLHUP); - } if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode)) { struct pipe_inode_info *info = inode->i_pipe; inode->i_pipe = NULL; @@ -516,7 +487,6 @@ PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0; PIPE_WAITING_WRITERS(*inode) = 0; PIPE_RCOUNTER(*inode) = PIPE_WCOUNTER(*inode) = 1; - PIPE_READFILE(*inode) = PIPE_WRITEFILE(*inode) = NULL; *PIPE_FASYNC_READERS(*inode) = *PIPE_FASYNC_WRITERS(*inode) = NULL; return inode; @@ -624,9 +594,6 @@ f2->f_op = &write_pipe_fops; f2->f_mode = 2; f2->f_version = 0; - - PIPE_READFILE(*inode) = f1; - PIPE_WRITEFILE(*inode) = f2; fd_install(i, f1); fd_install(j, f2); diff -Nru a/fs/posix_acl.c b/fs/posix_acl.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/posix_acl.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,423 @@ +/* + * linux/fs/posix_acl.c + * + * Copyright (C) 2002 by Andreas Gruenbacher + * + * Fixes from William Schumacher incorporated on 15 March 2001. + * (Reported by Charles Bertsch, ). + */ + +/* + * This file contains generic functions for manipulating + * POSIX 1003.1e draft standard 17 ACLs. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +EXPORT_SYMBOL(posix_acl_alloc); +EXPORT_SYMBOL(posix_acl_clone); +EXPORT_SYMBOL(posix_acl_valid); +EXPORT_SYMBOL(posix_acl_equiv_mode); +EXPORT_SYMBOL(posix_acl_from_mode); +EXPORT_SYMBOL(posix_acl_create_masq); +EXPORT_SYMBOL(posix_acl_chmod_masq); +EXPORT_SYMBOL(posix_acl_masq_nfs_mode); +EXPORT_SYMBOL(posix_acl_permission); + +/* + * Allocate a new ACL with the specified number of entries. + */ +struct posix_acl * +posix_acl_alloc(int count, int flags) +{ + const size_t size = sizeof(struct posix_acl) + + count * sizeof(struct posix_acl_entry); + struct posix_acl *acl = kmalloc(size, flags); + if (acl) { + atomic_set(&acl->a_refcount, 1); + acl->a_count = count; + } + return acl; +} + +/* + * Clone an ACL. + */ +struct posix_acl * +posix_acl_clone(const struct posix_acl *acl, int flags) +{ + struct posix_acl *clone = NULL; + + if (acl) { + int size = sizeof(struct posix_acl) + acl->a_count * + sizeof(struct posix_acl_entry); + clone = kmalloc(size, flags); + if (clone) { + memcpy(clone, acl, size); + atomic_set(&clone->a_refcount, 1); + } + } + return clone; +} + +/* + * Check if an acl is valid. Returns 0 if it is, or -E... otherwise. + */ +int +posix_acl_valid(const struct posix_acl *acl) +{ + const struct posix_acl_entry *pa, *pe; + int state = ACL_USER_OBJ; + unsigned int id = 0; /* keep gcc happy */ + int needs_mask = 0; + + FOREACH_ACL_ENTRY(pa, acl, pe) { + if (pa->e_perm & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE)) + return -EINVAL; + switch (pa->e_tag) { + case ACL_USER_OBJ: + if (state == ACL_USER_OBJ) { + id = 0; + state = ACL_USER; + break; + } + return -EINVAL; + + case ACL_USER: + if (state != ACL_USER) + return -EINVAL; + if (pa->e_id == ACL_UNDEFINED_ID || + pa->e_id < id) + return -EINVAL; + id = pa->e_id + 1; + needs_mask = 1; + break; + + case ACL_GROUP_OBJ: + if (state == ACL_USER) { + id = 0; + state = ACL_GROUP; + break; + } + return -EINVAL; + + case ACL_GROUP: + if (state != ACL_GROUP) + return -EINVAL; + if (pa->e_id == ACL_UNDEFINED_ID || + pa->e_id < id) + return -EINVAL; + id = pa->e_id + 1; + needs_mask = 1; + break; + + case ACL_MASK: + if (state != ACL_GROUP) + return -EINVAL; + state = ACL_OTHER; + break; + + case ACL_OTHER: + if (state == ACL_OTHER || + (state == ACL_GROUP && !needs_mask)) { + state = 0; + break; + } + return -EINVAL; + + default: + return -EINVAL; + } + } + if (state == 0) + return 0; + return -EINVAL; +} + +/* + * Returns 0 if the acl can be exactly represented in the traditional + * file mode permission bits, or else 1. Returns -E... on error. + */ +int +posix_acl_equiv_mode(const struct posix_acl *acl, mode_t *mode_p) +{ + const struct posix_acl_entry *pa, *pe; + mode_t mode = 0; + int not_equiv = 0; + + FOREACH_ACL_ENTRY(pa, acl, pe) { + switch (pa->e_tag) { + case ACL_USER_OBJ: + mode |= (pa->e_perm & S_IRWXO) << 6; + break; + case ACL_GROUP_OBJ: + mode |= (pa->e_perm & S_IRWXO) << 3; + break; + case ACL_OTHER: + mode |= pa->e_perm & S_IRWXO; + break; + case ACL_MASK: + mode = (mode & ~S_IRWXG) | + ((pa->e_perm & S_IRWXO) << 3); + not_equiv = 1; + break; + case ACL_USER: + case ACL_GROUP: + not_equiv = 1; + break; + default: + return -EINVAL; + } + } + if (mode_p) + *mode_p = (*mode_p & ~S_IRWXUGO) | mode; + return not_equiv; +} + +/* + * Create an ACL representing the file mode permission bits of an inode. + */ +struct posix_acl * +posix_acl_from_mode(mode_t mode, int flags) +{ + struct posix_acl *acl = posix_acl_alloc(3, flags); + if (!acl) + return ERR_PTR(-ENOMEM); + + acl->a_entries[0].e_tag = ACL_USER_OBJ; + acl->a_entries[0].e_id = ACL_UNDEFINED_ID; + acl->a_entries[0].e_perm = (mode & S_IRWXU) >> 6; + + acl->a_entries[1].e_tag = ACL_GROUP_OBJ; + acl->a_entries[1].e_id = ACL_UNDEFINED_ID; + acl->a_entries[1].e_perm = (mode & S_IRWXG) >> 3; + + acl->a_entries[2].e_tag = ACL_OTHER; + acl->a_entries[2].e_id = ACL_UNDEFINED_ID; + acl->a_entries[2].e_perm = (mode & S_IRWXO); + return acl; +} + +/* + * Return 0 if current is granted want access to the inode + * by the acl. Returns -E... otherwise. + */ +int +posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want) +{ + const struct posix_acl_entry *pa, *pe, *mask_obj; + int found = 0; + + FOREACH_ACL_ENTRY(pa, acl, pe) { + switch(pa->e_tag) { + case ACL_USER_OBJ: + /* (May have been checked already) */ + if (inode->i_uid == current->fsuid) + goto check_perm; + break; + case ACL_USER: + if (pa->e_id == current->fsuid) + goto mask; + break; + case ACL_GROUP_OBJ: + if (in_group_p(inode->i_gid)) { + found = 1; + if ((pa->e_perm & want) == want) + goto mask; + } + break; + case ACL_GROUP: + if (in_group_p(pa->e_id)) { + found = 1; + if ((pa->e_perm & want) == want) + goto mask; + } + break; + case ACL_MASK: + break; + case ACL_OTHER: + if (found) + return -EACCES; + else + goto check_perm; + default: + return -EIO; + } + } + return -EIO; + +mask: + for (mask_obj = pa+1; mask_obj != pe; mask_obj++) { + if (mask_obj->e_tag == ACL_MASK) { + if ((pa->e_perm & mask_obj->e_perm & want) == want) + return 0; + return -EACCES; + } + } + +check_perm: + if ((pa->e_perm & want) == want) + return 0; + return -EACCES; +} + +/* + * Modify acl when creating a new inode. The caller must ensure the acl is + * only referenced once. + * + * mode_p initially must contain the mode parameter to the open() / creat() + * system calls. All permissions that are not granted by the acl are removed. + * The permissions in the acl are changed to reflect the mode_p parameter. + */ +int +posix_acl_create_masq(struct posix_acl *acl, mode_t *mode_p) +{ + struct posix_acl_entry *pa, *pe; + struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL; + mode_t mode = *mode_p; + int not_equiv = 0; + + /* assert(atomic_read(acl->a_refcount) == 1); */ + + FOREACH_ACL_ENTRY(pa, acl, pe) { + switch(pa->e_tag) { + case ACL_USER_OBJ: + pa->e_perm &= (mode >> 6) | ~S_IRWXO; + mode &= (pa->e_perm << 6) | ~S_IRWXU; + break; + + case ACL_USER: + case ACL_GROUP: + not_equiv = 1; + break; + + case ACL_GROUP_OBJ: + group_obj = pa; + break; + + case ACL_OTHER: + pa->e_perm &= mode | ~S_IRWXO; + mode &= pa->e_perm | ~S_IRWXO; + break; + + case ACL_MASK: + mask_obj = pa; + not_equiv = 1; + break; + + default: + return -EIO; + } + } + + if (mask_obj) { + mask_obj->e_perm &= (mode >> 3) | ~S_IRWXO; + mode &= (mask_obj->e_perm << 3) | ~S_IRWXG; + } else { + if (!group_obj) + return -EIO; + group_obj->e_perm &= (mode >> 3) | ~S_IRWXO; + mode &= (group_obj->e_perm << 3) | ~S_IRWXG; + } + + *mode_p = (*mode_p & ~S_IRWXUGO) | mode; + return not_equiv; +} + +/* + * Modify the ACL for the chmod syscall. + */ +int +posix_acl_chmod_masq(struct posix_acl *acl, mode_t mode) +{ + struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL; + struct posix_acl_entry *pa, *pe; + + /* assert(atomic_read(acl->a_refcount) == 1); */ + + FOREACH_ACL_ENTRY(pa, acl, pe) { + switch(pa->e_tag) { + case ACL_USER_OBJ: + pa->e_perm = (mode & S_IRWXU) >> 6; + break; + + case ACL_USER: + case ACL_GROUP: + break; + + case ACL_GROUP_OBJ: + group_obj = pa; + break; + + case ACL_MASK: + mask_obj = pa; + break; + + case ACL_OTHER: + pa->e_perm = (mode & S_IRWXO); + break; + + default: + return -EIO; + } + } + + if (mask_obj) { + mask_obj->e_perm = (mode & S_IRWXG) >> 3; + } else { + if (!group_obj) + return -EIO; + group_obj->e_perm = (mode & S_IRWXG) >> 3; + } + + return 0; +} + +/* + * Adjust the mode parameter so that NFSv2 grants nobody permissions + * that may not be granted by the ACL. This is necessary because NFSv2 + * may compute access permissions on the client side, and may serve cached + * data whenever it assumes access would be granted. Since ACLs may also + * be used to deny access to specific users, the minimal permissions + * for secure operation over NFSv2 are very restrictive. Permissions + * granted to users via Access Control Lists will not be effective over + * NFSv2. + * + * Privilege escalation can only happen for read operations, as writes are + * always carried out on the NFS server, where the proper access checks are + * implemented. + */ +int +posix_acl_masq_nfs_mode(struct posix_acl *acl, mode_t *mode_p) +{ + struct posix_acl_entry *pa, *pe; int min_perm = S_IRWXO; + + FOREACH_ACL_ENTRY(pa, acl, pe) { + switch(pa->e_tag) { + case ACL_USER_OBJ: + break; + + case ACL_USER: + case ACL_GROUP_OBJ: + case ACL_GROUP: + case ACL_MASK: + case ACL_OTHER: + min_perm &= pa->e_perm; + break; + + default: + return -EIO; + } + } + *mode_p = (*mode_p & ~(S_IRWXG|S_IRWXO)) | (min_perm << 3) | min_perm; + + return 0; +} diff -Nru a/fs/proc/array.c b/fs/proc/array.c --- a/fs/proc/array.c Mon Nov 4 14:31:02 2002 +++ b/fs/proc/array.c Mon Nov 4 14:31:02 2002 @@ -64,6 +64,7 @@ #include #include #include +#include #include #include #include diff -Nru a/fs/proc/base.c b/fs/proc/base.c --- a/fs/proc/base.c Mon Nov 4 14:31:02 2002 +++ b/fs/proc/base.c Mon Nov 4 14:31:02 2002 @@ -28,6 +28,7 @@ #include #include #include +#include /* * For hysterical raisins we keep the same inumbers as in the old procfs. @@ -54,6 +55,7 @@ PROC_PID_MAPS, PROC_PID_CPU, PROC_PID_MOUNTS, + PROC_PID_WCHAN, PROC_PID_FD_DIR = 0x8000, /* 0x8000-0xffff */ }; @@ -81,6 +83,9 @@ E(PROC_PID_ROOT, "root", S_IFLNK|S_IRWXUGO), E(PROC_PID_EXE, "exe", S_IFLNK|S_IRWXUGO), E(PROC_PID_MOUNTS, "mounts", S_IFREG|S_IRUGO), +#ifdef CONFIG_KALLSYMS + E(PROC_PID_WCHAN, "wchan", S_IFREG|S_IRUGO), +#endif {0,0,NULL,0} }; #undef E @@ -245,6 +250,28 @@ return res; } +#ifdef CONFIG_KALLSYMS +/* + * Provides a wchan file via kallsyms in a proper one-value-per-file format. + * Returns the resolved symbol. If that fails, simply return the address. + */ +static int proc_pid_wchan(struct task_struct *task, char *buffer) +{ + const char *sym_name, *ignore; + unsigned long wchan, dummy; + + wchan = get_wchan(task); + + if (!kallsyms_address_to_symbol(wchan, &ignore, &dummy, &dummy, + &ignore, &dummy, &dummy, &sym_name, + &dummy, &dummy)) { + return sprintf(buffer, "%lu", wchan); + } + + return sprintf(buffer, "%s", sym_name); +} +#endif + /************************************************************************/ /* Here the fs part begins */ /************************************************************************/ @@ -1016,6 +1043,12 @@ case PROC_PID_MOUNTS: inode->i_fop = &proc_mounts_operations; break; +#ifdef CONFIG_KALLSYMS + case PROC_PID_WCHAN: + inode->i_fop = &proc_info_file_operations; + ei->op.proc_read = proc_pid_wchan; + break; +#endif default: printk("procfs: impossible type (%d)",p->type); iput(inode); diff -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c --- a/fs/proc/proc_misc.c Mon Nov 4 14:31:01 2002 +++ b/fs/proc/proc_misc.c Mon Nov 4 14:31:01 2002 @@ -62,7 +62,6 @@ extern int get_exec_domain_list(char *); extern int get_dma_list(char *); extern int get_locks_status (char *, char **, off_t, int); -extern int get_swaparea_info (char *); #ifdef CONFIG_SGI_DS1286 extern int get_ds1286_status(char *); #endif @@ -296,18 +295,6 @@ .release = seq_release, }; -extern struct seq_operations swaps_op; -static int swaps_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &swaps_op); -} -static struct file_operations proc_swaps_operations = { - .open = swaps_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - #ifdef CONFIG_MODULES extern struct seq_operations modules_op; static int modules_open(struct inode *inode, struct file *file) @@ -360,14 +347,14 @@ int j; if(!cpu_online(i)) continue; - user += kstat.per_cpu_user[i]; - nice += kstat.per_cpu_nice[i]; - system += kstat.per_cpu_system[i]; - idle += kstat.per_cpu_idle[i]; - iowait += kstat.per_cpu_iowait[i]; + user += kstat_cpu(i).cpustat.user; + nice += kstat_cpu(i).cpustat.nice; + system += kstat_cpu(i).cpustat.system; + idle += kstat_cpu(i).cpustat.idle; + iowait += kstat_cpu(i).cpustat.iowait; #if !defined(CONFIG_ARCH_S390) for (j = 0 ; j < NR_IRQS ; j++) - sum += kstat.irqs[i][j]; + sum += kstat_cpu(i).irqs[j]; #endif } @@ -381,11 +368,11 @@ if (!cpu_online(i)) continue; len += sprintf(page + len, "cpu%d %u %u %u %u %u\n", i, - jiffies_to_clock_t(kstat.per_cpu_user[i]), - jiffies_to_clock_t(kstat.per_cpu_nice[i]), - jiffies_to_clock_t(kstat.per_cpu_system[i]), - jiffies_to_clock_t(kstat.per_cpu_idle[i]), - jiffies_to_clock_t(kstat.per_cpu_iowait[i])); + jiffies_to_clock_t(kstat_cpu(i).cpustat.user), + jiffies_to_clock_t(kstat_cpu(i).cpustat.nice), + jiffies_to_clock_t(kstat_cpu(i).cpustat.system), + jiffies_to_clock_t(kstat_cpu(i).cpustat.idle), + jiffies_to_clock_t(kstat_cpu(i).cpustat.idle)); } len += sprintf(page + len, "intr %u", sum); @@ -398,18 +385,18 @@ for (major = 0; major < DK_MAX_MAJOR; major++) { for (disk = 0; disk < DK_MAX_DISK; disk++) { - int active = kstat.dk_drive[major][disk] + - kstat.dk_drive_rblk[major][disk] + - kstat.dk_drive_wblk[major][disk]; + int active = dkstat.drive[major][disk] + + dkstat.drive_rblk[major][disk] + + dkstat.drive_wblk[major][disk]; if (active) len += sprintf(page + len, "(%u,%u):(%u,%u,%u,%u,%u) ", major, disk, - kstat.dk_drive[major][disk], - kstat.dk_drive_rio[major][disk], - kstat.dk_drive_rblk[major][disk], - kstat.dk_drive_wio[major][disk], - kstat.dk_drive_wblk[major][disk] + dkstat.drive[major][disk], + dkstat.drive_rio[major][disk], + dkstat.drive_rblk[major][disk], + dkstat.drive_wio[major][disk], + dkstat.drive_wblk[major][disk] ); } } @@ -641,7 +628,6 @@ entry->proc_fops = &proc_kmsg_operations; create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); create_seq_entry("partitions", 0, &proc_partitions_operations); - create_seq_entry("swaps", 0, &proc_swaps_operations); #if !defined(CONFIG_ARCH_S390) create_seq_entry("interrupts", 0, &proc_interrupts_operations); #endif diff -Nru a/fs/select.c b/fs/select.c --- a/fs/select.c Mon Nov 4 14:31:00 2002 +++ b/fs/select.c Mon Nov 4 14:31:00 2002 @@ -77,6 +77,14 @@ { struct poll_table_page *table = p->table; + if (!p->queue) + return; + + if (p->qproc) { + p->qproc(p->priv, wait_address); + return; + } + if (!table || POLL_TABLE_FULL(table)) { struct poll_table_page *new_table; diff -Nru a/fs/xattr_acl.c b/fs/xattr_acl.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/xattr_acl.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,99 @@ +/* + * linux/fs/xattr_acl.c + * + * Almost all from linux/fs/ext2/acl.c: + * Copyright (C) 2001 by Andreas Gruenbacher, + */ + +#include +#include +#include +#include +#include + + +/* + * Convert from extended attribute to in-memory representation. + */ +struct posix_acl * +posix_acl_from_xattr(const void *value, size_t size) +{ + posix_acl_xattr_header *header = (posix_acl_xattr_header *)value; + posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end; + int count; + struct posix_acl *acl; + struct posix_acl_entry *acl_e; + + if (!value) + return NULL; + if (size < sizeof(posix_acl_xattr_header)) + return ERR_PTR(-EINVAL); + if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) + return ERR_PTR(-EINVAL); + + count = posix_acl_xattr_count(size); + if (count < 0) + return ERR_PTR(-EINVAL); + if (count == 0) + return NULL; + + acl = posix_acl_alloc(count, GFP_KERNEL); + if (!acl) + return ERR_PTR(-ENOMEM); + acl_e = acl->a_entries; + + for (end = entry + count; entry != end; acl_e++, entry++) { + acl_e->e_tag = le16_to_cpu(entry->e_tag); + acl_e->e_perm = le16_to_cpu(entry->e_perm); + + switch(acl_e->e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + acl_e->e_id = ACL_UNDEFINED_ID; + break; + + case ACL_USER: + case ACL_GROUP: + acl_e->e_id = le32_to_cpu(entry->e_id); + break; + + default: + goto fail; + } + } + return acl; + +fail: + posix_acl_release(acl); + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL (posix_acl_from_xattr); + +/* + * Convert from in-memory to extended attribute representation. + */ +int +posix_acl_to_xattr(const struct posix_acl *acl, void *buffer, size_t size) +{ + posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer; + posix_acl_xattr_entry *ext_entry = ext_acl->a_entries; + int real_size, n; + + real_size = posix_acl_xattr_size(acl->a_count); + if (!buffer) + return real_size; + if (real_size > size) + return -ERANGE; + + ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); + + for (n=0; n < acl->a_count; n++, ext_entry++) { + ext_entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag); + ext_entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm); + ext_entry->e_id = cpu_to_le32(acl->a_entries[n].e_id); + } + return real_size; +} +EXPORT_SYMBOL (posix_acl_to_xattr); diff -Nru a/include/asm-alpha/dma.h b/include/asm-alpha/dma.h --- a/include/asm-alpha/dma.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-alpha/dma.h Mon Nov 4 14:31:02 2002 @@ -85,43 +85,46 @@ /* The maximum address for ISA DMA transfer on Alpha XL, due to an hardware SIO limitation, is 64MB. */ -#define ALPHA_XL_MAX_DMA_ADDRESS (IDENT_ADDR+0x04000000UL) +#define ALPHA_XL_MAX_ISA_DMA_ADDRESS 0x04000000UL -/* The maximum address for ISA DMA transfer on RUFFIAN and NAUTILUS, +/* The maximum address for ISA DMA transfer on RUFFIAN, due to an hardware SIO limitation, is 16MB. */ -#define ALPHA_RUFFIAN_MAX_DMA_ADDRESS (IDENT_ADDR+0x01000000UL) -#define ALPHA_NAUTILUS_MAX_DMA_ADDRESS (IDENT_ADDR+0x01000000UL) +#define ALPHA_RUFFIAN_MAX_ISA_DMA_ADDRESS 0x01000000UL /* The maximum address for ISA DMA transfer on SABLE, and some ALCORs, due to an hardware SIO chip limitation, is 2GB. */ -#define ALPHA_SABLE_MAX_DMA_ADDRESS (IDENT_ADDR+0x80000000UL) -#define ALPHA_ALCOR_MAX_DMA_ADDRESS (IDENT_ADDR+0x80000000UL) +#define ALPHA_SABLE_MAX_ISA_DMA_ADDRESS 0x80000000UL +#define ALPHA_ALCOR_MAX_ISA_DMA_ADDRESS 0x80000000UL /* Maximum address for all the others is the complete 32-bit bus address space. */ -#define ALPHA_MAX_DMA_ADDRESS (IDENT_ADDR+0x100000000UL) +#define ALPHA_MAX_ISA_DMA_ADDRESS 0x100000000UL #ifdef CONFIG_ALPHA_GENERIC -# define MAX_DMA_ADDRESS (alpha_mv.max_dma_address) +# define MAX_ISA_DMA_ADDRESS (alpha_mv.max_isa_dma_address) #else # if defined(CONFIG_ALPHA_XL) -# define MAX_DMA_ADDRESS ALPHA_XL_MAX_DMA_ADDRESS +# define MAX_ISA_DMA_ADDRESS ALPHA_XL_MAX_ISA_DMA_ADDRESS # elif defined(CONFIG_ALPHA_RUFFIAN) -# define MAX_DMA_ADDRESS ALPHA_RUFFIAN_MAX_DMA_ADDRESS -# elif defined(CONFIG_ALPHA_NAUTILUS) -# define MAX_DMA_ADDRESS ALPHA_NAUTILUS_MAX_DMA_ADDRESS +# define MAX_ISA_DMA_ADDRESS ALPHA_RUFFIAN_MAX_ISA_DMA_ADDRESS # elif defined(CONFIG_ALPHA_SABLE) -# define MAX_DMA_ADDRESS ALPHA_SABLE_MAX_DMA_ADDRESS +# define MAX_ISA_DMA_ADDRESS ALPHA_SABLE_MAX_DMA_ISA_ADDRESS # elif defined(CONFIG_ALPHA_ALCOR) -# define MAX_DMA_ADDRESS ALPHA_ALCOR_MAX_DMA_ADDRESS +# define MAX_ISA_DMA_ADDRESS ALPHA_ALCOR_MAX_DMA_ISA_ADDRESS # else -# define MAX_DMA_ADDRESS ALPHA_MAX_DMA_ADDRESS +# define MAX_ISA_DMA_ADDRESS ALPHA_MAX_ISA_DMA_ADDRESS # endif #endif + +/* If we have the iommu, we don't have any address limitations on DMA. + Otherwise (Nautilus, RX164), we have to have 0-16 Mb DMA zone + like i386. */ +#define MAX_DMA_ADDRESS (alpha_mv.mv_pci_tbi ? \ + ~0UL : IDENT_ADDR + 0x01000000) /* 8237 DMA controllers */ #define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */ diff -Nru a/include/asm-alpha/floppy.h b/include/asm-alpha/floppy.h --- a/include/asm-alpha/floppy.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-alpha/floppy.h Mon Nov 4 14:31:02 2002 @@ -51,12 +51,12 @@ if (bus_addr && (addr != prev_addr || size != prev_size || dir != prev_dir)) { /* different from last time -- unmap prev */ - pci_unmap_single(NULL, bus_addr, prev_size, prev_dir); + pci_unmap_single(isa_bridge, bus_addr, prev_size, prev_dir); bus_addr = 0; } if (!bus_addr) /* need to map it */ - bus_addr = pci_map_single(NULL, addr, size, dir); + bus_addr = pci_map_single(isa_bridge, addr, size, dir); /* remember this one as prev */ prev_addr = addr; diff -Nru a/include/asm-alpha/hwrpb.h b/include/asm-alpha/hwrpb.h --- a/include/asm-alpha/hwrpb.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-alpha/hwrpb.h Mon Nov 4 14:31:01 2002 @@ -109,6 +109,9 @@ unsigned long ipc_buffer[21]; unsigned long palcode_avail[16]; unsigned long compatibility; + unsigned long console_data_log_pa; + unsigned long console_data_log_length; + unsigned long bcache_info; }; struct procdesc_struct { diff -Nru a/include/asm-alpha/machvec.h b/include/asm-alpha/machvec.h --- a/include/asm-alpha/machvec.h Mon Nov 4 14:31:00 2002 +++ b/include/asm-alpha/machvec.h Mon Nov 4 14:31:00 2002 @@ -34,7 +34,7 @@ int nr_irqs; int rtc_port; int max_asn; - unsigned long max_dma_address; + unsigned long max_isa_dma_address; unsigned long irq_probe_mask; unsigned long iack_sc; unsigned long min_io_address; diff -Nru a/include/asm-alpha/mman.h b/include/asm-alpha/mman.h --- a/include/asm-alpha/mman.h Mon Nov 4 14:31:00 2002 +++ b/include/asm-alpha/mman.h Mon Nov 4 14:31:00 2002 @@ -19,11 +19,13 @@ #define _MAP_UNALIGNED 0x0800 /* These are linux-specific */ -#define MAP_GROWSDOWN 0x1000 /* stack-like segment */ -#define MAP_DENYWRITE 0x2000 /* ETXTBSY */ -#define MAP_EXECUTABLE 0x4000 /* mark it as an executable */ -#define MAP_LOCKED 0x8000 /* lock the mapping */ +#define MAP_GROWSDOWN 0x01000 /* stack-like segment */ +#define MAP_DENYWRITE 0x02000 /* ETXTBSY */ +#define MAP_EXECUTABLE 0x04000 /* mark it as an executable */ +#define MAP_LOCKED 0x08000 /* lock the mapping */ #define MAP_NORESERVE 0x10000 /* don't check for reservations */ +#define MAP_POPULATE 0x20000 /* populate (prefault) pagetables */ +#define MAP_NONBLOCK 0x40000 /* do not block on IO */ #define MS_ASYNC 1 /* sync memory asynchronously */ #define MS_SYNC 2 /* synchronous memory sync */ diff -Nru a/include/asm-alpha/poll.h b/include/asm-alpha/poll.h --- a/include/asm-alpha/poll.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-alpha/poll.h Mon Nov 4 14:31:01 2002 @@ -1,17 +1,18 @@ #ifndef __ALPHA_POLL_H #define __ALPHA_POLL_H -#define POLLIN 1 -#define POLLPRI 2 -#define POLLOUT 4 -#define POLLERR 8 -#define POLLHUP 16 -#define POLLNVAL 32 -#define POLLRDNORM 64 -#define POLLRDBAND 128 -#define POLLWRNORM 256 -#define POLLWRBAND 512 -#define POLLMSG 1024 +#define POLLIN (1 << 0) +#define POLLPRI (1 << 1) +#define POLLOUT (1 << 2) +#define POLLERR (1 << 3) +#define POLLHUP (1 << 4) +#define POLLNVAL (1 << 5) +#define POLLRDNORM (1 << 6) +#define POLLRDBAND (1 << 7) +#define POLLWRNORM (1 << 8) +#define POLLWRBAND (1 << 9) +#define POLLMSG (1 << 10) +#define POLLREMOVE (1 << 11) struct pollfd { int fd; diff -Nru a/include/asm-alpha/processor.h b/include/asm-alpha/processor.h --- a/include/asm-alpha/processor.h Mon Nov 4 14:31:03 2002 +++ b/include/asm-alpha/processor.h Mon Nov 4 14:31:03 2002 @@ -55,9 +55,6 @@ /* Create a kernel thread without removing it from tasklists. */ extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); -#define copy_segments(tsk, mm) do { } while (0) -#define release_segments(mm) do { } while (0) - unsigned long get_wchan(struct task_struct *p); /* See arch/alpha/kernel/ptrace.c for details. */ diff -Nru a/include/asm-alpha/siginfo.h b/include/asm-alpha/siginfo.h --- a/include/asm-alpha/siginfo.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-alpha/siginfo.h Mon Nov 4 14:31:02 2002 @@ -1,26 +1,11 @@ #ifndef _ALPHA_SIGINFO_H #define _ALPHA_SIGINFO_H -#define SI_PAD_SIZE ((SI_MAX_SIZE/sizeof(int)) - 4) +#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) +#define __ARCH_SI_TRAPNO -#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 4) - -#define HAVE_ARCH_COPY_SIGINFO +#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 4) #include - -#ifdef __KERNEL__ -#include - -extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from) -{ - if (from->si_code < 0) - memcpy(to, from, sizeof(siginfo_t)); - else - /* _sigchld is currently the largest know union member */ - memcpy(to, from, 4*sizeof(int) + sizeof(from->_sifields._sigchld)); -} - -#endif /* __KERNEL__ */ #endif diff -Nru a/include/asm-alpha/system.h b/include/asm-alpha/system.h --- a/include/asm-alpha/system.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-alpha/system.h Mon Nov 4 14:31:02 2002 @@ -61,7 +61,8 @@ int retry : 1; /* retry flag */ unsigned int proc_offset; /* processor-specific offset */ unsigned int sys_offset; /* system-specific offset */ - unsigned long code; /* machine check code */ + unsigned int code; /* machine check code */ + unsigned int frame_rev; /* frame revision */ }; /* Machine Check Frame for uncorrectable errors (Large format) @@ -117,11 +118,11 @@ unsigned long DC0_SYNDROME; unsigned long C_STAT; unsigned long C_STS; - unsigned long RESERVED0; + unsigned long MM_STAT; unsigned long EXC_ADDR; unsigned long IER_CM; unsigned long ISUM; - unsigned long MM_STAT; + unsigned long RESERVED0; unsigned long PAL_BASE; unsigned long I_CTL; unsigned long PCTX; diff -Nru a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h --- a/include/asm-alpha/unistd.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-alpha/unistd.h Mon Nov 4 14:31:01 2002 @@ -552,9 +552,9 @@ } extern off_t sys_lseek(int, off_t, int); -static inline off_t lseek(int fd, off_t off, int whense) +static inline off_t lseek(int fd, off_t off, int whence) { - return sys_lseek(fd, off, whense); + return sys_lseek(fd, off, whence); } extern long sys_exit(int); @@ -565,14 +565,14 @@ #define exit(x) _exit(x) -extern long sys_write(int, const char *, int); -static inline long write(int fd, const char * buf, int nr) +extern long sys_write(int, const char *, size_t); +static inline long write(int fd, const char * buf, size_t nr) { return sys_write(fd, buf, nr); } -extern long sys_read(int, char *, int); -static inline long read(int fd, char * buf, int nr) +extern long sys_read(int, char *, size_t); +static inline long read(int fd, char * buf, size_t nr) { return sys_read(fd, buf, nr); } diff -Nru a/include/asm-arm/arch-ebsa285/hardware.h b/include/asm-arm/arch-ebsa285/hardware.h --- a/include/asm-arm/arch-ebsa285/hardware.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-arm/arch-ebsa285/hardware.h Mon Nov 4 14:31:02 2002 @@ -133,7 +133,7 @@ #define pcibios_assign_all_busses() 1 -#define PCIBIOS_MIN_IO 0x6000 -#define PCIBIOS_MIN_MEM 0x40000000 +#define PCIBIOS_MIN_IO 0x1000 +#define PCIBIOS_MIN_MEM 0x81000000 #endif diff -Nru a/include/asm-arm/arch-sa1100/badge4.h b/include/asm-arm/arch-sa1100/badge4.h --- a/include/asm-arm/arch-sa1100/badge4.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-arm/arch-sa1100/badge4.h Mon Nov 4 14:31:02 2002 @@ -68,6 +68,7 @@ #define BADGE4_5V_PCMCIA_SOCK1 (1<<1) #define BADGE4_5V_PCMCIA_SOCK(n) (1<<(n)) #define BADGE4_5V_USB (1<<2) +#define BADGE4_5V_INITIALLY (1<<3) #ifndef __ASSEMBLY__ extern void badge4_set_5V(unsigned subsystem, int on); diff -Nru a/include/asm-arm/io.h b/include/asm-arm/io.h --- a/include/asm-arm/io.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-arm/io.h Mon Nov 4 14:31:01 2002 @@ -22,7 +22,6 @@ #ifdef __KERNEL__ -#include #include #include #include @@ -94,6 +93,8 @@ * Note that we prevent GCC re-ordering or caching values in expressions * by introducing sequence points into the in*() definitions. Note that * __raw_* do not guarantee this behaviour. + * + * The {in,out}[bwl] macros are for emulating x86-style PCI/ISA IO space. */ #ifdef __io #define outb(v,p) __raw_writeb(v,__io(p)) diff -Nru a/include/asm-arm/mman.h b/include/asm-arm/mman.h --- a/include/asm-arm/mman.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-arm/mman.h Mon Nov 4 14:31:01 2002 @@ -18,6 +18,8 @@ #define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ #define MAP_LOCKED 0x2000 /* pages are locked */ #define MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define MAP_POPULATE 0x8000 /* populate (prefault) page tables */ +#define MAP_NONBLOCK 0x10000 /* do not block on IO */ #define MS_ASYNC 1 /* sync memory asynchronously */ #define MS_INVALIDATE 2 /* invalidate the caches */ diff -Nru a/include/asm-arm/pci.h b/include/asm-arm/pci.h --- a/include/asm-arm/pci.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-arm/pci.h Mon Nov 4 14:31:01 2002 @@ -241,7 +241,7 @@ /* kmem_cache style wrapper around pci_alloc_consistent() */ struct pci_pool *pci_pool_create (const char *name, struct pci_dev *dev, - size_t size, size_t align, size_t allocation, int flags); + size_t size, size_t align, size_t allocation); void pci_pool_destroy (struct pci_pool *pool); void *pci_pool_alloc (struct pci_pool *pool, int flags, dma_addr_t *handle); diff -Nru a/include/asm-arm/poll.h b/include/asm-arm/poll.h --- a/include/asm-arm/poll.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-arm/poll.h Mon Nov 4 14:31:02 2002 @@ -15,6 +15,7 @@ #define POLLWRNORM 0x0100 #define POLLWRBAND 0x0200 #define POLLMSG 0x0400 +#define POLLREMOVE 0x1000 struct pollfd { int fd; diff -Nru a/include/asm-arm/proc-armv/pgtable.h b/include/asm-arm/proc-armv/pgtable.h --- a/include/asm-arm/proc-armv/pgtable.h Mon Nov 4 14:31:00 2002 +++ b/include/asm-arm/proc-armv/pgtable.h Mon Nov 4 14:31:00 2002 @@ -38,7 +38,7 @@ #define PMD_TYPE_FAULT (0 << 0) #define PMD_TYPE_TABLE (1 << 0) #define PMD_TYPE_SECT (2 << 0) -#define PMD_UPDATABLE (1 << 4) +#define PMD_BIT4 (1 << 4) #define PMD_DOMAIN(x) ((x) << 5) #define PMD_PROTECTION (1 << 9) /* v5 */ /* @@ -49,6 +49,13 @@ #define PMD_SECT_AP_WRITE (1 << 10) #define PMD_SECT_AP_READ (1 << 11) #define PMD_SECT_TEX(x) ((x) << 12) /* v5 */ + +#define PMD_SECT_UNCACHED (0) +#define PMD_SECT_WT (PMD_SECT_CACHEABLE) +#define PMD_SECT_WB (PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE) +#define PMD_SECT_MINICACHE (PMD_SECT_TEX(1) | PMD_SECT_CACHEABLE) +#define PMD_SECT_WBWA (PMD_SECT_TEX(1) | PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE) + /* * - coarse table (not used) */ @@ -184,6 +191,7 @@ * Mark the prot value as uncacheable and unbufferable. */ #define pgprot_noncached(prot) __pgprot(pgprot_val(prot) & ~(L_PTE_CACHEABLE | L_PTE_BUFFERABLE)) +#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~L_PTE_CACHEABLE) #define pgtable_cache_init() do { } while (0) diff -Nru a/include/asm-arm/processor.h b/include/asm-arm/processor.h --- a/include/asm-arm/processor.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-arm/processor.h Mon Nov 4 14:31:01 2002 @@ -62,10 +62,6 @@ /* Free all resources held by a thread. */ extern void release_thread(struct task_struct *); -/* Copy and release all segment info associated with a VM */ -#define copy_segments(tsk, mm) do { } while (0) -#define release_segments(mm) do { } while (0) - unsigned long get_wchan(struct task_struct *p); #define cpu_relax() barrier() diff -Nru a/include/asm-arm/ptrace.h b/include/asm-arm/ptrace.h --- a/include/asm-arm/ptrace.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-arm/ptrace.h Mon Nov 4 14:31:02 2002 @@ -6,10 +6,7 @@ #define PTRACE_GETFPREGS 14 #define PTRACE_SETFPREGS 15 -#define PTRACE_SETOPTIONS 21 - -/* options set using PTRACE_SETOPTIONS */ -#define PTRACE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_OLDSETOPTIONS 21 #include diff -Nru a/include/asm-arm/system.h b/include/asm-arm/system.h --- a/include/asm-arm/system.h Mon Nov 4 14:31:00 2002 +++ b/include/asm-arm/system.h Mon Nov 4 14:31:00 2002 @@ -44,6 +44,16 @@ extern asmlinkage void __backtrace(void); +#define CPU_ARCH_UNKNOWN 0 +#define CPU_ARCH_ARMv3 1 +#define CPU_ARCH_ARMv4 2 +#define CPU_ARCH_ARMv4T 3 +#define CPU_ARCH_ARMv5 4 +#define CPU_ARCH_ARMv5T 5 +#define CPU_ARCH_ARMv5TE 6 + +extern int cpu_architecture(void); + /* * Include processor dependent parts */ diff -Nru a/include/asm-cris/processor.h b/include/asm-cris/processor.h --- a/include/asm-cris/processor.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-cris/processor.h Mon Nov 4 14:31:01 2002 @@ -108,10 +108,6 @@ #define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp) -#define copy_segments(tsk, mm) do { } while (0) -#define release_segments(mm) do { } while (0) -#define forget_segments() do { } while (0) - /* * Free current thread data structures etc.. */ diff -Nru a/include/asm-i386/cpu.h b/include/asm-i386/cpu.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-i386/cpu.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,26 @@ +#ifndef _ASM_I386_CPU_H_ +#define _ASM_I386_CPU_H_ + +#include +#include + +#include +#include + +struct i386_cpu { + struct cpu cpu; +}; +extern struct i386_cpu cpu_devices[NR_CPUS]; + + +static inline int arch_register_cpu(int num){ + struct node *parent = NULL; + +#ifdef CONFIG_NUMA + parent = &node_devices[__cpu_to_node(num)].node; +#endif /* CONFIG_NUMA */ + + return register_cpu(&cpu_devices[num].cpu, num, parent); +} + +#endif /* _ASM_I386_CPU_H_ */ diff -Nru a/include/asm-i386/memblk.h b/include/asm-i386/memblk.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-i386/memblk.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,23 @@ +#ifndef _ASM_I386_MEMBLK_H_ +#define _ASM_I386_MEMBLK_H_ + +#include +#include +#include + +#include +#include + +struct i386_memblk { + struct memblk memblk; +}; +extern struct i386_memblk memblk_devices[MAX_NR_MEMBLKS]; + +static inline int arch_register_memblk(int num){ + int p_node = __memblk_to_node(num); + + return register_memblk(&memblk_devices[num].memblk, num, + &node_devices[p_node].node); +} + +#endif /* _ASM_I386_MEMBLK_H_ */ diff -Nru a/include/asm-i386/mman.h b/include/asm-i386/mman.h --- a/include/asm-i386/mman.h Mon Nov 4 14:31:00 2002 +++ b/include/asm-i386/mman.h Mon Nov 4 14:31:00 2002 @@ -18,6 +18,8 @@ #define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ #define MAP_LOCKED 0x2000 /* pages are locked */ #define MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ +#define MAP_NONBLOCK 0x10000 /* do not block on IO */ #define MS_ASYNC 1 /* sync memory asynchronously */ #define MS_INVALIDATE 2 /* invalidate the caches */ diff -Nru a/include/asm-i386/mmu_context.h b/include/asm-i386/mmu_context.h --- a/include/asm-i386/mmu_context.h Mon Nov 4 14:31:00 2002 +++ b/include/asm-i386/mmu_context.h Mon Nov 4 14:31:00 2002 @@ -8,10 +8,10 @@ #include /* - * possibly do the LDT unload here? + * Used for LDT copy/destruction. */ -#define destroy_context(mm) do { } while(0) int init_new_context(struct task_struct *tsk, struct mm_struct *mm); +void destroy_context(struct mm_struct *mm); #ifdef CONFIG_SMP diff -Nru a/include/asm-i386/node.h b/include/asm-i386/node.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-i386/node.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,25 @@ +#ifndef _ASM_I386_NODE_H_ +#define _ASM_I386_NODE_H_ + +#include +#include +#include + +#include + +struct i386_node { + struct node node; +}; +extern struct i386_node node_devices[MAX_NUMNODES]; + +static inline int arch_register_node(int num){ + int p_node = __parent_node(num); + struct node *parent = NULL; + + if (p_node != num) + parent = &node_devices[p_node].node; + + return register_node(&node_devices[num].node, num, parent); +} + +#endif /* _ASM_I386_NODE_H_ */ diff -Nru a/include/asm-i386/processor.h b/include/asm-i386/processor.h --- a/include/asm-i386/processor.h Mon Nov 4 14:31:00 2002 +++ b/include/asm-i386/processor.h Mon Nov 4 14:31:00 2002 @@ -270,7 +270,7 @@ /* This decides where the kernel will search for a free chunk of vm * space during mmap's. */ -#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) +#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) /* * Size of io_bitmap in longwords: 32 is ports 0-0x3ff. @@ -433,9 +433,6 @@ * create a kernel thread without removing it from tasklists */ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); - -/* Release all segment info associated with a VM */ -extern void release_segments(struct mm_struct * mm); extern unsigned long thread_saved_pc(struct task_struct *tsk); diff -Nru a/include/asm-i386/ptrace.h b/include/asm-i386/ptrace.h --- a/include/asm-i386/ptrace.h Mon Nov 4 14:31:00 2002 +++ b/include/asm-i386/ptrace.h Mon Nov 4 14:31:00 2002 @@ -49,10 +49,7 @@ #define PTRACE_GETFPXREGS 18 #define PTRACE_SETFPXREGS 19 -#define PTRACE_SETOPTIONS 21 - -/* options set using PTRACE_SETOPTIONS */ -#define PTRACE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_OLDSETOPTIONS 21 #ifdef __KERNEL__ #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs)) diff -Nru a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h --- a/include/asm-i386/unistd.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-i386/unistd.h Mon Nov 4 14:31:02 2002 @@ -261,7 +261,8 @@ #define __NR_sys_epoll_create 254 #define __NR_sys_epoll_ctl 255 #define __NR_sys_epoll_wait 256 - +#define __NR_remap_file_pages 257 + /* user-visible error numbers are in the range -1 - -124: see */ diff -Nru a/include/asm-i386/vic.h b/include/asm-i386/vic.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-i386/vic.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,61 @@ +/* Copyright (C) 1999,2001 + * + * Author: J.E.J.Bottomley@HansenPartnership.com + * + * Standard include definitions for the NCR Voyager Interrupt Controller */ + +/* The eight CPI vectors. To activate a CPI, you write a bit mask + * corresponding to the processor set to be interrupted into the + * relevant register. That set of CPUs will then be interrupted with + * the CPI */ +static const int VIC_CPI_Registers[] = + {0xFC00, 0xFC01, 0xFC08, 0xFC09, + 0xFC10, 0xFC11, 0xFC18, 0xFC19 }; + +#define VIC_PROC_WHO_AM_I 0xfc29 +# define QUAD_IDENTIFIER 0xC0 +# define EIGHT_SLOT_IDENTIFIER 0xE0 +#define QIC_EXTENDED_PROCESSOR_SELECT 0xFC72 +#define VIC_CPI_BASE_REGISTER 0xFC41 +#define VIC_PROCESSOR_ID 0xFC21 +# define VIC_CPU_MASQUERADE_ENABLE 0x8 + +#define VIC_CLAIM_REGISTER_0 0xFC38 +#define VIC_CLAIM_REGISTER_1 0xFC39 +#define VIC_REDIRECT_REGISTER_0 0xFC60 +#define VIC_REDIRECT_REGISTER_1 0xFC61 +#define VIC_PRIORITY_REGISTER 0xFC20 + +#define VIC_PRIMARY_MC_BASE 0xFC48 +#define VIC_SECONDARY_MC_BASE 0xFC49 + +#define QIC_PROCESSOR_ID 0xFC71 +# define QIC_CPUID_ENABLE 0x08 + +#define QIC_VIC_CPI_BASE_REGISTER 0xFC79 +#define QIC_CPI_BASE_REGISTER 0xFC7A + +#define QIC_MASK_REGISTER0 0xFC80 +/* NOTE: these are masked high, enabled low */ +# define QIC_PERF_TIMER 0x01 +# define QIC_LPE 0x02 +# define QIC_SYS_INT 0x04 +# define QIC_CMN_INT 0x08 +/* at the moment, just enable CMN_INT, disable SYS_INT */ +# define QIC_DEFAULT_MASK0 (~(QIC_CMN_INT /* | VIC_SYS_INT */)) +#define QIC_MASK_REGISTER1 0xFC81 +# define QIC_BOOT_CPI_MASK 0xFE +/* Enable CPI's 1-6 inclusive */ +# define QIC_CPI_ENABLE 0x81 + +#define QIC_INTERRUPT_CLEAR0 0xFC8A +#define QIC_INTERRUPT_CLEAR1 0xFC8B + +/* this is where we place the CPI vectors */ +#define VIC_DEFAULT_CPI_BASE 0xC0 +/* this is where we place the QIC CPI vectors */ +#define QIC_DEFAULT_CPI_BASE 0xD0 + +#define VIC_BOOT_INTERRUPT_MASK 0xfe + +extern void smp_vic_timer_interrupt(struct pt_regs *regs); diff -Nru a/include/asm-ia64/ide.h b/include/asm-ia64/ide.h --- a/include/asm-ia64/ide.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-ia64/ide.h Mon Nov 4 14:31:02 2002 @@ -83,6 +83,7 @@ int index; for(index = 0; index < MAX_HWIFS; index++) { + memset(&hw, 0, sizeof hw); ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL); hw.irq = ide_default_irq(ide_default_io_base(index)); ide_register_hw(&hw, NULL); diff -Nru a/include/asm-ia64/numa.h b/include/asm-ia64/numa.h --- a/include/asm-ia64/numa.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-ia64/numa.h Mon Nov 4 14:31:01 2002 @@ -21,7 +21,9 @@ # define NR_MEMBLKS (NR_NODES * 8) #endif -extern char cpu_to_node_map[NR_CPUS] __cacheline_aligned; +#include +extern volatile char cpu_to_node_map[NR_CPUS] __cacheline_aligned; +extern volatile unsigned long node_to_cpu_mask[NR_NODES] __cacheline_aligned; /* Stuff below this line could be architecture independent */ diff -Nru a/include/asm-ia64/page.h b/include/asm-ia64/page.h --- a/include/asm-ia64/page.h Mon Nov 4 14:31:00 2002 +++ b/include/asm-ia64/page.h Mon Nov 4 14:31:00 2002 @@ -30,6 +30,9 @@ #define PAGE_MASK (~(PAGE_SIZE - 1)) #define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) +#define PERCPU_PAGE_SHIFT 16 /* log2() of max. size of per-CPU area */ +#define PERCPU_PAGE_SIZE (__IA64_UL_CONST(1) << PERCPU_PAGE_SHIFT) + #ifdef CONFIG_HUGETLB_PAGE # if defined(CONFIG_HUGETLB_PAGE_SIZE_4GB) diff -Nru a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h --- a/include/asm-ia64/pgtable.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-ia64/pgtable.h Mon Nov 4 14:31:01 2002 @@ -202,7 +202,7 @@ #define RGN_MAP_LIMIT ((1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE) /* per region addr limit */ #define RGN_KERNEL 7 -#define VMALLOC_START (0xa000000000000000 + 3*PAGE_SIZE) +#define VMALLOC_START (0xa000000000000000 + 3*PERCPU_PAGE_SIZE) #define VMALLOC_VMADDR(x) ((unsigned long)(x)) #define VMALLOC_END (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) diff -Nru a/include/asm-ia64/poll.h b/include/asm-ia64/poll.h --- a/include/asm-ia64/poll.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-ia64/poll.h Mon Nov 4 14:31:02 2002 @@ -4,8 +4,8 @@ /* * poll(2) bit definitions. Chosen to be compatible with Linux/x86. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1998, 1999, 2002 Hewlett-Packard Co + * David Mosberger-Tang */ #define POLLIN 0x0001 @@ -20,6 +20,7 @@ #define POLLWRNORM 0x0100 #define POLLWRBAND 0x0200 #define POLLMSG 0x0400 +#define POLLREMOVE 0x1000 struct pollfd { int fd; diff -Nru a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h --- a/include/asm-ia64/processor.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-ia64/processor.h Mon Nov 4 14:31:01 2002 @@ -179,7 +179,6 @@ #endif #ifdef CONFIG_NUMA struct ia64_node_data *node_data; - int nodeid; #endif }; @@ -192,10 +191,6 @@ #define local_cpu_data (&__get_cpu_var(cpu_info)) #define cpu_data(cpu) (&per_cpu(cpu_info, cpu)) -#ifdef CONFIG_NUMA -#define numa_node_id() (local_cpu_data->nodeid) -#endif - extern void identify_cpu (struct cpuinfo_ia64 *); extern void print_cpu_info (struct cpuinfo_ia64 *); @@ -366,10 +361,6 @@ * been called already. */ extern int kernel_thread (int (*fn)(void *), void *arg, unsigned long flags); - -/* Copy and release all segment info associated with a VM */ -#define copy_segments(tsk, mm) do { } while (0) -#define release_segments(mm) do { } while (0) /* Get wait channel for task P. */ extern unsigned long get_wchan (struct task_struct *p); diff -Nru a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h --- a/include/asm-ia64/ptrace.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-ia64/ptrace.h Mon Nov 4 14:31:02 2002 @@ -287,9 +287,6 @@ #define PTRACE_GETREGS 18 /* get all registers (pt_all_user_regs) in one shot */ #define PTRACE_SETREGS 19 /* set all registers (pt_all_user_regs) in one shot */ -#define PTRACE_SETOPTIONS 21 - -/* options set using PTRACE_SETOPTIONS */ -#define PTRACE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_OLDSETOPTIONS 21 #endif /* _ASM_IA64_PTRACE_H */ diff -Nru a/include/asm-ia64/system.h b/include/asm-ia64/system.h --- a/include/asm-ia64/system.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-ia64/system.h Mon Nov 4 14:31:01 2002 @@ -20,8 +20,9 @@ #define KERNEL_START (PAGE_OFFSET + 68*1024*1024) -#define GATE_ADDR (0xa000000000000000 + PAGE_SIZE) -#define PERCPU_ADDR (0xa000000000000000 + 2*PAGE_SIZE) +/* 0xa000000000000000 - 0xa000000000000000+PERCPU_MAX_SIZE remain unmapped */ +#define PERCPU_ADDR (0xa000000000000000 + PERCPU_PAGE_SIZE) +#define GATE_ADDR (0xa000000000000000 + 2*PERCPU_PAGE_SIZE) #ifndef __ASSEMBLY__ diff -Nru a/include/asm-ia64/topology.h b/include/asm-ia64/topology.h --- a/include/asm-ia64/topology.h Mon Nov 4 14:31:00 2002 +++ b/include/asm-ia64/topology.h Mon Nov 4 14:31:00 2002 @@ -15,12 +15,22 @@ #include #include +#include -/* Returns the number of the node containing CPU 'cpu' */ #ifdef CONFIG_NUMA -#define __cpu_to_node(cpu) cpu_to_node_map[cpu] +/* + * Returns the number of the node containing CPU 'cpu' + */ +#define __cpu_to_node(cpu) (int)(cpu_to_node_map[cpu]) + +/* + * Returns a bitmask of CPUs on Node 'node'. + */ +#define __node_to_cpu_mask(node) (node_to_cpu_mask[node]) + #else #define __cpu_to_node(cpu) (0) +#define __node_to_cpu_mask(node) (phys_cpu_present_map) #endif /* @@ -41,34 +51,8 @@ /* * Returns the number of the first CPU on Node 'node'. - * Slow in the current implementation. - * Who needs this? - */ -/* #define __node_to_first_cpu(node) pool_cpus[pool_ptr[node]] */ -static inline int __node_to_first_cpu(int node) -{ - int i; - - for (i=0; i phys conversions */ #define dvma_vtop(x) ((unsigned long)(x) & 0xffffff) #define dvma_ptov(x) ((unsigned long)(x) | 0xf000000) +#define dvma_vtovme(x) ((unsigned long)(x) & 0x00fffff) +#define dvma_vmetov(x) ((unsigned long)(x) | 0xff00000) #define dvma_vtob(x) dvma_vtop(x) #define dvma_btov(x) dvma_ptov(x) diff -Nru a/include/asm-m68k/floppy.h b/include/asm-m68k/floppy.h --- a/include/asm-m68k/floppy.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-m68k/floppy.h Mon Nov 4 14:31:02 2002 @@ -9,7 +9,7 @@ * * Copyright (C) 1999, 2000, 2001 * - * Sun3x support added 2/4/2000 Sam Creasey (sammy@oh.verio.com) + * Sun3x support added 2/4/2000 Sam Creasey (sammy@sammy.net) * */ diff -Nru a/include/asm-m68k/hardirq.h b/include/asm-m68k/hardirq.h --- a/include/asm-m68k/hardirq.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-m68k/hardirq.h Mon Nov 4 14:31:01 2002 @@ -7,24 +7,87 @@ /* entry.S is sensitive to the offsets of these fields */ typedef struct { unsigned int __softirq_pending; - unsigned int __local_irq_count; - unsigned int __local_bh_count; unsigned int __syscall_count; struct task_struct * __ksoftirqd_task; } ____cacheline_aligned irq_cpustat_t; #include /* Standard mappings for irq_cpustat_t above */ -#define in_interrupt() (local_irq_count(smp_processor_id()) + local_bh_count(smp_processor_id()) != 0) +/* + * We put the hardirq and softirq counter into the preemption + * counter. The bitmask has the following meaning: + * + * - bits 0-7 are the preemption count (max preemption depth: 256) + * - bits 8-15 are the softirq count (max # of softirqs: 256) + * - bits 16-23 are the hardirq count (max # of hardirqs: 256) + * + * - ( bit 26 is the PREEMPT_ACTIVE flag. ) + * + * PREEMPT_MASK: 0x000000ff + * HARDIRQ_MASK: 0x0000ff00 + * SOFTIRQ_MASK: 0x00ff0000 + */ + +#define PREEMPT_BITS 8 +#define SOFTIRQ_BITS 8 +#define HARDIRQ_BITS 8 + +#define PREEMPT_SHIFT 0 +#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS) +#define HARDIRQ_SHIFT (SOFTIRQ_SHIFT + SOFTIRQ_BITS) + +#define __MASK(x) ((1UL << (x))-1) + +#define PREEMPT_MASK (__MASK(PREEMPT_BITS) << PREEMPT_SHIFT) +#define HARDIRQ_MASK (__MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT) +#define SOFTIRQ_MASK (__MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT) + +#define hardirq_count() (preempt_count() & HARDIRQ_MASK) +#define softirq_count() (preempt_count() & SOFTIRQ_MASK) +#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK)) + +#define PREEMPT_OFFSET (1UL << PREEMPT_SHIFT) +#define SOFTIRQ_OFFSET (1UL << SOFTIRQ_SHIFT) +#define HARDIRQ_OFFSET (1UL << HARDIRQ_SHIFT) + +/* + * The hardirq mask has to be large enough to have + * space for potentially all IRQ sources in the system + * nesting on a single CPU: + */ +#if (1 << HARDIRQ_BITS) < NR_IRQS +# error HARDIRQ_BITS is too low! +#endif + +/* + * Are we doing bottom half or hardware interrupt processing? + * Are we in a softirq context? Interrupt context? + */ +#define in_irq() (hardirq_count()) +#define in_softirq() (softirq_count()) +#define in_interrupt() (irq_count()) + + +#define hardirq_trylock() (!in_interrupt()) +#define hardirq_endlock() do { } while (0) + +#define irq_enter() (preempt_count() += HARDIRQ_OFFSET) + +#if CONFIG_PREEMPT +# define in_atomic() (preempt_count() != kernel_locked()) +# define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) +#else +# define in_atomic() (preempt_count() != 0) +# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET +#endif +#define irq_exit() \ +do { \ + preempt_count() -= IRQ_EXIT_OFFSET; \ + if (!in_interrupt() && softirq_pending(smp_processor_id())) \ + do_softirq(); \ + preempt_enable_no_resched(); \ +} while (0) -#define in_irq() (local_irq_count(smp_processor_id()) != 0) - -#define hardirq_trylock(cpu) (local_irq_count(cpu) == 0) -#define hardirq_endlock(cpu) do { } while (0) - -#define irq_enter(cpu) (local_irq_count(cpu)++) -#define irq_exit(cpu) (local_irq_count(cpu)--) - -#define synchronize_irq() barrier() +#define synchronize_irq(irq) barrier() #endif diff -Nru a/include/asm-m68k/io.h b/include/asm-m68k/io.h --- a/include/asm-m68k/io.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-m68k/io.h Mon Nov 4 14:31:02 2002 @@ -280,18 +280,6 @@ #endif /* CONFIG_PCI */ -/* Values for nocacheflag and cmode */ -#define IOMAP_FULL_CACHING 0 -#define IOMAP_NOCACHE_SER 1 -#define IOMAP_NOCACHE_NONSER 2 -#define IOMAP_WRITETHROUGH 3 - -extern void iounmap(void *addr); - -extern void *__ioremap(unsigned long physaddr, unsigned long size, - int cacheflag); -extern void __iounmap(void *addr, unsigned long size); - extern inline void *ioremap(unsigned long physaddr, unsigned long size) { return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); diff -Nru a/include/asm-m68k/kmap_types.h b/include/asm-m68k/kmap_types.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68k/kmap_types.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,21 @@ +#ifndef __ASM_M68K_KMAP_TYPES_H +#define __ASM_M68K_KMAP_TYPES_H + +#include + +enum km_type { + KM_BOUNCE_READ, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BIO_SRC_IRQ, + KM_BIO_DST_IRQ, + KM_PTE0, + KM_PTE1, + KM_IRQ0, + KM_IRQ1, + KM_TYPE_NR +}; + +#endif /* __ASM_M68K_KMAP_TYPES_H */ diff -Nru a/include/asm-m68k/nubus.h b/include/asm-m68k/nubus.h --- a/include/asm-m68k/nubus.h Mon Nov 4 14:31:03 2002 +++ b/include/asm-m68k/nubus.h Mon Nov 4 14:31:03 2002 @@ -1,7 +1,7 @@ #ifndef _ASM_M68K_NUBUS_H #define _ASM_M68K_NUBUS_H -#include +#include #define nubus_readb raw_inb #define nubus_readw raw_inw diff -Nru a/include/asm-m68k/page.h b/include/asm-m68k/page.h --- a/include/asm-m68k/page.h Mon Nov 4 14:31:03 2002 +++ b/include/asm-m68k/page.h Mon Nov 4 14:31:03 2002 @@ -124,6 +124,7 @@ #ifndef CONFIG_SUN3 +#define WANT_PAGE_VIRTUAL #ifdef CONFIG_SINGLE_MEMORY_CHUNK extern unsigned long m68k_memoffset; diff -Nru a/include/asm-m68k/pci.h b/include/asm-m68k/pci.h --- a/include/asm-m68k/pci.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-m68k/pci.h Mon Nov 4 14:31:01 2002 @@ -30,7 +30,7 @@ struct pci_ops *m68k_pci_ops; void (*fixup)(int pci_modify); - void (*conf_device)(unsigned char bus, unsigned char device_fn); + void (*conf_device)(struct pci_dev *dev); }; #define pcibios_assign_all_busses() 0 diff -Nru a/include/asm-m68k/percpu.h b/include/asm-m68k/percpu.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68k/percpu.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,6 @@ +#ifndef __ASM_M68K_PERCPU_H +#define __ASM_M68K_PERCPU_H + +#include + +#endif /* __ASM_M68K_PERCPU_H */ diff -Nru a/include/asm-m68k/poll.h b/include/asm-m68k/poll.h --- a/include/asm-m68k/poll.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-m68k/poll.h Mon Nov 4 14:31:01 2002 @@ -12,6 +12,7 @@ #define POLLRDBAND 128 #define POLLWRBAND 256 #define POLLMSG 0x0400 +#define POLLREMOVE 0x1000 struct pollfd { int fd; diff -Nru a/include/asm-m68k/processor.h b/include/asm-m68k/processor.h --- a/include/asm-m68k/processor.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-m68k/processor.h Mon Nov 4 14:31:02 2002 @@ -114,9 +114,6 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); -#define copy_segments(tsk, mm) do { } while (0) -#define release_segments(mm) do { } while (0) - /* * Free current thread data structures etc.. */ diff -Nru a/include/asm-m68k/q40_master.h b/include/asm-m68k/q40_master.h --- a/include/asm-m68k/q40_master.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-m68k/q40_master.h Mon Nov 4 14:31:02 2002 @@ -10,7 +10,6 @@ #define q40_master_addr 0xff000000 -#define q40_rtc_addr 0xff021ffc #define IIRQ_REG 0x0 /* internal IRQ reg */ #define EIRQ_REG 0x4 /* external ... */ @@ -43,28 +42,25 @@ #define master_inb(_reg_) in_8((unsigned char *)q40_master_addr+_reg_) #define master_outb(_b_,_reg_) out_8((unsigned char *)q40_master_addr+_reg_,_b_) - -/* define some Q40 specific ints */ -#include "q40ints.h" - /* RTC defines */ -#define Q40_RTC_BASE (q40_rtc_addr) - -#define RTC_YEAR (*(unsigned char *)(Q40_RTC_BASE+0)) -#define RTC_MNTH (*(unsigned char *)(Q40_RTC_BASE-4)) -#define RTC_DATE (*(unsigned char *)(Q40_RTC_BASE-8)) -#define RTC_DOW (*(unsigned char *)(Q40_RTC_BASE-12)) -#define RTC_HOUR (*(unsigned char *)(Q40_RTC_BASE-16)) -#define RTC_MINS (*(unsigned char *)(Q40_RTC_BASE-20)) -#define RTC_SECS (*(unsigned char *)(Q40_RTC_BASE-24)) -#define RTC_CTRL (*(unsigned char *)(Q40_RTC_BASE-28)) +#define Q40_RTC_BASE (0xff021ffc) +#define Q40_RTC_YEAR (*(volatile unsigned char *)(Q40_RTC_BASE+0)) +#define Q40_RTC_MNTH (*(volatile unsigned char *)(Q40_RTC_BASE-4)) +#define Q40_RTC_DATE (*(volatile unsigned char *)(Q40_RTC_BASE-8)) +#define Q40_RTC_DOW (*(volatile unsigned char *)(Q40_RTC_BASE-12)) +#define Q40_RTC_HOUR (*(volatile unsigned char *)(Q40_RTC_BASE-16)) +#define Q40_RTC_MINS (*(volatile unsigned char *)(Q40_RTC_BASE-20)) +#define Q40_RTC_SECS (*(volatile unsigned char *)(Q40_RTC_BASE-24)) +#define Q40_RTC_CTRL (*(volatile unsigned char *)(Q40_RTC_BASE-28)) /* some control bits */ -#define RTC_READ 64 /* prepare for reading */ -#define RTC_WRITE 128 +#define Q40_RTC_READ 64 /* prepare for reading */ +#define Q40_RTC_WRITE 128 +/* define some Q40 specific ints */ +#include "q40ints.h" /* misc defs */ #define DAC_LEFT ((unsigned char *)0xff008000) diff -Nru a/include/asm-m68k/raw_io.h b/include/asm-m68k/raw_io.h --- a/include/asm-m68k/raw_io.h Mon Nov 4 14:31:03 2002 +++ b/include/asm-m68k/raw_io.h Mon Nov 4 14:31:03 2002 @@ -11,6 +11,19 @@ #ifdef __KERNEL__ +/* Values for nocacheflag and cmode */ +#define IOMAP_FULL_CACHING 0 +#define IOMAP_NOCACHE_SER 1 +#define IOMAP_NOCACHE_NONSER 2 +#define IOMAP_WRITETHROUGH 3 + +extern void iounmap(void *addr); + +extern void *__ioremap(unsigned long physaddr, unsigned long size, + int cacheflag); +extern void __iounmap(void *addr, unsigned long size); + + /* ++roman: The assignments to temp. vars avoid that gcc sometimes generates * two accesses to memory, which may be undesirable for some devices. */ diff -Nru a/include/asm-m68k/rtc.h b/include/asm-m68k/rtc.h --- a/include/asm-m68k/rtc.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-m68k/rtc.h Mon Nov 4 14:31:01 2002 @@ -33,6 +33,36 @@ #define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */ #define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */ +static inline void get_rtc_time(struct rtc_time *time) +{ + /* + * Only the values that we read from the RTC are set. We leave + * tm_wday, tm_yday and tm_isdst untouched. Even though the + * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated + * by the RTC when initially set to a non-zero value. + */ + mach_hwclk(0, time); +} + +static inline int set_rtc_time(struct rtc_time *time) +{ + return mach_hwclk(1, time); +} + +static inline int get_rtc_pll(struct rtc_pll_info *pll) +{ + if (mach_get_rtc_pll) + return mach_get_rtc_pll(pll); + else + return -EINVAL; +} +static inline int set_rtc_pll(struct rtc_pll_info *pll) +{ + if (mach_set_rtc_pll) + return mach_set_rtc_pll(pll); + else + return -EINVAL; +} #endif /* __KERNEL__ */ diff -Nru a/include/asm-m68k/softirq.h b/include/asm-m68k/softirq.h --- a/include/asm-m68k/softirq.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-m68k/softirq.h Mon Nov 4 14:31:01 2002 @@ -6,14 +6,19 @@ */ #include +#include -#define cpu_bh_disable(cpu) do { local_bh_count(cpu)++; barrier(); } while (0) -#define cpu_bh_enable(cpu) do { barrier(); local_bh_count(cpu)--; } while (0) +#define local_bh_disable() \ + do { preempt_count() += SOFTIRQ_OFFSET; barrier(); } while (0) +#define __local_bh_enable() \ + do { barrier(); preempt_count() -= SOFTIRQ_OFFSET; } while (0) -#define local_bh_disable() cpu_bh_disable(smp_processor_id()) -#define local_bh_enable() cpu_bh_enable(smp_processor_id()) -#define __local_bh_enable() local_bh_enable() - -#define in_softirq() (local_bh_count(smp_processor_id()) != 0) +#define local_bh_enable() \ +do { \ + __local_bh_enable(); \ + if (unlikely(!in_interrupt() && softirq_pending(smp_processor_id()))) \ + do_softirq(); \ + preempt_check_resched(); \ +} while (0) #endif diff -Nru a/include/asm-m68k/sun3_pgalloc.h b/include/asm-m68k/sun3_pgalloc.h --- a/include/asm-m68k/sun3_pgalloc.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-m68k/sun3_pgalloc.h Mon Nov 4 14:31:01 2002 @@ -95,14 +95,4 @@ #define pgd_populate(mm, pmd, pte) BUG() - -/* Reserved PMEGs. */ -extern char sun3_reserved_pmeg[SUN3_PMEGS_NUM]; -extern unsigned long pmeg_vaddr[SUN3_PMEGS_NUM]; -extern unsigned char pmeg_alloc[SUN3_PMEGS_NUM]; -extern unsigned char pmeg_ctx[SUN3_PMEGS_NUM]; - - -#define check_pgt_cache() do { } while (0) - #endif /* SUN3_PGALLOC_H */ diff -Nru a/include/asm-m68k/sun3ints.h b/include/asm-m68k/sun3ints.h --- a/include/asm-m68k/sun3ints.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-m68k/sun3ints.h Mon Nov 4 14:31:02 2002 @@ -21,6 +21,8 @@ #include #include +#define SUN3_INT_VECS 192 + void sun3_enable_irq(unsigned int irq); void sun3_disable_irq(unsigned int irq); int sun3_request_irq(unsigned int irq, @@ -36,6 +38,12 @@ extern int show_sun3_interrupts(struct seq_file *, void *); extern void sun3_process_int(int, struct pt_regs *); extern volatile unsigned char* sun3_intreg; + +/* master list of VME vectors -- don't fuck with this */ +#define SUN3_VEC_FLOPPY 0x40 +#define SUN3_VEC_VMESCSI0 0x40 +#define SUN3_VEC_VMESCSI1 0x41 +#define SUN3_VEC_CG 0xA8 #endif /* SUN3INTS_H */ diff -Nru a/include/asm-m68k/sun3mmu.h b/include/asm-m68k/sun3mmu.h --- a/include/asm-m68k/sun3mmu.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-m68k/sun3mmu.h Mon Nov 4 14:31:01 2002 @@ -161,6 +161,10 @@ return; } +extern void *sun3_ioremap(unsigned long phys, unsigned long size, + unsigned long type); + +extern int sun3_map_test(unsigned long addr, char *val); #endif /* !__ASSEMBLY__ */ diff -Nru a/include/asm-m68k/sun3xflop.h b/include/asm-m68k/sun3xflop.h --- a/include/asm-m68k/sun3xflop.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-m68k/sun3xflop.h Mon Nov 4 14:31:02 2002 @@ -3,7 +3,7 @@ * Derived partially from asm-sparc/floppy.h, which is: * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * - * Sun3x version 2/4/2000 Sam Creasey (sammy@oh.verio.com) + * Sun3x version 2/4/2000 Sam Creasey (sammy@sammy.net) */ #ifndef __ASM_SUN3X_FLOPPY_H diff -Nru a/include/asm-m68k/system.h b/include/asm-m68k/system.h --- a/include/asm-m68k/system.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-m68k/system.h Mon Nov 4 14:31:02 2002 @@ -7,11 +7,6 @@ #include #include -#define prepare_arch_schedule(prev) do { } while(0) -#define finish_arch_schedule(prev) do { } while(0) -#define prepare_arch_switch(rq) do { } while(0) -#define finish_arch_switch(rq) spin_unlock_irq(&(rq)->lock) - /* * switch_to(n) should switch tasks to task ptr, first checking that * ptr isn't the current task, in which case it does nothing. This @@ -52,24 +47,25 @@ #define local_irq_enable() asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory") #else #include -#define local_irq_enable() ({ \ - if (MACH_IS_Q40 || !local_irq_count(smp_processor_id())) \ - asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory"); \ +#define local_irq_enable() ({ \ + if (MACH_IS_Q40 || !hardirq_count()) \ + asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory"); \ }) #endif #define local_irq_disable() asm volatile ("oriw #0x0700,%%sr": : : "memory") #define local_save_flags(x) asm volatile ("movew %%sr,%0":"=d" (x) : : "memory") #define local_irq_restore(x) asm volatile ("movew %0,%%sr": :"d" (x) : "memory") +static inline int irqs_disabled(void) +{ + unsigned long flags; + local_save_flags(flags); + return flags & ~ALLOWINT; +} + /* For spinlocks etc */ #define local_irq_save(x) ({ local_save_flags(x); local_irq_disable(); }) -#define cli() local_irq_disable() -#define sti() local_irq_enable() -#define save_flags(x) local_save_flags(x) -#define restore_flags(x) local_irq_restore(x) -#define save_and_cli(flags) do { save_flags(flags); cli(); } while(0) - /* * Force strict CPU ordering. * Not really required on m68k... @@ -95,33 +91,29 @@ #ifndef CONFIG_RMW_INSNS static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) { - unsigned long tmp, flags; + unsigned long flags, tmp; + + local_irq_save(flags); - save_flags(flags); - cli(); + switch (size) { + case 1: + tmp = *(u8 *)ptr; + *(u8 *)ptr = x; + break; + case 2: + tmp = *(u16 *)ptr; + *(u16 *)ptr = x; + break; + case 4: + tmp = *(u32 *)ptr; + *(u32 *)ptr = x; + break; + default: + BUG(); + } - switch (size) { - case 1: - __asm__ __volatile__ - ("moveb %2,%0\n\t" - "moveb %1,%2" - : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory"); - break; - case 2: - __asm__ __volatile__ - ("movew %2,%0\n\t" - "movew %1,%2" - : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory"); - break; - case 4: - __asm__ __volatile__ - ("movel %2,%0\n\t" - "movel %1,%2" - : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory"); - break; - } - restore_flags(flags); - return tmp; + local_irq_restore(flags); + return tmp; } #else static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) diff -Nru a/include/asm-m68k/thread_info.h b/include/asm-m68k/thread_info.h --- a/include/asm-m68k/thread_info.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-m68k/thread_info.h Mon Nov 4 14:31:02 2002 @@ -18,8 +18,8 @@ #define INIT_THREAD_INFO(tsk) \ { \ - task: &tsk, \ - exec_domain: &default_exec_domain, \ + .task = &tsk, \ + .exec_domain = &default_exec_domain, \ } /* THREAD_SIZE should be 8k, so handle differently for 4k and 8k machines */ @@ -60,6 +60,9 @@ case TIF_NEED_RESCHED: \ tsk->thread.work.need_resched = val; \ break; \ + case TIF_SYSCALL_TRACE: \ + tsk->thread.work.syscall_trace = val; \ + break; \ default: \ thread_flag_fixme(); \ } \ @@ -73,6 +76,9 @@ break; \ case TIF_NEED_RESCHED: \ ___res = tsk->thread.work.need_resched; \ + break; \ + case TIF_SYSCALL_TRACE: \ + ___res = tsk->thread.work.syscall_trace;\ break; \ default: \ ___res = thread_flag_fixme(); \ diff -Nru a/include/asm-m68k/virtconvert.h b/include/asm-m68k/virtconvert.h --- a/include/asm-m68k/virtconvert.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-m68k/virtconvert.h Mon Nov 4 14:31:02 2002 @@ -20,7 +20,6 @@ */ #ifndef CONFIG_SUN3 extern unsigned long mm_vtop(unsigned long addr) __attribute__ ((const)); -extern unsigned long mm_vtop_fallback (unsigned long) __attribute__ ((const)); extern unsigned long mm_ptov(unsigned long addr) __attribute__ ((const)); #else extern inline unsigned long mm_vtop(unsigned long vaddr) @@ -35,39 +34,22 @@ #endif #ifdef CONFIG_SINGLE_MEMORY_CHUNK -extern inline unsigned long virt_to_phys(volatile void *vaddr) +static inline unsigned long virt_to_phys(void *vaddr) { - unsigned long voff = (unsigned long)vaddr - PAGE_OFFSET; - - if (voff < m68k_memory[0].size) - return voff + m68k_memory[0].addr; - return mm_vtop_fallback((unsigned long)vaddr); + return (unsigned long)vaddr - PAGE_OFFSET + m68k_memory[0].addr; } -extern inline void * phys_to_virt(unsigned long paddr) +static inline void * phys_to_virt(unsigned long paddr) { - unsigned long poff = paddr - m68k_memory[0].addr; - - if (poff < m68k_memory[0].size) - return (void *)(poff + PAGE_OFFSET); - -#ifdef CONFIG_AMIGA - /* - * if on an amiga and address is in first 16M, move it - * to the ZTWO_VADDR range - */ - if (MACH_IS_AMIGA && paddr < 16*1024*1024) - return (void *)ZTWO_VADDR(paddr); -#endif - return (void *)paddr; + return (void *)(paddr - m68k_memory[0].addr + PAGE_OFFSET); } #else -extern inline unsigned long virt_to_phys(volatile void * address) +static inline unsigned long virt_to_phys(void *address) { return mm_vtop((unsigned long)address); } -extern inline void * phys_to_virt(unsigned long address) +static inline void *phys_to_virt(unsigned long address) { return (void *) mm_ptov(address); } diff -Nru a/include/asm-m68k/zorro.h b/include/asm-m68k/zorro.h --- a/include/asm-m68k/zorro.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-m68k/zorro.h Mon Nov 4 14:31:01 2002 @@ -1,7 +1,7 @@ #ifndef _ASM_M68K_ZORRO_H #define _ASM_M68K_ZORRO_H -#include +#include #define z_readb raw_inb #define z_readw raw_inw diff -Nru a/include/asm-m68knommu/MC68328.h b/include/asm-m68knommu/MC68328.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/MC68328.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,1266 @@ + +/* include/asm-m68knommu/MC68328.h: '328 control registers + * + * Copyright (C) 1999 Vladimir Gurevich + * Bear & Hare Software, Inc. + * + * Based on include/asm-m68knommu/MC68332.h + * Copyright (C) 1998 Kenneth Albanowski , + * + */ + +#ifndef _MC68328_H_ +#define _MC68328_H_ + +#define BYTE_REF(addr) (*((volatile unsigned char*)addr)) +#define WORD_REF(addr) (*((volatile unsigned short*)addr)) +#define LONG_REF(addr) (*((volatile unsigned long*)addr)) + +#define PUT_FIELD(field, val) (((val) << field##_SHIFT) & field##_MASK) +#define GET_FIELD(reg, field) (((reg) & field##_MASK) >> field##_SHIFT) + +/********** + * + * 0xFFFFF0xx -- System Control + * + **********/ + +/* + * System Control Register (SCR) + */ +#define SCR_ADDR 0xfffff000 +#define SCR BYTE_REF(SCR_ADDR) + +#define SCR_WDTH8 0x01 /* 8-Bit Width Select */ +#define SCR_DMAP 0x04 /* Double Map */ +#define SCR_SO 0x08 /* Supervisor Only */ +#define SCR_BETEN 0x10 /* Bus-Error Time-Out Enable */ +#define SCR_PRV 0x20 /* Privilege Violation */ +#define SCR_WPV 0x40 /* Write Protect Violation */ +#define SCR_BETO 0x80 /* Bus-Error TimeOut */ + +/* + * Mask Revision Register + */ +#define MRR_ADDR 0xfffff004 +#define MRR LONG_REF(MRR_ADDR) + +/********** + * + * 0xFFFFF1xx -- Chip-Select logic + * + **********/ + +/********** + * + * 0xFFFFF2xx -- Phase Locked Loop (PLL) & Power Control + * + **********/ + +/* + * Group Base Address Registers + */ +#define GRPBASEA_ADDR 0xfffff100 +#define GRPBASEB_ADDR 0xfffff102 +#define GRPBASEC_ADDR 0xfffff104 +#define GRPBASED_ADDR 0xfffff106 + +#define GRPBASEA WORD_REF(GRPBASEA_ADDR) +#define GRPBASEB WORD_REF(GRPBASEB_ADDR) +#define GRPBASEC WORD_REF(GRPBASEC_ADDR) +#define GRPBASED WORD_REF(GRPBASED_ADDR) + +#define GRPBASE_V 0x0001 /* Valid */ +#define GRPBASE_GBA_MASK 0xfff0 /* Group Base Address (bits 31-20) */ + +/* + * Group Base Address Mask Registers + */ +#define GRPMASKA_ADDR 0xfffff108 +#define GRPMASKB_ADDR 0xfffff10a +#define GRPMASKC_ADDR 0xfffff10c +#define GRPMASKD_ADDR 0xfffff10e + +#define GRPMASKA WORD_REF(GRPMASKA_ADDR) +#define GRPMASKB WORD_REF(GRPMASKB_ADDR) +#define GRPMASKC WORD_REF(GRPMASKC_ADDR) +#define GRPMASKD WORD_REF(GRPMASKD_ADDR) + +#define GRMMASK_GMA_MASK 0xfffff0 /* Group Base Mask (bits 31-20) */ + +/* + * Chip-Select Option Registers (group A) + */ +#define CSA0_ADDR 0xfffff110 +#define CSA1_ADDR 0xfffff114 +#define CSA2_ADDR 0xfffff118 +#define CSA3_ADDR 0xfffff11c + +#define CSA0 LONG_REF(CSA0_ADDR) +#define CSA1 LONG_REF(CSA1_ADDR) +#define CSA2 LONG_REF(CSA2_ADDR) +#define CSA3 LONG_REF(CSA3_ADDR) + +#define CSA_WAIT_MASK 0x00000007 /* Wait State Selection */ +#define CSA_WAIT_SHIFT 0 +#define CSA_RO 0x00000008 /* Read-Only */ +#define CSA_AM_MASK 0x0000ff00 /* Address Mask (bits 23-16) */ +#define CSA_AM_SHIFT 8 +#define CSA_BUSW 0x00010000 /* Bus Width Select */ +#define CSA_AC_MASK 0xff000000 /* Address Compare (bits 23-16) */ +#define CSA_AC_SHIFT 24 + +/* + * Chip-Select Option Registers (group B) + */ +#define CSB0_ADDR 0xfffff120 +#define CSB1_ADDR 0xfffff124 +#define CSB2_ADDR 0xfffff128 +#define CSB3_ADDR 0xfffff12c + +#define CSB0 LONG_REF(CSB0_ADDR) +#define CSB1 LONG_REF(CSB1_ADDR) +#define CSB2 LONG_REF(CSB2_ADDR) +#define CSB3 LONG_REF(CSB3_ADDR) + +#define CSB_WAIT_MASK 0x00000007 /* Wait State Selection */ +#define CSB_WAIT_SHIFT 0 +#define CSB_RO 0x00000008 /* Read-Only */ +#define CSB_AM_MASK 0x0000ff00 /* Address Mask (bits 23-16) */ +#define CSB_AM_SHIFT 8 +#define CSB_BUSW 0x00010000 /* Bus Width Select */ +#define CSB_AC_MASK 0xff000000 /* Address Compare (bits 23-16) */ +#define CSB_AC_SHIFT 24 + +/* + * Chip-Select Option Registers (group C) + */ +#define CSC0_ADDR 0xfffff130 +#define CSC1_ADDR 0xfffff134 +#define CSC2_ADDR 0xfffff138 +#define CSC3_ADDR 0xfffff13c + +#define CSC0 LONG_REF(CSC0_ADDR) +#define CSC1 LONG_REF(CSC1_ADDR) +#define CSC2 LONG_REF(CSC2_ADDR) +#define CSC3 LONG_REF(CSC3_ADDR) + +#define CSC_WAIT_MASK 0x00000007 /* Wait State Selection */ +#define CSC_WAIT_SHIFT 0 +#define CSC_RO 0x00000008 /* Read-Only */ +#define CSC_AM_MASK 0x0000fff0 /* Address Mask (bits 23-12) */ +#define CSC_AM_SHIFT 4 +#define CSC_BUSW 0x00010000 /* Bus Width Select */ +#define CSC_AC_MASK 0xfff00000 /* Address Compare (bits 23-12) */ +#define CSC_AC_SHIFT 20 + +/* + * Chip-Select Option Registers (group D) + */ +#define CSD0_ADDR 0xfffff140 +#define CSD1_ADDR 0xfffff144 +#define CSD2_ADDR 0xfffff148 +#define CSD3_ADDR 0xfffff14c + +#define CSD0 LONG_REF(CSD0_ADDR) +#define CSD1 LONG_REF(CSD1_ADDR) +#define CSD2 LONG_REF(CSD2_ADDR) +#define CSD3 LONG_REF(CSD3_ADDR) + +#define CSD_WAIT_MASK 0x00000007 /* Wait State Selection */ +#define CSD_WAIT_SHIFT 0 +#define CSD_RO 0x00000008 /* Read-Only */ +#define CSD_AM_MASK 0x0000fff0 /* Address Mask (bits 23-12) */ +#define CSD_AM_SHIFT 4 +#define CSD_BUSW 0x00010000 /* Bus Width Select */ +#define CSD_AC_MASK 0xfff00000 /* Address Compare (bits 23-12) */ +#define CSD_AC_SHIFT 20 + +/********** + * + * 0xFFFFF2xx -- Phase Locked Loop (PLL) & Power Control + * + **********/ + +/* + * PLL Control Register + */ +#define PLLCR_ADDR 0xfffff200 +#define PLLCR WORD_REF(PLLCR_ADDR) + +#define PLLCR_DISPLL 0x0008 /* Disable PLL */ +#define PLLCR_CLKEN 0x0010 /* Clock (CLKO pin) enable */ +#define PLLCR_SYSCLK_SEL_MASK 0x0700 /* System Clock Selection */ +#define PLLCR_SYSCLK_SEL_SHIFT 8 +#define PLLCR_PIXCLK_SEL_MASK 0x3800 /* LCD Clock Selection */ +#define PLLCR_PIXCLK_SEL_SHIFT 11 + +/* 'EZ328-compatible definitions */ +#define PLLCR_LCDCLK_SEL_MASK PLLCR_PIXCLK_SEL_MASK +#define PLLCR_LCDCLK_SEL_SHIFT PLLCR_PIXCLK_SEL_SHIFT + +/* + * PLL Frequency Select Register + */ +#define PLLFSR_ADDR 0xfffff202 +#define PLLFSR WORD_REF(PLLFSR_ADDR) + +#define PLLFSR_PC_MASK 0x00ff /* P Count */ +#define PLLFSR_PC_SHIFT 0 +#define PLLFSR_QC_MASK 0x0f00 /* Q Count */ +#define PLLFSR_QC_SHIFT 8 +#define PLLFSR_PROT 0x4000 /* Protect P & Q */ +#define PLLFSR_CLK32 0x8000 /* Clock 32 (kHz) */ + +/* + * Power Control Register + */ +#define PCTRL_ADDR 0xfffff207 +#define PCTRL BYTE_REF(PCTRL_ADDR) + +#define PCTRL_WIDTH_MASK 0x1f /* CPU Clock bursts width */ +#define PCTRL_WIDTH_SHIFT 0 +#define PCTRL_STOP 0x40 /* Enter power-save mode immediately */ +#define PCTRL_PCEN 0x80 /* Power Control Enable */ + +/********** + * + * 0xFFFFF3xx -- Interrupt Controller + * + **********/ + +/* + * Interrupt Vector Register + */ +#define IVR_ADDR 0xfffff300 +#define IVR BYTE_REF(IVR_ADDR) + +#define IVR_VECTOR_MASK 0xF8 + +/* + * Interrupt control Register + */ +#define ICR_ADRR 0xfffff302 +#define ICR WORD_REF(ICR_ADDR) + +#define ICR_ET6 0x0100 /* Edge Trigger Select for IRQ6 */ +#define ICR_ET3 0x0200 /* Edge Trigger Select for IRQ3 */ +#define ICR_ET2 0x0400 /* Edge Trigger Select for IRQ2 */ +#define ICR_ET1 0x0800 /* Edge Trigger Select for IRQ1 */ +#define ICR_POL6 0x1000 /* Polarity Control for IRQ6 */ +#define ICR_POL3 0x2000 /* Polarity Control for IRQ3 */ +#define ICR_POL2 0x4000 /* Polarity Control for IRQ2 */ +#define ICR_POL1 0x8000 /* Polarity Control for IRQ1 */ + +/* + * Interrupt Mask Register + */ +#define IMR_ADDR 0xfffff304 +#define IMR LONG_REF(IMR_ADDR) + +/* + * Define the names for bit positions first. This is useful for + * request_irq + */ +#define SPIM_IRQ_NUM 0 /* SPI Master interrupt */ +#define TMR2_IRQ_NUM 1 /* Timer 2 interrupt */ +#define UART_IRQ_NUM 2 /* UART interrupt */ +#define WDT_IRQ_NUM 3 /* Watchdog Timer interrupt */ +#define RTC_IRQ_NUM 4 /* RTC interrupt */ +#define KB_IRQ_NUM 6 /* Keyboard Interrupt */ +#define PWM_IRQ_NUM 7 /* Pulse-Width Modulator int. */ +#define INT0_IRQ_NUM 8 /* External INT0 */ +#define INT1_IRQ_NUM 9 /* External INT1 */ +#define INT2_IRQ_NUM 10 /* External INT2 */ +#define INT3_IRQ_NUM 11 /* External INT3 */ +#define INT4_IRQ_NUM 12 /* External INT4 */ +#define INT5_IRQ_NUM 13 /* External INT5 */ +#define INT6_IRQ_NUM 14 /* External INT6 */ +#define INT7_IRQ_NUM 15 /* External INT7 */ +#define IRQ1_IRQ_NUM 16 /* IRQ1 */ +#define IRQ2_IRQ_NUM 17 /* IRQ2 */ +#define IRQ3_IRQ_NUM 18 /* IRQ3 */ +#define IRQ6_IRQ_NUM 19 /* IRQ6 */ +#define PEN_IRQ_NUM 20 /* Pen Interrupt */ +#define SPIS_IRQ_NUM 21 /* SPI Slave Interrupt */ +#define TMR1_IRQ_NUM 22 /* Timer 1 interrupt */ +#define IRQ7_IRQ_NUM 23 /* IRQ7 */ + +/* '328-compatible definitions */ +#define SPI_IRQ_NUM SPIM_IRQ_NUM +#define TMR_IRQ_NUM TMR1_IRQ_NUM + +/* + * Here go the bitmasks themselves + */ +#define IMR_MSPIM (1 << SPIM _IRQ_NUM) /* Mask SPI Master interrupt */ +#define IMR_MTMR2 (1 << TMR2_IRQ_NUM) /* Mask Timer 2 interrupt */ +#define IMR_MUART (1 << UART_IRQ_NUM) /* Mask UART interrupt */ +#define IMR_MWDT (1 << WDT_IRQ_NUM) /* Mask Watchdog Timer interrupt */ +#define IMR_MRTC (1 << RTC_IRQ_NUM) /* Mask RTC interrupt */ +#define IMR_MKB (1 << KB_IRQ_NUM) /* Mask Keyboard Interrupt */ +#define IMR_MPWM (1 << PWM_IRQ_NUM) /* Mask Pulse-Width Modulator int. */ +#define IMR_MINT0 (1 << INT0_IRQ_NUM) /* Mask External INT0 */ +#define IMR_MINT1 (1 << INT1_IRQ_NUM) /* Mask External INT1 */ +#define IMR_MINT2 (1 << INT2_IRQ_NUM) /* Mask External INT2 */ +#define IMR_MINT3 (1 << INT3_IRQ_NUM) /* Mask External INT3 */ +#define IMR_MINT4 (1 << INT4_IRQ_NUM) /* Mask External INT4 */ +#define IMR_MINT5 (1 << INT5_IRQ_NUM) /* Mask External INT5 */ +#define IMR_MINT6 (1 << INT6_IRQ_NUM) /* Mask External INT6 */ +#define IMR_MINT7 (1 << INT7_IRQ_NUM) /* Mask External INT7 */ +#define IMR_MIRQ1 (1 << IRQ1_IRQ_NUM) /* Mask IRQ1 */ +#define IMR_MIRQ2 (1 << IRQ2_IRQ_NUM) /* Mask IRQ2 */ +#define IMR_MIRQ3 (1 << IRQ3_IRQ_NUM) /* Mask IRQ3 */ +#define IMR_MIRQ6 (1 << IRQ6_IRQ_NUM) /* Mask IRQ6 */ +#define IMR_MPEN (1 << PEN_IRQ_NUM) /* Mask Pen Interrupt */ +#define IMR_MSPIS (1 << SPIS_IRQ_NUM) /* Mask SPI Slave Interrupt */ +#define IMR_MTMR1 (1 << TMR1_IRQ_NUM) /* Mask Timer 1 interrupt */ +#define IMR_MIRQ7 (1 << IRQ7_IRQ_NUM) /* Mask IRQ7 */ + +/* 'EZ328-compatible definitions */ +#define IMR_MSPI IMR_MSPIM +#define IMR_MTMR IMR_MTMR1 + +/* + * Interrupt Wake-Up Enable Register + */ +#define IWR_ADDR 0xfffff308 +#define IWR LONG_REF(IWR_ADDR) + +#define IWR_SPIM (1 << SPIM _IRQ_NUM) /* SPI Master interrupt */ +#define IWR_TMR2 (1 << TMR2_IRQ_NUM) /* Timer 2 interrupt */ +#define IWR_UART (1 << UART_IRQ_NUM) /* UART interrupt */ +#define IWR_WDT (1 << WDT_IRQ_NUM) /* Watchdog Timer interrupt */ +#define IWR_RTC (1 << RTC_IRQ_NUM) /* RTC interrupt */ +#define IWR_KB (1 << KB_IRQ_NUM) /* Keyboard Interrupt */ +#define IWR_PWM (1 << PWM_IRQ_NUM) /* Pulse-Width Modulator int. */ +#define IWR_INT0 (1 << INT0_IRQ_NUM) /* External INT0 */ +#define IWR_INT1 (1 << INT1_IRQ_NUM) /* External INT1 */ +#define IWR_INT2 (1 << INT2_IRQ_NUM) /* External INT2 */ +#define IWR_INT3 (1 << INT3_IRQ_NUM) /* External INT3 */ +#define IWR_INT4 (1 << INT4_IRQ_NUM) /* External INT4 */ +#define IWR_INT5 (1 << INT5_IRQ_NUM) /* External INT5 */ +#define IWR_INT6 (1 << INT6_IRQ_NUM) /* External INT6 */ +#define IWR_INT7 (1 << INT7_IRQ_NUM) /* External INT7 */ +#define IWR_IRQ1 (1 << IRQ1_IRQ_NUM) /* IRQ1 */ +#define IWR_IRQ2 (1 << IRQ2_IRQ_NUM) /* IRQ2 */ +#define IWR_IRQ3 (1 << IRQ3_IRQ_NUM) /* IRQ3 */ +#define IWR_IRQ6 (1 << IRQ6_IRQ_NUM) /* IRQ6 */ +#define IWR_PEN (1 << PEN_IRQ_NUM) /* Pen Interrupt */ +#define IWR_SPIS (1 << SPIS_IRQ_NUM) /* SPI Slave Interrupt */ +#define IWR_TMR1 (1 << TMR1_IRQ_NUM) /* Timer 1 interrupt */ +#define IWR_IRQ7 (1 << IRQ7_IRQ_NUM) /* IRQ7 */ + +/* + * Interrupt Status Register + */ +#define ISR_ADDR 0xfffff30c +#define ISR LONG_REF(ISR_ADDR) + +#define ISR_SPIM (1 << SPIM _IRQ_NUM) /* SPI Master interrupt */ +#define ISR_TMR2 (1 << TMR2_IRQ_NUM) /* Timer 2 interrupt */ +#define ISR_UART (1 << UART_IRQ_NUM) /* UART interrupt */ +#define ISR_WDT (1 << WDT_IRQ_NUM) /* Watchdog Timer interrupt */ +#define ISR_RTC (1 << RTC_IRQ_NUM) /* RTC interrupt */ +#define ISR_KB (1 << KB_IRQ_NUM) /* Keyboard Interrupt */ +#define ISR_PWM (1 << PWM_IRQ_NUM) /* Pulse-Width Modulator int. */ +#define ISR_INT0 (1 << INT0_IRQ_NUM) /* External INT0 */ +#define ISR_INT1 (1 << INT1_IRQ_NUM) /* External INT1 */ +#define ISR_INT2 (1 << INT2_IRQ_NUM) /* External INT2 */ +#define ISR_INT3 (1 << INT3_IRQ_NUM) /* External INT3 */ +#define ISR_INT4 (1 << INT4_IRQ_NUM) /* External INT4 */ +#define ISR_INT5 (1 << INT5_IRQ_NUM) /* External INT5 */ +#define ISR_INT6 (1 << INT6_IRQ_NUM) /* External INT6 */ +#define ISR_INT7 (1 << INT7_IRQ_NUM) /* External INT7 */ +#define ISR_IRQ1 (1 << IRQ1_IRQ_NUM) /* IRQ1 */ +#define ISR_IRQ2 (1 << IRQ2_IRQ_NUM) /* IRQ2 */ +#define ISR_IRQ3 (1 << IRQ3_IRQ_NUM) /* IRQ3 */ +#define ISR_IRQ6 (1 << IRQ6_IRQ_NUM) /* IRQ6 */ +#define ISR_PEN (1 << PEN_IRQ_NUM) /* Pen Interrupt */ +#define ISR_SPIS (1 << SPIS_IRQ_NUM) /* SPI Slave Interrupt */ +#define ISR_TMR1 (1 << TMR1_IRQ_NUM) /* Timer 1 interrupt */ +#define ISR_IRQ7 (1 << IRQ7_IRQ_NUM) /* IRQ7 */ + +/* 'EZ328-compatible definitions */ +#define ISR_SPI ISR_SPIM +#define ISR_TMR ISR_TMR1 + +/* + * Interrupt Pending Register + */ +#define IPR_ADDR 0xfffff310 +#define IPR LONG_REF(IPR_ADDR) + +#define IPR_SPIM (1 << SPIM _IRQ_NUM) /* SPI Master interrupt */ +#define IPR_TMR2 (1 << TMR2_IRQ_NUM) /* Timer 2 interrupt */ +#define IPR_UART (1 << UART_IRQ_NUM) /* UART interrupt */ +#define IPR_WDT (1 << WDT_IRQ_NUM) /* Watchdog Timer interrupt */ +#define IPR_RTC (1 << RTC_IRQ_NUM) /* RTC interrupt */ +#define IPR_KB (1 << KB_IRQ_NUM) /* Keyboard Interrupt */ +#define IPR_PWM (1 << PWM_IRQ_NUM) /* Pulse-Width Modulator int. */ +#define IPR_INT0 (1 << INT0_IRQ_NUM) /* External INT0 */ +#define IPR_INT1 (1 << INT1_IRQ_NUM) /* External INT1 */ +#define IPR_INT2 (1 << INT2_IRQ_NUM) /* External INT2 */ +#define IPR_INT3 (1 << INT3_IRQ_NUM) /* External INT3 */ +#define IPR_INT4 (1 << INT4_IRQ_NUM) /* External INT4 */ +#define IPR_INT5 (1 << INT5_IRQ_NUM) /* External INT5 */ +#define IPR_INT6 (1 << INT6_IRQ_NUM) /* External INT6 */ +#define IPR_INT7 (1 << INT7_IRQ_NUM) /* External INT7 */ +#define IPR_IRQ1 (1 << IRQ1_IRQ_NUM) /* IRQ1 */ +#define IPR_IRQ2 (1 << IRQ2_IRQ_NUM) /* IRQ2 */ +#define IPR_IRQ3 (1 << IRQ3_IRQ_NUM) /* IRQ3 */ +#define IPR_IRQ6 (1 << IRQ6_IRQ_NUM) /* IRQ6 */ +#define IPR_PEN (1 << PEN_IRQ_NUM) /* Pen Interrupt */ +#define IPR_SPIS (1 << SPIS_IRQ_NUM) /* SPI Slave Interrupt */ +#define IPR_TMR1 (1 << TMR1_IRQ_NUM) /* Timer 1 interrupt */ +#define IPR_IRQ7 (1 << IRQ7_IRQ_NUM) /* IRQ7 */ + +/* 'EZ328-compatible definitions */ +#define IPR_SPI IPR_SPIM +#define IPR_TMR IPR_TMR1 + +/********** + * + * 0xFFFFF4xx -- Parallel Ports + * + **********/ + +/* + * Port A + */ +#define PADIR_ADDR 0xfffff400 /* Port A direction reg */ +#define PADATA_ADDR 0xfffff401 /* Port A data register */ +#define PASEL_ADDR 0xfffff403 /* Port A Select register */ + +#define PADIR BYTE_REF(PADIR_ADDR) +#define PADATA BYTE_REF(PADATA_ADDR) +#define PASEL BYTE_REF(PASEL_ADDR) + +#define PA(x) (1 << (x)) +#define PA_A(x) PA((x) - 16) /* This is specific to PA only! */ + +#define PA_A16 PA(0) /* Use A16 as PA(0) */ +#define PA_A17 PA(1) /* Use A17 as PA(1) */ +#define PA_A18 PA(2) /* Use A18 as PA(2) */ +#define PA_A19 PA(3) /* Use A19 as PA(3) */ +#define PA_A20 PA(4) /* Use A20 as PA(4) */ +#define PA_A21 PA(5) /* Use A21 as PA(5) */ +#define PA_A22 PA(6) /* Use A22 as PA(6) */ +#define PA_A23 PA(7) /* Use A23 as PA(7) */ + +/* + * Port B + */ +#define PBDIR_ADDR 0xfffff408 /* Port B direction reg */ +#define PBDATA_ADDR 0xfffff409 /* Port B data register */ +#define PBSEL_ADDR 0xfffff40b /* Port B Select Register */ + +#define PBDIR BYTE_REF(PBDIR_ADDR) +#define PBDATA BYTE_REF(PBDATA_ADDR) +#define PBSEL BYTE_REF(PBSEL_ADDR) + +#define PB(x) (1 << (x)) +#define PB_D(x) PB(x) /* This is specific to port B only */ + +#define PB_D0 PB(0) /* Use D0 as PB(0) */ +#define PB_D1 PB(1) /* Use D1 as PB(1) */ +#define PB_D2 PB(2) /* Use D2 as PB(2) */ +#define PB_D3 PB(3) /* Use D3 as PB(3) */ +#define PB_D4 PB(4) /* Use D4 as PB(4) */ +#define PB_D5 PB(5) /* Use D5 as PB(5) */ +#define PB_D6 PB(6) /* Use D6 as PB(6) */ +#define PB_D7 PB(7) /* Use D7 as PB(7) */ + +/* + * Port C + */ +#define PCDIR_ADDR 0xfffff410 /* Port C direction reg */ +#define PCDATA_ADDR 0xfffff411 /* Port C data register */ +#define PCSEL_ADDR 0xfffff413 /* Port C Select Register */ + +#define PCDIR BYTE_REF(PCDIR_ADDR) +#define PCDATA BYTE_REF(PCDATA_ADDR) +#define PCSEL BYTE_REF(PCSEL_ADDR) + +#define PC(x) (1 << (x)) + +#define PC_WE PC(6) /* Use WE as PC(6) */ +#define PC_DTACK PC(5) /* Use DTACK as PC(5) */ +#define PC_IRQ7 PC(4) /* Use IRQ7 as PC(4) */ +#define PC_LDS PC(2) /* Use LDS as PC(2) */ +#define PC_UDS PC(1) /* Use UDS as PC(1) */ +#define PC_MOCLK PC(0) /* Use MOCLK as PC(0) */ + +/* + * Port D + */ +#define PDDIR_ADDR 0xfffff418 /* Port D direction reg */ +#define PDDATA_ADDR 0xfffff419 /* Port D data register */ +#define PDPUEN_ADDR 0xfffff41a /* Port D Pull-Up enable reg */ +#define PDPOL_ADDR 0xfffff41c /* Port D Polarity Register */ +#define PDIRQEN_ADDR 0xfffff41d /* Port D IRQ enable register */ +#define PDIQEG_ADDR 0xfffff41f /* Port D IRQ Edge Register */ + +#define PDDIR BYTE_REF(PDDIR_ADDR) +#define PDDATA BYTE_REF(PDDATA_ADDR) +#define PDPUEN BYTE_REF(PDPUEN_ADDR) +#define PDPOL BYTE_REF(PDPOL_ADDR) +#define PDIRQEN BYTE_REF(PDIRQEN_ADDR) +#define PDIQEG BYTE_REF(PDIQEG_ADDR) + +#define PD(x) (1 << (x)) +#define PD_KB(x) PD(x) /* This is specific for Port D only */ + +#define PD_KB0 PD(0) /* Use KB0 as PD(0) */ +#define PD_KB1 PD(1) /* Use KB1 as PD(1) */ +#define PD_KB2 PD(2) /* Use KB2 as PD(2) */ +#define PD_KB3 PD(3) /* Use KB3 as PD(3) */ +#define PD_KB4 PD(4) /* Use KB4 as PD(4) */ +#define PD_KB5 PD(5) /* Use KB5 as PD(5) */ +#define PD_KB6 PD(6) /* Use KB6 as PD(6) */ +#define PD_KB7 PD(7) /* Use KB7 as PD(7) */ + +/* + * Port E + */ +#define PEDIR_ADDR 0xfffff420 /* Port E direction reg */ +#define PEDATA_ADDR 0xfffff421 /* Port E data register */ +#define PEPUEN_ADDR 0xfffff422 /* Port E Pull-Up enable reg */ +#define PESEL_ADDR 0xfffff423 /* Port E Select Register */ + +#define PEDIR BYTE_REF(PEDIR_ADDR) +#define PEDATA BYTE_REF(PEDATA_ADDR) +#define PEPUEN BYTE_REF(PEPUEN_ADDR) +#define PESEL BYTE_REF(PESEL_ADDR) + +#define PE(x) (1 << (x)) + +#define PE_CSA1 PE(1) /* Use CSA1 as PE(1) */ +#define PE_CSA2 PE(2) /* Use CSA2 as PE(2) */ +#define PE_CSA3 PE(3) /* Use CSA3 as PE(3) */ +#define PE_CSB0 PE(4) /* Use CSB0 as PE(4) */ +#define PE_CSB1 PE(5) /* Use CSB1 as PE(5) */ +#define PE_CSB2 PE(6) /* Use CSB2 as PE(6) */ +#define PE_CSB3 PE(7) /* Use CSB3 as PE(7) */ + +/* + * Port F + */ +#define PFDIR_ADDR 0xfffff428 /* Port F direction reg */ +#define PFDATA_ADDR 0xfffff429 /* Port F data register */ +#define PFPUEN_ADDR 0xfffff42a /* Port F Pull-Up enable reg */ +#define PFSEL_ADDR 0xfffff42b /* Port F Select Register */ + +#define PFDIR BYTE_REF(PFDIR_ADDR) +#define PFDATA BYTE_REF(PFDATA_ADDR) +#define PFPUEN BYTE_REF(PFPUEN_ADDR) +#define PFSEL BYTE_REF(PFSEL_ADDR) + +#define PF(x) (1 << (x)) +#define PF_A(x) PF((x) - 24) /* This is Port F specific only */ + +#define PF_A24 PF(0) /* Use A24 as PF(0) */ +#define PF_A25 PF(1) /* Use A25 as PF(1) */ +#define PF_A26 PF(2) /* Use A26 as PF(2) */ +#define PF_A27 PF(3) /* Use A27 as PF(3) */ +#define PF_A28 PF(4) /* Use A28 as PF(4) */ +#define PF_A29 PF(5) /* Use A29 as PF(5) */ +#define PF_A30 PF(6) /* Use A30 as PF(6) */ +#define PF_A31 PF(7) /* Use A31 as PF(7) */ + +/* + * Port G + */ +#define PGDIR_ADDR 0xfffff430 /* Port G direction reg */ +#define PGDATA_ADDR 0xfffff431 /* Port G data register */ +#define PGPUEN_ADDR 0xfffff432 /* Port G Pull-Up enable reg */ +#define PGSEL_ADDR 0xfffff433 /* Port G Select Register */ + +#define PGDIR BYTE_REF(PGDIR_ADDR) +#define PGDATA BYTE_REF(PGDATA_ADDR) +#define PGPUEN BYTE_REF(PGPUEN_ADDR) +#define PGSEL BYTE_REF(PGSEL_ADDR) + +#define PG(x) (1 << (x)) + +#define PG_UART_TXD PG(0) /* Use UART_TXD as PG(0) */ +#define PG_UART_RXD PG(1) /* Use UART_RXD as PG(1) */ +#define PG_PWMOUT PG(2) /* Use PWMOUT as PG(2) */ +#define PG_TOUT2 PG(3) /* Use TOUT2 as PG(3) */ +#define PG_TIN2 PG(4) /* Use TIN2 as PG(4) */ +#define PG_TOUT1 PG(5) /* Use TOUT1 as PG(5) */ +#define PG_TIN1 PG(6) /* Use TIN1 as PG(6) */ +#define PG_RTCOUT PG(7) /* Use RTCOUT as PG(7) */ + +/* + * Port J + */ +#define PJDIR_ADDR 0xfffff438 /* Port J direction reg */ +#define PJDATA_ADDR 0xfffff439 /* Port J data register */ +#define PJSEL_ADDR 0xfffff43b /* Port J Select Register */ + +#define PJDIR BYTE_REF(PJDIR_ADDR) +#define PJDATA BYTE_REF(PJDATA_ADDR) +#define PJSEL BYTE_REF(PJSEL_ADDR) + +#define PJ(x) (1 << (x)) + +#define PJ_CSD3 PJ(7) /* Use CSD3 as PJ(7) */ + +/* + * Port K + */ +#define PKDIR_ADDR 0xfffff440 /* Port K direction reg */ +#define PKDATA_ADDR 0xfffff441 /* Port K data register */ +#define PKPUEN_ADDR 0xfffff442 /* Port K Pull-Up enable reg */ +#define PKSEL_ADDR 0xfffff443 /* Port K Select Register */ + +#define PKDIR BYTE_REF(PKDIR_ADDR) +#define PKDATA BYTE_REF(PKDATA_ADDR) +#define PKPUEN BYTE_REF(PKPUEN_ADDR) +#define PKSEL BYTE_REF(PKSEL_ADDR) + +#define PK(x) (1 << (x)) + +/* + * Port M + */ +#define PMDIR_ADDR 0xfffff438 /* Port M direction reg */ +#define PMDATA_ADDR 0xfffff439 /* Port M data register */ +#define PMPUEN_ADDR 0xfffff43a /* Port M Pull-Up enable reg */ +#define PMSEL_ADDR 0xfffff43b /* Port M Select Register */ + +#define PMDIR BYTE_REF(PMDIR_ADDR) +#define PMDATA BYTE_REF(PMDATA_ADDR) +#define PMPUEN BYTE_REF(PMPUEN_ADDR) +#define PMSEL BYTE_REF(PMSEL_ADDR) + +#define PM(x) (1 << (x)) + +/********** + * + * 0xFFFFF5xx -- Pulse-Width Modulator (PWM) + * + **********/ + +/* + * PWM Control Register + */ +#define PWMC_ADDR 0xfffff500 +#define PWMC WORD_REF(PWMC_ADDR) + +#define PWMC_CLKSEL_MASK 0x0007 /* Clock Selection */ +#define PWMC_CLKSEL_SHIFT 0 +#define PWMC_PWMEN 0x0010 /* Enable PWM */ +#define PMNC_POL 0x0020 /* PWM Output Bit Polarity */ +#define PWMC_PIN 0x0080 /* Current PWM output pin status */ +#define PWMC_LOAD 0x0100 /* Force a new period */ +#define PWMC_IRQEN 0x4000 /* Interrupt Request Enable */ +#define PWMC_CLKSRC 0x8000 /* Clock Source Select */ + +/* 'EZ328-compatible definitions */ +#define PWMC_EN PWMC_PWMEN + +/* + * PWM Period Register + */ +#define PWMP_ADDR 0xfffff502 +#define PWMP WORD_REF(PWMP_ADDR) + +/* + * PWM Width Register + */ +#define PWMW_ADDR 0xfffff504 +#define PWMW WORD_REF(PWMW_ADDR) + +/* + * PWM Counter Register + */ +#define PWMCNT_ADDR 0xfffff506 +#define PWMCNT WORD_REF(PWMCNT_ADDR) + +/********** + * + * 0xFFFFF6xx -- General-Purpose Timers + * + **********/ + +/* + * Timer Unit 1 and 2 Control Registers + */ +#define TCTL1_ADDR 0xfffff600 +#define TCTL1 WORD_REF(TCTL1_ADDR) +#define TCTL2_ADDR 0xfffff60c +#define TCTL2 WORD_REF(TCTL2_ADDR) + +#define TCTL_TEN 0x0001 /* Timer Enable */ +#define TCTL_CLKSOURCE_MASK 0x000e /* Clock Source: */ +#define TCTL_CLKSOURCE_STOP 0x0000 /* Stop count (disabled) */ +#define TCTL_CLKSOURCE_SYSCLK 0x0002 /* SYSCLK to prescaler */ +#define TCTL_CLKSOURCE_SYSCLK_16 0x0004 /* SYSCLK/16 to prescaler */ +#define TCTL_CLKSOURCE_TIN 0x0006 /* TIN to prescaler */ +#define TCTL_CLKSOURCE_32KHZ 0x0008 /* 32kHz clock to prescaler */ +#define TCTL_IRQEN 0x0010 /* IRQ Enable */ +#define TCTL_OM 0x0020 /* Output Mode */ +#define TCTL_CAP_MASK 0x00c0 /* Capture Edge: */ +#define TCTL_CAP_RE 0x0040 /* Capture on rizing edge */ +#define TCTL_CAP_FE 0x0080 /* Capture on falling edge */ +#define TCTL_FRR 0x0010 /* Free-Run Mode */ + +/* 'EZ328-compatible definitions */ +#define TCTL_ADDR TCTL1_ADDR +#define TCTL TCTL1 + +/* + * Timer Unit 1 and 2 Prescaler Registers + */ +#define TPRER1_ADDR 0xfffff602 +#define TPRER1 WORD_REF(TPRER1_ADDR) +#define TPRER2_ADDR 0xfffff60e +#define TPRER2 WORD_REF(TPRER2_ADDR) + +/* 'EZ328-compatible definitions */ +#define TPRER_ADDR TPRER1_ADDR +#define TPRER TPRER1 + +/* + * Timer Unit 1 and 2 Compare Registers + */ +#define TCMP1_ADDR 0xfffff604 +#define TCMP1 WORD_REF(TCMP1_ADDR) +#define TCMP2_ADDR 0xfffff610 +#define TCMP2 WORD_REF(TCMP2_ADDR) + +/* 'EZ328-compatible definitions */ +#define TCMP_ADDR TCMP1_ADDR +#define TCMP TCMP1 + +/* + * Timer Unit 1 and 2 Capture Registers + */ +#define TCR1_ADDR 0xfffff606 +#define TCR1 WORD_REF(TCR1_ADDR) +#define TCR2_ADDR 0xfffff612 +#define TCR2 WORD_REF(TCR2_ADDR) + +/* 'EZ328-compatible definitions */ +#define TCR_ADDR TCR1_ADDR +#define TCR TCR1 + +/* + * Timer Unit 1 and 2 Counter Registers + */ +#define TCN1_ADDR 0xfffff608 +#define TCN1 WORD_REF(TCN1_ADDR) +#define TCN2_ADDR 0xfffff614 +#define TCN2 WORD_REF(TCN2_ADDR) + +/* 'EZ328-compatible definitions */ +#define TCN_ADDR TCN1_ADDR +#define TCN TCN + +/* + * Timer Unit 1 and 2 Status Registers + */ +#define TSTAT1_ADDR 0xfffff60a +#define TSTAT1 WORD_REF(TSTAT1_ADDR) +#define TSTAT2_ADDR 0xfffff616 +#define TSTAT2 WORD_REF(TSTAT2_ADDR) + +#define TSTAT_COMP 0x0001 /* Compare Event occurred */ +#define TSTAT_CAPT 0x0001 /* Capture Event occurred */ + +/* 'EZ328-compatible definitions */ +#define TSTAT_ADDR TSTAT1_ADDR +#define TSTAT TSTAT1 + +/* + * Watchdog Compare Register + */ +#define WRR_ADDR 0xfffff61a +#define WRR WORD_REF(WRR_ADDR) + +/* + * Watchdog Counter Register + */ +#define WCN_ADDR 0xfffff61c +#define WCN WORD_REF(WCN_ADDR) + +/* + * Watchdog Control and Status Register + */ +#define WCSR_ADDR 0xfffff618 +#define WCSR WORD_REF(WCSR_ADDR) + +#define WCSR_WDEN 0x0001 /* Watchdog Enable */ +#define WCSR_FI 0x0002 /* Forced Interrupt (instead of SW reset)*/ +#define WCSR_WRST 0x0004 /* Watchdog Reset */ + +/********** + * + * 0xFFFFF7xx -- Serial Periferial Interface Slave (SPIS) + * + **********/ + +/* + * SPI Slave Register + */ +#define SPISR_ADDR 0xfffff700 +#define SPISR WORD_REF(SPISR_ADDR) + +#define SPISR_DATA_ADDR 0xfffff701 +#define SPISR_DATA BYTE_REF(SPISR_DATA_ADDR) + +#define SPISR_DATA_MASK 0x00ff /* Shifted data from the external device */ +#define SPISR_DATA_SHIFT 0 +#define SPISR_SPISEN 0x0100 /* SPIS module enable */ +#define SPISR_POL 0x0200 /* SPSCLK polarity control */ +#define SPISR_PHA 0x0400 /* Phase relationship between SPSCLK & SPSRxD */ +#define SPISR_OVWR 0x0800 /* Data buffer has been overwritten */ +#define SPISR_DATARDY 0x1000 /* Data ready */ +#define SPISR_ENPOL 0x2000 /* Enable Polarity */ +#define SPISR_IRQEN 0x4000 /* SPIS IRQ Enable */ +#define SPISR_SPISIRQ 0x8000 /* SPIS IRQ posted */ + +/********** + * + * 0xFFFFF8xx -- Serial Periferial Interface Master (SPIM) + * + **********/ + +/* + * SPIM Data Register + */ +#define SPIMDATA_ADDR 0xfffff800 +#define SPIMDATA WORD_REF(SPIMDATA_ADDR) + +/* + * SPIM Control/Status Register + */ +#define SPIMCONT_ADDR 0xfffff802 +#define SPIMCONT WORD_REF(SPIMCONT_ADDR) + +#define SPIMCONT_BIT_COUNT_MASK 0x000f /* Transfer Length in Bytes */ +#define SPIMCONT_BIT_COUNT_SHIFT 0 +#define SPIMCONT_POL 0x0010 /* SPMCLK Signel Polarity */ +#define SPIMCONT_PHA 0x0020 /* Clock/Data phase relationship */ +#define SPIMCONT_IRQEN 0x0040 /* IRQ Enable */ +#define SPIMCONT_SPIMIRQ 0x0080 /* Interrupt Request */ +#define SPIMCONT_XCH 0x0100 /* Exchange */ +#define SPIMCONT_RSPIMEN 0x0200 /* Enable SPIM */ +#define SPIMCONT_DATA_RATE_MASK 0xe000 /* SPIM Data Rate */ +#define SPIMCONT_DATA_RATE_SHIFT 13 + +/* 'EZ328-compatible definitions */ +#define SPIMCONT_IRQ SPIMCONT_SPIMIRQ +#define SPIMCONT_ENABLE SPIMCONT_SPIMEN +/********** + * + * 0xFFFFF9xx -- UART + * + **********/ + +/* + * UART Status/Control Register + */ +#define USTCNT_ADDR 0xfffff900 +#define USTCNT WORD_REF(USTCNT_ADDR) + +#define USTCNT_TXAVAILEN 0x0001 /* Transmitter Available Int Enable */ +#define USTCNT_TXHALFEN 0x0002 /* Transmitter Half Empty Int Enable */ +#define USTCNT_TXEMPTYEN 0x0004 /* Transmitter Empty Int Enable */ +#define USTCNT_RXREADYEN 0x0008 /* Receiver Ready Interrupt Enable */ +#define USTCNT_RXHALFEN 0x0010 /* Receiver Half-Full Int Enable */ +#define USTCNT_RXFULLEN 0x0020 /* Receiver Full Interrupt Enable */ +#define USTCNT_CTSDELTAEN 0x0040 /* CTS Delta Interrupt Enable */ +#define USTCNT_GPIODELTAEN 0x0080 /* Old Data Interrupt Enable */ +#define USTCNT_8_7 0x0100 /* Eight or seven-bit transmission */ +#define USTCNT_STOP 0x0200 /* Stop bit transmission */ +#define USTCNT_ODD_EVEN 0x0400 /* Odd Parity */ +#define USTCNT_PARITYEN 0x0800 /* Parity Enable */ +#define USTCNT_CLKMODE 0x1000 /* Clock Mode Select */ +#define USTCNT_TXEN 0x2000 /* Transmitter Enable */ +#define USTCNT_RXEN 0x4000 /* Receiver Enable */ +#define USTCNT_UARTEN 0x8000 /* UART Enable */ + +/* 'EZ328-compatible definitions */ +#define USTCNT_TXAE USTCNT_TXAVAILEN +#define USTCNT_TXHE USTCNT_TXHALFEN +#define USTCNT_TXEE USTCNT_TXEMPTYEN +#define USTCNT_RXRE USTCNT_RXREADYEN +#define USTCNT_RXHE USTCNT_RXHALFEN +#define USTCNT_RXFE USTCNT_RXFULLEN +#define USTCNT_CTSD USTCNT_CTSDELTAEN +#define USTCNT_ODD USTCNT_ODD_EVEN +#define USTCNT_PEN USTCNT_PARITYEN +#define USTCNT_CLKM USTCNT_CLKMODE +#define USTCNT_UEN USTCNT_UARTEN + +/* + * UART Baud Control Register + */ +#define UBAUD_ADDR 0xfffff902 +#define UBAUD WORD_REF(UBAUD_ADDR) + +#define UBAUD_PRESCALER_MASK 0x003f /* Actual divisor is 65 - PRESCALER */ +#define UBAUD_PRESCALER_SHIFT 0 +#define UBAUD_DIVIDE_MASK 0x0700 /* Baud Rate freq. divizor */ +#define UBAUD_DIVIDE_SHIFT 8 +#define UBAUD_BAUD_SRC 0x0800 /* Baud Rate Source */ +#define UBAUD_GPIOSRC 0x1000 /* GPIO source */ +#define UBAUD_GPIODIR 0x2000 /* GPIO Direction */ +#define UBAUD_GPIO 0x4000 /* Current GPIO pin status */ +#define UBAUD_GPIODELTA 0x8000 /* GPIO pin value changed */ + +/* + * UART Receiver Register + */ +#define URX_ADDR 0xfffff904 +#define URX WORD_REF(URX_ADDR) + +#define URX_RXDATA_ADDR 0xfffff905 +#define URX_RXDATA BYTE_REF(URX_RXDATA_ADDR) + +#define URX_RXDATA_MASK 0x00ff /* Received data */ +#define URX_RXDATA_SHIFT 0 +#define URX_PARITY_ERROR 0x0100 /* Parity Error */ +#define URX_BREAK 0x0200 /* Break Detected */ +#define URX_FRAME_ERROR 0x0400 /* Framing Error */ +#define URX_OVRUN 0x0800 /* Serial Overrun */ +#define URX_DATA_READY 0x2000 /* Data Ready (FIFO not empty) */ +#define URX_FIFO_HALF 0x4000 /* FIFO is Half-Full */ +#define URX_FIFO_FULL 0x8000 /* FIFO is Full */ + +/* + * UART Transmitter Register + */ +#define UTX_ADDR 0xfffff906 +#define UTX WORD_REF(UTX_ADDR) + +#define UTX_TXDATA_ADDR 0xfffff907 +#define UTX_TXDATA BYTE_REF(UTX_TXDATA_ADDR) + +#define UTX_TXDATA_MASK 0x00ff /* Data to be transmitted */ +#define UTX_TXDATA_SHIFT 0 +#define UTX_CTS_DELTA 0x0100 /* CTS changed */ +#define UTX_CTS_STATUS 0x0200 /* CTS State */ +#define UTX_IGNORE_CTS 0x0800 /* Ignore CTS */ +#define UTX_SEND_BREAK 0x1000 /* Send a BREAK */ +#define UTX_TX_AVAIL 0x2000 /* Transmit FIFO has a slot available */ +#define UTX_FIFO_HALF 0x4000 /* Transmit FIFO is half empty */ +#define UTX_FIFO_EMPTY 0x8000 /* Transmit FIFO is empty */ + +/* 'EZ328-compatible definitions */ +#define UTX_CTS_STAT UTX_CTS_STATUS +#define UTX_NOCTS UTX_IGNORE_CTS + +/* + * UART Miscellaneous Register + */ +#define UMISC_ADDR 0xfffff908 +#define UMISC WORD_REF(UMISC_ADDR) + +#define UMISC_TX_POL 0x0004 /* Transmit Polarity */ +#define UMISC_RX_POL 0x0008 /* Receive Polarity */ +#define UMISC_IRDA_LOOP 0x0010 /* IrDA Loopback Enable */ +#define UMISC_IRDA_EN 0x0020 /* Infra-Red Enable */ +#define UMISC_RTS 0x0040 /* Set RTS status */ +#define UMISC_RTSCONT 0x0080 /* Choose RTS control */ +#define UMISC_LOOP 0x1000 /* Serial Loopback Enable */ +#define UMISC_FORCE_PERR 0x2000 /* Force Parity Error */ +#define UMISC_CLKSRC 0x4000 /* Clock Source */ + + +/* generalization of uart control registers to support multiple ports: */ +typedef volatile struct { + volatile unsigned short int ustcnt; + volatile unsigned short int ubaud; + union { + volatile unsigned short int w; + struct { + volatile unsigned char status; + volatile unsigned char rxdata; + } b; + } urx; + union { + volatile unsigned short int w; + struct { + volatile unsigned char status; + volatile unsigned char txdata; + } b; + } utx; + volatile unsigned short int umisc; + volatile unsigned short int pad1; + volatile unsigned short int pad2; + volatile unsigned short int pad3; +} m68328_uart __attribute__((packed)); + + +/********** + * + * 0xFFFFFAxx -- LCD Controller + * + **********/ + +/* + * LCD Screen Starting Address Register + */ +#define LSSA_ADDR 0xfffffa00 +#define LSSA LONG_REF(LSSA_ADDR) + +#define LSSA_SSA_MASK 0xfffffffe /* Bit 0 is reserved */ + +/* + * LCD Virtual Page Width Register + */ +#define LVPW_ADDR 0xfffffa05 +#define LVPW BYTE_REF(LVPW_ADDR) + +/* + * LCD Screen Width Register (not compatible with 'EZ328 !!!) + */ +#define LXMAX_ADDR 0xfffffa08 +#define LXMAX WORD_REF(LXMAX_ADDR) + +#define LXMAX_XM_MASK 0x02ff /* Bits 0-3 are reserved */ + +/* + * LCD Screen Height Register + */ +#define LYMAX_ADDR 0xfffffa0a +#define LYMAX WORD_REF(LYMAX_ADDR) + +#define LYMAX_YM_MASK 0x02ff /* Bits 10-15 are reserved */ + +/* + * LCD Cursor X Position Register + */ +#define LCXP_ADDR 0xfffffa18 +#define LCXP WORD_REF(LCXP_ADDR) + +#define LCXP_CC_MASK 0xc000 /* Cursor Control */ +#define LCXP_CC_TRAMSPARENT 0x0000 +#define LCXP_CC_BLACK 0x4000 +#define LCXP_CC_REVERSED 0x8000 +#define LCXP_CC_WHITE 0xc000 +#define LCXP_CXP_MASK 0x02ff /* Cursor X position */ + +/* + * LCD Cursor Y Position Register + */ +#define LCYP_ADDR 0xfffffa1a +#define LCYP WORD_REF(LCYP_ADDR) + +#define LCYP_CYP_MASK 0x01ff /* Cursor Y Position */ + +/* + * LCD Cursor Width and Heigth Register + */ +#define LCWCH_ADDR 0xfffffa1c +#define LCWCH WORD_REF(LCWCH_ADDR) + +#define LCWCH_CH_MASK 0x001f /* Cursor Height */ +#define LCWCH_CH_SHIFT 0 +#define LCWCH_CW_MASK 0x1f00 /* Cursor Width */ +#define LCWCH_CW_SHIFT 8 + +/* + * LCD Blink Control Register + */ +#define LBLKC_ADDR 0xfffffa1f +#define LBLKC BYTE_REF(LBLKC_ADDR) + +#define LBLKC_BD_MASK 0x7f /* Blink Divisor */ +#define LBLKC_BD_SHIFT 0 +#define LBLKC_BKEN 0x80 /* Blink Enabled */ + +/* + * LCD Panel Interface Configuration Register + */ +#define LPICF_ADDR 0xfffffa20 +#define LPICF BYTE_REF(LPICF_ADDR) + +#define LPICF_GS_MASK 0x01 /* Gray-Scale Mode */ +#define LPICF_GS_BW 0x00 +#define LPICF_GS_GRAY_4 0x01 +#define LPICF_PBSIZ_MASK 0x06 /* Panel Bus Width */ +#define LPICF_PBSIZ_1 0x00 +#define LPICF_PBSIZ_2 0x02 +#define LPICF_PBSIZ_4 0x04 + +/* + * LCD Polarity Configuration Register + */ +#define LPOLCF_ADDR 0xfffffa21 +#define LPOLCF BYTE_REF(LPOLCF_ADDR) + +#define LPOLCF_PIXPOL 0x01 /* Pixel Polarity */ +#define LPOLCF_LPPOL 0x02 /* Line Pulse Polarity */ +#define LPOLCF_FLMPOL 0x04 /* Frame Marker Polarity */ +#define LPOLCF_LCKPOL 0x08 /* LCD Shift Lock Polarity */ + +/* + * LACD (LCD Alternate Crystal Direction) Rate Control Register + */ +#define LACDRC_ADDR 0xfffffa23 +#define LACDRC BYTE_REF(LACDRC_ADDR) + +#define LACDRC_ACD_MASK 0x0f /* Alternate Crystal Direction Control */ +#define LACDRC_ACD_SHIFT 0 + +/* + * LCD Pixel Clock Divider Register + */ +#define LPXCD_ADDR 0xfffffa25 +#define LPXCD BYTE_REF(LPXCD_ADDR) + +#define LPXCD_PCD_MASK 0x3f /* Pixel Clock Divider */ +#define LPXCD_PCD_SHIFT 0 + +/* + * LCD Clocking Control Register + */ +#define LCKCON_ADDR 0xfffffa27 +#define LCKCON BYTE_REF(LCKCON_ADDR) + +#define LCKCON_PCDS 0x01 /* Pixel Clock Divider Source Select */ +#define LCKCON_DWIDTH 0x02 /* Display Memory Width */ +#define LCKCON_DWS_MASK 0x3c /* Display Wait-State */ +#define LCKCON_DWS_SHIFT 2 +#define LCKCON_DMA16 0x40 /* DMA burst length */ +#define LCKCON_LCDON 0x80 /* Enable LCD Controller */ + +/* 'EZ328-compatible definitions */ +#define LCKCON_DW_MASK LCKCON_DWS_MASK +#define LCKCON_DW_SHIFT LCKCON_DWS_SHIFT + +/* + * LCD Last Buffer Address Register + */ +#define LLBAR_ADDR 0xfffffa29 +#define LLBAR BYTE_REF(LLBAR_ADDR) + +#define LLBAR_LBAR_MASK 0x7f /* Number of memory words to fill 1 line */ +#define LLBAR_LBAR_SHIFT 0 + +/* + * LCD Octet Terminal Count Register + */ +#define LOTCR_ADDR 0xfffffa2b +#define LOTCR BYTE_REF(LOTCR_ADDR) + +/* + * LCD Panning Offset Register + */ +#define LPOSR_ADDR 0xfffffa2d +#define LPOSR BYTE_REF(LPOSR_ADDR) + +#define LPOSR_BOS 0x08 /* Byte offset (for B/W mode only */ +#define LPOSR_POS_MASK 0x07 /* Pixel Offset Code */ +#define LPOSR_POS_SHIFT 0 + +/* + * LCD Frame Rate Control Modulation Register + */ +#define LFRCM_ADDR 0xfffffa31 +#define LFRCM BYTE_REF(LFRCM_ADDR) + +#define LFRCM_YMOD_MASK 0x0f /* Vertical Modulation */ +#define LFRCM_YMOD_SHIFT 0 +#define LFRCM_XMOD_MASK 0xf0 /* Horizontal Modulation */ +#define LFRCM_XMOD_SHIFT 4 + +/* + * LCD Gray Palette Mapping Register + */ +#define LGPMR_ADDR 0xfffffa32 +#define LGPMR WORD_REF(LGPMR_ADDR) + +#define LGPMR_GLEVEL3_MASK 0x000f +#define LGPMR_GLEVEL3_SHIFT 0 +#define LGPMR_GLEVEL2_MASK 0x00f0 +#define LGPMR_GLEVEL2_SHIFT 4 +#define LGPMR_GLEVEL0_MASK 0x0f00 +#define LGPMR_GLEVEL0_SHIFT 8 +#define LGPMR_GLEVEL1_MASK 0xf000 +#define LGPMR_GLEVEL1_SHIFT 12 + +/********** + * + * 0xFFFFFBxx -- Real-Time Clock (RTC) + * + **********/ + +/* + * RTC Hours Minutes and Seconds Register + */ +#define RTCTIME_ADDR 0xfffffb00 +#define RTCTIME LONG_REF(RTCTIME_ADDR) + +#define RTCTIME_SECONDS_MASK 0x0000003f /* Seconds */ +#define RTCTIME_SECONDS_SHIFT 0 +#define RTCTIME_MINUTES_MASK 0x003f0000 /* Minutes */ +#define RTCTIME_MINUTES_SHIFT 16 +#define RTCTIME_HOURS_MASK 0x1f000000 /* Hours */ +#define RTCTIME_HOURS_SHIFT 24 + +/* + * RTC Alarm Register + */ +#define RTCALRM_ADDR 0xfffffb04 +#define RTCALRM LONG_REF(RTCALRM_ADDR) + +#define RTCALRM_SECONDS_MASK 0x0000003f /* Seconds */ +#define RTCALRM_SECONDS_SHIFT 0 +#define RTCALRM_MINUTES_MASK 0x003f0000 /* Minutes */ +#define RTCALRM_MINUTES_SHIFT 16 +#define RTCALRM_HOURS_MASK 0x1f000000 /* Hours */ +#define RTCALRM_HOURS_SHIFT 24 + +/* + * RTC Control Register + */ +#define RTCCTL_ADDR 0xfffffb0c +#define RTCCTL WORD_REF(RTCCTL_ADDR) + +#define RTCCTL_384 0x0020 /* Crystal Selection */ +#define RTCCTL_ENABLE 0x0080 /* RTC Enable */ + +/* 'EZ328-compatible definitions */ +#define RTCCTL_XTL RTCCTL_384 +#define RTCCTL_EN RTCCTL_ENABLE + +/* + * RTC Interrupt Status Register + */ +#define RTCISR_ADDR 0xfffffb0e +#define RTCISR WORD_REF(RTCISR_ADDR) + +#define RTCISR_SW 0x0001 /* Stopwatch timed out */ +#define RTCISR_MIN 0x0002 /* 1-minute interrupt has occured */ +#define RTCISR_ALM 0x0004 /* Alarm interrupt has occured */ +#define RTCISR_DAY 0x0008 /* 24-hour rollover interrupt has occured */ +#define RTCISR_1HZ 0x0010 /* 1Hz interrupt has occured */ + +/* + * RTC Interrupt Enable Register + */ +#define RTCIENR_ADDR 0xfffffb10 +#define RTCIENR WORD_REF(RTCIENR_ADDR) + +#define RTCIENR_SW 0x0001 /* Stopwatch interrupt enable */ +#define RTCIENR_MIN 0x0002 /* 1-minute interrupt enable */ +#define RTCIENR_ALM 0x0004 /* Alarm interrupt enable */ +#define RTCIENR_DAY 0x0008 /* 24-hour rollover interrupt enable */ +#define RTCIENR_1HZ 0x0010 /* 1Hz interrupt enable */ + +/* + * Stopwatch Minutes Register + */ +#define STPWCH_ADDR 0xfffffb12 +#define STPWCH WORD_REF(STPWCH) + +#define STPWCH_CNT_MASK 0x00ff /* Stopwatch countdown value */ +#define SPTWCH_CNT_SHIFT 0 + +#endif /* _MC68328_H_ */ diff -Nru a/include/asm-m68knommu/MC68332.h b/include/asm-m68knommu/MC68332.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/MC68332.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,152 @@ + +/* include/asm-m68knommu/MC68332.h: '332 control registers + * + * Copyright (C) 1998 Kenneth Albanowski , + * + */ + +#ifndef _MC68332_H_ +#define _MC68332_H_ + +#define BYTE_REF(addr) (*((volatile unsigned char*)addr)) +#define WORD_REF(addr) (*((volatile unsigned short*)addr)) + +#define PORTE_ADDR 0xfffa11 +#define PORTE BYTE_REF(PORTE_ADDR) +#define DDRE_ADDR 0xfffa15 +#define DDRE BYTE_REF(DDRE_ADDR) +#define PEPAR_ADDR 0xfffa17 +#define PEPAR BYTE_REF(PEPAR_ADDR) + +#define PORTF_ADDR 0xfffa19 +#define PORTF BYTE_REF(PORTF_ADDR) +#define DDRF_ADDR 0xfffa1d +#define DDRF BYTE_REF(DDRF_ADDR) +#define PFPAR_ADDR 0xfffa1f +#define PFPAR BYTE_REF(PFPAR_ADDR) + +#define PORTQS_ADDR 0xfffc15 +#define PORTQS BYTE_REF(PORTQS_ADDR) +#define DDRQS_ADDR 0xfffc17 +#define DDRQS BYTE_REF(DDRQS_ADDR) +#define PQSPAR_ADDR 0xfffc16 +#define PQSPAR BYTE_REF(PQSPAR_ADDR) + +#define CSPAR0_ADDR 0xFFFA44 +#define CSPAR0 WORD_REF(CSPAR0_ADDR) +#define CSPAR1_ADDR 0xFFFA46 +#define CSPAR1 WORD_REF(CSPAR1_ADDR) +#define CSARBT_ADDR 0xFFFA48 +#define CSARBT WORD_REF(CSARBT_ADDR) +#define CSOPBT_ADDR 0xFFFA4A +#define CSOPBT WORD_REF(CSOPBT_ADDR) +#define CSBAR0_ADDR 0xFFFA4C +#define CSBAR0 WORD_REF(CSBAR0_ADDR) +#define CSOR0_ADDR 0xFFFA4E +#define CSOR0 WORD_REF(CSOR0_ADDR) +#define CSBAR1_ADDR 0xFFFA50 +#define CSBAR1 WORD_REF(CSBAR1_ADDR) +#define CSOR1_ADDR 0xFFFA52 +#define CSOR1 WORD_REF(CSOR1_ADDR) +#define CSBAR2_ADDR 0xFFFA54 +#define CSBAR2 WORD_REF(CSBAR2_ADDR) +#define CSOR2_ADDR 0xFFFA56 +#define CSOR2 WORD_REF(CSOR2_ADDR) +#define CSBAR3_ADDR 0xFFFA58 +#define CSBAR3 WORD_REF(CSBAR3_ADDR) +#define CSOR3_ADDR 0xFFFA5A +#define CSOR3 WORD_REF(CSOR3_ADDR) +#define CSBAR4_ADDR 0xFFFA5C +#define CSBAR4 WORD_REF(CSBAR4_ADDR) +#define CSOR4_ADDR 0xFFFA5E +#define CSOR4 WORD_REF(CSOR4_ADDR) +#define CSBAR5_ADDR 0xFFFA60 +#define CSBAR5 WORD_REF(CSBAR5_ADDR) +#define CSOR5_ADDR 0xFFFA62 +#define CSOR5 WORD_REF(CSOR5_ADDR) +#define CSBAR6_ADDR 0xFFFA64 +#define CSBAR6 WORD_REF(CSBAR6_ADDR) +#define CSOR6_ADDR 0xFFFA66 +#define CSOR6 WORD_REF(CSOR6_ADDR) +#define CSBAR7_ADDR 0xFFFA68 +#define CSBAR7 WORD_REF(CSBAR7_ADDR) +#define CSOR7_ADDR 0xFFFA6A +#define CSOR7 WORD_REF(CSOR7_ADDR) +#define CSBAR8_ADDR 0xFFFA6C +#define CSBAR8 WORD_REF(CSBAR8_ADDR) +#define CSOR8_ADDR 0xFFFA6E +#define CSOR8 WORD_REF(CSOR8_ADDR) +#define CSBAR9_ADDR 0xFFFA70 +#define CSBAR9 WORD_REF(CSBAR9_ADDR) +#define CSOR9_ADDR 0xFFFA72 +#define CSOR9 WORD_REF(CSOR9_ADDR) +#define CSBAR10_ADDR 0xFFFA74 +#define CSBAR10 WORD_REF(CSBAR10_ADDR) +#define CSOR10_ADDR 0xFFFA76 +#define CSOR10 WORD_REF(CSOR10_ADDR) + +#define CSOR_MODE_ASYNC 0x0000 +#define CSOR_MODE_SYNC 0x8000 +#define CSOR_MODE_MASK 0x8000 +#define CSOR_BYTE_DISABLE 0x0000 +#define CSOR_BYTE_UPPER 0x4000 +#define CSOR_BYTE_LOWER 0x2000 +#define CSOR_BYTE_BOTH 0x6000 +#define CSOR_BYTE_MASK 0x6000 +#define CSOR_RW_RSVD 0x0000 +#define CSOR_RW_READ 0x0800 +#define CSOR_RW_WRITE 0x1000 +#define CSOR_RW_BOTH 0x1800 +#define CSOR_RW_MASK 0x1800 +#define CSOR_STROBE_DS 0x0400 +#define CSOR_STROBE_AS 0x0000 +#define CSOR_STROBE_MASK 0x0400 +#define CSOR_DSACK_WAIT(x) (wait << 6) +#define CSOR_DSACK_FTERM (14 << 6) +#define CSOR_DSACK_EXTERNAL (15 << 6) +#define CSOR_DSACK_MASK 0x03c0 +#define CSOR_SPACE_CPU 0x0000 +#define CSOR_SPACE_USER 0x0010 +#define CSOR_SPACE_SU 0x0020 +#define CSOR_SPACE_BOTH 0x0030 +#define CSOR_SPACE_MASK 0x0030 +#define CSOR_IPL_ALL 0x0000 +#define CSOR_IPL_PRIORITY(x) (x << 1) +#define CSOR_IPL_MASK 0x000e +#define CSOR_AVEC_ON 0x0001 +#define CSOR_AVEC_OFF 0x0000 +#define CSOR_AVEC_MASK 0x0001 + +#define CSBAR_ADDR(x) ((addr >> 11) << 3) +#define CSBAR_ADDR_MASK 0xfff8 +#define CSBAR_BLKSIZE_2K 0x0000 +#define CSBAR_BLKSIZE_8K 0x0001 +#define CSBAR_BLKSIZE_16K 0x0002 +#define CSBAR_BLKSIZE_64K 0x0003 +#define CSBAR_BLKSIZE_128K 0x0004 +#define CSBAR_BLKSIZE_256K 0x0005 +#define CSBAR_BLKSIZE_512K 0x0006 +#define CSBAR_BLKSIZE_1M 0x0007 +#define CSBAR_BLKSIZE_MASK 0x0007 + +#define CSPAR_DISC 0 +#define CSPAR_ALT 1 +#define CSPAR_CS8 2 +#define CSPAR_CS16 3 +#define CSPAR_MASK 3 + +#define CSPAR0_CSBOOT(x) (x << 0) +#define CSPAR0_CS0(x) (x << 2) +#define CSPAR0_CS1(x) (x << 4) +#define CSPAR0_CS2(x) (x << 6) +#define CSPAR0_CS3(x) (x << 8) +#define CSPAR0_CS4(x) (x << 10) +#define CSPAR0_CS5(x) (x << 12) + +#define CSPAR1_CS6(x) (x << 0) +#define CSPAR1_CS7(x) (x << 2) +#define CSPAR1_CS8(x) (x << 4) +#define CSPAR1_CS9(x) (x << 6) +#define CSPAR1_CS10(x) (x << 8) + +#endif diff -Nru a/include/asm-m68knommu/MC68EZ328.h b/include/asm-m68knommu/MC68EZ328.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/MC68EZ328.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,1253 @@ + +/* include/asm-m68knommu/MC68EZ328.h: 'EZ328 control registers + * + * Copyright (C) 1999 Vladimir Gurevich + * Bear & Hare Software, Inc. + * + * Based on include/asm-m68knommu/MC68332.h + * Copyright (C) 1998 Kenneth Albanowski , + * The Silver Hammer Group, Ltd. + * + */ + +#ifndef _MC68EZ328_H_ +#define _MC68EZ328_H_ + +#define BYTE_REF(addr) (*((volatile unsigned char*)addr)) +#define WORD_REF(addr) (*((volatile unsigned short*)addr)) +#define LONG_REF(addr) (*((volatile unsigned long*)addr)) + +#define PUT_FIELD(field, val) (((val) << field##_SHIFT) & field##_MASK) +#define GET_FIELD(reg, field) (((reg) & field##_MASK) >> field##_SHIFT) + +/********** + * + * 0xFFFFF0xx -- System Control + * + **********/ + +/* + * System Control Register (SCR) + */ +#define SCR_ADDR 0xfffff000 +#define SCR BYTE_REF(SCR_ADDR) + +#define SCR_WDTH8 0x01 /* 8-Bit Width Select */ +#define SCR_DMAP 0x04 /* Double Map */ +#define SCR_SO 0x08 /* Supervisor Only */ +#define SCR_BETEN 0x10 /* Bus-Error Time-Out Enable */ +#define SCR_PRV 0x20 /* Privilege Violation */ +#define SCR_WPV 0x40 /* Write Protect Violation */ +#define SCR_BETO 0x80 /* Bus-Error TimeOut */ + +/* + * Silicon ID Register (Mask Revision Register (MRR) for '328 Compatibility) + */ +#define MRR_ADDR 0xfffff004 +#define MRR LONG_REF(MRR_ADDR) + +/********** + * + * 0xFFFFF1xx -- Chip-Select logic + * + **********/ + +/* + * Chip Select Group Base Registers + */ +#define CSGBA_ADDR 0xfffff100 +#define CSGBB_ADDR 0xfffff102 + +#define CSGBC_ADDR 0xfffff104 +#define CSGBD_ADDR 0xfffff106 + +#define CSGBA WORD_REF(CSGBA_ADDR) +#define CSGBB WORD_REF(CSGBB_ADDR) +#define CSGBC WORD_REF(CSGBC_ADDR) +#define CSGBD WORD_REF(CSGBD_ADDR) + +/* + * Chip Select Registers + */ +#define CSA_ADDR 0xfffff110 +#define CSB_ADDR 0xfffff112 +#define CSC_ADDR 0xfffff114 +#define CSD_ADDR 0xfffff116 + +#define CSA WORD_REF(CSA_ADDR) +#define CSB WORD_REF(CSB_ADDR) +#define CSC WORD_REF(CSC_ADDR) +#define CSD WORD_REF(CSD_ADDR) + +#define CSA_EN 0x0001 /* Chip-Select Enable */ +#define CSA_SIZ_MASK 0x000e /* Chip-Select Size */ +#define CSA_SIZ_SHIFT 1 +#define CSA_WS_MASK 0x0070 /* Wait State */ +#define CSA_WS_SHIFT 4 +#define CSA_BSW 0x0080 /* Data Bus Width */ +#define CSA_FLASH 0x0100 /* FLASH Memory Support */ +#define CSA_RO 0x8000 /* Read-Only */ + +#define CSB_EN 0x0001 /* Chip-Select Enable */ +#define CSB_SIZ_MASK 0x000e /* Chip-Select Size */ +#define CSB_SIZ_SHIFT 1 +#define CSB_WS_MASK 0x0070 /* Wait State */ +#define CSB_WS_SHIFT 4 +#define CSB_BSW 0x0080 /* Data Bus Width */ +#define CSB_FLASH 0x0100 /* FLASH Memory Support */ +#define CSB_UPSIZ_MASK 0x1800 /* Unprotected memory block size */ +#define CSB_UPSIZ_SHIFT 11 +#define CSB_ROP 0x2000 /* Readonly if protected */ +#define CSB_SOP 0x4000 /* Supervisor only if protected */ +#define CSB_RO 0x8000 /* Read-Only */ + +#define CSC_EN 0x0001 /* Chip-Select Enable */ +#define CSC_SIZ_MASK 0x000e /* Chip-Select Size */ +#define CSC_SIZ_SHIFT 1 +#define CSC_WS_MASK 0x0070 /* Wait State */ +#define CSC_WS_SHIFT 4 +#define CSC_BSW 0x0080 /* Data Bus Width */ +#define CSC_FLASH 0x0100 /* FLASH Memory Support */ +#define CSC_UPSIZ_MASK 0x1800 /* Unprotected memory block size */ +#define CSC_UPSIZ_SHIFT 11 +#define CSC_ROP 0x2000 /* Readonly if protected */ +#define CSC_SOP 0x4000 /* Supervisor only if protected */ +#define CSC_RO 0x8000 /* Read-Only */ + +#define CSD_EN 0x0001 /* Chip-Select Enable */ +#define CSD_SIZ_MASK 0x000e /* Chip-Select Size */ +#define CSD_SIZ_SHIFT 1 +#define CSD_WS_MASK 0x0070 /* Wait State */ +#define CSD_WS_SHIFT 4 +#define CSD_BSW 0x0080 /* Data Bus Width */ +#define CSD_FLASH 0x0100 /* FLASH Memory Support */ +#define CSD_DRAM 0x0200 /* Dram Selection */ +#define CSD_COMB 0x0400 /* Combining */ +#define CSD_UPSIZ_MASK 0x1800 /* Unprotected memory block size */ +#define CSD_UPSIZ_SHIFT 11 +#define CSD_ROP 0x2000 /* Readonly if protected */ +#define CSD_SOP 0x4000 /* Supervisor only if protected */ +#define CSD_RO 0x8000 /* Read-Only */ + +/* + * Emulation Chip-Select Register + */ +#define EMUCS_ADDR 0xfffff118 +#define EMUCS WORD_REF(EMUCS_ADDR) + +#define EMUCS_WS_MASK 0x0070 +#define EMUCS_WS_SHIFT 4 + +/********** + * + * 0xFFFFF2xx -- Phase Locked Loop (PLL) & Power Control + * + **********/ + +/* + * PLL Control Register + */ +#define PLLCR_ADDR 0xfffff200 +#define PLLCR WORD_REF(PLLCR_ADDR) + +#define PLLCR_DISPLL 0x0008 /* Disable PLL */ +#define PLLCR_CLKEN 0x0010 /* Clock (CLKO pin) enable */ +#define PLLCR_PRESC 0x0020 /* VCO prescaler */ +#define PLLCR_SYSCLK_SEL_MASK 0x0700 /* System Clock Selection */ +#define PLLCR_SYSCLK_SEL_SHIFT 8 +#define PLLCR_LCDCLK_SEL_MASK 0x3800 /* LCD Clock Selection */ +#define PLLCR_LCDCLK_SEL_SHIFT 11 + +/* '328-compatible definitions */ +#define PLLCR_PIXCLK_SEL_MASK PLLCR_LCDCLK_SEL_MASK +#define PLLCR_PIXCLK_SEL_SHIFT PLLCR_LCDCLK_SEL_SHIFT + +/* + * PLL Frequency Select Register + */ +#define PLLFSR_ADDR 0xfffff202 +#define PLLFSR WORD_REF(PLLFSR_ADDR) + +#define PLLFSR_PC_MASK 0x00ff /* P Count */ +#define PLLFSR_PC_SHIFT 0 +#define PLLFSR_QC_MASK 0x0f00 /* Q Count */ +#define PLLFSR_QC_SHIFT 8 +#define PLLFSR_PROT 0x4000 /* Protect P & Q */ +#define PLLFSR_CLK32 0x8000 /* Clock 32 (kHz) */ + +/* + * Power Control Register + */ +#define PCTRL_ADDR 0xfffff207 +#define PCTRL BYTE_REF(PCTRL_ADDR) + +#define PCTRL_WIDTH_MASK 0x1f /* CPU Clock bursts width */ +#define PCTRL_WIDTH_SHIFT 0 +#define PCTRL_PCEN 0x80 /* Power Control Enable */ + +/********** + * + * 0xFFFFF3xx -- Interrupt Controller + * + **********/ + +/* + * Interrupt Vector Register + */ +#define IVR_ADDR 0xfffff300 +#define IVR BYTE_REF(IVR_ADDR) + +#define IVR_VECTOR_MASK 0xF8 + +/* + * Interrupt control Register + */ +#define ICR_ADDR 0xfffff302 +#define ICR WORD_REF(ICR_ADDR) + +#define ICR_POL5 0x0080 /* Polarity Control for IRQ5 */ +#define ICR_ET6 0x0100 /* Edge Trigger Select for IRQ6 */ +#define ICR_ET3 0x0200 /* Edge Trigger Select for IRQ3 */ +#define ICR_ET2 0x0400 /* Edge Trigger Select for IRQ2 */ +#define ICR_ET1 0x0800 /* Edge Trigger Select for IRQ1 */ +#define ICR_POL6 0x1000 /* Polarity Control for IRQ6 */ +#define ICR_POL3 0x2000 /* Polarity Control for IRQ3 */ +#define ICR_POL2 0x4000 /* Polarity Control for IRQ2 */ +#define ICR_POL1 0x8000 /* Polarity Control for IRQ1 */ + +/* + * Interrupt Mask Register + */ +#define IMR_ADDR 0xfffff304 +#define IMR LONG_REF(IMR_ADDR) + +/* + * Define the names for bit positions first. This is useful for + * request_irq + */ +#define SPI_IRQ_NUM 0 /* SPI interrupt */ +#define TMR_IRQ_NUM 1 /* Timer interrupt */ +#define UART_IRQ_NUM 2 /* UART interrupt */ +#define WDT_IRQ_NUM 3 /* Watchdog Timer interrupt */ +#define RTC_IRQ_NUM 4 /* RTC interrupt */ +#define KB_IRQ_NUM 6 /* Keyboard Interrupt */ +#define PWM_IRQ_NUM 7 /* Pulse-Width Modulator int. */ +#define INT0_IRQ_NUM 8 /* External INT0 */ +#define INT1_IRQ_NUM 9 /* External INT1 */ +#define INT2_IRQ_NUM 10 /* External INT2 */ +#define INT3_IRQ_NUM 11 /* External INT3 */ +#define IRQ1_IRQ_NUM 16 /* IRQ1 */ +#define IRQ2_IRQ_NUM 17 /* IRQ2 */ +#define IRQ3_IRQ_NUM 18 /* IRQ3 */ +#define IRQ6_IRQ_NUM 19 /* IRQ6 */ +#define IRQ5_IRQ_NUM 20 /* IRQ5 */ +#define SAM_IRQ_NUM 22 /* Sampling Timer for RTC */ +#define EMIQ_IRQ_NUM 23 /* Emulator Interrupt */ + +/* '328-compatible definitions */ +#define SPIM_IRQ_NUM SPI_IRQ_NUM +#define TMR1_IRQ_NUM TMR_IRQ_NUM + +/* + * Here go the bitmasks themselves + */ +#define IMR_MSPI (1 << SPI_IRQ_NUM) /* Mask SPI interrupt */ +#define IMR_MTMR (1 << TMR_IRQ_NUM) /* Mask Timer interrupt */ +#define IMR_MUART (1 << UART_IRQ_NUM) /* Mask UART interrupt */ +#define IMR_MWDT (1 << WDT_IRQ_NUM) /* Mask Watchdog Timer interrupt */ +#define IMR_MRTC (1 << RTC_IRQ_NUM) /* Mask RTC interrupt */ +#define IMR_MKB (1 << KB_IRQ_NUM) /* Mask Keyboard Interrupt */ +#define IMR_MPWM (1 << PWM_IRQ_NUM) /* Mask Pulse-Width Modulator int. */ +#define IMR_MINT0 (1 << INT0_IRQ_NUM) /* Mask External INT0 */ +#define IMR_MINT1 (1 << INT1_IRQ_NUM) /* Mask External INT1 */ +#define IMR_MINT2 (1 << INT2_IRQ_NUM) /* Mask External INT2 */ +#define IMR_MINT3 (1 << INT3_IRQ_NUM) /* Mask External INT3 */ +#define IMR_MIRQ1 (1 << IRQ1_IRQ_NUM) /* Mask IRQ1 */ +#define IMR_MIRQ2 (1 << IRQ2_IRQ_NUM) /* Mask IRQ2 */ +#define IMR_MIRQ3 (1 << IRQ3_IRQ_NUM) /* Mask IRQ3 */ +#define IMR_MIRQ6 (1 << IRQ6_IRQ_NUM) /* Mask IRQ6 */ +#define IMR_MIRQ5 (1 << IRQ5_IRQ_NUM) /* Mask IRQ5 */ +#define IMR_MSAM (1 << SAM_IRQ_NUM) /* Mask Sampling Timer for RTC */ +#define IMR_MEMIQ (1 << EMIQ_IRQ_NUM) /* Mask Emulator Interrupt */ + +/* '328-compatible definitions */ +#define IMR_MSPIM IMR_MSPI +#define IMR_MTMR1 IMR_MTMR + +/* + * Interrupt Status Register + */ +#define ISR_ADDR 0xfffff30c +#define ISR LONG_REF(ISR_ADDR) + +#define ISR_SPI (1 << SPI_IRQ_NUM) /* SPI interrupt */ +#define ISR_TMR (1 << TMR_IRQ_NUM) /* Timer interrupt */ +#define ISR_UART (1 << UART_IRQ_NUM) /* UART interrupt */ +#define ISR_WDT (1 << WDT_IRQ_NUM) /* Watchdog Timer interrupt */ +#define ISR_RTC (1 << RTC_IRQ_NUM) /* RTC interrupt */ +#define ISR_KB (1 << KB_IRQ_NUM) /* Keyboard Interrupt */ +#define ISR_PWM (1 << PWM_IRQ_NUM) /* Pulse-Width Modulator interrupt */ +#define ISR_INT0 (1 << INT0_IRQ_NUM) /* External INT0 */ +#define ISR_INT1 (1 << INT1_IRQ_NUM) /* External INT1 */ +#define ISR_INT2 (1 << INT2_IRQ_NUM) /* External INT2 */ +#define ISR_INT3 (1 << INT3_IRQ_NUM) /* External INT3 */ +#define ISR_IRQ1 (1 << IRQ1_IRQ_NUM) /* IRQ1 */ +#define ISR_IRQ2 (1 << IRQ2_IRQ_NUM) /* IRQ2 */ +#define ISR_IRQ3 (1 << IRQ3_IRQ_NUM) /* IRQ3 */ +#define ISR_IRQ6 (1 << IRQ6_IRQ_NUM) /* IRQ6 */ +#define ISR_IRQ5 (1 << IRQ5_IRQ_NUM) /* IRQ5 */ +#define ISR_SAM (1 << SAM_IRQ_NUM) /* Sampling Timer for RTC */ +#define ISR_EMIQ (1 << EMIQ_IRQ_NUM) /* Emulator Interrupt */ + +/* '328-compatible definitions */ +#define ISR_SPIM ISR_SPI +#define ISR_TMR1 ISR_TMR + +/* + * Interrupt Pending Register + */ +#define IPR_ADDR 0xfffff30c +#define IPR LONG_REF(IPR_ADDR) + +#define IPR_SPI (1 << SPI_IRQ_NUM) /* SPI interrupt */ +#define IPR_TMR (1 << TMR_IRQ_NUM) /* Timer interrupt */ +#define IPR_UART (1 << UART_IRQ_NUM) /* UART interrupt */ +#define IPR_WDT (1 << WDT_IRQ_NUM) /* Watchdog Timer interrupt */ +#define IPR_RTC (1 << RTC_IRQ_NUM) /* RTC interrupt */ +#define IPR_KB (1 << KB_IRQ_NUM) /* Keyboard Interrupt */ +#define IPR_PWM (1 << PWM_IRQ_NUM) /* Pulse-Width Modulator interrupt */ +#define IPR_INT0 (1 << INT0_IRQ_NUM) /* External INT0 */ +#define IPR_INT1 (1 << INT1_IRQ_NUM) /* External INT1 */ +#define IPR_INT2 (1 << INT2_IRQ_NUM) /* External INT2 */ +#define IPR_INT3 (1 << INT3_IRQ_NUM) /* External INT3 */ +#define IPR_IRQ1 (1 << IRQ1_IRQ_NUM) /* IRQ1 */ +#define IPR_IRQ2 (1 << IRQ2_IRQ_NUM) /* IRQ2 */ +#define IPR_IRQ3 (1 << IRQ3_IRQ_NUM) /* IRQ3 */ +#define IPR_IRQ6 (1 << IRQ6_IRQ_NUM) /* IRQ6 */ +#define IPR_IRQ5 (1 << IRQ5_IRQ_NUM) /* IRQ5 */ +#define IPR_SAM (1 << SAM_IRQ_NUM) /* Sampling Timer for RTC */ +#define IPR_EMIQ (1 << EMIQ_IRQ_NUM) /* Emulator Interrupt */ + +/* '328-compatible definitions */ +#define IPR_SPIM IPR_SPI +#define IPR_TMR1 IPR_TMR + +/********** + * + * 0xFFFFF4xx -- Parallel Ports + * + **********/ + +/* + * Port A + */ +#define PADIR_ADDR 0xfffff400 /* Port A direction reg */ +#define PADATA_ADDR 0xfffff401 /* Port A data register */ +#define PAPUEN_ADDR 0xfffff402 /* Port A Pull-Up enable reg */ + +#define PADIR BYTE_REF(PADIR_ADDR) +#define PADATA BYTE_REF(PADATA_ADDR) +#define PAPUEN BYTE_REF(PAPUEN_ADDR) + +#define PA(x) (1 << (x)) + +/* + * Port B + */ +#define PBDIR_ADDR 0xfffff408 /* Port B direction reg */ +#define PBDATA_ADDR 0xfffff409 /* Port B data register */ +#define PBPUEN_ADDR 0xfffff40a /* Port B Pull-Up enable reg */ +#define PBSEL_ADDR 0xfffff40b /* Port B Select Register */ + +#define PBDIR BYTE_REF(PBDIR_ADDR) +#define PBDATA BYTE_REF(PBDATA_ADDR) +#define PBPUEN BYTE_REF(PBPUEN_ADDR) +#define PBSEL BYTE_REF(PBSEL_ADDR) + +#define PB(x) (1 << (x)) + +#define PB_CSB0 0x01 /* Use CSB0 as PB[0] */ +#define PB_CSB1 0x02 /* Use CSB1 as PB[1] */ +#define PB_CSC0_RAS0 0x04 /* Use CSC0/RAS0 as PB[2] */ +#define PB_CSC1_RAS1 0x08 /* Use CSC1/RAS1 as PB[3] */ +#define PB_CSD0_CAS0 0x10 /* Use CSD0/CAS0 as PB[4] */ +#define PB_CSD1_CAS1 0x20 /* Use CSD1/CAS1 as PB[5] */ +#define PB_TIN_TOUT 0x40 /* Use TIN/TOUT as PB[6] */ +#define PB_PWMO 0x80 /* Use PWMO as PB[7] */ + +/* + * Port C + */ +#define PCDIR_ADDR 0xfffff410 /* Port C direction reg */ +#define PCDATA_ADDR 0xfffff411 /* Port C data register */ +#define PCPDEN_ADDR 0xfffff412 /* Port C Pull-Down enb. reg */ +#define PCSEL_ADDR 0xfffff413 /* Port C Select Register */ + +#define PCDIR BYTE_REF(PCDIR_ADDR) +#define PCDATA BYTE_REF(PCDATA_ADDR) +#define PCPDEN BYTE_REF(PCPDEN_ADDR) +#define PCSEL BYTE_REF(PCSEL_ADDR) + +#define PC(x) (1 << (x)) + +#define PC_LD0 0x01 /* Use LD0 as PC[0] */ +#define PC_LD1 0x02 /* Use LD1 as PC[1] */ +#define PC_LD2 0x04 /* Use LD2 as PC[2] */ +#define PC_LD3 0x08 /* Use LD3 as PC[3] */ +#define PC_LFLM 0x10 /* Use LFLM as PC[4] */ +#define PC_LLP 0x20 /* Use LLP as PC[5] */ +#define PC_LCLK 0x40 /* Use LCLK as PC[6] */ +#define PC_LACD 0x80 /* Use LACD as PC[7] */ + +/* + * Port D + */ +#define PDDIR_ADDR 0xfffff418 /* Port D direction reg */ +#define PDDATA_ADDR 0xfffff419 /* Port D data register */ +#define PDPUEN_ADDR 0xfffff41a /* Port D Pull-Up enable reg */ +#define PDSEL_ADDR 0xfffff41b /* Port D Select Register */ +#define PDPOL_ADDR 0xfffff41c /* Port D Polarity Register */ +#define PDIRQEN_ADDR 0xfffff41d /* Port D IRQ enable register */ +#define PDKBEN_ADDR 0xfffff41e /* Port D Keyboard Enable reg */ +#define PDIQEG_ADDR 0xfffff41f /* Port D IRQ Edge Register */ + +#define PDDIR BYTE_REF(PDDIR_ADDR) +#define PDDATA BYTE_REF(PDDATA_ADDR) +#define PDPUEN BYTE_REF(PDPUEN_ADDR) +#define PDSEL BYTE_REF(PDSEL_ADDR) +#define PDPOL BYTE_REF(PDPOL_ADDR) +#define PDIRQEN BYTE_REF(PDIRQEN_ADDR) +#define PDKBEN BYTE_REF(PDKBEN_ADDR) +#define PDIQEG BYTE_REF(PDIQEG_ADDR) + +#define PD(x) (1 << (x)) + +#define PD_INT0 0x01 /* Use INT0 as PD[0] */ +#define PD_INT1 0x02 /* Use INT1 as PD[1] */ +#define PD_INT2 0x04 /* Use INT2 as PD[2] */ +#define PD_INT3 0x08 /* Use INT3 as PD[3] */ +#define PD_IRQ1 0x10 /* Use IRQ1 as PD[4] */ +#define PD_IRQ2 0x20 /* Use IRQ2 as PD[5] */ +#define PD_IRQ3 0x40 /* Use IRQ3 as PD[6] */ +#define PD_IRQ6 0x80 /* Use IRQ6 as PD[7] */ + +/* + * Port E + */ +#define PEDIR_ADDR 0xfffff420 /* Port E direction reg */ +#define PEDATA_ADDR 0xfffff421 /* Port E data register */ +#define PEPUEN_ADDR 0xfffff422 /* Port E Pull-Up enable reg */ +#define PESEL_ADDR 0xfffff423 /* Port E Select Register */ + +#define PEDIR BYTE_REF(PEDIR_ADDR) +#define PEDATA BYTE_REF(PEDATA_ADDR) +#define PEPUEN BYTE_REF(PEPUEN_ADDR) +#define PESEL BYTE_REF(PESEL_ADDR) + +#define PE(x) (1 << (x)) + +#define PE_SPMTXD 0x01 /* Use SPMTXD as PE[0] */ +#define PE_SPMRXD 0x02 /* Use SPMRXD as PE[1] */ +#define PE_SPMCLK 0x04 /* Use SPMCLK as PE[2] */ +#define PE_DWE 0x08 /* Use DWE as PE[3] */ +#define PE_RXD 0x10 /* Use RXD as PE[4] */ +#define PE_TXD 0x20 /* Use TXD as PE[5] */ +#define PE_RTS 0x40 /* Use RTS as PE[6] */ +#define PE_CTS 0x80 /* Use CTS as PE[7] */ + +/* + * Port F + */ +#define PFDIR_ADDR 0xfffff428 /* Port F direction reg */ +#define PFDATA_ADDR 0xfffff429 /* Port F data register */ +#define PFPUEN_ADDR 0xfffff42a /* Port F Pull-Up enable reg */ +#define PFSEL_ADDR 0xfffff42b /* Port F Select Register */ + +#define PFDIR BYTE_REF(PFDIR_ADDR) +#define PFDATA BYTE_REF(PFDATA_ADDR) +#define PFPUEN BYTE_REF(PFPUEN_ADDR) +#define PFSEL BYTE_REF(PFSEL_ADDR) + +#define PF(x) (1 << (x)) + +#define PF_LCONTRAST 0x01 /* Use LCONTRAST as PF[0] */ +#define PF_IRQ5 0x02 /* Use IRQ5 as PF[1] */ +#define PF_CLKO 0x04 /* Use CLKO as PF[2] */ +#define PF_A20 0x08 /* Use A20 as PF[3] */ +#define PF_A21 0x10 /* Use A21 as PF[4] */ +#define PF_A22 0x20 /* Use A22 as PF[5] */ +#define PF_A23 0x40 /* Use A23 as PF[6] */ +#define PF_CSA1 0x80 /* Use CSA1 as PF[7] */ + +/* + * Port G + */ +#define PGDIR_ADDR 0xfffff430 /* Port G direction reg */ +#define PGDATA_ADDR 0xfffff431 /* Port G data register */ +#define PGPUEN_ADDR 0xfffff432 /* Port G Pull-Up enable reg */ +#define PGSEL_ADDR 0xfffff433 /* Port G Select Register */ + +#define PGDIR BYTE_REF(PGDIR_ADDR) +#define PGDATA BYTE_REF(PGDATA_ADDR) +#define PGPUEN BYTE_REF(PGPUEN_ADDR) +#define PGSEL BYTE_REF(PGSEL_ADDR) + +#define PG(x) (1 << (x)) + +#define PG_BUSW_DTACK 0x01 /* Use BUSW/DTACK as PG[0] */ +#define PG_A0 0x02 /* Use A0 as PG[1] */ +#define PG_EMUIRQ 0x04 /* Use EMUIRQ as PG[2] */ +#define PG_HIZ_P_D 0x08 /* Use HIZ/P/D as PG[3] */ +#define PG_EMUCS 0x10 /* Use EMUCS as PG[4] */ +#define PG_EMUBRK 0x20 /* Use EMUBRK as PG[5] */ + +/********** + * + * 0xFFFFF5xx -- Pulse-Width Modulator (PWM) + * + **********/ + +/* + * PWM Control Register + */ +#define PWMC_ADDR 0xfffff500 +#define PWMC WORD_REF(PWMC_ADDR) + +#define PWMC_CLKSEL_MASK 0x0003 /* Clock Selection */ +#define PWMC_CLKSEL_SHIFT 0 +#define PWMC_REPEAT_MASK 0x000c /* Sample Repeats */ +#define PWMC_REPEAT_SHIFT 2 +#define PWMC_EN 0x0010 /* Enable PWM */ +#define PMNC_FIFOAV 0x0020 /* FIFO Available */ +#define PWMC_IRQEN 0x0040 /* Interrupt Request Enable */ +#define PWMC_IRQ 0x0080 /* Interrupt Request (FIFO empty) */ +#define PWMC_PRESCALER_MASK 0x7f00 /* Incoming Clock prescaler */ +#define PWMC_PRESCALER_SHIFT 8 +#define PWMC_CLKSRC 0x8000 /* Clock Source Select */ + +/* '328-compatible definitions */ +#define PWMC_PWMEN PWMC_EN + +/* + * PWM Sample Register + */ +#define PWMS_ADDR 0xfffff502 +#define PWMS WORD_REF(PWMS_ADDR) + +/* + * PWM Period Register + */ +#define PWMP_ADDR 0xfffff504 +#define PWMP BYTE_REF(PWMP_ADDR) + +/* + * PWM Counter Register + */ +#define PWMCNT_ADDR 0xfffff505 +#define PWMCNT BYTE_REF(PWMCNT_ADDR) + +/********** + * + * 0xFFFFF6xx -- General-Purpose Timer + * + **********/ + +/* + * Timer Control register + */ +#define TCTL_ADDR 0xfffff600 +#define TCTL WORD_REF(TCTL_ADDR) + +#define TCTL_TEN 0x0001 /* Timer Enable */ +#define TCTL_CLKSOURCE_MASK 0x000e /* Clock Source: */ +#define TCTL_CLKSOURCE_STOP 0x0000 /* Stop count (disabled) */ +#define TCTL_CLKSOURCE_SYSCLK 0x0002 /* SYSCLK to prescaler */ +#define TCTL_CLKSOURCE_SYSCLK_16 0x0004 /* SYSCLK/16 to prescaler */ +#define TCTL_CLKSOURCE_TIN 0x0006 /* TIN to prescaler */ +#define TCTL_CLKSOURCE_32KHZ 0x0008 /* 32kHz clock to prescaler */ +#define TCTL_IRQEN 0x0010 /* IRQ Enable */ +#define TCTL_OM 0x0020 /* Output Mode */ +#define TCTL_CAP_MASK 0x00c0 /* Capture Edge: */ +#define TCTL_CAP_RE 0x0040 /* Capture on rizing edge */ +#define TCTL_CAP_FE 0x0080 /* Capture on falling edge */ +#define TCTL_FRR 0x0010 /* Free-Run Mode */ + +/* '328-compatible definitions */ +#define TCTL1_ADDR TCTL_ADDR +#define TCTL1 TCTL + +/* + * Timer Prescaler Register + */ +#define TPRER_ADDR 0xfffff602 +#define TPRER WORD_REF(TPRER_ADDR) + +/* '328-compatible definitions */ +#define TPRER1_ADDR TPRER_ADDR +#define TPRER1 TPRER + +/* + * Timer Compare Register + */ +#define TCMP_ADDR 0xfffff604 +#define TCMP WORD_REF(TCMP_ADDR) + +/* '328-compatible definitions */ +#define TCMP1_ADDR TCMP_ADDR +#define TCMP1 TCMP + +/* + * Timer Capture register + */ +#define TCR_ADDR 0xfffff606 +#define TCR WORD_REF(TCR_ADDR) + +/* '328-compatible definitions */ +#define TCR1_ADDR TCR_ADDR +#define TCR1 TCR + +/* + * Timer Counter Register + */ +#define TCN_ADDR 0xfffff608 +#define TCN WORD_REF(TCN_ADDR) + +/* '328-compatible definitions */ +#define TCN1_ADDR TCN_ADDR +#define TCN1 TCN + +/* + * Timer Status Register + */ +#define TSTAT_ADDR 0xfffff60a +#define TSTAT WORD_REF(TSTAT_ADDR) + +#define TSTAT_COMP 0x0001 /* Compare Event occurred */ +#define TSTAT_CAPT 0x0001 /* Capture Event occurred */ + +/* '328-compatible definitions */ +#define TSTAT1_ADDR TSTAT_ADDR +#define TSTAT1 TSTAT + +/********** + * + * 0xFFFFF8xx -- Serial Periferial Interface Master (SPIM) + * + **********/ + +/* + * SPIM Data Register + */ +#define SPIMDATA_ADDR 0xfffff800 +#define SPIMDATA WORD_REF(SPIMDATA_ADDR) + +/* + * SPIM Control/Status Register + */ +#define SPIMCONT_ADDR 0xfffff802 +#define SPIMCONT WORD_REF(SPIMCONT_ADDR) + +#define SPIMCONT_BIT_COUNT_MASK 0x000f /* Transfer Length in Bytes */ +#define SPIMCONT_BIT_COUNT_SHIFT 0 +#define SPIMCONT_POL 0x0010 /* SPMCLK Signel Polarity */ +#define SPIMCONT_PHA 0x0020 /* Clock/Data phase relationship */ +#define SPIMCONT_IRQEN 0x0040 /* IRQ Enable */ +#define SPIMCONT_IRQ 0x0080 /* Interrupt Request */ +#define SPIMCONT_XCH 0x0100 /* Exchange */ +#define SPIMCONT_ENABLE 0x0200 /* Enable SPIM */ +#define SPIMCONT_DATA_RATE_MASK 0xe000 /* SPIM Data Rate */ +#define SPIMCONT_DATA_RATE_SHIFT 13 + +/* '328-compatible definitions */ +#define SPIMCONT_SPIMIRQ SPIMCONT_IRQ +#define SPIMCONT_SPIMEN SPIMCONT_ENABLE + +/********** + * + * 0xFFFFF9xx -- UART + * + **********/ + +/* + * UART Status/Control Register + */ +#define USTCNT_ADDR 0xfffff900 +#define USTCNT WORD_REF(USTCNT_ADDR) + +#define USTCNT_TXAE 0x0001 /* Transmitter Available Interrupt Enable */ +#define USTCNT_TXHE 0x0002 /* Transmitter Half Empty Enable */ +#define USTCNT_TXEE 0x0004 /* Transmitter Empty Interrupt Enable */ +#define USTCNT_RXRE 0x0008 /* Receiver Ready Interrupt Enable */ +#define USTCNT_RXHE 0x0010 /* Receiver Half-Full Interrupt Enable */ +#define USTCNT_RXFE 0x0020 /* Receiver Full Interrupt Enable */ +#define USTCNT_CTSD 0x0040 /* CTS Delta Interrupt Enable */ +#define USTCNT_ODEN 0x0080 /* Old Data Interrupt Enable */ +#define USTCNT_8_7 0x0100 /* Eight or seven-bit transmission */ +#define USTCNT_STOP 0x0200 /* Stop bit transmission */ +#define USTCNT_ODD 0x0400 /* Odd Parity */ +#define USTCNT_PEN 0x0800 /* Parity Enable */ +#define USTCNT_CLKM 0x1000 /* Clock Mode Select */ +#define USTCNT_TXEN 0x2000 /* Transmitter Enable */ +#define USTCNT_RXEN 0x4000 /* Receiver Enable */ +#define USTCNT_UEN 0x8000 /* UART Enable */ + +/* '328-compatible definitions */ +#define USTCNT_TXAVAILEN USTCNT_TXAE +#define USTCNT_TXHALFEN USTCNT_TXHE +#define USTCNT_TXEMPTYEN USTCNT_TXEE +#define USTCNT_RXREADYEN USTCNT_RXRE +#define USTCNT_RXHALFEN USTCNT_RXHE +#define USTCNT_RXFULLEN USTCNT_RXFE +#define USTCNT_CTSDELTAEN USTCNT_CTSD +#define USTCNT_ODD_EVEN USTCNT_ODD +#define USTCNT_PARITYEN USTCNT_PEN +#define USTCNT_CLKMODE USTCNT_CLKM +#define USTCNT_UARTEN USTCNT_UEN + +/* + * UART Baud Control Register + */ +#define UBAUD_ADDR 0xfffff902 +#define UBAUD WORD_REF(UBAUD_ADDR) + +#define UBAUD_PRESCALER_MASK 0x003f /* Actual divisor is 65 - PRESCALER */ +#define UBAUD_PRESCALER_SHIFT 0 +#define UBAUD_DIVIDE_MASK 0x0700 /* Baud Rate freq. divizor */ +#define UBAUD_DIVIDE_SHIFT 8 +#define UBAUD_BAUD_SRC 0x0800 /* Baud Rate Source */ +#define UBAUD_UCLKDIR 0x2000 /* UCLK Direction */ + +/* + * UART Receiver Register + */ +#define URX_ADDR 0xfffff904 +#define URX WORD_REF(URX_ADDR) + +#define URX_RXDATA_ADDR 0xfffff905 +#define URX_RXDATA BYTE_REF(URX_RXDATA_ADDR) + +#define URX_RXDATA_MASK 0x00ff /* Received data */ +#define URX_RXDATA_SHIFT 0 +#define URX_PARITY_ERROR 0x0100 /* Parity Error */ +#define URX_BREAK 0x0200 /* Break Detected */ +#define URX_FRAME_ERROR 0x0400 /* Framing Error */ +#define URX_OVRUN 0x0800 /* Serial Overrun */ +#define URX_OLD_DATA 0x1000 /* Old data in FIFO */ +#define URX_DATA_READY 0x2000 /* Data Ready (FIFO not empty) */ +#define URX_FIFO_HALF 0x4000 /* FIFO is Half-Full */ +#define URX_FIFO_FULL 0x8000 /* FIFO is Full */ + +/* + * UART Transmitter Register + */ +#define UTX_ADDR 0xfffff906 +#define UTX WORD_REF(UTX_ADDR) + +#define UTX_TXDATA_ADDR 0xfffff907 +#define UTX_TXDATA BYTE_REF(UTX_TXDATA_ADDR) + +#define UTX_TXDATA_MASK 0x00ff /* Data to be transmitted */ +#define UTX_TXDATA_SHIFT 0 +#define UTX_CTS_DELTA 0x0100 /* CTS changed */ +#define UTX_CTS_STAT 0x0200 /* CTS State */ +#define UTX_BUSY 0x0400 /* FIFO is busy, sending a character */ +#define UTX_NOCTS 0x0800 /* Ignore CTS */ +#define UTX_SEND_BREAK 0x1000 /* Send a BREAK */ +#define UTX_TX_AVAIL 0x2000 /* Transmit FIFO has a slot available */ +#define UTX_FIFO_HALF 0x4000 /* Transmit FIFO is half empty */ +#define UTX_FIFO_EMPTY 0x8000 /* Transmit FIFO is empty */ + +/* '328-compatible definitions */ +#define UTX_CTS_STATUS UTX_CTS_STAT +#define UTX_IGNORE_CTS UTX_NOCTS + +/* + * UART Miscellaneous Register + */ +#define UMISC_ADDR 0xfffff908 +#define UMISC WORD_REF(UMISC_ADDR) + +#define UMISC_TX_POL 0x0004 /* Transmit Polarity */ +#define UMISC_RX_POL 0x0008 /* Receive Polarity */ +#define UMISC_IRDA_LOOP 0x0010 /* IrDA Loopback Enable */ +#define UMISC_IRDA_EN 0x0020 /* Infra-Red Enable */ +#define UMISC_RTS 0x0040 /* Set RTS status */ +#define UMISC_RTSCONT 0x0080 /* Choose RTS control */ +#define UMISC_IR_TEST 0x0400 /* IRDA Test Enable */ +#define UMISC_BAUD_RESET 0x0800 /* Reset Baud Rate Generation Counters */ +#define UMISC_LOOP 0x1000 /* Serial Loopback Enable */ +#define UMISC_FORCE_PERR 0x2000 /* Force Parity Error */ +#define UMISC_CLKSRC 0x4000 /* Clock Source */ +#define UMISC_BAUD_TEST 0x8000 /* Enable Baud Test Mode */ + +/* + * UART Non-integer Prescaler Register + */ +#define NIPR_ADDR 0xfffff90a +#define NIPR WORD_REF(NIPR_ADDR) + +#define NIPR_STEP_VALUE_MASK 0x00ff /* NI prescaler step value */ +#define NIPR_STEP_VALUE_SHIFT 0 +#define NIPR_SELECT_MASK 0x0700 /* Tap Selection */ +#define NIPR_SELECT_SHIFT 8 +#define NIPR_PRE_SEL 0x8000 /* Non-integer prescaler select */ + + +/* generalization of uart control registers to support multiple ports: */ +typedef volatile struct { + volatile unsigned short int ustcnt; + volatile unsigned short int ubaud; + union { + volatile unsigned short int w; + struct { + volatile unsigned char status; + volatile unsigned char rxdata; + } b; + } urx; + union { + volatile unsigned short int w; + struct { + volatile unsigned char status; + volatile unsigned char txdata; + } b; + } utx; + volatile unsigned short int umisc; + volatile unsigned short int nipr; + volatile unsigned short int pad1; + volatile unsigned short int pad2; +} m68328_uart __attribute__((packed)); + + +/********** + * + * 0xFFFFFAxx -- LCD Controller + * + **********/ + +/* + * LCD Screen Starting Address Register + */ +#define LSSA_ADDR 0xfffffa00 +#define LSSA LONG_REF(LSSA_ADDR) + +#define LSSA_SSA_MASK 0x1ffffffe /* Bits 0 and 29-31 are reserved */ + +/* + * LCD Virtual Page Width Register + */ +#define LVPW_ADDR 0xfffffa05 +#define LVPW BYTE_REF(LVPW_ADDR) + +/* + * LCD Screen Width Register (not compatible with '328 !!!) + */ +#define LXMAX_ADDR 0xfffffa08 +#define LXMAX WORD_REF(LXMAX_ADDR) + +#define LXMAX_XM_MASK 0x02f0 /* Bits 0-3 and 10-15 are reserved */ + +/* + * LCD Screen Height Register + */ +#define LYMAX_ADDR 0xfffffa0a +#define LYMAX WORD_REF(LYMAX_ADDR) + +#define LYMAX_YM_MASK 0x01ff /* Bits 9-15 are reserved */ + +/* + * LCD Cursor X Position Register + */ +#define LCXP_ADDR 0xfffffa18 +#define LCXP WORD_REF(LCXP_ADDR) + +#define LCXP_CC_MASK 0xc000 /* Cursor Control */ +#define LCXP_CC_TRAMSPARENT 0x0000 +#define LCXP_CC_BLACK 0x4000 +#define LCXP_CC_REVERSED 0x8000 +#define LCXP_CC_WHITE 0xc000 +#define LCXP_CXP_MASK 0x02ff /* Cursor X position */ + +/* + * LCD Cursor Y Position Register + */ +#define LCYP_ADDR 0xfffffa1a +#define LCYP WORD_REF(LCYP_ADDR) + +#define LCYP_CYP_MASK 0x01ff /* Cursor Y Position */ + +/* + * LCD Cursor Width and Heigth Register + */ +#define LCWCH_ADDR 0xfffffa1c +#define LCWCH WORD_REF(LCWCH_ADDR) + +#define LCWCH_CH_MASK 0x001f /* Cursor Height */ +#define LCWCH_CH_SHIFT 0 +#define LCWCH_CW_MASK 0x1f00 /* Cursor Width */ +#define LCWCH_CW_SHIFT 8 + +/* + * LCD Blink Control Register + */ +#define LBLKC_ADDR 0xfffffa1f +#define LBLKC BYTE_REF(LBLKC_ADDR) + +#define LBLKC_BD_MASK 0x7f /* Blink Divisor */ +#define LBLKC_BD_SHIFT 0 +#define LBLKC_BKEN 0x80 /* Blink Enabled */ + +/* + * LCD Panel Interface Configuration Register + */ +#define LPICF_ADDR 0xfffffa20 +#define LPICF BYTE_REF(LPICF_ADDR) + +#define LPICF_GS_MASK 0x03 /* Gray-Scale Mode */ +#define LPICF_GS_BW 0x00 +#define LPICF_GS_GRAY_4 0x01 +#define LPICF_GS_GRAY_16 0x02 +#define LPICF_PBSIZ_MASK 0x0c /* Panel Bus Width */ +#define LPICF_PBSIZ_1 0x00 +#define LPICF_PBSIZ_2 0x04 +#define LPICF_PBSIZ_4 0x08 + +/* + * LCD Polarity Configuration Register + */ +#define LPOLCF_ADDR 0xfffffa21 +#define LPOLCF BYTE_REF(LPOLCF_ADDR) + +#define LPOLCF_PIXPOL 0x01 /* Pixel Polarity */ +#define LPOLCF_LPPOL 0x02 /* Line Pulse Polarity */ +#define LPOLCF_FLMPOL 0x04 /* Frame Marker Polarity */ +#define LPOLCF_LCKPOL 0x08 /* LCD Shift Lock Polarity */ + +/* + * LACD (LCD Alternate Crystal Direction) Rate Control Register + */ +#define LACDRC_ADDR 0xfffffa23 +#define LACDRC BYTE_REF(LACDRC_ADDR) + +#define LACDRC_ACDSLT 0x80 /* Signal Source Select */ +#define LACDRC_ACD_MASK 0x0f /* Alternate Crystal Direction Control */ +#define LACDRC_ACD_SHIFT 0 + +/* + * LCD Pixel Clock Divider Register + */ +#define LPXCD_ADDR 0xfffffa25 +#define LPXCD BYTE_REF(LPXCD_ADDR) + +#define LPXCD_PCD_MASK 0x3f /* Pixel Clock Divider */ +#define LPXCD_PCD_SHIFT 0 + +/* + * LCD Clocking Control Register + */ +#define LCKCON_ADDR 0xfffffa27 +#define LCKCON BYTE_REF(LCKCON_ADDR) + +#define LCKCON_DWS_MASK 0x0f /* Display Wait-State */ +#define LCKCON_DWS_SHIFT 0 +#define LCKCON_DWIDTH 0x40 /* Display Memory Width */ +#define LCKCON_LCDON 0x80 /* Enable LCD Controller */ + +/* '328-compatible definitions */ +#define LCKCON_DW_MASK LCKCON_DWS_MASK +#define LCKCON_DW_SHIFT LCKCON_DWS_SHIFT + +/* + * LCD Refresh Rate Adjustment Register + */ +#define LRRA_ADDR 0xfffffa29 +#define LRRA BYTE_REF(LRRA_ADDR) + +/* + * LCD Panning Offset Register + */ +#define LPOSR_ADDR 0xfffffa2d +#define LPOSR BYTE_REF(LPOSR_ADDR) + +#define LPOSR_POS_MASK 0x0f /* Pixel Offset Code */ +#define LPOSR_POS_SHIFT 0 + +/* + * LCD Frame Rate Control Modulation Register + */ +#define LFRCM_ADDR 0xfffffa31 +#define LFRCM BYTE_REF(LFRCM_ADDR) + +#define LFRCM_YMOD_MASK 0x0f /* Vertical Modulation */ +#define LFRCM_YMOD_SHIFT 0 +#define LFRCM_XMOD_MASK 0xf0 /* Horizontal Modulation */ +#define LFRCM_XMOD_SHIFT 4 + +/* + * LCD Gray Palette Mapping Register + */ +#define LGPMR_ADDR 0xfffffa33 +#define LGPMR BYTE_REF(LGPMR_ADDR) + +#define LGPMR_G1_MASK 0x0f +#define LGPMR_G1_SHIFT 0 +#define LGPMR_G2_MASK 0xf0 +#define LGPMR_G2_SHIFT 4 + +/* + * PWM Contrast Control Register + */ +#define PWMR_ADDR 0xfffffa36 +#define PWMR WORD_REF(PWMR_ADDR) + +#define PWMR_PW_MASK 0x00ff /* Pulse Width */ +#define PWMR_PW_SHIFT 0 +#define PWMR_CCPEN 0x0100 /* Contrast Control Enable */ +#define PWMR_SRC_MASK 0x0600 /* Input Clock Source */ +#define PWMR_SRC_LINE 0x0000 /* Line Pulse */ +#define PWMR_SRC_PIXEL 0x0200 /* Pixel Clock */ +#define PWMR_SRC_LCD 0x4000 /* LCD clock */ + +/********** + * + * 0xFFFFFBxx -- Real-Time Clock (RTC) + * + **********/ + +/* + * RTC Hours Minutes and Seconds Register + */ +#define RTCTIME_ADDR 0xfffffb00 +#define RTCTIME LONG_REF(RTCTIME_ADDR) + +#define RTCTIME_SECONDS_MASK 0x0000003f /* Seconds */ +#define RTCTIME_SECONDS_SHIFT 0 +#define RTCTIME_MINUTES_MASK 0x003f0000 /* Minutes */ +#define RTCTIME_MINUTES_SHIFT 16 +#define RTCTIME_HOURS_MASK 0x1f000000 /* Hours */ +#define RTCTIME_HOURS_SHIFT 24 + +/* + * RTC Alarm Register + */ +#define RTCALRM_ADDR 0xfffffb04 +#define RTCALRM LONG_REF(RTCALRM_ADDR) + +#define RTCALRM_SECONDS_MASK 0x0000003f /* Seconds */ +#define RTCALRM_SECONDS_SHIFT 0 +#define RTCALRM_MINUTES_MASK 0x003f0000 /* Minutes */ +#define RTCALRM_MINUTES_SHIFT 16 +#define RTCALRM_HOURS_MASK 0x1f000000 /* Hours */ +#define RTCALRM_HOURS_SHIFT 24 + +/* + * Watchdog Timer Register + */ +#define WATCHDOG_ADDR 0xfffffb0a +#define WATCHDOG WORD_REF(WATCHDOG_ADDR) + +#define WATCHDOG_EN 0x0001 /* Watchdog Enabled */ +#define WATCHDOG_ISEL 0x0002 /* Select the watchdog interrupt */ +#define WATCHDOG_INTF 0x0080 /* Watchdog interrupt occcured */ +#define WATCHDOG_CNT_MASK 0x0300 /* Watchdog Counter */ +#define WATCHDOG_CNT_SHIFT 8 + +/* + * RTC Control Register + */ +#define RTCCTL_ADDR 0xfffffb0c +#define RTCCTL WORD_REF(RTCCTL_ADDR) + +#define RTCCTL_XTL 0x0020 /* Crystal Selection */ +#define RTCCTL_EN 0x0080 /* RTC Enable */ + +/* '328-compatible definitions */ +#define RTCCTL_384 RTCCTL_XTL +#define RTCCTL_ENABLE RTCCTL_EN + +/* + * RTC Interrupt Status Register + */ +#define RTCISR_ADDR 0xfffffb0e +#define RTCISR WORD_REF(RTCISR_ADDR) + +#define RTCISR_SW 0x0001 /* Stopwatch timed out */ +#define RTCISR_MIN 0x0002 /* 1-minute interrupt has occured */ +#define RTCISR_ALM 0x0004 /* Alarm interrupt has occured */ +#define RTCISR_DAY 0x0008 /* 24-hour rollover interrupt has occured */ +#define RTCISR_1HZ 0x0010 /* 1Hz interrupt has occured */ +#define RTCISR_HR 0x0020 /* 1-hour interrupt has occured */ +#define RTCISR_SAM0 0x0100 /* 4Hz / 4.6875Hz interrupt has occured */ +#define RTCISR_SAM1 0x0200 /* 8Hz / 9.3750Hz interrupt has occured */ +#define RTCISR_SAM2 0x0400 /* 16Hz / 18.7500Hz interrupt has occured */ +#define RTCISR_SAM3 0x0800 /* 32Hz / 37.5000Hz interrupt has occured */ +#define RTCISR_SAM4 0x1000 /* 64Hz / 75.0000Hz interrupt has occured */ +#define RTCISR_SAM5 0x2000 /* 128Hz / 150.0000Hz interrupt has occured */ +#define RTCISR_SAM6 0x4000 /* 256Hz / 300.0000Hz interrupt has occured */ +#define RTCISR_SAM7 0x8000 /* 512Hz / 600.0000Hz interrupt has occured */ + +/* + * RTC Interrupt Enable Register + */ +#define RTCIENR_ADDR 0xfffffb10 +#define RTCIENR WORD_REF(RTCIENR_ADDR) + +#define RTCIENR_SW 0x0001 /* Stopwatch interrupt enable */ +#define RTCIENR_MIN 0x0002 /* 1-minute interrupt enable */ +#define RTCIENR_ALM 0x0004 /* Alarm interrupt enable */ +#define RTCIENR_DAY 0x0008 /* 24-hour rollover interrupt enable */ +#define RTCIENR_1HZ 0x0010 /* 1Hz interrupt enable */ +#define RTCIENR_HR 0x0020 /* 1-hour interrupt enable */ +#define RTCIENR_SAM0 0x0100 /* 4Hz / 4.6875Hz interrupt enable */ +#define RTCIENR_SAM1 0x0200 /* 8Hz / 9.3750Hz interrupt enable */ +#define RTCIENR_SAM2 0x0400 /* 16Hz / 18.7500Hz interrupt enable */ +#define RTCIENR_SAM3 0x0800 /* 32Hz / 37.5000Hz interrupt enable */ +#define RTCIENR_SAM4 0x1000 /* 64Hz / 75.0000Hz interrupt enable */ +#define RTCIENR_SAM5 0x2000 /* 128Hz / 150.0000Hz interrupt enable */ +#define RTCIENR_SAM6 0x4000 /* 256Hz / 300.0000Hz interrupt enable */ +#define RTCIENR_SAM7 0x8000 /* 512Hz / 600.0000Hz interrupt enable */ + +/* + * Stopwatch Minutes Register + */ +#define STPWCH_ADDR 0xfffffb12 +#define STPWCH WORD_REF(STPWCH) + +#define STPWCH_CNT_MASK 0x003f /* Stopwatch countdown value */ +#define SPTWCH_CNT_SHIFT 0 + +/* + * RTC Day Count Register + */ +#define DAYR_ADDR 0xfffffb1a +#define DAYR WORD_REF(DAYR_ADDR) + +#define DAYR_DAYS_MASK 0x1ff /* Day Setting */ +#define DAYR_DAYS_SHIFT 0 + +/* + * RTC Day Alarm Register + */ +#define DAYALARM_ADDR 0xfffffb1c +#define DAYALARM WORD_REF(DAYALARM_ADDR) + +#define DAYALARM_DAYSAL_MASK 0x01ff /* Day Setting of the Alarm */ +#define DAYALARM_DAYSAL_SHIFT 0 + +/********** + * + * 0xFFFFFCxx -- DRAM Controller + * + **********/ + +/* + * DRAM Memory Configuration Register + */ +#define DRAMMC_ADDR 0xfffffc00 +#define DRAMMC WORD_REF(DRAMMC_ADDR) + +#define DRAMMC_ROW12_MASK 0xc000 /* Row address bit for MD12 */ +#define DRAMMC_ROW12_PA10 0x0000 +#define DRAMMC_ROW12_PA21 0x4000 +#define DRAMMC_ROW12_PA23 0x8000 +#define DRAMMC_ROW0_MASK 0x3000 /* Row address bit for MD0 */ +#define DRAMMC_ROW0_PA11 0x0000 +#define DRAMMC_ROW0_PA22 0x1000 +#define DRAMMC_ROW0_PA23 0x2000 +#define DRAMMC_ROW11 0x0800 /* Row address bit for MD11 PA20/PA22 */ +#define DRAMMC_ROW10 0x0400 /* Row address bit for MD10 PA19/PA21 */ +#define DRAMMC_ROW9 0x0200 /* Row address bit for MD9 PA9/PA19 */ +#define DRAMMC_ROW8 0x0100 /* Row address bit for MD8 PA10/PA20 */ +#define DRAMMC_COL10 0x0080 /* Col address bit for MD10 PA11/PA0 */ +#define DRAMMC_COL9 0x0040 /* Col address bit for MD9 PA10/PA0 */ +#define DRAMMC_COL8 0x0020 /* Col address bit for MD8 PA9/PA0 */ +#define DRAMMC_REF_MASK 0x001f /* Reresh Cycle */ +#define DRAMMC_REF_SHIFT 0 + +/* + * DRAM Control Register + */ +#define DRAMC_ADDR 0xfffffc02 +#define DRAMC WORD_REF(DRAMC_ADDR) + +#define DRAMC_DWE 0x0001 /* DRAM Write Enable */ +#define DRAMC_RST 0x0002 /* Reset Burst Refresh Enable */ +#define DRAMC_LPR 0x0004 /* Low-Power Refresh Enable */ +#define DRAMC_SLW 0x0008 /* Slow RAM */ +#define DRAMC_LSP 0x0010 /* Light Sleep */ +#define DRAMC_MSW 0x0020 /* Slow Multiplexing */ +#define DRAMC_WS_MASK 0x00c0 /* Wait-states */ +#define DRAMC_WS_SHIFT 6 +#define DRAMC_PGSZ_MASK 0x0300 /* Page Size for fast page mode */ +#define DRAMC_PGSZ_SHIFT 8 +#define DRAMC_PGSZ_256K 0x0000 +#define DRAMC_PGSZ_512K 0x0100 +#define DRAMC_PGSZ_1024K 0x0200 +#define DRAMC_PGSZ_2048K 0x0300 +#define DRAMC_EDO 0x0400 /* EDO DRAM */ +#define DRAMC_CLK 0x0800 /* Refresh Timer Clock source select */ +#define DRAMC_BC_MASK 0x3000 /* Page Access Clock Cycle (FP mode) */ +#define DRAMC_BC_SHIFT 12 +#define DRAMC_RM 0x4000 /* Refresh Mode */ +#define DRAMC_EN 0x8000 /* DRAM Controller enable */ + + +/********** + * + * 0xFFFFFDxx -- In-Circuit Emulation (ICE) + * + **********/ + +/* + * ICE Module Address Compare Register + */ +#define ICEMACR_ADDR 0xfffffd00 +#define ICEMACR LONG_REF(ICEMACR_ADDR) + +/* + * ICE Module Address Mask Register + */ +#define ICEMAMR_ADDR 0xfffffd04 +#define ICEMAMR LONG_REF(ICEMAMR_ADDR) + +/* + * ICE Module Control Compare Register + */ +#define ICEMCCR_ADDR 0xfffffd08 +#define ICEMCCR WORD_REF(ICEMCCR_ADDR) + +#define ICEMCCR_PD 0x0001 /* Program/Data Cycle Selection */ +#define ICEMCCR_RW 0x0002 /* Read/Write Cycle Selection */ + +/* + * ICE Module Control Mask Register + */ +#define ICEMCMR_ADDR 0xfffffd0a +#define ICEMCMR WORD_REF(ICEMCMR_ADDR) + +#define ICEMCMR_PDM 0x0001 /* Program/Data Cycle Mask */ +#define ICEMCMR_RWM 0x0002 /* Read/Write Cycle Mask */ + +/* + * ICE Module Control Register + */ +#define ICEMCR_ADDR 0xfffffd0c +#define ICEMCR WORD_REF(ICEMCR_ADDR) + +#define ICEMCR_CEN 0x0001 /* Compare Enable */ +#define ICEMCR_PBEN 0x0002 /* Program Break Enable */ +#define ICEMCR_SB 0x0004 /* Single Breakpoint */ +#define ICEMCR_HMDIS 0x0008 /* HardMap disable */ +#define ICEMCR_BBIEN 0x0010 /* Bus Break Interrupt Enable */ + +/* + * ICE Module Status Register + */ +#define ICEMSR_ADDR 0xfffffd0e +#define ICEMSR WORD_REF(ICEMSR_ADDR) + +#define ICEMSR_EMUEN 0x0001 /* Emulation Enable */ +#define ICEMSR_BRKIRQ 0x0002 /* A-Line Vector Fetch Detected */ +#define ICEMSR_BBIRQ 0x0004 /* Bus Break Interrupt Detected */ +#define ICEMSR_EMIRQ 0x0008 /* EMUIRQ Falling Edge Detected */ + +#endif /* _MC68EZ328_H_ */ diff -Nru a/include/asm-m68knommu/MC68VZ328.h b/include/asm-m68knommu/MC68VZ328.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/MC68VZ328.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,1349 @@ + +/* include/asm-m68knommu/MC68VZ328.h: 'VZ328 control registers + * + * Copyright (c) 2000-2001 Lineo Inc. + * Copyright (c) 2000-2001 Lineo Canada Corp. + * Copyright (C) 1999 Vladimir Gurevich + * Bare & Hare Software, Inc. + * Based on include/asm-m68knommu/MC68332.h + * Copyright (C) 1998 Kenneth Albanowski , + * The Silver Hammer Group, Ltd. + * + * M68VZ328 fixes by Evan Stawnyczy + * vz multiport fixes by Michael Leslie + */ + +#ifndef _MC68VZ328_H_ +#define _MC68VZ328_H_ + +#define BYTE_REF(addr) (*((volatile unsigned char*)addr)) +#define WORD_REF(addr) (*((volatile unsigned short*)addr)) +#define LONG_REF(addr) (*((volatile unsigned long*)addr)) + +#define PUT_FIELD(field, val) (((val) << field##_SHIFT) & field##_MASK) +#define GET_FIELD(reg, field) (((reg) & field##_MASK) >> field##_SHIFT) + +/********** + * + * 0xFFFFF0xx -- System Control + * + **********/ + +/* + * System Control Register (SCR) + */ +#define SCR_ADDR 0xfffff000 +#define SCR BYTE_REF(SCR_ADDR) + +#define SCR_WDTH8 0x01 /* 8-Bit Width Select */ +#define SCR_DMAP 0x04 /* Double Map */ +#define SCR_SO 0x08 /* Supervisor Only */ +#define SCR_BETEN 0x10 /* Bus-Error Time-Out Enable */ +#define SCR_PRV 0x20 /* Privilege Violation */ +#define SCR_WPV 0x40 /* Write Protect Violation */ +#define SCR_BETO 0x80 /* Bus-Error TimeOut */ + +/* + * Silicon ID Register (Mask Revision Register (MRR) for '328 Compatibility) + */ +#define MRR_ADDR 0xfffff004 +#define MRR LONG_REF(MRR_ADDR) + +/********** + * + * 0xFFFFF1xx -- Chip-Select logic + * + **********/ + +/* + * Chip Select Group Base Registers + */ +#define CSGBA_ADDR 0xfffff100 +#define CSGBB_ADDR 0xfffff102 + +#define CSGBC_ADDR 0xfffff104 +#define CSGBD_ADDR 0xfffff106 + +#define CSGBA WORD_REF(CSGBA_ADDR) +#define CSGBB WORD_REF(CSGBB_ADDR) +#define CSGBC WORD_REF(CSGBC_ADDR) +#define CSGBD WORD_REF(CSGBD_ADDR) + +/* + * Chip Select Registers + */ +#define CSA_ADDR 0xfffff110 +#define CSB_ADDR 0xfffff112 +#define CSC_ADDR 0xfffff114 +#define CSD_ADDR 0xfffff116 + +#define CSA WORD_REF(CSA_ADDR) +#define CSB WORD_REF(CSB_ADDR) +#define CSC WORD_REF(CSC_ADDR) +#define CSD WORD_REF(CSD_ADDR) + +#define CSA_EN 0x0001 /* Chip-Select Enable */ +#define CSA_SIZ_MASK 0x000e /* Chip-Select Size */ +#define CSA_SIZ_SHIFT 1 +#define CSA_WS_MASK 0x0070 /* Wait State */ +#define CSA_WS_SHIFT 4 +#define CSA_BSW 0x0080 /* Data Bus Width */ +#define CSA_FLASH 0x0100 /* FLASH Memory Support */ +#define CSA_RO 0x8000 /* Read-Only */ + +#define CSB_EN 0x0001 /* Chip-Select Enable */ +#define CSB_SIZ_MASK 0x000e /* Chip-Select Size */ +#define CSB_SIZ_SHIFT 1 +#define CSB_WS_MASK 0x0070 /* Wait State */ +#define CSB_WS_SHIFT 4 +#define CSB_BSW 0x0080 /* Data Bus Width */ +#define CSB_FLASH 0x0100 /* FLASH Memory Support */ +#define CSB_UPSIZ_MASK 0x1800 /* Unprotected memory block size */ +#define CSB_UPSIZ_SHIFT 11 +#define CSB_ROP 0x2000 /* Readonly if protected */ +#define CSB_SOP 0x4000 /* Supervisor only if protected */ +#define CSB_RO 0x8000 /* Read-Only */ + +#define CSC_EN 0x0001 /* Chip-Select Enable */ +#define CSC_SIZ_MASK 0x000e /* Chip-Select Size */ +#define CSC_SIZ_SHIFT 1 +#define CSC_WS_MASK 0x0070 /* Wait State */ +#define CSC_WS_SHIFT 4 +#define CSC_BSW 0x0080 /* Data Bus Width */ +#define CSC_FLASH 0x0100 /* FLASH Memory Support */ +#define CSC_UPSIZ_MASK 0x1800 /* Unprotected memory block size */ +#define CSC_UPSIZ_SHIFT 11 +#define CSC_ROP 0x2000 /* Readonly if protected */ +#define CSC_SOP 0x4000 /* Supervisor only if protected */ +#define CSC_RO 0x8000 /* Read-Only */ + +#define CSD_EN 0x0001 /* Chip-Select Enable */ +#define CSD_SIZ_MASK 0x000e /* Chip-Select Size */ +#define CSD_SIZ_SHIFT 1 +#define CSD_WS_MASK 0x0070 /* Wait State */ +#define CSD_WS_SHIFT 4 +#define CSD_BSW 0x0080 /* Data Bus Width */ +#define CSD_FLASH 0x0100 /* FLASH Memory Support */ +#define CSD_DRAM 0x0200 /* Dram Selection */ +#define CSD_COMB 0x0400 /* Combining */ +#define CSD_UPSIZ_MASK 0x1800 /* Unprotected memory block size */ +#define CSD_UPSIZ_SHIFT 11 +#define CSD_ROP 0x2000 /* Readonly if protected */ +#define CSD_SOP 0x4000 /* Supervisor only if protected */ +#define CSD_RO 0x8000 /* Read-Only */ + +/* + * Emulation Chip-Select Register + */ +#define EMUCS_ADDR 0xfffff118 +#define EMUCS WORD_REF(EMUCS_ADDR) + +#define EMUCS_WS_MASK 0x0070 +#define EMUCS_WS_SHIFT 4 + +/********** + * + * 0xFFFFF2xx -- Phase Locked Loop (PLL) & Power Control + * + **********/ + +/* + * PLL Control Register + */ +#define PLLCR_ADDR 0xfffff200 +#define PLLCR WORD_REF(PLLCR_ADDR) + +#define PLLCR_DISPLL 0x0008 /* Disable PLL */ +#define PLLCR_CLKEN 0x0010 /* Clock (CLKO pin) enable */ +#define PLLCR_PRESC 0x0020 /* VCO prescaler */ +#define PLLCR_SYSCLK_SEL_MASK 0x0700 /* System Clock Selection */ +#define PLLCR_SYSCLK_SEL_SHIFT 8 +#define PLLCR_LCDCLK_SEL_MASK 0x3800 /* LCD Clock Selection */ +#define PLLCR_LCDCLK_SEL_SHIFT 11 + +/* '328-compatible definitions */ +#define PLLCR_PIXCLK_SEL_MASK PLLCR_LCDCLK_SEL_MASK +#define PLLCR_PIXCLK_SEL_SHIFT PLLCR_LCDCLK_SEL_SHIFT + +/* + * PLL Frequency Select Register + */ +#define PLLFSR_ADDR 0xfffff202 +#define PLLFSR WORD_REF(PLLFSR_ADDR) + +#define PLLFSR_PC_MASK 0x00ff /* P Count */ +#define PLLFSR_PC_SHIFT 0 +#define PLLFSR_QC_MASK 0x0f00 /* Q Count */ +#define PLLFSR_QC_SHIFT 8 +#define PLLFSR_PROT 0x4000 /* Protect P & Q */ +#define PLLFSR_CLK32 0x8000 /* Clock 32 (kHz) */ + +/* + * Power Control Register + */ +#define PCTRL_ADDR 0xfffff207 +#define PCTRL BYTE_REF(PCTRL_ADDR) + +#define PCTRL_WIDTH_MASK 0x1f /* CPU Clock bursts width */ +#define PCTRL_WIDTH_SHIFT 0 +#define PCTRL_PCEN 0x80 /* Power Control Enable */ + +/********** + * + * 0xFFFFF3xx -- Interrupt Controller + * + **********/ + +/* + * Interrupt Vector Register + */ +#define IVR_ADDR 0xfffff300 +#define IVR BYTE_REF(IVR_ADDR) + +#define IVR_VECTOR_MASK 0xF8 + +/* + * Interrupt control Register + */ +#define ICR_ADDR 0xfffff302 +#define ICR WORD_REF(ICR_ADDR) + +#define ICR_POL5 0x0080 /* Polarity Control for IRQ5 */ +#define ICR_ET6 0x0100 /* Edge Trigger Select for IRQ6 */ +#define ICR_ET3 0x0200 /* Edge Trigger Select for IRQ3 */ +#define ICR_ET2 0x0400 /* Edge Trigger Select for IRQ2 */ +#define ICR_ET1 0x0800 /* Edge Trigger Select for IRQ1 */ +#define ICR_POL6 0x1000 /* Polarity Control for IRQ6 */ +#define ICR_POL3 0x2000 /* Polarity Control for IRQ3 */ +#define ICR_POL2 0x4000 /* Polarity Control for IRQ2 */ +#define ICR_POL1 0x8000 /* Polarity Control for IRQ1 */ + +/* + * Interrupt Mask Register + */ +#define IMR_ADDR 0xfffff304 +#define IMR LONG_REF(IMR_ADDR) + +/* + * Define the names for bit positions first. This is useful for + * request_irq + */ +#define SPI2_IRQ_NUM 0 /* SPI 2 interrupt */ +#define TMR_IRQ_NUM 1 /* Timer 1 interrupt */ +#define UART1_IRQ_NUM 2 /* UART 1 interrupt */ +#define WDT_IRQ_NUM 3 /* Watchdog Timer interrupt */ +#define RTC_IRQ_NUM 4 /* RTC interrupt */ +#define TMR2_IRQ_NUM 5 /* Timer 2 interrupt */ +#define KB_IRQ_NUM 6 /* Keyboard Interrupt */ +#define PWM1_IRQ_NUM 7 /* Pulse-Width Modulator 1 int. */ +#define INT0_IRQ_NUM 8 /* External INT0 */ +#define INT1_IRQ_NUM 9 /* External INT1 */ +#define INT2_IRQ_NUM 10 /* External INT2 */ +#define INT3_IRQ_NUM 11 /* External INT3 */ +#define UART2_IRQ_NUM 12 /* UART 2 interrupt */ +#define PWM2_IRQ_NUM 13 /* Pulse-Width Modulator 1 int. */ +#define IRQ1_IRQ_NUM 16 /* IRQ1 */ +#define IRQ2_IRQ_NUM 17 /* IRQ2 */ +#define IRQ3_IRQ_NUM 18 /* IRQ3 */ +#define IRQ6_IRQ_NUM 19 /* IRQ6 */ +#define IRQ5_IRQ_NUM 20 /* IRQ5 */ +#define SPI1_IRQ_NUM 21 /* SPI 1 interrupt */ +#define SAM_IRQ_NUM 22 /* Sampling Timer for RTC */ +#define EMIQ_IRQ_NUM 23 /* Emulator Interrupt */ + +#define SPI_IRQ_NUM SPI2_IRQ_NUM + +/* '328-compatible definitions */ +#define SPIM_IRQ_NUM SPI_IRQ_NUM +#define TMR1_IRQ_NUM TMR_IRQ_NUM +#define UART_IRQ_NUM UART1_IRQ_NUM + +/* + * Here go the bitmasks themselves + */ +#define IMR_MSPI (1 << SPI_IRQ_NUM) /* Mask SPI interrupt */ +#define IMR_MTMR (1 << TMR_IRQ_NUM) /* Mask Timer interrupt */ +#define IMR_MUART (1 << UART_IRQ_NUM) /* Mask UART interrupt */ +#define IMR_MWDT (1 << WDT_IRQ_NUM) /* Mask Watchdog Timer interrupt */ +#define IMR_MRTC (1 << RTC_IRQ_NUM) /* Mask RTC interrupt */ +#define IMR_MKB (1 << KB_IRQ_NUM) /* Mask Keyboard Interrupt */ +#define IMR_MPWM (1 << PWM_IRQ_NUM) /* Mask Pulse-Width Modulator int. */ +#define IMR_MINT0 (1 << INT0_IRQ_NUM) /* Mask External INT0 */ +#define IMR_MINT1 (1 << INT1_IRQ_NUM) /* Mask External INT1 */ +#define IMR_MINT2 (1 << INT2_IRQ_NUM) /* Mask External INT2 */ +#define IMR_MINT3 (1 << INT3_IRQ_NUM) /* Mask External INT3 */ +#define IMR_MIRQ1 (1 << IRQ1_IRQ_NUM) /* Mask IRQ1 */ +#define IMR_MIRQ2 (1 << IRQ2_IRQ_NUM) /* Mask IRQ2 */ +#define IMR_MIRQ3 (1 << IRQ3_IRQ_NUM) /* Mask IRQ3 */ +#define IMR_MIRQ6 (1 << IRQ6_IRQ_NUM) /* Mask IRQ6 */ +#define IMR_MIRQ5 (1 << IRQ5_IRQ_NUM) /* Mask IRQ5 */ +#define IMR_MSAM (1 << SAM_IRQ_NUM) /* Mask Sampling Timer for RTC */ +#define IMR_MEMIQ (1 << EMIQ_IRQ_NUM) /* Mask Emulator Interrupt */ + +/* '328-compatible definitions */ +#define IMR_MSPIM IMR_MSPI +#define IMR_MTMR1 IMR_MTMR + +/* + * Interrupt Status Register + */ +#define ISR_ADDR 0xfffff30c +#define ISR LONG_REF(ISR_ADDR) + +#define ISR_SPI (1 << SPI_IRQ_NUM) /* SPI interrupt */ +#define ISR_TMR (1 << TMR_IRQ_NUM) /* Timer interrupt */ +#define ISR_UART (1 << UART_IRQ_NUM) /* UART interrupt */ +#define ISR_WDT (1 << WDT_IRQ_NUM) /* Watchdog Timer interrupt */ +#define ISR_RTC (1 << RTC_IRQ_NUM) /* RTC interrupt */ +#define ISR_KB (1 << KB_IRQ_NUM) /* Keyboard Interrupt */ +#define ISR_PWM (1 << PWM_IRQ_NUM) /* Pulse-Width Modulator interrupt */ +#define ISR_INT0 (1 << INT0_IRQ_NUM) /* External INT0 */ +#define ISR_INT1 (1 << INT1_IRQ_NUM) /* External INT1 */ +#define ISR_INT2 (1 << INT2_IRQ_NUM) /* External INT2 */ +#define ISR_INT3 (1 << INT3_IRQ_NUM) /* External INT3 */ +#define ISR_IRQ1 (1 << IRQ1_IRQ_NUM) /* IRQ1 */ +#define ISR_IRQ2 (1 << IRQ2_IRQ_NUM) /* IRQ2 */ +#define ISR_IRQ3 (1 << IRQ3_IRQ_NUM) /* IRQ3 */ +#define ISR_IRQ6 (1 << IRQ6_IRQ_NUM) /* IRQ6 */ +#define ISR_IRQ5 (1 << IRQ5_IRQ_NUM) /* IRQ5 */ +#define ISR_SAM (1 << SAM_IRQ_NUM) /* Sampling Timer for RTC */ +#define ISR_EMIQ (1 << EMIQ_IRQ_NUM) /* Emulator Interrupt */ + +/* '328-compatible definitions */ +#define ISR_SPIM ISR_SPI +#define ISR_TMR1 ISR_TMR + +/* + * Interrupt Pending Register + */ +#define IPR_ADDR 0xfffff30c +#define IPR LONG_REF(IPR_ADDR) + +#define IPR_SPI (1 << SPI_IRQ_NUM) /* SPI interrupt */ +#define IPR_TMR (1 << TMR_IRQ_NUM) /* Timer interrupt */ +#define IPR_UART (1 << UART_IRQ_NUM) /* UART interrupt */ +#define IPR_WDT (1 << WDT_IRQ_NUM) /* Watchdog Timer interrupt */ +#define IPR_RTC (1 << RTC_IRQ_NUM) /* RTC interrupt */ +#define IPR_KB (1 << KB_IRQ_NUM) /* Keyboard Interrupt */ +#define IPR_PWM (1 << PWM_IRQ_NUM) /* Pulse-Width Modulator interrupt */ +#define IPR_INT0 (1 << INT0_IRQ_NUM) /* External INT0 */ +#define IPR_INT1 (1 << INT1_IRQ_NUM) /* External INT1 */ +#define IPR_INT2 (1 << INT2_IRQ_NUM) /* External INT2 */ +#define IPR_INT3 (1 << INT3_IRQ_NUM) /* External INT3 */ +#define IPR_IRQ1 (1 << IRQ1_IRQ_NUM) /* IRQ1 */ +#define IPR_IRQ2 (1 << IRQ2_IRQ_NUM) /* IRQ2 */ +#define IPR_IRQ3 (1 << IRQ3_IRQ_NUM) /* IRQ3 */ +#define IPR_IRQ6 (1 << IRQ6_IRQ_NUM) /* IRQ6 */ +#define IPR_IRQ5 (1 << IRQ5_IRQ_NUM) /* IRQ5 */ +#define IPR_SAM (1 << SAM_IRQ_NUM) /* Sampling Timer for RTC */ +#define IPR_EMIQ (1 << EMIQ_IRQ_NUM) /* Emulator Interrupt */ + +/* '328-compatible definitions */ +#define IPR_SPIM IPR_SPI +#define IPR_TMR1 IPR_TMR + +/********** + * + * 0xFFFFF4xx -- Parallel Ports + * + **********/ + +/* + * Port A + */ +#define PADIR_ADDR 0xfffff400 /* Port A direction reg */ +#define PADATA_ADDR 0xfffff401 /* Port A data register */ +#define PAPUEN_ADDR 0xfffff402 /* Port A Pull-Up enable reg */ + +#define PADIR BYTE_REF(PADIR_ADDR) +#define PADATA BYTE_REF(PADATA_ADDR) +#define PAPUEN BYTE_REF(PAPUEN_ADDR) + +#define PA(x) (1 << (x)) + +/* + * Port B + */ +#define PBDIR_ADDR 0xfffff408 /* Port B direction reg */ +#define PBDATA_ADDR 0xfffff409 /* Port B data register */ +#define PBPUEN_ADDR 0xfffff40a /* Port B Pull-Up enable reg */ +#define PBSEL_ADDR 0xfffff40b /* Port B Select Register */ + +#define PBDIR BYTE_REF(PBDIR_ADDR) +#define PBDATA BYTE_REF(PBDATA_ADDR) +#define PBPUEN BYTE_REF(PBPUEN_ADDR) +#define PBSEL BYTE_REF(PBSEL_ADDR) + +#define PB(x) (1 << (x)) + +#define PB_CSB0 0x01 /* Use CSB0 as PB[0] */ +#define PB_CSB1 0x02 /* Use CSB1 as PB[1] */ +#define PB_CSC0_RAS0 0x04 /* Use CSC0/RAS0 as PB[2] */ +#define PB_CSC1_RAS1 0x08 /* Use CSC1/RAS1 as PB[3] */ +#define PB_CSD0_CAS0 0x10 /* Use CSD0/CAS0 as PB[4] */ +#define PB_CSD1_CAS1 0x20 /* Use CSD1/CAS1 as PB[5] */ +#define PB_TIN_TOUT 0x40 /* Use TIN/TOUT as PB[6] */ +#define PB_PWMO 0x80 /* Use PWMO as PB[7] */ + +/* + * Port C + */ +#define PCDIR_ADDR 0xfffff410 /* Port C direction reg */ +#define PCDATA_ADDR 0xfffff411 /* Port C data register */ +#define PCPDEN_ADDR 0xfffff412 /* Port C Pull-Down enb. reg */ +#define PCSEL_ADDR 0xfffff413 /* Port C Select Register */ + +#define PCDIR BYTE_REF(PCDIR_ADDR) +#define PCDATA BYTE_REF(PCDATA_ADDR) +#define PCPDEN BYTE_REF(PCPDEN_ADDR) +#define PCSEL BYTE_REF(PCSEL_ADDR) + +#define PC(x) (1 << (x)) + +#define PC_LD0 0x01 /* Use LD0 as PC[0] */ +#define PC_LD1 0x02 /* Use LD1 as PC[1] */ +#define PC_LD2 0x04 /* Use LD2 as PC[2] */ +#define PC_LD3 0x08 /* Use LD3 as PC[3] */ +#define PC_LFLM 0x10 /* Use LFLM as PC[4] */ +#define PC_LLP 0x20 /* Use LLP as PC[5] */ +#define PC_LCLK 0x40 /* Use LCLK as PC[6] */ +#define PC_LACD 0x80 /* Use LACD as PC[7] */ + +/* + * Port D + */ +#define PDDIR_ADDR 0xfffff418 /* Port D direction reg */ +#define PDDATA_ADDR 0xfffff419 /* Port D data register */ +#define PDPUEN_ADDR 0xfffff41a /* Port D Pull-Up enable reg */ +#define PDSEL_ADDR 0xfffff41b /* Port D Select Register */ +#define PDPOL_ADDR 0xfffff41c /* Port D Polarity Register */ +#define PDIRQEN_ADDR 0xfffff41d /* Port D IRQ enable register */ +#define PDKBEN_ADDR 0xfffff41e /* Port D Keyboard Enable reg */ +#define PDIQEG_ADDR 0xfffff41f /* Port D IRQ Edge Register */ + +#define PDDIR BYTE_REF(PDDIR_ADDR) +#define PDDATA BYTE_REF(PDDATA_ADDR) +#define PDPUEN BYTE_REF(PDPUEN_ADDR) +#define PDSEL BYTE_REF(PDSEL_ADDR) +#define PDPOL BYTE_REF(PDPOL_ADDR) +#define PDIRQEN BYTE_REF(PDIRQEN_ADDR) +#define PDKBEN BYTE_REF(PDKBEN_ADDR) +#define PDIQEG BYTE_REF(PDIQEG_ADDR) + +#define PD(x) (1 << (x)) + +#define PD_INT0 0x01 /* Use INT0 as PD[0] */ +#define PD_INT1 0x02 /* Use INT1 as PD[1] */ +#define PD_INT2 0x04 /* Use INT2 as PD[2] */ +#define PD_INT3 0x08 /* Use INT3 as PD[3] */ +#define PD_IRQ1 0x10 /* Use IRQ1 as PD[4] */ +#define PD_IRQ2 0x20 /* Use IRQ2 as PD[5] */ +#define PD_IRQ3 0x40 /* Use IRQ3 as PD[6] */ +#define PD_IRQ6 0x80 /* Use IRQ6 as PD[7] */ + +/* + * Port E + */ +#define PEDIR_ADDR 0xfffff420 /* Port E direction reg */ +#define PEDATA_ADDR 0xfffff421 /* Port E data register */ +#define PEPUEN_ADDR 0xfffff422 /* Port E Pull-Up enable reg */ +#define PESEL_ADDR 0xfffff423 /* Port E Select Register */ + +#define PEDIR BYTE_REF(PEDIR_ADDR) +#define PEDATA BYTE_REF(PEDATA_ADDR) +#define PEPUEN BYTE_REF(PEPUEN_ADDR) +#define PESEL BYTE_REF(PESEL_ADDR) + +#define PE(x) (1 << (x)) + +#define PE_SPMTXD 0x01 /* Use SPMTXD as PE[0] */ +#define PE_SPMRXD 0x02 /* Use SPMRXD as PE[1] */ +#define PE_SPMCLK 0x04 /* Use SPMCLK as PE[2] */ +#define PE_DWE 0x08 /* Use DWE as PE[3] */ +#define PE_RXD 0x10 /* Use RXD as PE[4] */ +#define PE_TXD 0x20 /* Use TXD as PE[5] */ +#define PE_RTS 0x40 /* Use RTS as PE[6] */ +#define PE_CTS 0x80 /* Use CTS as PE[7] */ + +/* + * Port F + */ +#define PFDIR_ADDR 0xfffff428 /* Port F direction reg */ +#define PFDATA_ADDR 0xfffff429 /* Port F data register */ +#define PFPUEN_ADDR 0xfffff42a /* Port F Pull-Up enable reg */ +#define PFSEL_ADDR 0xfffff42b /* Port F Select Register */ + +#define PFDIR BYTE_REF(PFDIR_ADDR) +#define PFDATA BYTE_REF(PFDATA_ADDR) +#define PFPUEN BYTE_REF(PFPUEN_ADDR) +#define PFSEL BYTE_REF(PFSEL_ADDR) + +#define PF(x) (1 << (x)) + +#define PF_LCONTRAST 0x01 /* Use LCONTRAST as PF[0] */ +#define PF_IRQ5 0x02 /* Use IRQ5 as PF[1] */ +#define PF_CLKO 0x04 /* Use CLKO as PF[2] */ +#define PF_A20 0x08 /* Use A20 as PF[3] */ +#define PF_A21 0x10 /* Use A21 as PF[4] */ +#define PF_A22 0x20 /* Use A22 as PF[5] */ +#define PF_A23 0x40 /* Use A23 as PF[6] */ +#define PF_CSA1 0x80 /* Use CSA1 as PF[7] */ + +/* + * Port G + */ +#define PGDIR_ADDR 0xfffff430 /* Port G direction reg */ +#define PGDATA_ADDR 0xfffff431 /* Port G data register */ +#define PGPUEN_ADDR 0xfffff432 /* Port G Pull-Up enable reg */ +#define PGSEL_ADDR 0xfffff433 /* Port G Select Register */ + +#define PGDIR BYTE_REF(PGDIR_ADDR) +#define PGDATA BYTE_REF(PGDATA_ADDR) +#define PGPUEN BYTE_REF(PGPUEN_ADDR) +#define PGSEL BYTE_REF(PGSEL_ADDR) + +#define PG(x) (1 << (x)) + +#define PG_BUSW_DTACK 0x01 /* Use BUSW/DTACK as PG[0] */ +#define PG_A0 0x02 /* Use A0 as PG[1] */ +#define PG_EMUIRQ 0x04 /* Use EMUIRQ as PG[2] */ +#define PG_HIZ_P_D 0x08 /* Use HIZ/P/D as PG[3] */ +#define PG_EMUCS 0x10 /* Use EMUCS as PG[4] */ +#define PG_EMUBRK 0x20 /* Use EMUBRK as PG[5] */ + +/* + * Port J + */ +#define PJDIR_ADDR 0xfffff438 /* Port J direction reg */ +#define PJDATA_ADDR 0xfffff439 /* Port J data register */ +#define PJPUEN_ADDR 0xfffff43A /* Port J Pull-Up enb. reg */ +#define PJSEL_ADDR 0xfffff43B /* Port J Select Register */ + +#define PJDIR BYTE_REF(PJDIR_ADDR) +#define PJDATA BYTE_REF(PJDATA_ADDR) +#define PJPUEN BYTE_REF(PJPUEN_ADDR) +#define PJSEL BYTE_REF(PJSEL_ADDR) + +#define PJ(x) (1 << (x)) + +/* + * Port K + */ +#define PKDIR_ADDR 0xfffff440 /* Port K direction reg */ +#define PKDATA_ADDR 0xfffff441 /* Port K data register */ +#define PKPUEN_ADDR 0xfffff442 /* Port K Pull-Up enb. reg */ +#define PKSEL_ADDR 0xfffff443 /* Port K Select Register */ + +#define PKDIR BYTE_REF(PKDIR_ADDR) +#define PKDATA BYTE_REF(PKDATA_ADDR) +#define PKPUEN BYTE_REF(PKPUEN_ADDR) +#define PKSEL BYTE_REF(PKSEL_ADDR) + +#define PK(x) (1 << (x)) + +#define PK_DATAREADY 0x01 /* Use ~DATA_READY as PK[0] */ +#define PK_PWM2 0x01 /* Use PWM2 as PK[0] */ +#define PK_R_W 0x02 /* Use R/W as PK[1] */ +#define PK_LDS 0x04 /* Use /LDS as PK[2] */ +#define PK_UDS 0x08 /* Use /UDS as PK[3] */ +#define PK_LD4 0x10 /* Use LD4 as PK[4] */ +#define PK_LD5 0x20 /* Use LD5 as PK[5] */ +#define PK_LD6 0x40 /* Use LD6 as PK[6] */ +#define PK_LD7 0x80 /* Use LD7 as PK[7] */ + +#define PJDIR_ADDR 0xfffff438 /* Port J direction reg */ +#define PJDATA_ADDR 0xfffff439 /* Port J data register */ +#define PJPUEN_ADDR 0xfffff43A /* Port J Pull-Up enable reg */ +#define PJSEL_ADDR 0xfffff43B /* Port J Select Register */ + +#define PJDIR BYTE_REF(PJDIR_ADDR) +#define PJDATA BYTE_REF(PJDATA_ADDR) +#define PJPUEN BYTE_REF(PJPUEN_ADDR) +#define PJSEL BYTE_REF(PJSEL_ADDR) + +#define PJ(x) (1 << (x)) + +#define PJ_MOSI 0x01 /* Use MOSI as PJ[0] */ +#define PJ_MISO 0x02 /* Use MISO as PJ[1] */ +#define PJ_SPICLK1 0x04 /* Use SPICLK1 as PJ[2] */ +#define PJ_SS 0x08 /* Use SS as PJ[3] */ +#define PJ_RXD2 0x10 /* Use RXD2 as PJ[4] */ +#define PJ_TXD2 0x20 /* Use TXD2 as PJ[5] */ +#define PJ_RTS2 0x40 /* Use RTS2 as PJ[5] */ +#define PJ_CTS2 0x80 /* Use CTS2 as PJ[5] */ + +/* + * Port M + */ +#define PMDIR_ADDR 0xfffff448 /* Port M direction reg */ +#define PMDATA_ADDR 0xfffff449 /* Port M data register */ +#define PMPUEN_ADDR 0xfffff44a /* Port M Pull-Up enable reg */ +#define PMSEL_ADDR 0xfffff44b /* Port M Select Register */ + +#define PMDIR BYTE_REF(PMDIR_ADDR) +#define PMDATA BYTE_REF(PMDATA_ADDR) +#define PMPUEN BYTE_REF(PMPUEN_ADDR) +#define PMSEL BYTE_REF(PMSEL_ADDR) + +#define PM(x) (1 << (x)) + +#define PM_SDCLK 0x01 /* Use SDCLK as PM[0] */ +#define PM_SDCE 0x02 /* Use SDCE as PM[1] */ +#define PM_DQMH 0x04 /* Use DQMH as PM[2] */ +#define PM_DQML 0x08 /* Use DQML as PM[3] */ +#define PM_SDA10 0x10 /* Use SDA10 as PM[4] */ +#define PM_DMOE 0x20 /* Use DMOE as PM[5] */ + +/********** + * + * 0xFFFFF5xx -- Pulse-Width Modulator (PWM) + * + **********/ + +/* + * PWM Control Register + */ +#define PWMC_ADDR 0xfffff500 +#define PWMC WORD_REF(PWMC_ADDR) + +#define PWMC_CLKSEL_MASK 0x0003 /* Clock Selection */ +#define PWMC_CLKSEL_SHIFT 0 +#define PWMC_REPEAT_MASK 0x000c /* Sample Repeats */ +#define PWMC_REPEAT_SHIFT 2 +#define PWMC_EN 0x0010 /* Enable PWM */ +#define PMNC_FIFOAV 0x0020 /* FIFO Available */ +#define PWMC_IRQEN 0x0040 /* Interrupt Request Enable */ +#define PWMC_IRQ 0x0080 /* Interrupt Request (FIFO empty) */ +#define PWMC_PRESCALER_MASK 0x7f00 /* Incoming Clock prescaler */ +#define PWMC_PRESCALER_SHIFT 8 +#define PWMC_CLKSRC 0x8000 /* Clock Source Select */ + +/* '328-compatible definitions */ +#define PWMC_PWMEN PWMC_EN + +/* + * PWM Sample Register + */ +#define PWMS_ADDR 0xfffff502 +#define PWMS WORD_REF(PWMS_ADDR) + +/* + * PWM Period Register + */ +#define PWMP_ADDR 0xfffff504 +#define PWMP BYTE_REF(PWMP_ADDR) + +/* + * PWM Counter Register + */ +#define PWMCNT_ADDR 0xfffff505 +#define PWMCNT BYTE_REF(PWMCNT_ADDR) + +/********** + * + * 0xFFFFF6xx -- General-Purpose Timer + * + **********/ + +/* + * Timer Control register + */ +#define TCTL_ADDR 0xfffff600 +#define TCTL WORD_REF(TCTL_ADDR) + +#define TCTL_TEN 0x0001 /* Timer Enable */ +#define TCTL_CLKSOURCE_MASK 0x000e /* Clock Source: */ +#define TCTL_CLKSOURCE_STOP 0x0000 /* Stop count (disabled) */ +#define TCTL_CLKSOURCE_SYSCLK 0x0002 /* SYSCLK to prescaler */ +#define TCTL_CLKSOURCE_SYSCLK_16 0x0004 /* SYSCLK/16 to prescaler */ +#define TCTL_CLKSOURCE_TIN 0x0006 /* TIN to prescaler */ +#define TCTL_CLKSOURCE_32KHZ 0x0008 /* 32kHz clock to prescaler */ +#define TCTL_IRQEN 0x0010 /* IRQ Enable */ +#define TCTL_OM 0x0020 /* Output Mode */ +#define TCTL_CAP_MASK 0x00c0 /* Capture Edge: */ +#define TCTL_CAP_RE 0x0040 /* Capture on rizing edge */ +#define TCTL_CAP_FE 0x0080 /* Capture on falling edge */ +#define TCTL_FRR 0x0010 /* Free-Run Mode */ + +/* '328-compatible definitions */ +#define TCTL1_ADDR TCTL_ADDR +#define TCTL1 TCTL + +/* + * Timer Prescaler Register + */ +#define TPRER_ADDR 0xfffff602 +#define TPRER WORD_REF(TPRER_ADDR) + +/* '328-compatible definitions */ +#define TPRER1_ADDR TPRER_ADDR +#define TPRER1 TPRER + +/* + * Timer Compare Register + */ +#define TCMP_ADDR 0xfffff604 +#define TCMP WORD_REF(TCMP_ADDR) + +/* '328-compatible definitions */ +#define TCMP1_ADDR TCMP_ADDR +#define TCMP1 TCMP + +/* + * Timer Capture register + */ +#define TCR_ADDR 0xfffff606 +#define TCR WORD_REF(TCR_ADDR) + +/* '328-compatible definitions */ +#define TCR1_ADDR TCR_ADDR +#define TCR1 TCR + +/* + * Timer Counter Register + */ +#define TCN_ADDR 0xfffff608 +#define TCN WORD_REF(TCN_ADDR) + +/* '328-compatible definitions */ +#define TCN1_ADDR TCN_ADDR +#define TCN1 TCN + +/* + * Timer Status Register + */ +#define TSTAT_ADDR 0xfffff60a +#define TSTAT WORD_REF(TSTAT_ADDR) + +#define TSTAT_COMP 0x0001 /* Compare Event occurred */ +#define TSTAT_CAPT 0x0001 /* Capture Event occurred */ + +/* '328-compatible definitions */ +#define TSTAT1_ADDR TSTAT_ADDR +#define TSTAT1 TSTAT + +/********** + * + * 0xFFFFF8xx -- Serial Periferial Interface Master (SPIM) + * + **********/ + +/* + * SPIM Data Register + */ +#define SPIMDATA_ADDR 0xfffff800 +#define SPIMDATA WORD_REF(SPIMDATA_ADDR) + +/* + * SPIM Control/Status Register + */ +#define SPIMCONT_ADDR 0xfffff802 +#define SPIMCONT WORD_REF(SPIMCONT_ADDR) + +#define SPIMCONT_BIT_COUNT_MASK 0x000f /* Transfer Length in Bytes */ +#define SPIMCONT_BIT_COUNT_SHIFT 0 +#define SPIMCONT_POL 0x0010 /* SPMCLK Signel Polarity */ +#define SPIMCONT_PHA 0x0020 /* Clock/Data phase relationship */ +#define SPIMCONT_IRQEN 0x0040 /* IRQ Enable */ +#define SPIMCONT_IRQ 0x0080 /* Interrupt Request */ +#define SPIMCONT_XCH 0x0100 /* Exchange */ +#define SPIMCONT_ENABLE 0x0200 /* Enable SPIM */ +#define SPIMCONT_DATA_RATE_MASK 0xe000 /* SPIM Data Rate */ +#define SPIMCONT_DATA_RATE_SHIFT 13 + +/* '328-compatible definitions */ +#define SPIMCONT_SPIMIRQ SPIMCONT_IRQ +#define SPIMCONT_SPIMEN SPIMCONT_ENABLE + +/********** + * + * 0xFFFFF9xx -- UART + * + **********/ + +/* + * UART Status/Control Register + */ + +#define USTCNT_ADDR 0xfffff900 +#define USTCNT WORD_REF(USTCNT_ADDR) + +#define USTCNT_TXAE 0x0001 /* Transmitter Available Interrupt Enable */ +#define USTCNT_TXHE 0x0002 /* Transmitter Half Empty Enable */ +#define USTCNT_TXEE 0x0004 /* Transmitter Empty Interrupt Enable */ +#define USTCNT_RXRE 0x0008 /* Receiver Ready Interrupt Enable */ +#define USTCNT_RXHE 0x0010 /* Receiver Half-Full Interrupt Enable */ +#define USTCNT_RXFE 0x0020 /* Receiver Full Interrupt Enable */ +#define USTCNT_CTSD 0x0040 /* CTS Delta Interrupt Enable */ +#define USTCNT_ODEN 0x0080 /* Old Data Interrupt Enable */ +#define USTCNT_8_7 0x0100 /* Eight or seven-bit transmission */ +#define USTCNT_STOP 0x0200 /* Stop bit transmission */ +#define USTCNT_ODD 0x0400 /* Odd Parity */ +#define USTCNT_PEN 0x0800 /* Parity Enable */ +#define USTCNT_CLKM 0x1000 /* Clock Mode Select */ +#define USTCNT_TXEN 0x2000 /* Transmitter Enable */ +#define USTCNT_RXEN 0x4000 /* Receiver Enable */ +#define USTCNT_UEN 0x8000 /* UART Enable */ + +/* '328-compatible definitions */ +#define USTCNT_TXAVAILEN USTCNT_TXAE +#define USTCNT_TXHALFEN USTCNT_TXHE +#define USTCNT_TXEMPTYEN USTCNT_TXEE +#define USTCNT_RXREADYEN USTCNT_RXRE +#define USTCNT_RXHALFEN USTCNT_RXHE +#define USTCNT_RXFULLEN USTCNT_RXFE +#define USTCNT_CTSDELTAEN USTCNT_CTSD +#define USTCNT_ODD_EVEN USTCNT_ODD +#define USTCNT_PARITYEN USTCNT_PEN +#define USTCNT_CLKMODE USTCNT_CLKM +#define USTCNT_UARTEN USTCNT_UEN + +/* + * UART Baud Control Register + */ +#define UBAUD_ADDR 0xfffff902 +#define UBAUD WORD_REF(UBAUD_ADDR) + +#define UBAUD_PRESCALER_MASK 0x003f /* Actual divisor is 65 - PRESCALER */ +#define UBAUD_PRESCALER_SHIFT 0 +#define UBAUD_DIVIDE_MASK 0x0700 /* Baud Rate freq. divizor */ +#define UBAUD_DIVIDE_SHIFT 8 +#define UBAUD_BAUD_SRC 0x0800 /* Baud Rate Source */ +#define UBAUD_UCLKDIR 0x2000 /* UCLK Direction */ + +/* + * UART Receiver Register + */ +#define URX_ADDR 0xfffff904 +#define URX WORD_REF(URX_ADDR) + +#define URX_RXDATA_ADDR 0xfffff905 +#define URX_RXDATA BYTE_REF(URX_RXDATA_ADDR) + +#define URX_RXDATA_MASK 0x00ff /* Received data */ +#define URX_RXDATA_SHIFT 0 +#define URX_PARITY_ERROR 0x0100 /* Parity Error */ +#define URX_BREAK 0x0200 /* Break Detected */ +#define URX_FRAME_ERROR 0x0400 /* Framing Error */ +#define URX_OVRUN 0x0800 /* Serial Overrun */ +#define URX_OLD_DATA 0x1000 /* Old data in FIFO */ +#define URX_DATA_READY 0x2000 /* Data Ready (FIFO not empty) */ +#define URX_FIFO_HALF 0x4000 /* FIFO is Half-Full */ +#define URX_FIFO_FULL 0x8000 /* FIFO is Full */ + +/* + * UART Transmitter Register + */ +#define UTX_ADDR 0xfffff906 +#define UTX WORD_REF(UTX_ADDR) + +#define UTX_TXDATA_ADDR 0xfffff907 +#define UTX_TXDATA BYTE_REF(UTX_TXDATA_ADDR) + +#define UTX_TXDATA_MASK 0x00ff /* Data to be transmitted */ +#define UTX_TXDATA_SHIFT 0 +#define UTX_CTS_DELTA 0x0100 /* CTS changed */ +#define UTX_CTS_STAT 0x0200 /* CTS State */ +#define UTX_BUSY 0x0400 /* FIFO is busy, sending a character */ +#define UTX_NOCTS 0x0800 /* Ignore CTS */ +#define UTX_SEND_BREAK 0x1000 /* Send a BREAK */ +#define UTX_TX_AVAIL 0x2000 /* Transmit FIFO has a slot available */ +#define UTX_FIFO_HALF 0x4000 /* Transmit FIFO is half empty */ +#define UTX_FIFO_EMPTY 0x8000 /* Transmit FIFO is empty */ + +/* '328-compatible definitions */ +#define UTX_CTS_STATUS UTX_CTS_STAT +#define UTX_IGNORE_CTS UTX_NOCTS + +/* + * UART Miscellaneous Register + */ +#define UMISC_ADDR 0xfffff908 +#define UMISC WORD_REF(UMISC_ADDR) + +#define UMISC_TX_POL 0x0004 /* Transmit Polarity */ +#define UMISC_RX_POL 0x0008 /* Receive Polarity */ +#define UMISC_IRDA_LOOP 0x0010 /* IrDA Loopback Enable */ +#define UMISC_IRDA_EN 0x0020 /* Infra-Red Enable */ +#define UMISC_RTS 0x0040 /* Set RTS status */ +#define UMISC_RTSCONT 0x0080 /* Choose RTS control */ +#define UMISC_IR_TEST 0x0400 /* IRDA Test Enable */ +#define UMISC_BAUD_RESET 0x0800 /* Reset Baud Rate Generation Counters */ +#define UMISC_LOOP 0x1000 /* Serial Loopback Enable */ +#define UMISC_FORCE_PERR 0x2000 /* Force Parity Error */ +#define UMISC_CLKSRC 0x4000 /* Clock Source */ +#define UMISC_BAUD_TEST 0x8000 /* Enable Baud Test Mode */ + +/* + * UART Non-integer Prescaler Register + */ +#define NIPR_ADDR 0xfffff90a +#define NIPR WORD_REF(NIPR_ADDR) + +#define NIPR_STEP_VALUE_MASK 0x00ff /* NI prescaler step value */ +#define NIPR_STEP_VALUE_SHIFT 0 +#define NIPR_SELECT_MASK 0x0700 /* Tap Selection */ +#define NIPR_SELECT_SHIFT 8 +#define NIPR_PRE_SEL 0x8000 /* Non-integer prescaler select */ + + +/* generalization of uart control registers to support multiple ports: */ +typedef struct { + volatile unsigned short int ustcnt; + volatile unsigned short int ubaud; + union { + volatile unsigned short int w; + struct { + volatile unsigned char status; + volatile unsigned char rxdata; + } b; + } urx; + union { + volatile unsigned short int w; + struct { + volatile unsigned char status; + volatile unsigned char txdata; + } b; + } utx; + volatile unsigned short int umisc; + volatile unsigned short int nipr; + volatile unsigned short int hmark; + volatile unsigned short int unused; +} m68328_uart __attribute__((packed)); + + + + +/********** + * + * 0xFFFFFAxx -- LCD Controller + * + **********/ + +/* + * LCD Screen Starting Address Register + */ +#define LSSA_ADDR 0xfffffa00 +#define LSSA LONG_REF(LSSA_ADDR) + +#define LSSA_SSA_MASK 0x1ffffffe /* Bits 0 and 29-31 are reserved */ + +/* + * LCD Virtual Page Width Register + */ +#define LVPW_ADDR 0xfffffa05 +#define LVPW BYTE_REF(LVPW_ADDR) + +/* + * LCD Screen Width Register (not compatible with '328 !!!) + */ +#define LXMAX_ADDR 0xfffffa08 +#define LXMAX WORD_REF(LXMAX_ADDR) + +#define LXMAX_XM_MASK 0x02f0 /* Bits 0-3 and 10-15 are reserved */ + +/* + * LCD Screen Height Register + */ +#define LYMAX_ADDR 0xfffffa0a +#define LYMAX WORD_REF(LYMAX_ADDR) + +#define LYMAX_YM_MASK 0x01ff /* Bits 9-15 are reserved */ + +/* + * LCD Cursor X Position Register + */ +#define LCXP_ADDR 0xfffffa18 +#define LCXP WORD_REF(LCXP_ADDR) + +#define LCXP_CC_MASK 0xc000 /* Cursor Control */ +#define LCXP_CC_TRAMSPARENT 0x0000 +#define LCXP_CC_BLACK 0x4000 +#define LCXP_CC_REVERSED 0x8000 +#define LCXP_CC_WHITE 0xc000 +#define LCXP_CXP_MASK 0x02ff /* Cursor X position */ + +/* + * LCD Cursor Y Position Register + */ +#define LCYP_ADDR 0xfffffa1a +#define LCYP WORD_REF(LCYP_ADDR) + +#define LCYP_CYP_MASK 0x01ff /* Cursor Y Position */ + +/* + * LCD Cursor Width and Heigth Register + */ +#define LCWCH_ADDR 0xfffffa1c +#define LCWCH WORD_REF(LCWCH_ADDR) + +#define LCWCH_CH_MASK 0x001f /* Cursor Height */ +#define LCWCH_CH_SHIFT 0 +#define LCWCH_CW_MASK 0x1f00 /* Cursor Width */ +#define LCWCH_CW_SHIFT 8 + +/* + * LCD Blink Control Register + */ +#define LBLKC_ADDR 0xfffffa1f +#define LBLKC BYTE_REF(LBLKC_ADDR) + +#define LBLKC_BD_MASK 0x7f /* Blink Divisor */ +#define LBLKC_BD_SHIFT 0 +#define LBLKC_BKEN 0x80 /* Blink Enabled */ + +/* + * LCD Panel Interface Configuration Register + */ +#define LPICF_ADDR 0xfffffa20 +#define LPICF BYTE_REF(LPICF_ADDR) + +#define LPICF_GS_MASK 0x03 /* Gray-Scale Mode */ +#define LPICF_GS_BW 0x00 +#define LPICF_GS_GRAY_4 0x01 +#define LPICF_GS_GRAY_16 0x02 +#define LPICF_PBSIZ_MASK 0x0c /* Panel Bus Width */ +#define LPICF_PBSIZ_1 0x00 +#define LPICF_PBSIZ_2 0x04 +#define LPICF_PBSIZ_4 0x08 + +/* + * LCD Polarity Configuration Register + */ +#define LPOLCF_ADDR 0xfffffa21 +#define LPOLCF BYTE_REF(LPOLCF_ADDR) + +#define LPOLCF_PIXPOL 0x01 /* Pixel Polarity */ +#define LPOLCF_LPPOL 0x02 /* Line Pulse Polarity */ +#define LPOLCF_FLMPOL 0x04 /* Frame Marker Polarity */ +#define LPOLCF_LCKPOL 0x08 /* LCD Shift Lock Polarity */ + +/* + * LACD (LCD Alternate Crystal Direction) Rate Control Register + */ +#define LACDRC_ADDR 0xfffffa23 +#define LACDRC BYTE_REF(LACDRC_ADDR) + +#define LACDRC_ACDSLT 0x80 /* Signal Source Select */ +#define LACDRC_ACD_MASK 0x0f /* Alternate Crystal Direction Control */ +#define LACDRC_ACD_SHIFT 0 + +/* + * LCD Pixel Clock Divider Register + */ +#define LPXCD_ADDR 0xfffffa25 +#define LPXCD BYTE_REF(LPXCD_ADDR) + +#define LPXCD_PCD_MASK 0x3f /* Pixel Clock Divider */ +#define LPXCD_PCD_SHIFT 0 + +/* + * LCD Clocking Control Register + */ +#define LCKCON_ADDR 0xfffffa27 +#define LCKCON BYTE_REF(LCKCON_ADDR) + +#define LCKCON_DWS_MASK 0x0f /* Display Wait-State */ +#define LCKCON_DWS_SHIFT 0 +#define LCKCON_DWIDTH 0x40 /* Display Memory Width */ +#define LCKCON_LCDON 0x80 /* Enable LCD Controller */ + +/* '328-compatible definitions */ +#define LCKCON_DW_MASK LCKCON_DWS_MASK +#define LCKCON_DW_SHIFT LCKCON_DWS_SHIFT + +/* + * LCD Refresh Rate Adjustment Register + */ +#define LRRA_ADDR 0xfffffa29 +#define LRRA BYTE_REF(LRRA_ADDR) + +/* + * LCD Panning Offset Register + */ +#define LPOSR_ADDR 0xfffffa2d +#define LPOSR BYTE_REF(LPOSR_ADDR) + +#define LPOSR_POS_MASK 0x0f /* Pixel Offset Code */ +#define LPOSR_POS_SHIFT 0 + +/* + * LCD Frame Rate Control Modulation Register + */ +#define LFRCM_ADDR 0xfffffa31 +#define LFRCM BYTE_REF(LFRCM_ADDR) + +#define LFRCM_YMOD_MASK 0x0f /* Vertical Modulation */ +#define LFRCM_YMOD_SHIFT 0 +#define LFRCM_XMOD_MASK 0xf0 /* Horizontal Modulation */ +#define LFRCM_XMOD_SHIFT 4 + +/* + * LCD Gray Palette Mapping Register + */ +#define LGPMR_ADDR 0xfffffa33 +#define LGPMR BYTE_REF(LGPMR_ADDR) + +#define LGPMR_G1_MASK 0x0f +#define LGPMR_G1_SHIFT 0 +#define LGPMR_G2_MASK 0xf0 +#define LGPMR_G2_SHIFT 4 + +/* + * PWM Contrast Control Register + */ +#define PWMR_ADDR 0xfffffa36 +#define PWMR WORD_REF(PWMR_ADDR) + +#define PWMR_PW_MASK 0x00ff /* Pulse Width */ +#define PWMR_PW_SHIFT 0 +#define PWMR_CCPEN 0x0100 /* Contrast Control Enable */ +#define PWMR_SRC_MASK 0x0600 /* Input Clock Source */ +#define PWMR_SRC_LINE 0x0000 /* Line Pulse */ +#define PWMR_SRC_PIXEL 0x0200 /* Pixel Clock */ +#define PWMR_SRC_LCD 0x4000 /* LCD clock */ + +/********** + * + * 0xFFFFFBxx -- Real-Time Clock (RTC) + * + **********/ + +/* + * RTC Hours Minutes and Seconds Register + */ +#define RTCTIME_ADDR 0xfffffb00 +#define RTCTIME LONG_REF(RTCTIME_ADDR) + +#define RTCTIME_SECONDS_MASK 0x0000003f /* Seconds */ +#define RTCTIME_SECONDS_SHIFT 0 +#define RTCTIME_MINUTES_MASK 0x003f0000 /* Minutes */ +#define RTCTIME_MINUTES_SHIFT 16 +#define RTCTIME_HOURS_MASK 0x1f000000 /* Hours */ +#define RTCTIME_HOURS_SHIFT 24 + +/* + * RTC Alarm Register + */ +#define RTCALRM_ADDR 0xfffffb04 +#define RTCALRM LONG_REF(RTCALRM_ADDR) + +#define RTCALRM_SECONDS_MASK 0x0000003f /* Seconds */ +#define RTCALRM_SECONDS_SHIFT 0 +#define RTCALRM_MINUTES_MASK 0x003f0000 /* Minutes */ +#define RTCALRM_MINUTES_SHIFT 16 +#define RTCALRM_HOURS_MASK 0x1f000000 /* Hours */ +#define RTCALRM_HOURS_SHIFT 24 + +/* + * Watchdog Timer Register + */ +#define WATCHDOG_ADDR 0xfffffb0a +#define WATCHDOG WORD_REF(WATCHDOG_ADDR) + +#define WATCHDOG_EN 0x0001 /* Watchdog Enabled */ +#define WATCHDOG_ISEL 0x0002 /* Select the watchdog interrupt */ +#define WATCHDOG_INTF 0x0080 /* Watchdog interrupt occcured */ +#define WATCHDOG_CNT_MASK 0x0300 /* Watchdog Counter */ +#define WATCHDOG_CNT_SHIFT 8 + +/* + * RTC Control Register + */ +#define RTCCTL_ADDR 0xfffffb0c +#define RTCCTL WORD_REF(RTCCTL_ADDR) + +#define RTCCTL_XTL 0x0020 /* Crystal Selection */ +#define RTCCTL_EN 0x0080 /* RTC Enable */ + +/* '328-compatible definitions */ +#define RTCCTL_384 RTCCTL_XTL +#define RTCCTL_ENABLE RTCCTL_EN + +/* + * RTC Interrupt Status Register + */ +#define RTCISR_ADDR 0xfffffb0e +#define RTCISR WORD_REF(RTCISR_ADDR) + +#define RTCISR_SW 0x0001 /* Stopwatch timed out */ +#define RTCISR_MIN 0x0002 /* 1-minute interrupt has occured */ +#define RTCISR_ALM 0x0004 /* Alarm interrupt has occured */ +#define RTCISR_DAY 0x0008 /* 24-hour rollover interrupt has occured */ +#define RTCISR_1HZ 0x0010 /* 1Hz interrupt has occured */ +#define RTCISR_HR 0x0020 /* 1-hour interrupt has occured */ +#define RTCISR_SAM0 0x0100 /* 4Hz / 4.6875Hz interrupt has occured */ +#define RTCISR_SAM1 0x0200 /* 8Hz / 9.3750Hz interrupt has occured */ +#define RTCISR_SAM2 0x0400 /* 16Hz / 18.7500Hz interrupt has occured */ +#define RTCISR_SAM3 0x0800 /* 32Hz / 37.5000Hz interrupt has occured */ +#define RTCISR_SAM4 0x1000 /* 64Hz / 75.0000Hz interrupt has occured */ +#define RTCISR_SAM5 0x2000 /* 128Hz / 150.0000Hz interrupt has occured */ +#define RTCISR_SAM6 0x4000 /* 256Hz / 300.0000Hz interrupt has occured */ +#define RTCISR_SAM7 0x8000 /* 512Hz / 600.0000Hz interrupt has occured */ + +/* + * RTC Interrupt Enable Register + */ +#define RTCIENR_ADDR 0xfffffb10 +#define RTCIENR WORD_REF(RTCIENR_ADDR) + +#define RTCIENR_SW 0x0001 /* Stopwatch interrupt enable */ +#define RTCIENR_MIN 0x0002 /* 1-minute interrupt enable */ +#define RTCIENR_ALM 0x0004 /* Alarm interrupt enable */ +#define RTCIENR_DAY 0x0008 /* 24-hour rollover interrupt enable */ +#define RTCIENR_1HZ 0x0010 /* 1Hz interrupt enable */ +#define RTCIENR_HR 0x0020 /* 1-hour interrupt enable */ +#define RTCIENR_SAM0 0x0100 /* 4Hz / 4.6875Hz interrupt enable */ +#define RTCIENR_SAM1 0x0200 /* 8Hz / 9.3750Hz interrupt enable */ +#define RTCIENR_SAM2 0x0400 /* 16Hz / 18.7500Hz interrupt enable */ +#define RTCIENR_SAM3 0x0800 /* 32Hz / 37.5000Hz interrupt enable */ +#define RTCIENR_SAM4 0x1000 /* 64Hz / 75.0000Hz interrupt enable */ +#define RTCIENR_SAM5 0x2000 /* 128Hz / 150.0000Hz interrupt enable */ +#define RTCIENR_SAM6 0x4000 /* 256Hz / 300.0000Hz interrupt enable */ +#define RTCIENR_SAM7 0x8000 /* 512Hz / 600.0000Hz interrupt enable */ + +/* + * Stopwatch Minutes Register + */ +#define STPWCH_ADDR 0xfffffb12 +#define STPWCH WORD_REF(STPWCH_ADDR) + +#define STPWCH_CNT_MASK 0x003f /* Stopwatch countdown value */ +#define SPTWCH_CNT_SHIFT 0 + +/* + * RTC Day Count Register + */ +#define DAYR_ADDR 0xfffffb1a +#define DAYR WORD_REF(DAYR_ADDR) + +#define DAYR_DAYS_MASK 0x1ff /* Day Setting */ +#define DAYR_DAYS_SHIFT 0 + +/* + * RTC Day Alarm Register + */ +#define DAYALARM_ADDR 0xfffffb1c +#define DAYALARM WORD_REF(DAYALARM_ADDR) + +#define DAYALARM_DAYSAL_MASK 0x01ff /* Day Setting of the Alarm */ +#define DAYALARM_DAYSAL_SHIFT 0 + +/********** + * + * 0xFFFFFCxx -- DRAM Controller + * + **********/ + +/* + * DRAM Memory Configuration Register + */ +#define DRAMMC_ADDR 0xfffffc00 +#define DRAMMC WORD_REF(DRAMMC_ADDR) + +#define DRAMMC_ROW12_MASK 0xc000 /* Row address bit for MD12 */ +#define DRAMMC_ROW12_PA10 0x0000 +#define DRAMMC_ROW12_PA21 0x4000 +#define DRAMMC_ROW12_PA23 0x8000 +#define DRAMMC_ROW0_MASK 0x3000 /* Row address bit for MD0 */ +#define DRAMMC_ROW0_PA11 0x0000 +#define DRAMMC_ROW0_PA22 0x1000 +#define DRAMMC_ROW0_PA23 0x2000 +#define DRAMMC_ROW11 0x0800 /* Row address bit for MD11 PA20/PA22 */ +#define DRAMMC_ROW10 0x0400 /* Row address bit for MD10 PA19/PA21 */ +#define DRAMMC_ROW9 0x0200 /* Row address bit for MD9 PA9/PA19 */ +#define DRAMMC_ROW8 0x0100 /* Row address bit for MD8 PA10/PA20 */ +#define DRAMMC_COL10 0x0080 /* Col address bit for MD10 PA11/PA0 */ +#define DRAMMC_COL9 0x0040 /* Col address bit for MD9 PA10/PA0 */ +#define DRAMMC_COL8 0x0020 /* Col address bit for MD8 PA9/PA0 */ +#define DRAMMC_REF_MASK 0x001f /* Reresh Cycle */ +#define DRAMMC_REF_SHIFT 0 + +/* + * DRAM Control Register + */ +#define DRAMC_ADDR 0xfffffc02 +#define DRAMC WORD_REF(DRAMC_ADDR) + +#define DRAMC_DWE 0x0001 /* DRAM Write Enable */ +#define DRAMC_RST 0x0002 /* Reset Burst Refresh Enable */ +#define DRAMC_LPR 0x0004 /* Low-Power Refresh Enable */ +#define DRAMC_SLW 0x0008 /* Slow RAM */ +#define DRAMC_LSP 0x0010 /* Light Sleep */ +#define DRAMC_MSW 0x0020 /* Slow Multiplexing */ +#define DRAMC_WS_MASK 0x00c0 /* Wait-states */ +#define DRAMC_WS_SHIFT 6 +#define DRAMC_PGSZ_MASK 0x0300 /* Page Size for fast page mode */ +#define DRAMC_PGSZ_SHIFT 8 +#define DRAMC_PGSZ_256K 0x0000 +#define DRAMC_PGSZ_512K 0x0100 +#define DRAMC_PGSZ_1024K 0x0200 +#define DRAMC_PGSZ_2048K 0x0300 +#define DRAMC_EDO 0x0400 /* EDO DRAM */ +#define DRAMC_CLK 0x0800 /* Refresh Timer Clock source select */ +#define DRAMC_BC_MASK 0x3000 /* Page Access Clock Cycle (FP mode) */ +#define DRAMC_BC_SHIFT 12 +#define DRAMC_RM 0x4000 /* Refresh Mode */ +#define DRAMC_EN 0x8000 /* DRAM Controller enable */ + + +/********** + * + * 0xFFFFFDxx -- In-Circuit Emulation (ICE) + * + **********/ + +/* + * ICE Module Address Compare Register + */ +#define ICEMACR_ADDR 0xfffffd00 +#define ICEMACR LONG_REF(ICEMACR_ADDR) + +/* + * ICE Module Address Mask Register + */ +#define ICEMAMR_ADDR 0xfffffd04 +#define ICEMAMR LONG_REF(ICEMAMR_ADDR) + +/* + * ICE Module Control Compare Register + */ +#define ICEMCCR_ADDR 0xfffffd08 +#define ICEMCCR WORD_REF(ICEMCCR_ADDR) + +#define ICEMCCR_PD 0x0001 /* Program/Data Cycle Selection */ +#define ICEMCCR_RW 0x0002 /* Read/Write Cycle Selection */ + +/* + * ICE Module Control Mask Register + */ +#define ICEMCMR_ADDR 0xfffffd0a +#define ICEMCMR WORD_REF(ICEMCMR_ADDR) + +#define ICEMCMR_PDM 0x0001 /* Program/Data Cycle Mask */ +#define ICEMCMR_RWM 0x0002 /* Read/Write Cycle Mask */ + +/* + * ICE Module Control Register + */ +#define ICEMCR_ADDR 0xfffffd0c +#define ICEMCR WORD_REF(ICEMCR_ADDR) + +#define ICEMCR_CEN 0x0001 /* Compare Enable */ +#define ICEMCR_PBEN 0x0002 /* Program Break Enable */ +#define ICEMCR_SB 0x0004 /* Single Breakpoint */ +#define ICEMCR_HMDIS 0x0008 /* HardMap disable */ +#define ICEMCR_BBIEN 0x0010 /* Bus Break Interrupt Enable */ + +/* + * ICE Module Status Register + */ +#define ICEMSR_ADDR 0xfffffd0e +#define ICEMSR WORD_REF(ICEMSR_ADDR) + +#define ICEMSR_EMUEN 0x0001 /* Emulation Enable */ +#define ICEMSR_BRKIRQ 0x0002 /* A-Line Vector Fetch Detected */ +#define ICEMSR_BBIRQ 0x0004 /* Bus Break Interrupt Detected */ +#define ICEMSR_EMIRQ 0x0008 /* EMUIRQ Falling Edge Detected */ + +#endif /* _MC68VZ328_H_ */ diff -Nru a/include/asm-m68knommu/a.out.h b/include/asm-m68knommu/a.out.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/a.out.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/anchor.h b/include/asm-m68knommu/anchor.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/anchor.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,112 @@ +/****************************************************************************/ + +/* + * anchor.h -- Anchor CO-MEM Lite PCI host bridge part. + * + * (C) Copyright 2000, Moreton Bay (www.moreton.com.au) + */ + +/****************************************************************************/ +#ifndef anchor_h +#define anchor_h +/****************************************************************************/ + +/* + * Define basic addressing info. + */ +#if defined(CONFIG_MOTOROLA) && defined(CONFIG_M5407) +#define COMEM_BASE 0xFFFF0000 /* Base of CO-MEM address space */ +#define COMEM_IRQ 25 /* IRQ of anchor part */ +#else +#define COMEM_BASE 0x80000000 /* Base of CO-MEM address space */ +#define COMEM_IRQ 25 /* IRQ of anchor part */ +#endif + +/****************************************************************************/ + +/* + * 4-byte registers of CO-MEM, so adjust register addresses for + * easy access. Handy macro for word access too. + */ +#define LREG(a) ((a) >> 2) +#define WREG(a) ((a) >> 1) + + +/* + * Define base addresses within CO-MEM Lite register address space. + */ +#define COMEM_I2O 0x0000 /* I2O registers */ +#define COMEM_OPREGS 0x0400 /* Operation registers */ +#define COMEM_PCIBUS 0x2000 /* Direct access to PCI bus */ +#define COMEM_SHMEM 0x4000 /* Shared memory region */ + +#define COMEM_SHMEMSIZE 0x4000 /* Size of shared memory */ + + +/* + * Define CO-MEM Registers. + */ +#define COMEM_I2OHISR 0x0030 /* I2O host interrupt status */ +#define COMEM_I2OHIMR 0x0034 /* I2O host interrupt mask */ +#define COMEM_I2OLISR 0x0038 /* I2O local interrupt status */ +#define COMEM_I2OLIMR 0x003c /* I2O local interrupt mask */ +#define COMEM_IBFPFIFO 0x0040 /* I2O inbound free/post FIFO */ +#define COMEM_OBPFFIFO 0x0044 /* I2O outbound post/free FIFO */ +#define COMEM_IBPFFIFO 0x0048 /* I2O inbound post/free FIFO */ +#define COMEM_OBFPFIFO 0x004c /* I2O outbound free/post FIFO */ + +#define COMEM_DAHBASE 0x0460 /* Direct access base address */ + +#define COMEM_NVCMD 0x04a0 /* I2C serial command */ +#define COMEM_NVREAD 0x04a4 /* I2C serial read */ +#define COMEM_NVSTAT 0x04a8 /* I2C status */ + +#define COMEM_DMALBASE 0x04b0 /* DMA local base address */ +#define COMEM_DMAHBASE 0x04b4 /* DMA host base address */ +#define COMEM_DMASIZE 0x04b8 /* DMA size */ +#define COMEM_DMACTL 0x04bc /* DMA control */ + +#define COMEM_HCTL 0x04e0 /* Host control */ +#define COMEM_HINT 0x04e4 /* Host interrupt control/status */ +#define COMEM_HLDATA 0x04e8 /* Host to local data mailbox */ +#define COMEM_LINT 0x04f4 /* Local interrupt contole status */ +#define COMEM_LHDATA 0x04f8 /* Local to host data mailbox */ + +#define COMEM_LBUSCFG 0x04fc /* Local bus configuration */ + + +/* + * Commands and flags for use with Direct Access Register. + */ +#define COMEM_DA_IACK 0x00000000 /* Interrupt acknowledge (read) */ +#define COMEM_DA_SPCL 0x00000010 /* Special cycle (write) */ +#define COMEM_DA_MEMRD 0x00000004 /* Memory read cycle */ +#define COMEM_DA_MEMWR 0x00000004 /* Memory write cycle */ +#define COMEM_DA_IORD 0x00000002 /* I/O read cycle */ +#define COMEM_DA_IOWR 0x00000002 /* I/O write cycle */ +#define COMEM_DA_CFGRD 0x00000006 /* Configuration read cycle */ +#define COMEM_DA_CFGWR 0x00000006 /* Configuration write cycle */ + +#define COMEM_DA_ADDR(a) ((a) & 0xffffe000) + +#define COMEM_DA_OFFSET(a) ((a) & 0x00001fff) + + +/* + * The PCI bus will be limited in what slots will actually be used. + * Define valid device numbers for different boards. + */ +#if defined(CONFIG_MOTOROLA) && defined(CONFIG_M5407) +#define COMEM_MINDEV 14 /* Minimum valid DEVICE */ +#define COMEM_MAXDEV 14 /* Maximum valid DEVICE */ +#define COMEM_BRIDGEDEV 15 /* Slot bridge is in */ +#else +#define COMEM_MINDEV 0 /* Minimum valid DEVICE */ +#define COMEM_MAXDEV 3 /* Maximum valid DEVICE */ +#endif + +#define COMEM_MAXPCI (COMEM_MAXDEV+1) /* Maximum PCI devices */ + + +/****************************************************************************/ +#endif /* anchor_h */ diff -Nru a/include/asm-m68knommu/asm-offsets.h b/include/asm-m68knommu/asm-offsets.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/asm-offsets.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,49 @@ +#ifndef __ASM_OFFSETS_H__ +#define __ASM_OFFSETS_H__ +/* + * DO NOT MODIFY. + * + * This file was generated by arch/m68knommu/Makefile + * + */ + +#define TASK_STATE 0 /* offsetof(struct task_struct, state) */ +#define TASK_FLAGS 12 /* offsetof(struct task_struct, flags) */ +#define TASK_PTRACE 16 /* offsetof(struct task_struct, ptrace) */ +#define TASK_BLOCKED 922 /* offsetof(struct task_struct, blocked) */ +#define TASK_THREAD 772 /* offsetof(struct task_struct, thread) */ +#define TASK_THREAD_INFO 4 /* offsetof(struct task_struct, thread_info) */ +#define TASK_MM 92 /* offsetof(struct task_struct, mm) */ +#define TASK_ACTIVE_MM 96 /* offsetof(struct task_struct, active_mm) */ +#define CPUSTAT_SOFTIRQ_PENDING 0 /* offsetof(irq_cpustat_t, __softirq_pending) */ +#define THREAD_KSP 0 /* offsetof(struct thread_struct, ksp) */ +#define THREAD_USP 4 /* offsetof(struct thread_struct, usp) */ +#define THREAD_SR 8 /* offsetof(struct thread_struct, sr) */ +#define THREAD_FS 10 /* offsetof(struct thread_struct, fs) */ +#define THREAD_CRP 12 /* offsetof(struct thread_struct, crp) */ +#define THREAD_ESP0 20 /* offsetof(struct thread_struct, esp0) */ +#define THREAD_FPREG 24 /* offsetof(struct thread_struct, fp) */ +#define THREAD_FPCNTL 120 /* offsetof(struct thread_struct, fpcntl) */ +#define THREAD_FPSTATE 132 /* offsetof(struct thread_struct, fpstate) */ +#define PT_D0 32 /* offsetof(struct pt_regs, d0) */ +#define PT_ORIG_D0 36 /* offsetof(struct pt_regs, orig_d0) */ +#define PT_D1 0 /* offsetof(struct pt_regs, d1) */ +#define PT_D2 4 /* offsetof(struct pt_regs, d2) */ +#define PT_D3 8 /* offsetof(struct pt_regs, d3) */ +#define PT_D4 12 /* offsetof(struct pt_regs, d4) */ +#define PT_D5 16 /* offsetof(struct pt_regs, d5) */ +#define PT_A0 20 /* offsetof(struct pt_regs, a0) */ +#define PT_A1 24 /* offsetof(struct pt_regs, a1) */ +#define PT_A2 28 /* offsetof(struct pt_regs, a2) */ +#define PT_PC 48 /* offsetof(struct pt_regs, pc) */ +#define PT_SR 46 /* offsetof(struct pt_regs, sr) */ +#define PT_VECTOR 52 /* offsetof(struct pt_regs, pc) + 4 */ +#define STAT_IRQ 5140 /* offsetof(struct kernel_stat, irqs) */ +#define SIGSEGV 11 /* SIGSEGV */ +#define SEGV_MAPERR 196609 /* SEGV_MAPERR */ +#define SIGTRAP 5 /* SIGTRAP */ +#define TRAP_TRACE 196610 /* TRAP_TRACE */ +#define PT_PTRACED 1 /* PT_PTRACED */ +#define PT_DTRACE 2 /* PT_DTRACE */ + +#endif diff -Nru a/include/asm-m68knommu/atomic.h b/include/asm-m68knommu/atomic.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/atomic.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,118 @@ +#ifndef __ARCH_M68KNOMMU_ATOMIC__ +#define __ARCH_M68KNOMMU_ATOMIC__ + +#include /* local_irq_XXX() */ + +/* + * Atomic operations that C can't guarantee us. Useful for + * resource counting etc.. + */ + +/* + * We do not have SMP m68k systems, so we don't have to deal with that. + */ + +typedef struct { int counter; } atomic_t; +#define ATOMIC_INIT(i) { (i) } + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v, i) (((v)->counter) = i) + +#ifdef CONFIG_COLDFIRE + +static __inline__ void atomic_add(int i, atomic_t *v) +{ + __asm__ __volatile__( + "movel %1,%%d0\t\n" + "addl %%d0,%0" + : + : "m" (*v), "id" (i) + : "d0"); +} + +static __inline__ void atomic_sub(int i, atomic_t *v) +{ + __asm__ __volatile__( + "movel %1,%%d0\t\n" + "subl %%d0,%0" + : + : "m" (*v), "id" (i) + : "d0"); +} + +#else + +static __inline__ void atomic_add(int i, atomic_t *v) +{ + __asm__ __volatile__("addl %1,%0" : "=m" (*v) : "d" (i), "0" (*v)); +} + +static __inline__ void atomic_sub(int i, atomic_t *v) +{ + __asm__ __volatile__("subl %1,%0" : "=m" (*v) : "d" (i), "0" (*v)); +} + +#endif /* COLDFIRE */ + +static __inline__ void atomic_inc(volatile atomic_t *v) +{ + __asm__ __volatile__("addql #1,%0" : "=m" (*v): "0" (*v)); +} + +static __inline__ void atomic_dec(volatile atomic_t *v) +{ + __asm__ __volatile__("subql #1,%0" : "=m" (*v): "0" (*v)); +} + +static __inline__ int atomic_dec_and_test(volatile atomic_t *v) +{ + char c; + __asm__ __volatile__("subql #1,%1; seq %0" : "=d" (c), "=m" (*v): "1" (*v)); + return c != 0; +} + +#define atomic_clear_mask(mask, v) \ + __asm__ __volatile__("andl %1,%0" : "=m" (*v) : "id" (~(mask)),"0"(*v)) + +#define atomic_set_mask(mask, v) \ + __asm__ __volatile__("orl %1,%0" : "=m" (*v) : "id" (mask),"0"(*v)) + +/* Atomic operations are already serializing */ +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() + +extern __inline__ int atomic_add_return(int i, atomic_t * v) +{ + unsigned long temp, flags; + + local_irq_save(flags); + temp = *(long *)v; + temp += i; + *(long *)v = temp; + local_irq_restore(flags); + + return temp; +} + +extern __inline__ int atomic_sub_return(int i, atomic_t * v) +{ + unsigned long temp, flags; + + local_irq_save(flags); + temp = *(long *)v; + temp -= i; + *(long *)v = temp; + local_irq_restore(flags); + + return temp; +} + +#define atomic_dec_return(v) atomic_sub_return(1,(v)) +#define atomic_inc_return(v) atomic_add_return(1,(v)) + +#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0) +#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) + +#endif /* __ARCH_M68KNOMMU_ATOMIC __ */ diff -Nru a/include/asm-m68knommu/bitops.h b/include/asm-m68knommu/bitops.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/bitops.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,488 @@ +#ifndef _M68KNOMMU_BITOPS_H +#define _M68KNOMMU_BITOPS_H + +/* + * Copyright 1992, Linus Torvalds. + */ + +#include +#include +#include /* swab32 */ +#include /* save_flags */ + +#ifdef __KERNEL__ +/* + * Function prototypes to keep gcc -Wall happy + */ + +/* + * The __ functions are not atomic + */ + +extern void set_bit(int nr, volatile void * addr); +extern void __set_bit(int nr, volatile void * addr); +extern void clear_bit(int nr, volatile void * addr); +extern void __clear_bit(int nr, volatile void * addr); +extern void change_bit(int nr, volatile void * addr); +extern void __change_bit(int nr, volatile void * addr); +extern int test_and_set_bit(int nr, volatile void * addr); +extern int __test_and_set_bit(int nr, volatile void * addr); +extern int test_and_clear_bit(int nr, volatile void * addr); +extern int __test_and_clear_bit(int nr, volatile void * addr); +extern int test_and_change_bit(int nr, volatile void * addr); +extern int __test_and_change_bit(int nr, volatile void * addr); +extern int __constant_test_bit(int nr, const volatile void * addr); +extern int __test_bit(int nr, volatile void * addr); +extern int find_first_zero_bit(void * addr, unsigned size); +extern int find_next_zero_bit (void * addr, int size, int offset); + + +/* + * Generic ffs(). + */ +static inline int ffs(int x) +{ + int r = 1; + + if (!x) + return 0; + if (!(x & 0xffff)) { + x >>= 16; + r += 16; + } + if (!(x & 0xff)) { + x >>= 8; + r += 8; + } + if (!(x & 0xf)) { + x >>= 4; + r += 4; + } + if (!(x & 3)) { + x >>= 2; + r += 2; + } + if (!(x & 1)) { + x >>= 1; + r += 1; + } + return r; +} + +/* + * Generic __ffs(). + */ +static inline int __ffs(int x) +{ + int r = 0; + + if (!x) + return 0; + if (!(x & 0xffff)) { + x >>= 16; + r += 16; + } + if (!(x & 0xff)) { + x >>= 8; + r += 8; + } + if (!(x & 0xf)) { + x >>= 4; + r += 4; + } + if (!(x & 3)) { + x >>= 2; + r += 2; + } + if (!(x & 1)) { + x >>= 1; + r += 1; + } + return r; +} + +/* + * fls: find last bit set. + */ +#define fls(x) generic_fls(x) + + +/* + * Every architecture must define this function. It's the fastest + * way of searching a 140-bit bitmap where the first 100 bits are + * unlikely to be set. It's guaranteed that at least one of the 140 + * bits is cleared. + */ +static inline int sched_find_first_bit(unsigned long *b) +{ + if (unlikely(b[0])) + return __ffs(b[0]); + if (unlikely(b[1])) + return __ffs(b[1]) + 32; + if (unlikely(b[2])) + return __ffs(b[2]) + 64; + if (b[3]) + return __ffs(b[3]) + 96; + return __ffs(b[4]) + 128; +} + +/* + * ffz = Find First Zero in word. Undefined if no zero exists, + * so code should check against ~0UL first.. + */ +extern __inline__ unsigned long ffz(unsigned long word) +{ + unsigned long result = 0; + + while(word & 1) { + result++; + word >>= 1; + } + return result; +} + + +extern __inline__ void set_bit(int nr, volatile void * addr) +{ + int * a = (int *) addr; + int mask; + unsigned long flags; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + local_irq_save(flags); + *a |= mask; + local_irq_restore(flags); +} + +extern __inline__ void __set_bit(int nr, volatile void * addr) +{ + int * a = (int *) addr; + int mask; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + *a |= mask; +} + +/* + * clear_bit() doesn't provide any barrier for the compiler. + */ +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() + +extern __inline__ void clear_bit(int nr, volatile void * addr) +{ + int * a = (int *) addr; + int mask; + unsigned long flags; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + local_irq_save(flags); + *a &= ~mask; + local_irq_restore(flags); +} + +extern __inline__ void __clear_bit(int nr, volatile void * addr) +{ + int * a = (int *) addr; + int mask; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + *a &= ~mask; +} + +extern __inline__ void change_bit(int nr, volatile void * addr) +{ + int mask, flags; + unsigned long *ADDR = (unsigned long *) addr; + + ADDR += nr >> 5; + mask = 1 << (nr & 31); + local_irq_save(flags); + *ADDR ^= mask; + local_irq_restore(flags); +} + +extern __inline__ void __change_bit(int nr, volatile void * addr) +{ + int mask; + unsigned long *ADDR = (unsigned long *) addr; + + ADDR += nr >> 5; + mask = 1 << (nr & 31); + *ADDR ^= mask; +} + +extern __inline__ int test_and_set_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = (volatile unsigned int *) addr; + unsigned long flags; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + local_irq_save(flags); + retval = (mask & *a) != 0; + *a |= mask; + local_irq_restore(flags); + + return retval; +} + +extern __inline__ int __test_and_set_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = (volatile unsigned int *) addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + retval = (mask & *a) != 0; + *a |= mask; + return retval; +} + +extern __inline__ int test_and_clear_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = (volatile unsigned int *) addr; + unsigned long flags; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + local_irq_save(flags); + retval = (mask & *a) != 0; + *a &= ~mask; + local_irq_restore(flags); + + return retval; +} + +extern __inline__ int __test_and_clear_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = (volatile unsigned int *) addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + retval = (mask & *a) != 0; + *a &= ~mask; + return retval; +} + +extern __inline__ int test_and_change_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = (volatile unsigned int *) addr; + unsigned long flags; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + local_irq_save(flags); + retval = (mask & *a) != 0; + *a ^= mask; + local_irq_restore(flags); + + return retval; +} + +extern __inline__ int __test_and_change_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = (volatile unsigned int *) addr; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + retval = (mask & *a) != 0; + *a ^= mask; + return retval; +} + +/* + * This routine doesn't need to be atomic. + */ +extern __inline__ int __constant_test_bit(int nr, const volatile void * addr) +{ + return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0; +} + +extern __inline__ int __test_bit(int nr, volatile void * addr) +{ + int * a = (int *) addr; + int mask; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + return ((mask & *a) != 0); +} + +#define test_bit(nr,addr) \ +(__builtin_constant_p(nr) ? \ + __constant_test_bit((nr),(addr)) : \ + __test_bit((nr),(addr))) + +#define find_first_zero_bit(addr, size) \ + find_next_zero_bit((addr), (size), 0) + +extern __inline__ int find_next_zero_bit (void * addr, int size, int offset) +{ + unsigned long *p = ((unsigned long *) addr) + (offset >> 5); + unsigned long result = offset & ~31UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 31UL; + if (offset) { + tmp = *(p++); + tmp |= ~0UL >> (32-offset); + if (size < 32) + goto found_first; + if (~tmp) + goto found_middle; + size -= 32; + result += 32; + } + while (size & ~31UL) { + if (~(tmp = *(p++))) + goto found_middle; + result += 32; + size -= 32; + } + if (!size) + return result; + tmp = *p; + +found_first: + tmp |= ~0UL >> size; +found_middle: + return result + ffz(tmp); +} + +/* + * hweightN: returns the hamming weight (i.e. the number + * of bits set) of a N-bit word + */ + +#define hweight32(x) generic_hweight32(x) +#define hweight16(x) generic_hweight16(x) +#define hweight8(x) generic_hweight8(x) + + +extern __inline__ int ext2_set_bit(int nr, volatile void * addr) +{ + int mask, retval; + unsigned long flags; + volatile unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + local_irq_save(flags); + retval = (mask & *ADDR) != 0; + *ADDR |= mask; + local_irq_restore(flags); + return retval; +} + +extern __inline__ int ext2_clear_bit(int nr, volatile void * addr) +{ + int mask, retval; + unsigned long flags; + volatile unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + local_irq_save(flags); + retval = (mask & *ADDR) != 0; + *ADDR &= ~mask; + local_irq_restore(flags); + return retval; +} + +extern __inline__ int ext2_test_bit(int nr, const volatile void * addr) +{ + int mask; + const volatile unsigned char *ADDR = (const unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + return ((mask & *ADDR) != 0); +} + +#define ext2_find_first_zero_bit(addr, size) \ + ext2_find_next_zero_bit((addr), (size), 0) + +extern __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) +{ + unsigned long *p = ((unsigned long *) addr) + (offset >> 5); + unsigned long result = offset & ~31UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 31UL; + if(offset) { + /* We hold the little endian value in tmp, but then the + * shift is illegal. So we could keep a big endian value + * in tmp, like this: + * + * tmp = __swab32(*(p++)); + * tmp |= ~0UL >> (32-offset); + * + * but this would decrease preformance, so we change the + * shift: + */ + tmp = *(p++); + tmp |= __swab32(~0UL >> (32-offset)); + if(size < 32) + goto found_first; + if(~tmp) + goto found_middle; + size -= 32; + result += 32; + } + while(size & ~31UL) { + if(~(tmp = *(p++))) + goto found_middle; + result += 32; + size -= 32; + } + if(!size) + return result; + tmp = *p; + +found_first: + /* tmp is little endian, so we would have to swab the shift, + * see above. But then we have to swab tmp below for ffz, so + * we might as well do this here. + */ + return result + ffz(__swab32(tmp) | (~0UL << size)); +found_middle: + return result + ffz(__swab32(tmp)); +} + +/* Bitmap functions for the minix filesystem. */ +#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr) +#define minix_set_bit(nr,addr) set_bit(nr,addr) +#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr) +#define minix_test_bit(nr,addr) test_bit(nr,addr) +#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size) + +/** + * hweightN - returns the hamming weight of a N-bit word + * @x: the word to weigh + * + * The Hamming Weight of a number is the total number of bits set in it. + */ + +#define hweight32(x) generic_hweight32(x) +#define hweight16(x) generic_hweight16(x) +#define hweight8(x) generic_hweight8(x) + +#endif /* __KERNEL__ */ + +#endif /* _M68KNOMMU_BITOPS_H */ diff -Nru a/include/asm-m68knommu/bootinfo.h b/include/asm-m68knommu/bootinfo.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/bootinfo.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,2 @@ + +/* Nothing for m68knommu */ diff -Nru a/include/asm-m68knommu/bootstd.h b/include/asm-m68knommu/bootstd.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/bootstd.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,132 @@ +/* bootstd.h: Bootloader system call interface + * + * (c) 1999, Rt-Control, Inc. + */ + +#ifndef __BOOTSTD_H__ +#define __BOOTSTD_H__ + +#define NR_BSC 21 /* last used bootloader system call */ + +#define __BN_reset 0 /* reset and start the bootloader */ +#define __BN_test 1 /* tests the system call interface */ +#define __BN_exec 2 /* executes a bootloader image */ +#define __BN_exit 3 /* terminates a bootloader image */ +#define __BN_program 4 /* program FLASH from a chain */ +#define __BN_erase 5 /* erase sector(s) of FLASH */ +#define __BN_open 6 +#define __BN_write 7 +#define __BN_read 8 +#define __BN_close 9 +#define __BN_mmap 10 /* map a file descriptor into memory */ +#define __BN_munmap 11 /* remove a file to memory mapping */ +#define __BN_gethwaddr 12 /* get the hardware address of my interfaces */ +#define __BN_getserialnum 13 /* get the serial number of this board */ +#define __BN_getbenv 14 /* get a bootloader envvar */ +#define __BN_setbenv 15 /* get a bootloader envvar */ +#define __BN_setpmask 16 /* set the protection mask */ +#define __BN_readenv 17 /* read environment variables */ +#define __BN_flash_chattr_range 18 +#define __BN_flash_erase_range 19 +#define __BN_flash_write_range 20 + +/* Calling conventions compatible to (uC)linux/68k + * We use simmilar macros to call into the bootloader as for uClinux + */ + +#define __bsc_return(type, res) \ +do { \ + if ((unsigned long)(res) >= (unsigned long)(-64)) { \ + /* let errno be a function, preserve res in %d0 */ \ + int __err = -(res); \ + errno = __err; \ + res = -1; \ + } \ + return (type)(res); \ +} while (0) + +#define _bsc0(type,name) \ +type name(void) \ +{ \ + register long __res __asm__ ("%d0") = __BN_##name; \ + __asm__ __volatile__ ("trap #2" \ + : "=g" (__res) \ + : "0" (__res) \ + : "%d0"); \ + __bsc_return(type,__res); \ +} + +#define _bsc1(type,name,atype,a) \ +type name(atype a) \ +{ \ + register long __res __asm__ ("%d0") = __BN_##name; \ + register long __a __asm__ ("%d1") = (long)a; \ + __asm__ __volatile__ ("trap #2" \ + : "=g" (__res) \ + : "0" (__res), "d" (__a) \ + : "%d0"); \ + __bsc_return(type,__res); \ +} + +#define _bsc2(type,name,atype,a,btype,b) \ +type name(atype a, btype b) \ +{ \ + register long __res __asm__ ("%d0") = __BN_##name; \ + register long __a __asm__ ("%d1") = (long)a; \ + register long __b __asm__ ("%d2") = (long)b; \ + __asm__ __volatile__ ("trap #2" \ + : "=g" (__res) \ + : "0" (__res), "d" (__a), "d" (__b) \ + : "%d0"); \ + __bsc_return(type,__res); \ +} + +#define _bsc3(type,name,atype,a,btype,b,ctype,c) \ +type name(atype a, btype b, ctype c) \ +{ \ + register long __res __asm__ ("%d0") = __BN_##name; \ + register long __a __asm__ ("%d1") = (long)a; \ + register long __b __asm__ ("%d2") = (long)b; \ + register long __c __asm__ ("%d3") = (long)c; \ + __asm__ __volatile__ ("trap #2" \ + : "=g" (__res) \ + : "0" (__res), "d" (__a), "d" (__b), \ + "d" (__c) \ + : "%d0"); \ + __bsc_return(type,__res); \ +} + +#define _bsc4(type,name,atype,a,btype,b,ctype,c,dtype,d) \ +type name(atype a, btype b, ctype c, dtype d) \ +{ \ + register long __res __asm__ ("%d0") = __BN_##name; \ + register long __a __asm__ ("%d1") = (long)a; \ + register long __b __asm__ ("%d2") = (long)b; \ + register long __c __asm__ ("%d3") = (long)c; \ + register long __d __asm__ ("%d4") = (long)d; \ + __asm__ __volatile__ ("trap #2" \ + : "=g" (__res) \ + : "0" (__res), "d" (__a), "d" (__b), \ + "d" (__c), "d" (__d) \ + : "%d0"); \ + __bsc_return(type,__res); \ +} + +#define _bsc5(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e) \ +type name(atype a, btype b, ctype c, dtype d, etype e) \ +{ \ + register long __res __asm__ ("%d0") = __BN_##name; \ + register long __a __asm__ ("%d1") = (long)a; \ + register long __b __asm__ ("%d2") = (long)b; \ + register long __c __asm__ ("%d3") = (long)c; \ + register long __d __asm__ ("%d4") = (long)d; \ + register long __e __asm__ ("%d5") = (long)e; \ + __asm__ __volatile__ ("trap #2" \ + : "=g" (__res) \ + : "0" (__res), "d" (__a), "d" (__b), \ + "d" (__c), "d" (__d), "d" (__e) \ + : "%d0"); \ + __bsc_return(type,__res); \ +} + +#endif /* __BOOTSTD_H__ */ diff -Nru a/include/asm-m68knommu/bugs.h b/include/asm-m68knommu/bugs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/bugs.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,16 @@ +/* + * include/asm-m68k/bugs.h + * + * Copyright (C) 1994 Linus Torvalds + */ + +/* + * This is included by init/main.c to check for architecture-dependent bugs. + * + * Needs: + * void check_bugs(void); + */ + +static void check_bugs(void) +{ +} diff -Nru a/include/asm-m68knommu/byteorder.h b/include/asm-m68knommu/byteorder.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/byteorder.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,13 @@ +#ifndef _M68KNOMMU_BYTEORDER_H +#define _M68KNOMMU_BYTEORDER_H + +#include + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__) +# define __BYTEORDER_HAS_U64__ +# define __SWAB_64_THRU_32__ +#endif + +#include + +#endif /* _M68KNOMMU_BYTEORDER_H */ diff -Nru a/include/asm-m68knommu/cache.h b/include/asm-m68knommu/cache.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/cache.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,12 @@ +#ifndef __ARCH_M68KNOMMU_CACHE_H +#define __ARCH_M68KNOMMU_CACHE_H + +/* bytes per L1 cache line */ +#define L1_CACHE_BYTES 16 /* this need to be at least 1 */ + +/* m68k-elf-gcc 2.95.2 doesn't like these */ + +#define __cacheline_aligned +#define ____cacheline_aligned + +#endif diff -Nru a/include/asm-m68knommu/cachectl.h b/include/asm-m68knommu/cachectl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/cachectl.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/cacheflush.h b/include/asm-m68knommu/cacheflush.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/cacheflush.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,82 @@ +#ifndef _M68KNOMMU_CACHEFLUSH_H +#define _M68KNOMMU_CACHEFLUSH_H + +/* + * (C) Copyright 2000-2002, Greg Ungerer + */ + +#include + +/* + * Cache handling functions + */ + +#define flush_cache_all() __flush_cache_all() + +extern inline void __flush_cache_all(void) +{ +#ifdef CONFIG_M5407 + __asm__ __volatile__ ( + "nop\n\t" + "clrl %%d0\n\t" + "1:\n\t" + "movel %%d0,%%a0\n\t" + "2:\n\t" + ".word 0xf4e8\n\t" + "addl #0x10,%%a0\n\t" + "cmpl #0x00000800,%%a0\n\t" + "blt 2b\n\t" + "addql #1,%%d0\n\t" + "cmpil #4,%%d0\n\t" + "bne 1b\n\t" + "movel #0x01040100,%%d0\n\t" + "movec %%d0,%%CACR\n\t" + "nop\n\t" + "movel #0x86088400,%%d0\n\t" + "movec %%d0,%%CACR\n\t" + : : : "d0", "a0" ); +#endif /* CONFIG_M5407 */ +#ifdef CONFIG_M5272 + __asm__ __volatile__ ( + "movel #0x01000000, %%d0\n\t" + "movec %%d0, %%CACR\n\t" + "nop\n\t" + "movel #0x80000100, %%d0\n\t" + "movec %%d0, %%CACR\n\t" + "nop\n\t" + : : : "d0" ); +#endif /* CONFIG_M5272 */ +#if 0 /* CONFIG_M5249 */ + __asm__ __volatile__ ( + "movel #0x01000000, %%d0\n\t" + "movec %%d0, %%CACR\n\t" + "nop\n\t" + "movel #0xa0000200, %%d0\n\t" + "movec %%d0, %%CACR\n\t" + "nop\n\t" + : : : "d0" ); +#endif /* CONFIG_M5249 */ +} + +/* + * FIXME: we could do better than an entire flush in most cases. + * But this will always work :-) + */ +#define flush_cache_all() __flush_cache_all() +#define flush_cache_mm(mm) __flush_cache_all() +#define flush_cache_range(vma,a,b) __flush_cache_all() +#define flush_cache_page(vma,p) __flush_cache_all() +#define flush_page_to_ram(page) __flush_cache_all() +#define flush_dcache_page(page) __flush_cache_all() +#define flush_icache() __flush_cache_all() +#define flush_icache_page(page) __flush_cache_all() +#define flush_icache_range(start,len) __flush_cache_all() +#define cache_push_v(vaddr,len) __flush_cache_all() +#define cache_push(paddr,len) __flush_cache_all() +#define cache_clear(paddr,len) __flush_cache_all() + +#define flush_dcache_range(a,b) + +#define flush_icache_user_range(vma,page,addr,len) __flush_cache_all() + +#endif /* _M68KNOMMU_CACHEFLUSH_H */ diff -Nru a/include/asm-m68knommu/checksum.h b/include/asm-m68knommu/checksum.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/checksum.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,131 @@ +#ifndef _M68K_CHECKSUM_H +#define _M68K_CHECKSUM_H + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum); + +/* + * the same as csum_partial, but copies from src while it + * checksums + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ + +unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum); + + +/* + * the same as csum_partial_copy, but copies from user space. + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ + +extern unsigned int csum_partial_copy_from_user(const char *src, char *dst, + int len, int sum, int *csum_err); + +#define csum_partial_copy_nocheck(src, dst, len, sum) \ + csum_partial_copy((src), (dst), (len), (sum)) + +unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl); + +/* + * Fold a partial checksum + */ + +static inline unsigned int csum_fold(unsigned int sum) +{ +#ifdef CONFIG_COLDFIRE + sum = (sum & 0xffff) + (sum >> 16); + sum = (sum & 0xffff) + (sum >> 16); +#else + unsigned int tmp = sum; + __asm__("swap %1\n\t" + "addw %1, %0\n\t" + "clrw %1\n\t" + "addxw %1, %0" + : "=&d" (sum), "=&d" (tmp) + : "0" (sum), "1" (sum)); +#endif + return ~sum; +} + + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ + +static inline unsigned int +csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len, + unsigned short proto, unsigned int sum) +{ + __asm__ ("addl %1,%0\n\t" + "addxl %4,%0\n\t" + "addxl %5,%0\n\t" + "clrl %1\n\t" + "addxl %1,%0" + : "=&d" (sum), "=&d" (saddr) + : "0" (daddr), "1" (saddr), "d" (len + proto), + "d"(sum)); + return sum; +} + +static inline unsigned short int +csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len, + unsigned short proto, unsigned int sum) +{ + return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); +} + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ + +extern unsigned short ip_compute_csum(const unsigned char * buff, int len); + +#define _HAVE_ARCH_IPV6_CSUM +static __inline__ unsigned short int +csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr, + __u32 len, unsigned short proto, unsigned int sum) +{ + register unsigned long tmp; + __asm__("addl %2@,%0\n\t" + "movel %2@(4),%1\n\t" + "addxl %1,%0\n\t" + "movel %2@(8),%1\n\t" + "addxl %1,%0\n\t" + "movel %2@(12),%1\n\t" + "addxl %1,%0\n\t" + "movel %3@,%1\n\t" + "addxl %1,%0\n\t" + "movel %3@(4),%1\n\t" + "addxl %1,%0\n\t" + "movel %3@(8),%1\n\t" + "addxl %1,%0\n\t" + "movel %3@(12),%1\n\t" + "addxl %1,%0\n\t" + "addxl %4,%0\n\t" + "clrl %1\n\t" + "addxl %1,%0" + : "=&d" (sum), "=&d" (tmp) + : "a" (saddr), "a" (daddr), "d" (len + proto), + "0" (sum)); + + return csum_fold(sum); +} + +#endif /* _M68K_CHECKSUM_H */ diff -Nru a/include/asm-m68knommu/coldfire.h b/include/asm-m68knommu/coldfire.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/coldfire.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,72 @@ +/****************************************************************************/ + +/* + * coldfire.h -- Motorola ColdFire CPU sepecific defines + * + * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com) + * (C) Copyright 2000, Lineo (www.lineo.com) + */ + +/****************************************************************************/ +#ifndef coldfire_h +#define coldfire_h +/****************************************************************************/ + +#include + +/* + * Define the processor support peripherals base address. + * This is generally setup by the boards start up code. + */ +#define MCF_MBAR 0x10000000 +#define MCF_MBAR2 0x80000000 + +/* + * Define master clock frequency. + */ +#if defined(CONFIG_CLOCK_11MHz) +#define MCF_CLK 11289600 +#elif defined(CONFIG_CLOCK_16MHz) +#define MCF_CLK 16000000 +#elif defined(CONFIG_CLOCK_20MHz) +#define MCF_CLK 20000000 +#elif defined(CONFIG_CLOCK_24MHz) +#define MCF_CLK 24000000 +#elif defined(CONFIG_CLOCK_25MHz) +#define MCF_CLK 25000000 +#elif defined(CONFIG_CLOCK_33MHz) +#define MCF_CLK 33000000 +#elif defined(CONFIG_CLOCK_40MHz) +#define MCF_CLK 40000000 +#elif defined(CONFIG_CLOCK_45MHz) +#define MCF_CLK 45000000 +#elif defined(CONFIG_CLOCK_48MHz) +#define MCF_CLK 48000000 +#elif defined(CONFIG_CLOCK_50MHz) +#define MCF_CLK 50000000 +#elif defined(CONFIG_CLOCK_54MHz) +#define MCF_CLK 54000000 +#elif defined(CONFIG_CLOCK_60MHz) +#define MCF_CLK 60000000 +#elif defined(CONFIG_CLOCK_66MHz) +#define MCF_CLK 66000000 +#elif defined(CONFIG_CLOCK_70MHz) +#define MCF_CLK 70000000 +#elif defined(CONFIG_CLOCK_140MHz) +#define MCF_CLK 140000000 +#else +#error "Don't know what your ColdFire CPU clock frequency is??" +#endif + +/* + * One some ColdFire family members the bus clock (used by internal + * peripherals) is not the same as the CPU clock. + */ +#ifdef CONFIG_M5249 +#define MCF_BUSCLK (MCF_CLK / 2) +#else +#define MCF_BUSCLK MCF_CLK +#endif + +/****************************************************************************/ +#endif /* coldfire_h */ diff -Nru a/include/asm-m68knommu/commproc.h b/include/asm-m68knommu/commproc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/commproc.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,723 @@ + +/* + * 68360 Communication Processor Module. + * Copyright (c) 2000 Michael Leslie (mc68360) after: + * Copyright (c) 1997 Dan Malek (mpc8xx) + * + * This file contains structures and information for the communication + * processor channels. Some CPM control and status is available + * through the 68360 internal memory map. See include/asm/360_immap.h for details. + * This file is not a complete map of all of the 360 QUICC's capabilities + * + * On the MBX board, EPPC-Bug loads CPM microcode into the first 512 + * bytes of the DP RAM and relocates the I2C parameter area to the + * IDMA1 space. The remaining DP RAM is available for buffer descriptors + * or other use. + */ +#ifndef __CPM_360__ +#define __CPM_360__ + +#include + +/* CPM Command register masks: */ +#define CPM_CR_RST ((ushort)0x8000) +#define CPM_CR_OPCODE ((ushort)0x0f00) +#define CPM_CR_CHAN ((ushort)0x00f0) +#define CPM_CR_FLG ((ushort)0x0001) + +/* CPM Command set (opcodes): */ +#define CPM_CR_INIT_TRX ((ushort)0x0000) +#define CPM_CR_INIT_RX ((ushort)0x0001) +#define CPM_CR_INIT_TX ((ushort)0x0002) +#define CPM_CR_HUNT_MODE ((ushort)0x0003) +#define CPM_CR_STOP_TX ((ushort)0x0004) +#define CPM_CR_GRSTOP_TX ((ushort)0x0005) +#define CPM_CR_RESTART_TX ((ushort)0x0006) +#define CPM_CR_CLOSE_RXBD ((ushort)0x0007) +#define CPM_CR_SET_GADDR ((ushort)0x0008) +#define CPM_CR_GCI_TIMEOUT ((ushort)0x0009) +#define CPM_CR_GCI_ABORT ((ushort)0x000a) +#define CPM_CR_RESET_BCS ((ushort)0x000a) + +/* CPM Channel numbers. */ +#define CPM_CR_CH_SCC1 ((ushort)0x0000) +#define CPM_CR_CH_SCC2 ((ushort)0x0004) +#define CPM_CR_CH_SPI ((ushort)0x0005) /* SPI / Timers */ +#define CPM_CR_CH_TMR ((ushort)0x0005) +#define CPM_CR_CH_SCC3 ((ushort)0x0008) +#define CPM_CR_CH_SMC1 ((ushort)0x0009) /* SMC1 / IDMA1 */ +#define CPM_CR_CH_IDMA1 ((ushort)0x0009) +#define CPM_CR_CH_SCC4 ((ushort)0x000c) +#define CPM_CR_CH_SMC2 ((ushort)0x000d) /* SMC2 / IDMA2 */ +#define CPM_CR_CH_IDMA2 ((ushort)0x000d) + + +#define mk_cr_cmd(CH, CMD) ((CMD << 8) | (CH << 4)) + +#if 1 /* mleslie: I dinna think we have any such restrictions on + * DP RAM aboard the 360 board - see the MC68360UM p.3-3 */ + +/* The dual ported RAM is multi-functional. Some areas can be (and are + * being) used for microcode. There is an area that can only be used + * as data ram for buffer descriptors, which is all we use right now. + * Currently the first 512 and last 256 bytes are used for microcode. + */ +/* mleslie: The uCquicc board is using no extra microcode in DPRAM */ +#define CPM_DATAONLY_BASE ((uint)0x0000) +#define CPM_DATAONLY_SIZE ((uint)0x0800) +#define CPM_DP_NOSPACE ((uint)0x7fffffff) + +#endif + + +/* Export the base address of the communication processor registers + * and dual port ram. */ +/* extern cpm360_t *cpmp; */ /* Pointer to comm processor */ +extern QUICC *pquicc; +uint m360_cpm_dpalloc(uint size); +/* void *m360_cpm_hostalloc(uint size); */ +void m360_cpm_setbrg(uint brg, uint rate); + +#if 0 /* use QUICC_BD declared in include/asm/m68360_quicc.h */ +/* Buffer descriptors used by many of the CPM protocols. */ +typedef struct cpm_buf_desc { + ushort cbd_sc; /* Status and Control */ + ushort cbd_datlen; /* Data length in buffer */ + uint cbd_bufaddr; /* Buffer address in host memory */ +} cbd_t; +#endif + + +/* rx bd status/control bits */ +#define BD_SC_EMPTY ((ushort)0x8000) /* Recieve is empty */ +#define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor in table */ +#define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */ +#define BD_SC_LAST ((ushort)0x0800) /* Last buffer in frame OR control char */ + +#define BD_SC_FIRST ((ushort)0x0400) /* 1st buffer in an HDLC frame */ +#define BD_SC_ADDR ((ushort)0x0400) /* 1st byte is a multidrop address */ + +#define BD_SC_CM ((ushort)0x0200) /* Continous mode */ +#define BD_SC_ID ((ushort)0x0100) /* Received too many idles */ + +#define BD_SC_AM ((ushort)0x0080) /* Multidrop address match */ +#define BD_SC_DE ((ushort)0x0080) /* DPLL Error (HDLC) */ + +#define BD_SC_BR ((ushort)0x0020) /* Break received */ +#define BD_SC_LG ((ushort)0x0020) /* Frame length violation (HDLC) */ + +#define BD_SC_FR ((ushort)0x0010) /* Framing error */ +#define BD_SC_NO ((ushort)0x0010) /* Nonoctet aligned frame (HDLC) */ + +#define BD_SC_PR ((ushort)0x0008) /* Parity error */ +#define BD_SC_AB ((ushort)0x0008) /* Received abort Sequence (HDLC) */ + +#define BD_SC_OV ((ushort)0x0002) /* Overrun */ +#define BD_SC_CD ((ushort)0x0001) /* Carrier Detect lost */ + +/* tx bd status/control bits (as differ from rx bd) */ +#define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */ +#define BD_SC_TC ((ushort)0x0400) /* Transmit CRC */ +#define BD_SC_P ((ushort)0x0100) /* xmt preamble */ +#define BD_SC_UN ((ushort)0x0002) /* Underrun */ + + + + +/* Parameter RAM offsets. */ + + + +/* In 2.4 ppc, the PROFF_S?C? are used as byte offsets into DPRAM. + * In 2.0, we use a more structured C struct map of DPRAM, and so + * instead, we need only a parameter ram `slot' */ + +#define PRSLOT_SCC1 0 +#define PRSLOT_SCC2 1 +#define PRSLOT_SCC3 2 +#define PRSLOT_SMC1 2 +#define PRSLOT_SCC4 3 +#define PRSLOT_SMC2 3 + + +/* #define PROFF_SCC1 ((uint)0x0000) */ +/* #define PROFF_SCC2 ((uint)0x0100) */ +/* #define PROFF_SCC3 ((uint)0x0200) */ +/* #define PROFF_SMC1 ((uint)0x0280) */ +/* #define PROFF_SCC4 ((uint)0x0300) */ +/* #define PROFF_SMC2 ((uint)0x0380) */ + + +/* Define enough so I can at least use the serial port as a UART. + * The MBX uses SMC1 as the host serial port. + */ +typedef struct smc_uart { + ushort smc_rbase; /* Rx Buffer descriptor base address */ + ushort smc_tbase; /* Tx Buffer descriptor base address */ + u_char smc_rfcr; /* Rx function code */ + u_char smc_tfcr; /* Tx function code */ + ushort smc_mrblr; /* Max receive buffer length */ + uint smc_rstate; /* Internal */ + uint smc_idp; /* Internal */ + ushort smc_rbptr; /* Internal */ + ushort smc_ibc; /* Internal */ + uint smc_rxtmp; /* Internal */ + uint smc_tstate; /* Internal */ + uint smc_tdp; /* Internal */ + ushort smc_tbptr; /* Internal */ + ushort smc_tbc; /* Internal */ + uint smc_txtmp; /* Internal */ + ushort smc_maxidl; /* Maximum idle characters */ + ushort smc_tmpidl; /* Temporary idle counter */ + ushort smc_brklen; /* Last received break length */ + ushort smc_brkec; /* rcv'd break condition counter */ + ushort smc_brkcr; /* xmt break count register */ + ushort smc_rmask; /* Temporary bit mask */ +} smc_uart_t; + +/* Function code bits. +*/ +#define SMC_EB ((u_char)0x10) /* Set big endian byte order */ + +/* SMC uart mode register. +*/ +#define SMCMR_REN ((ushort)0x0001) +#define SMCMR_TEN ((ushort)0x0002) +#define SMCMR_DM ((ushort)0x000c) +#define SMCMR_SM_GCI ((ushort)0x0000) +#define SMCMR_SM_UART ((ushort)0x0020) +#define SMCMR_SM_TRANS ((ushort)0x0030) +#define SMCMR_SM_MASK ((ushort)0x0030) +#define SMCMR_PM_EVEN ((ushort)0x0100) /* Even parity, else odd */ +#define SMCMR_REVD SMCMR_PM_EVEN +#define SMCMR_PEN ((ushort)0x0200) /* Parity enable */ +#define SMCMR_BS SMCMR_PEN +#define SMCMR_SL ((ushort)0x0400) /* Two stops, else one */ +#define SMCR_CLEN_MASK ((ushort)0x7800) /* Character length */ +#define smcr_mk_clen(C) (((C) << 11) & SMCR_CLEN_MASK) + +/* SMC2 as Centronics parallel printer. It is half duplex, in that + * it can only receive or transmit. The parameter ram values for + * each direction are either unique or properly overlap, so we can + * include them in one structure. + */ +typedef struct smc_centronics { + ushort scent_rbase; + ushort scent_tbase; + u_char scent_cfcr; + u_char scent_smask; + ushort scent_mrblr; + uint scent_rstate; + uint scent_r_ptr; + ushort scent_rbptr; + ushort scent_r_cnt; + uint scent_rtemp; + uint scent_tstate; + uint scent_t_ptr; + ushort scent_tbptr; + ushort scent_t_cnt; + uint scent_ttemp; + ushort scent_max_sl; + ushort scent_sl_cnt; + ushort scent_character1; + ushort scent_character2; + ushort scent_character3; + ushort scent_character4; + ushort scent_character5; + ushort scent_character6; + ushort scent_character7; + ushort scent_character8; + ushort scent_rccm; + ushort scent_rccr; +} smc_cent_t; + +/* Centronics Status Mask Register. +*/ +#define SMC_CENT_F ((u_char)0x08) +#define SMC_CENT_PE ((u_char)0x04) +#define SMC_CENT_S ((u_char)0x02) + +/* SMC Event and Mask register. +*/ +#define SMCM_BRKE ((unsigned char)0x40) /* When in UART Mode */ +#define SMCM_BRK ((unsigned char)0x10) /* When in UART Mode */ +#define SMCM_TXE ((unsigned char)0x10) /* When in Transparent Mode */ +#define SMCM_BSY ((unsigned char)0x04) +#define SMCM_TX ((unsigned char)0x02) +#define SMCM_RX ((unsigned char)0x01) + +/* Baud rate generators. +*/ +#define CPM_BRG_RST ((uint)0x00020000) +#define CPM_BRG_EN ((uint)0x00010000) +#define CPM_BRG_EXTC_INT ((uint)0x00000000) +#define CPM_BRG_EXTC_CLK2 ((uint)0x00004000) +#define CPM_BRG_EXTC_CLK6 ((uint)0x00008000) +#define CPM_BRG_ATB ((uint)0x00002000) +#define CPM_BRG_CD_MASK ((uint)0x00001ffe) +#define CPM_BRG_DIV16 ((uint)0x00000001) + +/* SCCs. +*/ +#define SCC_GSMRH_IRP ((uint)0x00040000) +#define SCC_GSMRH_GDE ((uint)0x00010000) +#define SCC_GSMRH_TCRC_CCITT ((uint)0x00008000) +#define SCC_GSMRH_TCRC_BISYNC ((uint)0x00004000) +#define SCC_GSMRH_TCRC_HDLC ((uint)0x00000000) +#define SCC_GSMRH_REVD ((uint)0x00002000) +#define SCC_GSMRH_TRX ((uint)0x00001000) +#define SCC_GSMRH_TTX ((uint)0x00000800) +#define SCC_GSMRH_CDP ((uint)0x00000400) +#define SCC_GSMRH_CTSP ((uint)0x00000200) +#define SCC_GSMRH_CDS ((uint)0x00000100) +#define SCC_GSMRH_CTSS ((uint)0x00000080) +#define SCC_GSMRH_TFL ((uint)0x00000040) +#define SCC_GSMRH_RFW ((uint)0x00000020) +#define SCC_GSMRH_TXSY ((uint)0x00000010) +#define SCC_GSMRH_SYNL16 ((uint)0x0000000c) +#define SCC_GSMRH_SYNL8 ((uint)0x00000008) +#define SCC_GSMRH_SYNL4 ((uint)0x00000004) +#define SCC_GSMRH_RTSM ((uint)0x00000002) +#define SCC_GSMRH_RSYN ((uint)0x00000001) + +#define SCC_GSMRL_SIR ((uint)0x80000000) /* SCC2 only */ +#define SCC_GSMRL_EDGE_NONE ((uint)0x60000000) +#define SCC_GSMRL_EDGE_NEG ((uint)0x40000000) +#define SCC_GSMRL_EDGE_POS ((uint)0x20000000) +#define SCC_GSMRL_EDGE_BOTH ((uint)0x00000000) +#define SCC_GSMRL_TCI ((uint)0x10000000) +#define SCC_GSMRL_TSNC_3 ((uint)0x0c000000) +#define SCC_GSMRL_TSNC_4 ((uint)0x08000000) +#define SCC_GSMRL_TSNC_14 ((uint)0x04000000) +#define SCC_GSMRL_TSNC_INF ((uint)0x00000000) +#define SCC_GSMRL_RINV ((uint)0x02000000) +#define SCC_GSMRL_TINV ((uint)0x01000000) +#define SCC_GSMRL_TPL_128 ((uint)0x00c00000) +#define SCC_GSMRL_TPL_64 ((uint)0x00a00000) +#define SCC_GSMRL_TPL_48 ((uint)0x00800000) +#define SCC_GSMRL_TPL_32 ((uint)0x00600000) +#define SCC_GSMRL_TPL_16 ((uint)0x00400000) +#define SCC_GSMRL_TPL_8 ((uint)0x00200000) +#define SCC_GSMRL_TPL_NONE ((uint)0x00000000) +#define SCC_GSMRL_TPP_ALL1 ((uint)0x00180000) +#define SCC_GSMRL_TPP_01 ((uint)0x00100000) +#define SCC_GSMRL_TPP_10 ((uint)0x00080000) +#define SCC_GSMRL_TPP_ZEROS ((uint)0x00000000) +#define SCC_GSMRL_TEND ((uint)0x00040000) +#define SCC_GSMRL_TDCR_32 ((uint)0x00030000) +#define SCC_GSMRL_TDCR_16 ((uint)0x00020000) +#define SCC_GSMRL_TDCR_8 ((uint)0x00010000) +#define SCC_GSMRL_TDCR_1 ((uint)0x00000000) +#define SCC_GSMRL_RDCR_32 ((uint)0x0000c000) +#define SCC_GSMRL_RDCR_16 ((uint)0x00008000) +#define SCC_GSMRL_RDCR_8 ((uint)0x00004000) +#define SCC_GSMRL_RDCR_1 ((uint)0x00000000) +#define SCC_GSMRL_RENC_DFMAN ((uint)0x00003000) +#define SCC_GSMRL_RENC_MANCH ((uint)0x00002000) +#define SCC_GSMRL_RENC_FM0 ((uint)0x00001000) +#define SCC_GSMRL_RENC_NRZI ((uint)0x00000800) +#define SCC_GSMRL_RENC_NRZ ((uint)0x00000000) +#define SCC_GSMRL_TENC_DFMAN ((uint)0x00000600) +#define SCC_GSMRL_TENC_MANCH ((uint)0x00000400) +#define SCC_GSMRL_TENC_FM0 ((uint)0x00000200) +#define SCC_GSMRL_TENC_NRZI ((uint)0x00000100) +#define SCC_GSMRL_TENC_NRZ ((uint)0x00000000) +#define SCC_GSMRL_DIAG_LE ((uint)0x000000c0) /* Loop and echo */ +#define SCC_GSMRL_DIAG_ECHO ((uint)0x00000080) +#define SCC_GSMRL_DIAG_LOOP ((uint)0x00000040) +#define SCC_GSMRL_DIAG_NORM ((uint)0x00000000) +#define SCC_GSMRL_ENR ((uint)0x00000020) +#define SCC_GSMRL_ENT ((uint)0x00000010) +#define SCC_GSMRL_MODE_ENET ((uint)0x0000000c) +#define SCC_GSMRL_MODE_DDCMP ((uint)0x00000009) +#define SCC_GSMRL_MODE_BISYNC ((uint)0x00000008) +#define SCC_GSMRL_MODE_V14 ((uint)0x00000007) +#define SCC_GSMRL_MODE_AHDLC ((uint)0x00000006) +#define SCC_GSMRL_MODE_PROFIBUS ((uint)0x00000005) +#define SCC_GSMRL_MODE_UART ((uint)0x00000004) +#define SCC_GSMRL_MODE_SS7 ((uint)0x00000003) +#define SCC_GSMRL_MODE_ATALK ((uint)0x00000002) +#define SCC_GSMRL_MODE_HDLC ((uint)0x00000000) + +#define SCC_TODR_TOD ((ushort)0x8000) + +/* SCC Event and Mask register. +*/ +#define SCCM_TXE ((unsigned char)0x10) +#define SCCM_BSY ((unsigned char)0x04) +#define SCCM_TX ((unsigned char)0x02) +#define SCCM_RX ((unsigned char)0x01) + +typedef struct scc_param { + ushort scc_rbase; /* Rx Buffer descriptor base address */ + ushort scc_tbase; /* Tx Buffer descriptor base address */ + u_char scc_rfcr; /* Rx function code */ + u_char scc_tfcr; /* Tx function code */ + ushort scc_mrblr; /* Max receive buffer length */ + uint scc_rstate; /* Internal */ + uint scc_idp; /* Internal */ + ushort scc_rbptr; /* Internal */ + ushort scc_ibc; /* Internal */ + uint scc_rxtmp; /* Internal */ + uint scc_tstate; /* Internal */ + uint scc_tdp; /* Internal */ + ushort scc_tbptr; /* Internal */ + ushort scc_tbc; /* Internal */ + uint scc_txtmp; /* Internal */ + uint scc_rcrc; /* Internal */ + uint scc_tcrc; /* Internal */ +} sccp_t; + + +/* Function code bits. + */ +#define SCC_EB ((u_char)0x10) /* Set big endian byte order */ +#define SCC_FC_DMA ((u_char)0x08) /* Set SDMA */ + +/* CPM Ethernet through SCC1. + */ +typedef struct scc_enet { + sccp_t sen_genscc; + uint sen_cpres; /* Preset CRC */ + uint sen_cmask; /* Constant mask for CRC */ + uint sen_crcec; /* CRC Error counter */ + uint sen_alec; /* alignment error counter */ + uint sen_disfc; /* discard frame counter */ + ushort sen_pads; /* Tx short frame pad character */ + ushort sen_retlim; /* Retry limit threshold */ + ushort sen_retcnt; /* Retry limit counter */ + ushort sen_maxflr; /* maximum frame length register */ + ushort sen_minflr; /* minimum frame length register */ + ushort sen_maxd1; /* maximum DMA1 length */ + ushort sen_maxd2; /* maximum DMA2 length */ + ushort sen_maxd; /* Rx max DMA */ + ushort sen_dmacnt; /* Rx DMA counter */ + ushort sen_maxb; /* Max BD byte count */ + ushort sen_gaddr1; /* Group address filter */ + ushort sen_gaddr2; + ushort sen_gaddr3; + ushort sen_gaddr4; + uint sen_tbuf0data0; /* Save area 0 - current frame */ + uint sen_tbuf0data1; /* Save area 1 - current frame */ + uint sen_tbuf0rba; /* Internal */ + uint sen_tbuf0crc; /* Internal */ + ushort sen_tbuf0bcnt; /* Internal */ + ushort sen_paddrh; /* physical address (MSB) */ + ushort sen_paddrm; + ushort sen_paddrl; /* physical address (LSB) */ + ushort sen_pper; /* persistence */ + ushort sen_rfbdptr; /* Rx first BD pointer */ + ushort sen_tfbdptr; /* Tx first BD pointer */ + ushort sen_tlbdptr; /* Tx last BD pointer */ + uint sen_tbuf1data0; /* Save area 0 - current frame */ + uint sen_tbuf1data1; /* Save area 1 - current frame */ + uint sen_tbuf1rba; /* Internal */ + uint sen_tbuf1crc; /* Internal */ + ushort sen_tbuf1bcnt; /* Internal */ + ushort sen_txlen; /* Tx Frame length counter */ + ushort sen_iaddr1; /* Individual address filter */ + ushort sen_iaddr2; + ushort sen_iaddr3; + ushort sen_iaddr4; + ushort sen_boffcnt; /* Backoff counter */ + + /* NOTE: Some versions of the manual have the following items + * incorrectly documented. Below is the proper order. + */ + ushort sen_taddrh; /* temp address (MSB) */ + ushort sen_taddrm; + ushort sen_taddrl; /* temp address (LSB) */ +} scc_enet_t; + + + +#if defined (CONFIG_UCQUICC) +/* uCquicc has the following signals connected to Ethernet: + * 68360 - lxt905 + * PA0/RXD1 - rxd + * PA1/TXD1 - txd + * PA8/CLK1 - tclk + * PA9/CLK2 - rclk + * PC0/!RTS1 - t_en + * PC1/!CTS1 - col + * PC5/!CD1 - cd + */ +#define PA_ENET_RXD PA_RXD1 +#define PA_ENET_TXD PA_TXD1 +#define PA_ENET_TCLK PA_CLK1 +#define PA_ENET_RCLK PA_CLK2 +#define PC_ENET_TENA PC_RTS1 +#define PC_ENET_CLSN PC_CTS1 +#define PC_ENET_RENA PC_CD1 + +/* Control bits in the SICR to route TCLK (CLK1) and RCLK (CLK2) to + * SCC1. + */ +#define SICR_ENET_MASK ((uint)0x000000ff) +#define SICR_ENET_CLKRT ((uint)0x0000002c) + +#endif /* config_ucquicc */ + + +#ifdef MBX +/* Bits in parallel I/O port registers that have to be set/cleared + * to configure the pins for SCC1 use. The TCLK and RCLK seem unique + * to the MBX860 board. Any two of the four available clocks could be + * used, and the MPC860 cookbook manual has an example using different + * clock pins. + */ +#define PA_ENET_RXD ((ushort)0x0001) +#define PA_ENET_TXD ((ushort)0x0002) +#define PA_ENET_TCLK ((ushort)0x0200) +#define PA_ENET_RCLK ((ushort)0x0800) +#define PC_ENET_TENA ((ushort)0x0001) +#define PC_ENET_CLSN ((ushort)0x0010) +#define PC_ENET_RENA ((ushort)0x0020) + +/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to + * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero. + */ +#define SICR_ENET_MASK ((uint)0x000000ff) +#define SICR_ENET_CLKRT ((uint)0x0000003d) +#endif + +#ifdef CONFIG_RPXLITE +/* This ENET stuff is for the MPC850 with ethernet on SCC2. Some of + * this may be unique to the RPX-Lite configuration. + * Note TENA is on Port B. + */ +#define PA_ENET_RXD ((ushort)0x0004) +#define PA_ENET_TXD ((ushort)0x0008) +#define PA_ENET_TCLK ((ushort)0x0200) +#define PA_ENET_RCLK ((ushort)0x0800) +#define PB_ENET_TENA ((uint)0x00002000) +#define PC_ENET_CLSN ((ushort)0x0040) +#define PC_ENET_RENA ((ushort)0x0080) + +#define SICR_ENET_MASK ((uint)0x0000ff00) +#define SICR_ENET_CLKRT ((uint)0x00003d00) +#endif + +#ifdef CONFIG_BSEIP +/* This ENET stuff is for the MPC823 with ethernet on SCC2. + * This is unique to the BSE ip-Engine board. + */ +#define PA_ENET_RXD ((ushort)0x0004) +#define PA_ENET_TXD ((ushort)0x0008) +#define PA_ENET_TCLK ((ushort)0x0100) +#define PA_ENET_RCLK ((ushort)0x0200) +#define PB_ENET_TENA ((uint)0x00002000) +#define PC_ENET_CLSN ((ushort)0x0040) +#define PC_ENET_RENA ((ushort)0x0080) + +/* BSE uses port B and C bits for PHY control also. +*/ +#define PB_BSE_POWERUP ((uint)0x00000004) +#define PB_BSE_FDXDIS ((uint)0x00008000) +#define PC_BSE_LOOPBACK ((ushort)0x0800) + +#define SICR_ENET_MASK ((uint)0x0000ff00) +#define SICR_ENET_CLKRT ((uint)0x00002c00) +#endif + +#ifdef CONFIG_RPXCLASSIC +/* Bits in parallel I/O port registers that have to be set/cleared + * to configure the pins for SCC1 use. + */ +#define PA_ENET_RXD ((ushort)0x0001) +#define PA_ENET_TXD ((ushort)0x0002) +#define PA_ENET_TCLK ((ushort)0x0200) +#define PA_ENET_RCLK ((ushort)0x0800) +#define PB_ENET_TENA ((uint)0x00001000) +#define PC_ENET_CLSN ((ushort)0x0010) +#define PC_ENET_RENA ((ushort)0x0020) + +/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to + * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero. + */ +#define SICR_ENET_MASK ((uint)0x000000ff) +#define SICR_ENET_CLKRT ((uint)0x0000003d) +#endif + +/* SCC Event register as used by Ethernet. +*/ +#define SCCE_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */ +#define SCCE_ENET_TXE ((ushort)0x0010) /* Transmit Error */ +#define SCCE_ENET_RXF ((ushort)0x0008) /* Full frame received */ +#define SCCE_ENET_BSY ((ushort)0x0004) /* All incoming buffers full */ +#define SCCE_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */ +#define SCCE_ENET_RXB ((ushort)0x0001) /* A buffer was received */ + +/* SCC Mode Register (PMSR) as used by Ethernet. +*/ +#define SCC_PMSR_HBC ((ushort)0x8000) /* Enable heartbeat */ +#define SCC_PMSR_FC ((ushort)0x4000) /* Force collision */ +#define SCC_PMSR_RSH ((ushort)0x2000) /* Receive short frames */ +#define SCC_PMSR_IAM ((ushort)0x1000) /* Check individual hash */ +#define SCC_PMSR_ENCRC ((ushort)0x0800) /* Ethernet CRC mode */ +#define SCC_PMSR_PRO ((ushort)0x0200) /* Promiscuous mode */ +#define SCC_PMSR_BRO ((ushort)0x0100) /* Catch broadcast pkts */ +#define SCC_PMSR_SBT ((ushort)0x0080) /* Special backoff timer */ +#define SCC_PMSR_LPB ((ushort)0x0040) /* Set Loopback mode */ +#define SCC_PMSR_SIP ((ushort)0x0020) /* Sample Input Pins */ +#define SCC_PMSR_LCW ((ushort)0x0010) /* Late collision window */ +#define SCC_PMSR_NIB22 ((ushort)0x000a) /* Start frame search */ +#define SCC_PMSR_FDE ((ushort)0x0001) /* Full duplex enable */ + +/* Buffer descriptor control/status used by Ethernet receive. +*/ +#define BD_ENET_RX_EMPTY ((ushort)0x8000) +#define BD_ENET_RX_WRAP ((ushort)0x2000) +#define BD_ENET_RX_INTR ((ushort)0x1000) +#define BD_ENET_RX_LAST ((ushort)0x0800) +#define BD_ENET_RX_FIRST ((ushort)0x0400) +#define BD_ENET_RX_MISS ((ushort)0x0100) +#define BD_ENET_RX_LG ((ushort)0x0020) +#define BD_ENET_RX_NO ((ushort)0x0010) +#define BD_ENET_RX_SH ((ushort)0x0008) +#define BD_ENET_RX_CR ((ushort)0x0004) +#define BD_ENET_RX_OV ((ushort)0x0002) +#define BD_ENET_RX_CL ((ushort)0x0001) +#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */ + +/* Buffer descriptor control/status used by Ethernet transmit. +*/ +#define BD_ENET_TX_READY ((ushort)0x8000) +#define BD_ENET_TX_PAD ((ushort)0x4000) +#define BD_ENET_TX_WRAP ((ushort)0x2000) +#define BD_ENET_TX_INTR ((ushort)0x1000) +#define BD_ENET_TX_LAST ((ushort)0x0800) +#define BD_ENET_TX_TC ((ushort)0x0400) +#define BD_ENET_TX_DEF ((ushort)0x0200) +#define BD_ENET_TX_HB ((ushort)0x0100) +#define BD_ENET_TX_LC ((ushort)0x0080) +#define BD_ENET_TX_RL ((ushort)0x0040) +#define BD_ENET_TX_RCMASK ((ushort)0x003c) +#define BD_ENET_TX_UN ((ushort)0x0002) +#define BD_ENET_TX_CSL ((ushort)0x0001) +#define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */ + +/* SCC as UART +*/ +typedef struct scc_uart { + sccp_t scc_genscc; + uint scc_res1; /* Reserved */ + uint scc_res2; /* Reserved */ + ushort scc_maxidl; /* Maximum idle chars */ + ushort scc_idlc; /* temp idle counter */ + ushort scc_brkcr; /* Break count register */ + ushort scc_parec; /* receive parity error counter */ + ushort scc_frmec; /* receive framing error counter */ + ushort scc_nosec; /* receive noise counter */ + ushort scc_brkec; /* receive break condition counter */ + ushort scc_brkln; /* last received break length */ + ushort scc_uaddr1; /* UART address character 1 */ + ushort scc_uaddr2; /* UART address character 2 */ + ushort scc_rtemp; /* Temp storage */ + ushort scc_toseq; /* Transmit out of sequence char */ + ushort scc_char1; /* control character 1 */ + ushort scc_char2; /* control character 2 */ + ushort scc_char3; /* control character 3 */ + ushort scc_char4; /* control character 4 */ + ushort scc_char5; /* control character 5 */ + ushort scc_char6; /* control character 6 */ + ushort scc_char7; /* control character 7 */ + ushort scc_char8; /* control character 8 */ + ushort scc_rccm; /* receive control character mask */ + ushort scc_rccr; /* receive control character register */ + ushort scc_rlbc; /* receive last break character */ +} scc_uart_t; + +/* SCC Event and Mask registers when it is used as a UART. +*/ +#define UART_SCCM_GLR ((ushort)0x1000) +#define UART_SCCM_GLT ((ushort)0x0800) +#define UART_SCCM_AB ((ushort)0x0200) +#define UART_SCCM_IDL ((ushort)0x0100) +#define UART_SCCM_GRA ((ushort)0x0080) +#define UART_SCCM_BRKE ((ushort)0x0040) +#define UART_SCCM_BRKS ((ushort)0x0020) +#define UART_SCCM_CCR ((ushort)0x0008) +#define UART_SCCM_BSY ((ushort)0x0004) +#define UART_SCCM_TX ((ushort)0x0002) +#define UART_SCCM_RX ((ushort)0x0001) + +/* The SCC PMSR when used as a UART. +*/ +#define SCU_PMSR_FLC ((ushort)0x8000) +#define SCU_PMSR_SL ((ushort)0x4000) +#define SCU_PMSR_CL ((ushort)0x3000) +#define SCU_PMSR_UM ((ushort)0x0c00) +#define SCU_PMSR_FRZ ((ushort)0x0200) +#define SCU_PMSR_RZS ((ushort)0x0100) +#define SCU_PMSR_SYN ((ushort)0x0080) +#define SCU_PMSR_DRT ((ushort)0x0040) +#define SCU_PMSR_PEN ((ushort)0x0010) +#define SCU_PMSR_RPM ((ushort)0x000c) +#define SCU_PMSR_REVP ((ushort)0x0008) +#define SCU_PMSR_TPM ((ushort)0x0003) +#define SCU_PMSR_TEVP ((ushort)0x0003) + +/* CPM Transparent mode SCC. + */ +typedef struct scc_trans { + sccp_t st_genscc; + uint st_cpres; /* Preset CRC */ + uint st_cmask; /* Constant mask for CRC */ +} scc_trans_t; + +#define BD_SCC_TX_LAST ((ushort)0x0800) + + + +/* CPM interrupts. There are nearly 32 interrupts generated by CPM + * channels or devices. All of these are presented to the PPC core + * as a single interrupt. The CPM interrupt handler dispatches its + * own handlers, in a similar fashion to the PPC core handler. We + * use the table as defined in the manuals (i.e. no special high + * priority and SCC1 == SCCa, etc...). + */ +/* #define CPMVEC_NR 32 */ +/* #define CPMVEC_PIO_PC15 ((ushort)0x1f) */ +/* #define CPMVEC_SCC1 ((ushort)0x1e) */ +/* #define CPMVEC_SCC2 ((ushort)0x1d) */ +/* #define CPMVEC_SCC3 ((ushort)0x1c) */ +/* #define CPMVEC_SCC4 ((ushort)0x1b) */ +/* #define CPMVEC_PIO_PC14 ((ushort)0x1a) */ +/* #define CPMVEC_TIMER1 ((ushort)0x19) */ +/* #define CPMVEC_PIO_PC13 ((ushort)0x18) */ +/* #define CPMVEC_PIO_PC12 ((ushort)0x17) */ +/* #define CPMVEC_SDMA_CB_ERR ((ushort)0x16) */ +/* #define CPMVEC_IDMA1 ((ushort)0x15) */ +/* #define CPMVEC_IDMA2 ((ushort)0x14) */ +/* #define CPMVEC_TIMER2 ((ushort)0x12) */ +/* #define CPMVEC_RISCTIMER ((ushort)0x11) */ +/* #define CPMVEC_I2C ((ushort)0x10) */ +/* #define CPMVEC_PIO_PC11 ((ushort)0x0f) */ +/* #define CPMVEC_PIO_PC10 ((ushort)0x0e) */ +/* #define CPMVEC_TIMER3 ((ushort)0x0c) */ +/* #define CPMVEC_PIO_PC9 ((ushort)0x0b) */ +/* #define CPMVEC_PIO_PC8 ((ushort)0x0a) */ +/* #define CPMVEC_PIO_PC7 ((ushort)0x09) */ +/* #define CPMVEC_TIMER4 ((ushort)0x07) */ +/* #define CPMVEC_PIO_PC6 ((ushort)0x06) */ +/* #define CPMVEC_SPI ((ushort)0x05) */ +/* #define CPMVEC_SMC1 ((ushort)0x04) */ +/* #define CPMVEC_SMC2 ((ushort)0x03) */ +/* #define CPMVEC_PIO_PC5 ((ushort)0x02) */ +/* #define CPMVEC_PIO_PC4 ((ushort)0x01) */ +/* #define CPMVEC_ERROR ((ushort)0x00) */ + +extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id); + +/* CPM interrupt configuration vector. +*/ +#define CICR_SCD_SCC4 ((uint)0x00c00000) /* SCC4 @ SCCd */ +#define CICR_SCC_SCC3 ((uint)0x00200000) /* SCC3 @ SCCc */ +#define CICR_SCB_SCC2 ((uint)0x00040000) /* SCC2 @ SCCb */ +#define CICR_SCA_SCC1 ((uint)0x00000000) /* SCC1 @ SCCa */ +#define CICR_IRL_MASK ((uint)0x0000e000) /* Core interrrupt */ +#define CICR_HP_MASK ((uint)0x00001f00) /* Hi-pri int. */ +#define CICR_IEN ((uint)0x00000080) /* Int. enable */ +#define CICR_SPS ((uint)0x00000001) /* SCC Spread */ +#endif /* __CPM_360__ */ diff -Nru a/include/asm-m68knommu/current.h b/include/asm-m68knommu/current.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/current.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,24 @@ +#ifndef _M68KNOMMU_CURRENT_H +#define _M68KNOMMU_CURRENT_H +/* + * current.h + * (C) Copyright 2000, Lineo, David McCullough + * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) + * + * rather than dedicate a register (as the m68k source does), we + * just keep a global, we should probably just change it all to be + * current and lose _current_task. + */ + +#include + +struct task_struct; + +static inline struct task_struct *get_current(void) +{ + return(current_thread_info()->task); +} + +#define current get_current() + +#endif /* _M68KNOMMU_CURRENT_H */ diff -Nru a/include/asm-m68knommu/dbg.h b/include/asm-m68knommu/dbg.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/dbg.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,6 @@ +#define DEBUG 1 +#ifdef CONFIG_COLDFIRE +#define BREAK asm volatile ("halt") +#else +#define BREAK *(volatile unsigned char *)0xdeadbee0 = 0 +#endif diff -Nru a/include/asm-m68knommu/delay.h b/include/asm-m68knommu/delay.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/delay.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,77 @@ +#ifndef _M68KNOMMU_DELAY_H +#define _M68KNOMMU_DELAY_H + +#include + +/* + * Copyright (C) 1994 Hamish Macdonald + * + * Delay routines, using a pre-computed "loops_per_second" value. + */ + +extern __inline__ void __delay(unsigned long loops) +{ +#if defined(CONFIG_COLDFIRE) + /* The coldfire runs this loop at significantly different speeds + * depending upon long word alignment or not. We'll pad it to + * long word alignment which is the faster version. + * The 0x4a8e is of course a 'tstl %fp' instruction. This is better + * than using a NOP (0x4e71) instruction because it executes in one + * cycle not three and doesn't allow for an arbitary delay waiting + * for bus cycles to finish. Also fp/a6 isn't likely to cause a + * stall waiting for the register to become valid if such is added + * to the coldfire at some stage. + */ + __asm__ __volatile__ ( ".balignw 4, 0x4a8e\n\t" + "1: subql #1, %0\n\t" + "jcc 1b" + : "=d" (loops) : "0" (loops)); +#else + __asm__ __volatile__ ( "1: subql #1, %0\n\t" + "jcc 1b" + : "=d" (loops) : "0" (loops)); +#endif +} + +/* + * Use only for very small delays ( < 1 msec). Should probably use a + * lookup table, really, as the multiplications take much too long with + * short delays. This is a "reasonable" implementation, though (and the + * first constant multiplications gets optimized away if the delay is + * a constant) + */ + +extern unsigned long loops_per_jiffy; + +extern __inline__ void udelay(unsigned long usecs) +{ +#ifdef CONFIG_M68332 + usecs *= 0x000010c6; + __asm__ __volatile__ ("mulul %1,%0:%2" + : "=d" (usecs) + : "d" (usecs), + "d" (loops_per_jiffy*HZ)); + __delay(usecs); + +#elif defined(CONFIG_M68328) || defined(CONFIG_M68EZ328) || \ + defined(CONFIG_COLDFIRE) || defined(CONFIG_M68360) || \ + defined(CONFIG_M68VZ328) + register unsigned long full_loops, part_loops; + + full_loops = ((usecs * HZ) / 1000000) * loops_per_jiffy; + usecs %= (1000000 / HZ); + part_loops = (usecs * HZ * loops_per_jiffy) / 1000000; + + __delay(full_loops + part_loops); +#else + unsigned long tmp; + + usecs *= 4295; /* 2**32 / 1000000 */ + __asm__ ("mulul %2,%0:%1" + : "=d" (usecs), "=d" (tmp) + : "d" (usecs), "1" (loops_per_jiffy*HZ)); + __delay(usecs); +#endif +} + +#endif /* defined(_M68KNOMMU_DELAY_H) */ diff -Nru a/include/asm-m68knommu/div64.h b/include/asm-m68knommu/div64.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/div64.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,13 @@ +#ifndef _M68KNOMMU_DIV64_H +#define _M68KNOMMU_DIV64_H + +/* n = n / base; return rem; */ + +#define do_div(n,base) ({ \ + int __res; \ + __res = ((unsigned long) n) % (unsigned) base; \ + n = ((unsigned long) n) / (unsigned) base; \ + __res; \ +}) + +#endif /* _M68K_DIV64_H */ diff -Nru a/include/asm-m68knommu/dma.h b/include/asm-m68knommu/dma.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/dma.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,492 @@ +#ifndef _M68K_DMA_H +#define _M68K_DMA_H 1 + +//#define DMA_DEBUG 1 + +#include + +#ifdef CONFIG_COLDFIRE +/* + * ColdFire DMA Model: + * ColdFire DMA supports two forms of DMA: Single and Dual address. Single + * address mode emits a source address, and expects that the device will either + * pick up the data (DMA READ) or source data (DMA WRITE). This implies that + * the device will place data on the correct byte(s) of the data bus, as the + * memory transactions are always 32 bits. This implies that only 32 bit + * devices will find single mode transfers useful. Dual address DMA mode + * performs two cycles: source read and destination write. ColdFire will + * align the data so that the device will always get the correct bytes, thus + * is useful for 8 and 16 bit devices. This is the mode that is supported + * below. + * + * AUG/22/2000 : added support for 32-bit Dual-Address-Mode (K) 2000 + * Oliver Kamphenkel (O.Kamphenkel@tu-bs.de) + * + * AUG/25/2000 : addad support for 8, 16 and 32-bit Single-Address-Mode (K)2000 + * Oliver Kamphenkel (O.Kamphenkel@tu-bs.de) + * + * APR/18/2002 : added proper support for MCF5272 DMA controller. + * Arthur Shipkowski (art@videon-central.com) + */ + +#include +#include +#include + +/* + * Set number of channels of DMA on ColdFire for different implementations. + */ +#if defined(CONFIG_M5307) || defined(CONFIG_M5407) +#define MAX_M68K_DMA_CHANNELS 4 +#elif defined(CONFIG_M5272) +#define MAX_M68K_DMA_CHANNELS 1 +#else +#define MAX_M68K_DMA_CHANNELS 2 +#endif + +extern unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS]; +extern unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; + +#if !defined(CONFIG_M5272) +#define DMA_MODE_WRITE_BIT 0x01 /* Memory/IO to IO/Memory select */ +#define DMA_MODE_WORD_BIT 0x02 /* 8 or 16 bit transfers */ +#define DMA_MODE_LONG_BIT 0x04 /* or 32 bit transfers */ +#define DMA_MODE_SINGLE_BIT 0x08 /* single-address-mode */ + +/* I/O to memory, 8 bits, mode */ +#define DMA_MODE_READ 0 +/* memory to I/O, 8 bits, mode */ +#define DMA_MODE_WRITE 1 +/* I/O to memory, 16 bits, mode */ +#define DMA_MODE_READ_WORD 2 +/* memory to I/O, 16 bits, mode */ +#define DMA_MODE_WRITE_WORD 3 +/* I/O to memory, 32 bits, mode */ +#define DMA_MODE_READ_LONG 4 +/* memory to I/O, 32 bits, mode */ +#define DMA_MODE_WRITE_LONG 5 +/* I/O to memory, 8 bits, single-address-mode */ +#define DMA_MODE_READ_SINGLE 8 +/* memory to I/O, 8 bits, single-address-mode */ +#define DMA_MODE_WRITE_SINGLE 9 +/* I/O to memory, 16 bits, single-address-mode */ +#define DMA_MODE_READ_WORD_SINGLE 10 +/* memory to I/O, 16 bits, single-address-mode */ +#define DMA_MODE_WRITE_WORD_SINGLE 11 +/* I/O to memory, 32 bits, single-address-mode */ +#define DMA_MODE_READ_LONG_SINGLE 12 +/* memory to I/O, 32 bits, single-address-mode */ +#define DMA_MODE_WRITE_LONG_SINGLE 13 + +#else /* CONFIG_M5272 is defined */ + +/* Source static-address mode */ +#define DMA_MODE_SRC_SA_BIT 0x01 +/* Two bits to select between all four modes */ +#define DMA_MODE_SSIZE_MASK 0x06 +/* Offset to shift bits in */ +#define DMA_MODE_SSIZE_OFF 0x01 +/* Destination static-address mode */ +#define DMA_MODE_DES_SA_BIT 0x10 +/* Two bits to select between all four modes */ +#define DMA_MODE_DSIZE_MASK 0x60 +/* Offset to shift bits in */ +#define DMA_MODE_DSIZE_OFF 0x05 +/* Size modifiers */ +#define DMA_MODE_SIZE_LONG 0x00 +#define DMA_MODE_SIZE_BYTE 0x01 +#define DMA_MODE_SIZE_WORD 0x02 +#define DMA_MODE_SIZE_LINE 0x03 + +/* + * Aliases to help speed quick ports; these may be suboptimal, however. They + * do not include the SINGLE mode modifiers since the MCF5272 does not have a + * mode where the device is in control of its addressing. + */ + +/* I/O to memory, 8 bits, mode */ +#define DMA_MODE_READ ((DMA_MODE_SIZE_BYTE << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_BYTE << DMA_MODE_SSIZE_OFF) | DMA_SRC_SA_BIT) +/* memory to I/O, 8 bits, mode */ +#define DMA_MODE_WRITE ((DMA_MODE_SIZE_BYTE << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_BYTE << DMA_MODE_SSIZE_OFF) | DMA_DES_SA_BIT) +/* I/O to memory, 16 bits, mode */ +#define DMA_MODE_READ_WORD ((DMA_MODE_SIZE_WORD << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_WORD << DMA_MODE_SSIZE_OFF) | DMA_SRC_SA_BIT) +/* memory to I/O, 16 bits, mode */ +#define DMA_MODE_WRITE_WORD ((DMA_MODE_SIZE_WORD << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_WORD << DMA_MODE_SSIZE_OFF) | DMA_DES_SA_BIT) +/* I/O to memory, 32 bits, mode */ +#define DMA_MODE_READ_LONG ((DMA_MODE_SIZE_LONG << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_LONG << DMA_MODE_SSIZE_OFF) | DMA_SRC_SA_BIT) +/* memory to I/O, 32 bits, mode */ +#define DMA_MODE_WRITE_LONG ((DMA_MODE_SIZE_LONG << DMA_MODE_DSIZE_OFF) | (DMA_MODE_SIZE_LONG << DMA_MODE_SSIZE_OFF) | DMA_DES_SA_BIT) + +#endif /* !defined(CONFIG_M5272) */ + +#if !defined(CONFIG_M5272) +/* enable/disable a specific DMA channel */ +static __inline__ void enable_dma(unsigned int dmanr) +{ + volatile unsigned short *dmawp; + +#ifdef DMA_DEBUG + printk("enable_dma(dmanr=%d)\n", dmanr); +#endif + + dmawp = (unsigned short *) dma_base_addr[dmanr]; + dmawp[MCFDMA_DCR] |= MCFDMA_DCR_EEXT; +} + +static __inline__ void disable_dma(unsigned int dmanr) +{ + volatile unsigned short *dmawp; + volatile unsigned char *dmapb; + +#ifdef DMA_DEBUG + printk("disable_dma(dmanr=%d)\n", dmanr); +#endif + + dmawp = (unsigned short *) dma_base_addr[dmanr]; + dmapb = (unsigned char *) dma_base_addr[dmanr]; + + /* Turn off external requests, and stop any DMA in progress */ + dmawp[MCFDMA_DCR] &= ~MCFDMA_DCR_EEXT; + dmapb[MCFDMA_DSR] = MCFDMA_DSR_DONE; +} + +/* + * Clear the 'DMA Pointer Flip Flop'. + * Write 0 for LSB/MSB, 1 for MSB/LSB access. + * Use this once to initialize the FF to a known state. + * After that, keep track of it. :-) + * --- In order to do that, the DMA routines below should --- + * --- only be used while interrupts are disabled! --- + * + * This is a NOP for ColdFire. Provide a stub for compatibility. + */ +static __inline__ void clear_dma_ff(unsigned int dmanr) +{ +} + +/* set mode (above) for a specific DMA channel */ +static __inline__ void set_dma_mode(unsigned int dmanr, char mode) +{ + + volatile unsigned char *dmabp; + volatile unsigned short *dmawp; + +#ifdef DMA_DEBUG + printk("set_dma_mode(dmanr=%d,mode=%d)\n", dmanr, mode); +#endif + + dmabp = (unsigned char *) dma_base_addr[dmanr]; + dmawp = (unsigned short *) dma_base_addr[dmanr]; + + // Clear config errors + dmabp[MCFDMA_DSR] = MCFDMA_DSR_DONE; + + // Set command register + dmawp[MCFDMA_DCR] = + MCFDMA_DCR_INT | // Enable completion irq + MCFDMA_DCR_CS | // Force one xfer per request + MCFDMA_DCR_AA | // Enable auto alignment + // single-address-mode + ((mode & DMA_MODE_SINGLE_BIT) ? MCFDMA_DCR_SAA : 0) | + // sets s_rw (-> r/w) high if Memory to I/0 + ((mode & DMA_MODE_WRITE_BIT) ? MCFDMA_DCR_S_RW : 0) | + // Memory to I/O or I/O to Memory + ((mode & DMA_MODE_WRITE_BIT) ? MCFDMA_DCR_SINC : MCFDMA_DCR_DINC) | + // 32 bit, 16 bit or 8 bit transfers + ((mode & DMA_MODE_WORD_BIT) ? MCFDMA_DCR_SSIZE_WORD : + ((mode & DMA_MODE_LONG_BIT) ? MCFDMA_DCR_SSIZE_LONG : + MCFDMA_DCR_SSIZE_BYTE)) | + ((mode & DMA_MODE_WORD_BIT) ? MCFDMA_DCR_DSIZE_WORD : + ((mode & DMA_MODE_LONG_BIT) ? MCFDMA_DCR_DSIZE_LONG : + MCFDMA_DCR_DSIZE_BYTE)); + +#ifdef DEBUG_DMA + printk("%s(%d): dmanr=%d DSR[%x]=%x DCR[%x]=%x\n", __FILE__, __LINE__, + dmanr, (int) &dmabp[MCFDMA_DSR], dmabp[MCFDMA_DSR], + (int) &dmawp[MCFDMA_DCR], dmawp[MCFDMA_DCR]); +#endif +} + +/* Set transfer address for specific DMA channel */ +static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a) +{ + volatile unsigned short *dmawp; + volatile unsigned int *dmalp; + +#ifdef DMA_DEBUG + printk("set_dma_addr(dmanr=%d,a=%x)\n", dmanr, a); +#endif + + dmawp = (unsigned short *) dma_base_addr[dmanr]; + dmalp = (unsigned int *) dma_base_addr[dmanr]; + + // Determine which address registers are used for memory/device accesses + if (dmawp[MCFDMA_DCR] & MCFDMA_DCR_SINC) { + // Source incrementing, must be memory + dmalp[MCFDMA_SAR] = a; + // Set dest address, must be device + dmalp[MCFDMA_DAR] = dma_device_address[dmanr]; + } else { + // Destination incrementing, must be memory + dmalp[MCFDMA_DAR] = a; + // Set source address, must be device + dmalp[MCFDMA_SAR] = dma_device_address[dmanr]; + } + +#ifdef DEBUG_DMA + printk("%s(%d): dmanr=%d DCR[%x]=%x SAR[%x]=%08x DAR[%x]=%08x\n", + __FILE__, __LINE__, dmanr, (int) &dmawp[MCFDMA_DCR], dmawp[MCFDMA_DCR], + (int) &dmalp[MCFDMA_SAR], dmalp[MCFDMA_SAR], + (int) &dmalp[MCFDMA_DAR], dmalp[MCFDMA_DAR]); +#endif +} + +/* + * Specific for Coldfire - sets device address. + * Should be called after the mode set call, and before set DMA address. + */ +static __inline__ void set_dma_device_addr(unsigned int dmanr, unsigned int a) +{ +#ifdef DMA_DEBUG + printk("set_dma_device_addr(dmanr=%d,a=%x)\n", dmanr, a); +#endif + + dma_device_address[dmanr] = a; +} + +/* + * NOTE 2: "count" represents _bytes_. + */ +static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count) +{ + volatile unsigned short *dmawp; + +#ifdef DMA_DEBUG + printk("set_dma_count(dmanr=%d,count=%d)\n", dmanr, count); +#endif + + dmawp = (unsigned short *) dma_base_addr[dmanr]; + dmawp[MCFDMA_BCR] = (unsigned short)count; +} + +/* + * Get DMA residue count. After a DMA transfer, this + * should return zero. Reading this while a DMA transfer is + * still in progress will return unpredictable results. + * Otherwise, it returns the number of _bytes_ left to transfer. + */ +static __inline__ int get_dma_residue(unsigned int dmanr) +{ + volatile unsigned short *dmawp; + unsigned short count; + +#ifdef DMA_DEBUG + printk("get_dma_residue(dmanr=%d)\n", dmanr); +#endif + + dmawp = (unsigned short *) dma_base_addr[dmanr]; + count = dmawp[MCFDMA_BCR]; + return((int) count); +} +#else /* CONFIG_M5272 is defined */ + +/* + * The MCF5272 DMA controller is very different than the controller defined above + * in terms of register mapping. For instance, with the exception of the 16-bit + * interrupt register (IRQ#85, for reference), all of the registers are 32-bit. + * + * The big difference, however, is the lack of device-requested DMA. All modes + * are dual address transfer, and there is no 'device' setup or direction bit. + * You can DMA between a device and memory, between memory and memory, or even between + * two devices directly, with any combination of incrementing and non-incrementing + * addresses you choose. This puts a crimp in distinguishing between the 'device + * address' set up by set_dma_device_addr. + * + * Therefore, there are two options. One is to use set_dma_addr and set_dma_device_addr, + * which will act exactly as above in -- it will look to see if the source is set to + * autoincrement, and if so it will make the source use the set_dma_addr value and the + * destination the set_dma_device_addr value. Otherwise the source will be set to the + * set_dma_device_addr value and the destination will get the set_dma_addr value. + * + * The other is to use the provided set_dma_src_addr and set_dma_dest_addr functions + * and make it explicit. Depending on what you're doing, one of these two should work + * for you, but don't mix them in the same transfer setup. + */ + +/* enable/disable a specific DMA channel */ +static __inline__ void enable_dma(unsigned int dmanr) +{ + volatile unsigned int *dmalp; + +#ifdef DMA_DEBUG + printk("enable_dma(dmanr=%d)\n", dmanr); +#endif + + dmalp = (unsigned int *) dma_base_addr[dmanr]; + dmalp[MCFDMA_DMR] |= MCFDMA_DMR_EN; +} + +static __inline__ void disable_dma(unsigned int dmanr) +{ + volatile unsigned int *dmalp; + +#ifdef DMA_DEBUG + printk("disable_dma(dmanr=%d)\n", dmanr); +#endif + + dmalp = (unsigned int *) dma_base_addr[dmanr]; + + /* Turn off external requests, and stop any DMA in progress */ + dmalp[MCFDMA_DMR] &= ~MCFDMA_DMR_EN; + dmalp[MCFDMA_DMR] |= MCFDMA_DMR_RESET; +} + +/* + * Clear the 'DMA Pointer Flip Flop'. + * Write 0 for LSB/MSB, 1 for MSB/LSB access. + * Use this once to initialize the FF to a known state. + * After that, keep track of it. :-) + * --- In order to do that, the DMA routines below should --- + * --- only be used while interrupts are disabled! --- + * + * This is a NOP for ColdFire. Provide a stub for compatibility. + */ +static __inline__ void clear_dma_ff(unsigned int dmanr) +{ +} + +/* set mode (above) for a specific DMA channel */ +static __inline__ void set_dma_mode(unsigned int dmanr, char mode) +{ + + volatile unsigned int *dmalp; + volatile unsigned short *dmawp; + +#ifdef DMA_DEBUG + printk("set_dma_mode(dmanr=%d,mode=%d)\n", dmanr, mode); +#endif + dmalp = (unsigned int *) dma_base_addr[dmanr]; + dmawp = (unsigned short *) dma_base_addr[dmanr]; + + // Clear config errors + dmalp[MCFDMA_DMR] |= MCFDMA_DMR_RESET; + + // Set command register + dmalp[MCFDMA_DMR] = + MCFDMA_DMR_RQM_DUAL | // Mandatory Request Mode setting + MCFDMA_DMR_DSTT_SD | // Set up addressing types; set to supervisor-data. + MCFDMA_DMR_SRCT_SD | // Set up addressing types; set to supervisor-data. + // source static-address-mode + ((mode & DMA_MODE_SRC_SA_BIT) ? MCFDMA_DMR_SRCM_SA : MCFDMA_DMR_SRCM_IA) | + // dest static-address-mode + ((mode & DMA_MODE_DES_SA_BIT) ? MCFDMA_DMR_DSTM_SA : MCFDMA_DMR_DSTM_IA) | + // burst, 32 bit, 16 bit or 8 bit transfers are separately configurable on the MCF5272 + (((mode & DMA_MODE_SSIZE_MASK) >> DMA_MODE_SSIZE_OFF) << MCFDMA_DMR_DSTS_OFF) | + (((mode & DMA_MODE_SSIZE_MASK) >> DMA_MODE_SSIZE_OFF) << MCFDMA_DMR_SRCS_OFF); + + dmawp[MCFDMA_DIR] |= MCFDMA_DIR_ASCEN; /* Enable completion interrupts */ + +#ifdef DEBUG_DMA + printk("%s(%d): dmanr=%d DMR[%x]=%x DIR[%x]=%x\n", __FILE__, __LINE__, + dmanr, (int) &dmalp[MCFDMA_DMR], dmabp[MCFDMA_DMR], + (int) &dmawp[MCFDMA_DIR], dmawp[MCFDMA_DIR]); +#endif +} + +/* Set transfer address for specific DMA channel */ +static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a) +{ + volatile unsigned int *dmalp; + +#ifdef DMA_DEBUG + printk("set_dma_addr(dmanr=%d,a=%x)\n", dmanr, a); +#endif + + dmalp = (unsigned int *) dma_base_addr[dmanr]; + + // Determine which address registers are used for memory/device accesses + if (dmalp[MCFDMA_DMR] & MCFDMA_DMR_SRCM) { + // Source incrementing, must be memory + dmalp[MCFDMA_DSAR] = a; + // Set dest address, must be device + dmalp[MCFDMA_DDAR] = dma_device_address[dmanr]; + } else { + // Destination incrementing, must be memory + dmalp[MCFDMA_DDAR] = a; + // Set source address, must be device + dmalp[MCFDMA_DSAR] = dma_device_address[dmanr]; + } + +#ifdef DEBUG_DMA + printk("%s(%d): dmanr=%d DMR[%x]=%x SAR[%x]=%08x DAR[%x]=%08x\n", + __FILE__, __LINE__, dmanr, (int) &dmawp[MCFDMA_DMR], dmawp[MCFDMA_DMR], + (int) &dmalp[MCFDMA_DSAR], dmalp[MCFDMA_DSAR], + (int) &dmalp[MCFDMA_DDAR], dmalp[MCFDMA_DDAR]); +#endif +} + +/* + * Specific for Coldfire - sets device address. + * Should be called after the mode set call, and before set DMA address. + */ +static __inline__ void set_dma_device_addr(unsigned int dmanr, unsigned int a) +{ +#ifdef DMA_DEBUG + printk("set_dma_device_addr(dmanr=%d,a=%x)\n", dmanr, a); +#endif + + dma_device_address[dmanr] = a; +} + +/* + * NOTE 2: "count" represents _bytes_. + * + * NOTE 3: While a 32-bit register, "count" is only a maximum 24-bit value. + */ +static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count) +{ + volatile unsigned int *dmalp; + +#ifdef DMA_DEBUG + printk("set_dma_count(dmanr=%d,count=%d)\n", dmanr, count); +#endif + + dmalp = (unsigned int *) dma_base_addr[dmanr]; + dmalp[MCFDMA_DBCR] = count; +} + +/* + * Get DMA residue count. After a DMA transfer, this + * should return zero. Reading this while a DMA transfer is + * still in progress will return unpredictable results. + * Otherwise, it returns the number of _bytes_ left to transfer. + */ +static __inline__ int get_dma_residue(unsigned int dmanr) +{ + volatile unsigned int *dmalp; + unsigned int count; + +#ifdef DMA_DEBUG + printk("get_dma_residue(dmanr=%d)\n", dmanr); +#endif + + dmalp = (unsigned int *) dma_base_addr[dmanr]; + count = dmalp[MCFDMA_DBCR]; + return(count); +} + +#endif /* !defined(CONFIG_M5272) */ +#endif /* CONFIG_COLDFIRE */ + +#define MAX_DMA_CHANNELS 8 + +/* Don't define MAX_DMA_ADDRESS; it's useless on the m68k/coldfire and any + occurrence should be flagged as an error. */ +/* under 2.4 it is actually needed by the new bootmem allocator */ +#define MAX_DMA_ADDRESS PAGE_OFFSET + +/* These are in kernel/dma.c: */ +extern int request_dma(unsigned int dmanr, const char *device_id); /* reserve a DMA channel */ +extern void free_dma(unsigned int dmanr); /* release it again */ + +#endif /* _M68K_DMA_H */ diff -Nru a/include/asm-m68knommu/elf.h b/include/asm-m68knommu/elf.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/elf.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,95 @@ +#ifndef __ASMm68k_ELF_H +#define __ASMm68k_ELF_H + +/* + * ELF register definitions.. + */ + +#include +#include +#include + +typedef unsigned long elf_greg_t; + +#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct user_m68kfp_struct elf_fpregset_t; + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ((x)->e_machine == EM_68K) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_68K + +/* For SVR4/m68k the function pointer to be registered with `atexit' is + passed in %a1. Although my copy of the ABI has no such statement, it + is actually used on ASV. */ +#define ELF_PLAT_INIT(_r) _r->a1 = 0 + +#define USE_ELF_CORE_DUMP +#ifndef CONFIG_SUN3 +#define ELF_EXEC_PAGESIZE 4096 +#else +#define ELF_EXEC_PAGESIZE 8192 +#endif + +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#ifndef CONFIG_SUN3 +#define ELF_ET_DYN_BASE 0xD0000000UL +#else +#define ELF_ET_DYN_BASE 0x0D800000UL +#endif + +#define ELF_CORE_COPY_REGS(pr_reg, regs) \ + /* Bleech. */ \ + pr_reg[0] = regs->d1; \ + pr_reg[1] = regs->d2; \ + pr_reg[2] = regs->d3; \ + pr_reg[3] = regs->d4; \ + pr_reg[4] = regs->d5; \ + pr_reg[7] = regs->a0; \ + pr_reg[8] = regs->a1; \ + pr_reg[14] = regs->d0; \ + pr_reg[15] = rdusp(); \ + pr_reg[16] = 0 /* regs->orig_d0; */ \ + pr_reg[17] = regs->sr; \ + pr_reg[18] = regs->pc; \ + /* pr_reg[19] = (regs->format << 12) | regs->vector; */ \ + { \ + struct switch_stack *sw = ((struct switch_stack *)regs) - 1; \ + pr_reg[5] = sw->d6; \ + pr_reg[6] = sw->d7; \ + pr_reg[9] = sw->a2; \ + pr_reg[10] = sw->a3; \ + pr_reg[11] = sw->a4; \ + pr_reg[12] = sw->a5; \ + pr_reg[13] = sw->a6; \ + } + +/* This yields a mask that user programs can use to figure out what + instruction set this cpu supports. */ + +#define ELF_HWCAP (0) + +/* This yields a string that ld.so will use to load implementation + specific libraries for optimization. This is more specific in + intent than poking at uname or /proc/cpuinfo. */ + +#define ELF_PLATFORM (NULL) + +#ifdef __KERNEL__ +#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) +#endif + +#endif diff -Nru a/include/asm-m68knommu/elia.h b/include/asm-m68knommu/elia.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/elia.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,42 @@ +/****************************************************************************/ + +/* + * elia.h -- Lineo (formerly Moreton Bay) eLIA platform support. + * + * (C) Copyright 1999-2000, Moreton Bay (www.moreton.com.au) + * (C) Copyright 1999-2000, Lineo (www.lineo.com) + */ + +/****************************************************************************/ +#ifndef elia_h +#define elia_h +/****************************************************************************/ + +#include +#include + +#ifdef CONFIG_eLIA + +/* + * The serial port DTR and DCD lines are also on the Parallel I/O + * as well, so define those too. + */ + +#define eLIA_DCD1 0x0001 +#define eLIA_DCD0 0x0002 +#define eLIA_DTR1 0x0004 +#define eLIA_DTR0 0x0008 + +#define eLIA_PCIRESET 0x0020 + +/* + * Kernel macros to set and unset the LEDs. + */ +#ifndef __ASSEMBLY__ +extern unsigned short ppdata; +#endif /* __ASSEMBLY__ */ + +#endif /* CONFIG_eLIA */ + +/****************************************************************************/ +#endif /* elia_h */ diff -Nru a/include/asm-m68knommu/entry.h b/include/asm-m68knommu/entry.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/entry.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,129 @@ +#ifndef __M68K_ENTRY_H +#define __M68K_ENTRY_H + +#include +#ifndef CONFIG_COLDFIRE +#include +#include + +/* + * Stack layout in 'ret_from_exception': + * + * This allows access to the syscall arguments in registers d1-d5 + * + * 0(sp) - d1 + * 4(sp) - d2 + * 8(sp) - d3 + * C(sp) - d4 + * 10(sp) - d5 + * 14(sp) - a0 + * 18(sp) - a1 + * 1C(sp) - a2 + * 20(sp) - d0 + * 24(sp) - orig_d0 + * 28(sp) - stack adjustment + * 2C(sp) - sr + * 2E(sp) - pc + * 32(sp) - format & vector + */ + +/* + * 97/05/14 Andreas: Register %a2 is now set to the current task throughout + * the whole kernel. + */ + +/* the following macro is used when enabling interrupts */ +#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES) + /* block out HSYNC on the atari */ +#define ALLOWINT 0xfbff +#define MAX_NOINT_IPL 3 +#else + /* portable version */ +#define ALLOWINT 0xf8ff +#define MAX_NOINT_IPL 0 +#endif /* machine compilation types */ + +#ifdef __ASSEMBLY__ + +#define curptr a2 + +LFLUSH_I_AND_D = 0x00000808 +LSIGTRAP = 5 + +/* process bits for task_struct.flags */ +PF_TRACESYS_OFF = 3 +PF_TRACESYS_BIT = 5 +PF_PTRACED_OFF = 3 +PF_PTRACED_BIT = 4 +PF_DTRACE_OFF = 1 +PF_DTRACE_BIT = 5 + +#define SAVE_ALL_INT save_all_int +#define SAVE_ALL_SYS save_all_sys +#define RESTORE_ALL restore_all +/* + * This defines the normal kernel pt-regs layout. + * + * regs a3-a6 and d6-d7 are preserved by C code + * the kernel doesn't mess with usp unless it needs to + */ + +/* + * a -1 in the orig_d0 field signifies + * that the stack frame is NOT for syscall + */ +.macro save_all_int VEC=0 + oriw #0x0700,%sr /* disable interrupts */ + clrl %sp@- /* stk_adj */ + pea -1:w /* orig d0 */ + movel %d0,%sp@- /* d0 */ + moveml %d1-%d5/%a0-%a1/%curptr,%sp@- +.endm + +.macro save_all_sys VEC=0 + clrl %sp@- /* stk_adj */ + movel %d0,%sp@- /* orig d0 */ + movel %d0,%sp@- /* d0 */ + moveml %d1-%d5/%a0-%a1/%curptr,%sp@- +.endm + +.macro restore_all + moveml %sp@+,%a0-%a1/%curptr/%d1-%d5 + movel %sp@+,%d0 + addql #4,%sp /* orig d0 */ + addl %sp@+,%sp /* stk adj */ + rte +.endm + +#define SWITCH_STACK_SIZE (6*4+4) /* includes return address */ + +#define SAVE_SWITCH_STACK save_switch_stack +#define RESTORE_SWITCH_STACK restore_switch_stack +#define GET_CURRENT(tmp) + +.macro save_switch_stack + moveml %a3-%a6/%d6-%d7,%sp@- +.endm + +.macro restore_switch_stack + moveml %sp@+,%a3-%a6/%d6-%d7 +.endm + +#else /* C source */ + +#define STR(X) STR1(X) +#define STR1(X) #X + +#define PT_OFF_ORIG_D0 0x24 +#define PT_OFF_FORMATVEC 0x32 +#define PT_OFF_SR 0x2C +#define SAVE_ALL_INT \ + "clrl %%sp@-;" /* stk_adj */ \ + "pea -1:w;" /* orig d0 = -1 */ \ + "movel %%d0,%%sp@-;" /* d0 */ \ + "moveml %%d1-%%d5/%%a0-%%a2,%%sp@-" + +#endif + +#endif /* CONFIG_COLDFIRE */ +#endif /* __M68K_ENTRY_H */ diff -Nru a/include/asm-m68knommu/errno.h b/include/asm-m68knommu/errno.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/errno.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/fcntl.h b/include/asm-m68knommu/fcntl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/fcntl.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/fpu.h b/include/asm-m68knommu/fpu.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/fpu.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,22 @@ +#ifndef __M68KNOMMU_FPU_H +#define __M68KNOMMU_FPU_H + +#include + +/* + * MAX floating point unit state size (FSAVE/FRESTORE) + */ +#if defined(CONFIG_M68020) || defined(CONFIG_M68030) +#define FPSTATESIZE (216/sizeof(unsigned char)) +#elif defined(CONFIG_M68040) +#define FPSTATESIZE (96/sizeof(unsigned char)) +#elif defined(CONFIG_M68KFPU_EMU) +#define FPSTATESIZE (28/sizeof(unsigned char)) +#elif defined(CONFIG_M68060) +#define FPSTATESIZE (12/sizeof(unsigned char)) +#else +/* Assume no FP unit present then... */ +#define FPSTATESIZE (2) /* dummy size */ +#endif + +#endif /* __M68K_FPU_H */ diff -Nru a/include/asm-m68knommu/hardirq.h b/include/asm-m68knommu/hardirq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/hardirq.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,102 @@ +#ifndef __M68K_HARDIRQ_H +#define __M68K_HARDIRQ_H + +#include +#include + +typedef struct { + unsigned int __softirq_pending; + unsigned int __syscall_count; + struct task_struct * __ksoftirqd_task; +} ____cacheline_aligned irq_cpustat_t; + +#include /* Standard mappings for irq_cpustat_t above */ + +/* + * We put the hardirq and softirq counter into the preemption + * counter. The bitmask has the following meaning: + * + * - bits 0-7 are the preemption count (max preemption depth: 256) + * - bits 8-15 are the softirq count (max # of softirqs: 256) + * - bits 16-23 are the hardirq count (max # of hardirqs: 256) + * + * - ( bit 26 is the PREEMPT_ACTIVE flag. ) + * + * PREEMPT_MASK: 0x000000ff + * HARDIRQ_MASK: 0x0000ff00 + * SOFTIRQ_MASK: 0x00ff0000 + */ + +#define PREEMPT_BITS 8 +#define SOFTIRQ_BITS 8 +#define HARDIRQ_BITS 8 + +#define PREEMPT_SHIFT 0 +#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS) +#define HARDIRQ_SHIFT (SOFTIRQ_SHIFT + SOFTIRQ_BITS) + +#define __MASK(x) ((1UL << (x))-1) + +#define PREEMPT_MASK (__MASK(PREEMPT_BITS) << PREEMPT_SHIFT) +#define HARDIRQ_MASK (__MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT) +#define SOFTIRQ_MASK (__MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT) + +#define hardirq_count() (preempt_count() & HARDIRQ_MASK) +#define softirq_count() (preempt_count() & SOFTIRQ_MASK) +#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK)) + +#define PREEMPT_OFFSET (1UL << PREEMPT_SHIFT) +#define SOFTIRQ_OFFSET (1UL << SOFTIRQ_SHIFT) +#define HARDIRQ_OFFSET (1UL << HARDIRQ_SHIFT) + +/* + * The hardirq mask has to be large enough to have + * space for potentially all IRQ sources in the system + * nesting on a single CPU: + */ +#if (1 << HARDIRQ_BITS) < NR_IRQS +# error HARDIRQ_BITS is too low! +#endif + +/* + * Are we doing bottom half or hardware interrupt processing? + * Are we in a softirq context? Interrupt context? + */ +#define in_irq() (hardirq_count()) +#define in_softirq() (softirq_count()) +#define in_interrupt() (irq_count()) + +#define hardirq_trylock() (!in_interrupt()) +#define hardirq_endlock() do { } while (0) + +#define irq_enter() (preempt_count() += HARDIRQ_OFFSET) + +#if CONFIG_PREEMPT +# define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) +#else +# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET +#endif + +#if CONFIG_PREEMPT +# define in_atomic() (preempt_count() != kernel_locked()) +# define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) +#else +# define in_atomic() (preempt_count() != 0) +# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET +#endif + +#define irq_exit() \ +do { \ + preempt_count() -= IRQ_EXIT_OFFSET; \ + if (!in_interrupt() && softirq_pending(smp_processor_id())) \ + do_softirq(); \ + preempt_enable_no_resched(); \ +} while (0) + +#ifndef CONFIG_SMP +# define synchronize_irq(irq) barrier() +#else +# error m68knommu SMP is not available +#endif /* CONFIG_SMP */ + +#endif /* __M68K_HARDIRQ_H */ diff -Nru a/include/asm-m68knommu/hdreg.h b/include/asm-m68knommu/hdreg.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/hdreg.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/hwtest.h b/include/asm-m68knommu/hwtest.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/hwtest.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/ide.h b/include/asm-m68knommu/ide.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/ide.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,465 @@ +/****************************************************************************/ +/* + * linux/include/asm-m68knommu/ide.h + * + * Copyright (C) 1994-1996 Linus Torvalds & authors + * Copyright (C) 2001 Lineo Inc., davidm@uclinux.org + */ +/****************************************************************************/ +#ifndef _M68KNOMMU_IDE_H +#define _M68KNOMMU_IDE_H + +#ifdef __KERNEL__ +/****************************************************************************/ + +#include +#include + +#include +#include +#include + +/****************************************************************************/ +/* + * some coldfire specifics + */ + +#ifdef CONFIG_COLDFIRE +#include +#include + +/* + * Save some space, only have 1 interface + */ +#define MAX_HWIFS 1 /* we only have one interface for now */ + +#ifdef CONFIG_SECUREEDGEMP3 +#define MCFSIM_LOCALCS MCFSIM_CSCR4 +#else +#define MCFSIM_LOCALCS MCFSIM_CSCR6 +#endif + +#endif /* CONFIG_COLDFIRE */ + +/****************************************************************************/ +/* + * Fix up things that may not have been provided + */ + +#ifndef MAX_HWIFS +#define MAX_HWIFS 4 /* same as the other archs */ +#endif + +#undef SUPPORT_SLOW_DATA_PORTS +#define SUPPORT_SLOW_DATA_PORTS 0 + +#undef SUPPORT_VLB_SYNC +#define SUPPORT_VLB_SYNC 0 + +/* this definition is used only on startup .. */ +#undef HD_DATA +#define HD_DATA NULL + +#define DBGIDE(fmt,a...) +// #define DBGIDE(fmt,a...) printk(fmt, ##a) +#define IDE_INLINE __inline__ +// #define IDE_INLINE + +/****************************************************************************/ + +typedef union { + unsigned all : 8; /* all of the bits together */ + struct { + unsigned bit7 : 1; /* always 1 */ + unsigned lba : 1; /* using LBA instead of CHS */ + unsigned bit5 : 1; /* always 1 */ + unsigned unit : 1; /* drive select number, 0 or 1 */ + unsigned head : 4; /* always zeros here */ + } b; +} select_t; + +/* + * our list of ports/irq's for different boards + */ + +static struct m68k_ide_defaults { + ide_ioreg_t base; + int irq; +} m68k_ide_defaults[MAX_HWIFS] = { +#if defined(CONFIG_SECUREEDGEMP3) + { ((ide_ioreg_t)0x30800000), 29 }, +#elif defined(CONFIG_eLIA) + { ((ide_ioreg_t)0x30c00000), 29 }, +#else + { ((ide_ioreg_t)0x0), 0 } +#endif +}; + +/****************************************************************************/ + +static IDE_INLINE int ide_default_irq(ide_ioreg_t base) +{ + int i; + + for (i = 0; i < MAX_HWIFS; i++) + if (m68k_ide_defaults[i].base == base) + return(m68k_ide_defaults[i].irq); + return 0; +} + +static IDE_INLINE ide_ioreg_t ide_default_io_base(int index) +{ + if (index >= 0 && index < MAX_HWIFS) + return(m68k_ide_defaults[index].base); + return 0; +} + + +/* + * Set up a hw structure for a specified data port, control port and IRQ. + * This should follow whatever the default interface uses. + */ +static IDE_INLINE void ide_init_hwif_ports( + hw_regs_t *hw, + ide_ioreg_t data_port, + ide_ioreg_t ctrl_port, + int *irq) +{ + ide_ioreg_t reg = data_port; + int i; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg; + reg += 1; + } + if (ctrl_port) { + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + } else { + hw->io_ports[IDE_CONTROL_OFFSET] = data_port + 0xe; + } +} + + +/* + * This registers the standard ports for this architecture with the IDE + * driver. + */ +static IDE_INLINE void ide_init_default_hwifs(void) +{ + hw_regs_t hw; + ide_ioreg_t base; + int index; + + for (index = 0; index < MAX_HWIFS; index++) { + base = ide_default_io_base(index); + if (!base) + continue; + memset(&hw, 0, sizeof(hw)); + ide_init_hwif_ports(&hw, base, 0, NULL); + hw.irq = ide_default_irq(base); + ide_register_hw(&hw, NULL); + } +} + + +static IDE_INLINE int +ide_request_irq( + unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, + const char *device, + void *dev_id) +{ +#ifdef CONFIG_COLDFIRE + mcf_autovector(irq); +#endif + return(request_irq(irq, handler, flags, device, dev_id)); +} + + +static IDE_INLINE void +ide_free_irq(unsigned int irq, void *dev_id) +{ + free_irq(irq, dev_id); +} + + +static IDE_INLINE int +ide_check_region(ide_ioreg_t from, unsigned int extent) +{ + return 0; +} + + +static IDE_INLINE void +ide_request_region(ide_ioreg_t from, unsigned int extent, const char *name) +{ +} + + +static IDE_INLINE void +ide_release_region(ide_ioreg_t from, unsigned int extent) +{ +} + + +static IDE_INLINE void +ide_fix_driveid(struct hd_driveid *id) +{ +#ifdef CONFIG_COLDFIRE + int i, n; + unsigned short *wp = (unsigned short *) id; + int avoid[] = {49, 51, 52, 59, -1 }; /* do not swap these words */ + + /* Need to byte swap shorts, but not char fields */ + for (i = n = 0; i < sizeof(*id) / sizeof(*wp); i++, wp++) { + if (avoid[n] == i) { + n++; + continue; + } + *wp = ((*wp & 0xff) << 8) | ((*wp >> 8) & 0xff); + } + /* have to word swap the one 32 bit field */ + id->lba_capacity = ((id->lba_capacity & 0xffff) << 16) | + ((id->lba_capacity >> 16) & 0xffff); +#endif +} + + +static IDE_INLINE void +ide_release_lock (int *ide_lock) +{ +} + + +static IDE_INLINE void +ide_get_lock( + int *ide_lock, + void (*handler)(int, void *, struct pt_regs *), + void *data) +{ +} + + +#define ide_ack_intr(hwif) \ + ((hwif)->hw.ack_intr ? (hwif)->hw.ack_intr(hwif) : 1) +#define ide__sti() __sti() + +/****************************************************************************/ +/* + * System specific IO requirements + */ + +#ifdef CONFIG_COLDFIRE + +#ifdef CONFIG_SECUREEDGEMP3 + +/* Replace standard IO functions for funky mapping of MP3 board */ +#undef outb +#undef outb_p +#undef inb +#undef inb_p + +#define outb(v, a) ide_outb(v, (unsigned long) (a)) +#define outb_p(v, a) ide_outb(v, (unsigned long) (a)) +#define inb(a) ide_inb((unsigned long) (a)) +#define inb_p(a) ide_inb((unsigned long) (a)) + +#define ADDR8_PTR(addr) (((addr) & 0x1) ? (0x8000 + (addr) - 1) : (addr)) +#define ADDR16_PTR(addr) (addr) +#define ADDR32_PTR(addr) (addr) +#define SWAP8(w) ((((w) & 0xffff) << 8) | (((w) & 0xffff) >> 8)) +#define SWAP16(w) (w) +#define SWAP32(w) (w) + + +static IDE_INLINE void +ide_outb(unsigned int val, unsigned int addr) +{ + volatile unsigned short *rp; + + DBGIDE("%s(val=%x,addr=%x)\n", __FUNCTION__, val, addr); + rp = (volatile unsigned short *) ADDR8_PTR(addr); + *rp = SWAP8(val); +} + + +static IDE_INLINE int +ide_inb(unsigned int addr) +{ + volatile unsigned short *rp, val; + + DBGIDE("%s(addr=%x)\n", __FUNCTION__, addr); + rp = (volatile unsigned short *) ADDR8_PTR(addr); + val = *rp; + return(SWAP8(val)); +} + + +static IDE_INLINE void +ide_outw(unsigned int val, unsigned int addr) +{ + volatile unsigned short *rp; + + DBGIDE("%s(val=%x,addr=%x)\n", __FUNCTION__, val, addr); + rp = (volatile unsigned short *) ADDR16_PTR(addr); + *rp = SWAP16(val); +} + +static IDE_INLINE void +ide_outsw(unsigned int addr, const void *vbuf, unsigned long len) +{ + volatile unsigned short *rp, val; + unsigned short *buf; + + DBGIDE("%s(addr=%x,vbuf=%p,len=%x)\n", __FUNCTION__, addr, vbuf, len); + buf = (unsigned short *) vbuf; + rp = (volatile unsigned short *) ADDR16_PTR(addr); + for (; (len > 0); len--) { + val = *buf++; + *rp = SWAP16(val); + } +} + +static IDE_INLINE int +ide_inw(unsigned int addr) +{ + volatile unsigned short *rp, val; + + DBGIDE("%s(addr=%x)\n", __FUNCTION__, addr); + rp = (volatile unsigned short *) ADDR16_PTR(addr); + val = *rp; + return(SWAP16(val)); +} + +static IDE_INLINE void +ide_insw(unsigned int addr, void *vbuf, unsigned long len) +{ + volatile unsigned short *rp; + unsigned short w, *buf; + + DBGIDE("%s(addr=%x,vbuf=%p,len=%x)\n", __FUNCTION__, addr, vbuf, len); + buf = (unsigned short *) vbuf; + rp = (volatile unsigned short *) ADDR16_PTR(addr); + for (; (len > 0); len--) { + w = *rp; + *buf++ = SWAP16(w); + } +} + +static IDE_INLINE void +ide_insl(unsigned int addr, void *vbuf, unsigned long len) +{ + volatile unsigned long *rp; + unsigned long w, *buf; + + DBGIDE("%s(addr=%x,vbuf=%p,len=%x)\n", __FUNCTION__, addr, vbuf, len); + buf = (unsigned long *) vbuf; + rp = (volatile unsigned long *) ADDR32_PTR(addr); + for (; (len > 0); len--) { + w = *rp; + *buf++ = SWAP32(w); + } +} + +static IDE_INLINE void +ide_outsl(unsigned int addr, const void *vbuf, unsigned long len) +{ + volatile unsigned long *rp, val; + unsigned long *buf; + + DBGIDE("%s(addr=%x,vbuf=%p,len=%x)\n", __FUNCTION__, addr, vbuf, len); + buf = (unsigned long *) vbuf; + rp = (volatile unsigned long *) ADDR32_PTR(addr); + for (; (len > 0); len--) { + val = *buf++; + *rp = SWAP32(val); + } +} + +#elif CONFIG_eLIA + +/* 8/16 bit acesses are controlled by flicking bits in the CS register */ +#define ACCESS_MODE_16BIT() \ + *((volatile unsigned short *) (MCF_MBAR + MCFSIM_LOCALCS)) = 0x0080 +#define ACCESS_MODE_8BIT() \ + *((volatile unsigned short *) (MCF_MBAR + MCFSIM_LOCALCS)) = 0x0040 + + +static IDE_INLINE void +ide_outw(unsigned int val, unsigned int addr) +{ + ACCESS_MODE_16BIT(); + outw(val, addr); + ACCESS_MODE_8BIT(); +} + +static IDE_INLINE void +ide_outsw(unsigned int addr, const void *vbuf, unsigned long len) +{ + ACCESS_MODE_16BIT(); + outsw(addr, vbuf, len); + ACCESS_MODE_8BIT(); +} + +static IDE_INLINE int +ide_inw(unsigned int addr) +{ + int ret; + + ACCESS_MODE_16BIT(); + ret = inw(addr); + ACCESS_MODE_8BIT(); + return(ret); +} + +static IDE_INLINE void +ide_insw(unsigned int addr, void *vbuf, unsigned long len) +{ + ACCESS_MODE_16BIT(); + insw(addr, vbuf, len); + ACCESS_MODE_8BIT(); +} + +static IDE_INLINE void +ide_insl(unsigned int addr, void *vbuf, unsigned long len) +{ + ACCESS_MODE_16BIT(); + insl(addr, vbuf, len); + ACCESS_MODE_8BIT(); +} + +static IDE_INLINE void +ide_outsl(unsigned int addr, const void *vbuf, unsigned long len) +{ + ACCESS_MODE_16BIT(); + outsl(addr, vbuf, len); + ACCESS_MODE_8BIT(); +} + +#endif /* CONFIG_SECUREEDGEMP3 */ + +#undef outw +#undef outw_p +#undef outsw +#undef inw +#undef inw_p +#undef insw +#undef insl +#undef outsl + +#define outw(v, a) ide_outw(v, (unsigned long) (a)) +#define outw_p(v, a) ide_outw(v, (unsigned long) (a)) +#define outsw(a, b, n) ide_outsw((unsigned long) (a), b, n) +#define inw(a) ide_inw((unsigned long) (a)) +#define inw_p(a) ide_inw((unsigned long) (a)) +#define insw(a, b, n) ide_insw((unsigned long) (a), b, n) +#define insl(a, b, n) ide_insl((unsigned long) (a), b, n) +#define outsl(a, b, n) ide_outsl((unsigned long) (a), b, n) + +#endif CONFIG_COLDFIRE + +/****************************************************************************/ +#endif /* __KERNEL__ */ +#endif /* _M68KNOMMU_IDE_H */ +/****************************************************************************/ diff -Nru a/include/asm-m68knommu/init.h b/include/asm-m68knommu/init.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/init.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/io.h b/include/asm-m68knommu/io.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/io.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,179 @@ +#ifndef _M68KNOMMU_IO_H +#define _M68KNOMMU_IO_H + +#ifdef __KERNEL__ + +#include + +/* + * These are for ISA/PCI shared memory _only_ and should never be used + * on any other type of memory, including Zorro memory. They are meant to + * access the bus in the bus byte order which is little-endian!. + * + * readX/writeX() are used to access memory mapped devices. On some + * architectures the memory mapped IO stuff needs to be accessed + * differently. On the m68k architecture, we just read/write the + * memory location directly. + */ +/* ++roman: The assignments to temp. vars avoid that gcc sometimes generates + * two accesses to memory, which may be undesireable for some devices. + */ + +/* + * swap functions are sometimes needed to interface little-endian hardware + */ +static inline unsigned short _swapw(volatile unsigned short v) +{ + return ((v << 8) | (v >> 8)); +} + +static inline unsigned int _swapl(volatile unsigned long v) +{ + return ((v << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | (v >> 24)); +} + +#define readb(addr) \ + ({ unsigned char __v = (*(volatile unsigned char *) (addr)); __v; }) +#define readw(addr) \ + ({ unsigned short __v = (*(volatile unsigned short *) (addr)); __v; }) +#define readl(addr) \ + ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; }) + +#define writeb(b,addr) (void)((*(volatile unsigned char *) (addr)) = (b)) +#define writew(b,addr) (void)((*(volatile unsigned short *) (addr)) = (b)) +#define writel(b,addr) (void)((*(volatile unsigned int *) (addr)) = (b)) + +static inline void io_outsb(unsigned int addr, void *buf, int len) +{ + volatile unsigned char *ap = (volatile unsigned char *) addr; + unsigned char *bp = (unsigned char *) buf; + while (len--) + *ap = *bp++; +} + +static inline void io_outsw(unsigned int addr, void *buf, int len) +{ + volatile unsigned short *ap = (volatile unsigned short *) addr; + unsigned short *bp = (unsigned short *) buf; + while (len--) + *ap = _swapw(*bp++); +} + +static inline void io_outsl(unsigned int addr, void *buf, int len) +{ + volatile unsigned int *ap = (volatile unsigned int *) addr; + unsigned int *bp = (unsigned int *) buf; + while (len--) + *ap = _swapl(*bp++); +} + +static inline void io_insb(unsigned int addr, void *buf, int len) +{ + volatile unsigned char *ap = (volatile unsigned char *) addr; + unsigned char *bp = (unsigned char *) buf; + while (len--) + *bp++ = *ap; +} + +static inline void io_insw(unsigned int addr, void *buf, int len) +{ + volatile unsigned short *ap = (volatile unsigned short *) addr; + unsigned short *bp = (unsigned short *) buf; + while (len--) + *bp++ = _swapw(*ap); +} + +static inline void io_insl(unsigned int addr, void *buf, int len) +{ + volatile unsigned int *ap = (volatile unsigned int *) addr; + unsigned int *bp = (unsigned int *) buf; + while (len--) + *bp++ = _swapl(*ap); +} + +/* + * make the short names macros so specific devices + * can override them as required + */ + +#define memset_io(a,b,c) memset((void *)(a),(b),(c)) +#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) +#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c)) + +#define inb(addr) readb(addr) +#define inw(addr) readw(addr) +#define inl(addr) readl(addr) +#define outb(x,addr) ((void) writeb(x,addr)) +#define outw(x,addr) ((void) writew(x,addr)) +#define outl(x,addr) ((void) writel(x,addr)) + +#define inb_p(addr) inb(addr) +#define inw_p(addr) inw(addr) +#define inl_p(addr) inl(addr) +#define outb_p(x,addr) outb(x,addr) +#define outw_p(x,addr) outw(x,addr) +#define outl_p(x,addr) outl(x,addr) + +#define outsb(a,b,l) io_outsb(a,b,l) +#define outsw(a,b,l) io_outsw(a,b,l) +#define outsl(a,b,l) io_outsl(a,b,l) + +#define insb(a,b,l) io_insb(a,b,l) +#define insw(a,b,l) io_insw(a,b,l) +#define insl(a,b,l) io_insl(a,b,l) + +#define IO_SPACE_LIMIT 0xffff + + +/* Values for nocacheflag and cmode */ +#define IOMAP_FULL_CACHING 0 +#define IOMAP_NOCACHE_SER 1 +#define IOMAP_NOCACHE_NONSER 2 +#define IOMAP_WRITETHROUGH 3 + +extern void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag); +extern void __iounmap(void *addr, unsigned long size); + +extern inline void *ioremap(unsigned long physaddr, unsigned long size) +{ + return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); +} +extern inline void *ioremap_nocache(unsigned long physaddr, unsigned long size) +{ + return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); +} +extern inline void *ioremap_writethrough(unsigned long physaddr, unsigned long size) +{ + return __ioremap(physaddr, size, IOMAP_WRITETHROUGH); +} +extern inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size) +{ + return __ioremap(physaddr, size, IOMAP_FULL_CACHING); +} + +extern void iounmap(void *addr); + +/* Nothing to do */ + +#define dma_cache_inv(_start,_size) do { } while (0) +#define dma_cache_wback(_start,_size) do { } while (0) +#define dma_cache_wback_inv(_start,_size) do { } while (0) + +/* Pages to physical address... */ +#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT) +#define page_to_bus(page) ((page - mem_map) << PAGE_SHIFT) + +/* + * Macros used for converting between virtual and physical mappings. + */ +#define mm_ptov(vaddr) ((void *) (vaddr)) +#define mm_vtop(vaddr) ((unsigned long) (vaddr)) +#define phys_to_virt(vaddr) ((void *) (vaddr)) +#define virt_to_phys(vaddr) ((unsigned long) (vaddr)) + +#define virt_to_bus virt_to_phys +#define bus_to_virt phys_to_virt + +#endif /* __KERNEL__ */ + +#endif /* _M68KNOMMU_IO_H */ diff -Nru a/include/asm-m68knommu/io_hw_swap.h b/include/asm-m68knommu/io_hw_swap.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/io_hw_swap.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,113 @@ +#ifndef _M68K_IO_HW_SWAP_H +#define _M68K_IO_HW_SWAP_H + +/* + * swap functions are sometimes needed to interface little-endian hardware + */ +static inline unsigned short _swapw(volatile unsigned short v) +{ + return ((v << 8) | (v >> 8)); +} + +static inline unsigned int _swapl(volatile unsigned long v) +{ + return ((v << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | (v >> 24)); +} + +/* + * readX/writeX() are used to access memory mapped devices. On some + * architectures the memory mapped IO stuff needs to be accessed + * differently. On the m68k architecture, we just read/write the + * memory location directly. + */ +/* ++roman: The assignments to temp. vars avoid that gcc sometimes generates + * two accesses to memory, which may be undesireable for some devices. + */ +#define readb(addr) \ + ({ unsigned char __v = (*(volatile unsigned char *) (addr)); __v; }) +#define readw(addr) \ + ({ unsigned short __v = (*(volatile unsigned short *) (addr)); __v; }) +#define readl(addr) \ + ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; }) + +#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b)) +#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b)) +#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b)) + +/* There is no difference between I/O and memory on 68k, these are the same */ +#define inb(addr) \ + ({ unsigned char __v = (*(volatile unsigned char *) (addr)); __v; }) +#define inw(addr) \ + ({ unsigned short __v = (*(volatile unsigned short *) (addr)); \ + _swapw(__v); }) +#define inl(addr) \ + ({ unsigned int __v = (*(volatile unsigned int *) (addr)); _swapl(__v); }) + +#define outb(b,addr) ((*(volatile unsigned char *) (addr)) = (b)) +#define outw(b,addr) ((*(volatile unsigned short *) (addr)) = (_swapw(b))) +#define outl(b,addr) ((*(volatile unsigned int *) (addr)) = (_swapl(b))) + +/* FIXME: these need to be optimized. Watch out for byte swapping, they + * are used mostly for Intel devices... */ +#define outsw(addr,buf,len) \ + ({ unsigned short * __p = (unsigned short *)(buf); \ + unsigned short * __e = (unsigned short *)(__p) + (len); \ + while (__p < __e) { \ + *(volatile unsigned short *)(addr) = *__p++;\ + } \ + }) + +#define insw(addr,buf,len) \ + ({ unsigned short * __p = (unsigned short *)(buf); \ + unsigned short * __e = (unsigned short *)(__p) + (len); \ + while (__p < __e) { \ + *(__p++) = *(volatile unsigned short *)(addr); \ + } \ + }) + + +static inline unsigned char get_user_byte_io(const char * addr) +{ + register unsigned char _v; + + __asm__ __volatile__ ("moveb %1,%0":"=dm" (_v):"m" (*addr)); + return _v; +} +#define inb_p(addr) get_user_byte_io((char *)(addr)) + +static inline void put_user_byte_io(char val,char *addr) +{ + __asm__ __volatile__ ("moveb %0,%1" + : /* no outputs */ + :"idm" (val),"m" (*addr) + : "memory"); +} +#define outb_p(x,addr) put_user_byte_io((x),(char *)(addr)) + +/* + * Change virtual addresses to physical addresses and vv. + * These are trivial on the 1:1 Linux/i386 mapping (but if we ever + * make the kernel segment mapped at 0, we need to do translation + * on the i386 as well) + */ +extern unsigned long mm_vtop(unsigned long addr); +extern unsigned long mm_ptov(unsigned long addr); + +extern inline unsigned long virt_to_phys(volatile void * address) +{ + return (unsigned long) mm_vtop((unsigned long)address); +} + +extern inline void * phys_to_virt(unsigned long address) +{ + return (void *) mm_ptov(address); +} + +/* + * IO bus memory addresses are also 1:1 with the physical address + */ +#define virt_to_bus virt_to_phys +#define bus_to_virt phys_to_virt + + +#endif /* _M68K_IO_HW_SWAP_H */ diff -Nru a/include/asm-m68knommu/ioctl.h b/include/asm-m68knommu/ioctl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/ioctl.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/ioctls.h b/include/asm-m68knommu/ioctls.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/ioctls.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/ipc.h b/include/asm-m68knommu/ipc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/ipc.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/ipcbuf.h b/include/asm-m68knommu/ipcbuf.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/ipcbuf.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/irq.h b/include/asm-m68knommu/irq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/irq.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,128 @@ +#ifndef _M68K_IRQ_H_ +#define _M68K_IRQ_H_ + +#include +#include + +#ifdef CONFIG_COLDFIRE +/* + * On the ColdFire we keep track of all vectors. That way drivers + * can register whatever vector number they wish, and we can deal + * with it. + */ +#define SYS_IRQS 256 +#define NR_IRQS SYS_IRQS + +#else + +/* + * # of m68k interrupts + */ +#define SYS_IRQS 8 +#define NR_IRQS (24+SYS_IRQS) + +#endif /* CONFIG_COLDFIRE */ + +/* + * Interrupt source definitions + * General interrupt sources are the level 1-7. + * Adding an interrupt service routine for one of these sources + * results in the addition of that routine to a chain of routines. + * Each one is called in succession. Each individual interrupt + * service routine should determine if the device associated with + * that routine requires service. + */ + +#define IRQ1 (1) /* level 1 interrupt */ +#define IRQ2 (2) /* level 2 interrupt */ +#define IRQ3 (3) /* level 3 interrupt */ +#define IRQ4 (4) /* level 4 interrupt */ +#define IRQ5 (5) /* level 5 interrupt */ +#define IRQ6 (6) /* level 6 interrupt */ +#define IRQ7 (7) /* level 7 interrupt (non-maskable) */ + +/* + * Machine specific interrupt sources. + * + * Adding an interrupt service routine for a source with this bit + * set indicates a special machine specific interrupt source. + * The machine specific files define these sources. + * + * The IRQ_MACHSPEC bit is now gone - the only thing it did was to + * introduce unnecessary overhead. + * + * All interrupt handling is actually machine specific so it is better + * to use function pointers, as used by the Sparc port, and select the + * interrupt handling functions when initializing the kernel. This way + * we save some unnecessary overhead at run-time. + * 01/11/97 - Jes + */ + +extern void (*mach_enable_irq)(unsigned int); +extern void (*mach_disable_irq)(unsigned int); + +extern int sys_request_irq(unsigned int, + void (*)(int, void *, struct pt_regs *), + unsigned long, const char *, void *); +extern void sys_free_irq(unsigned int, void *); + +/* + * various flags for request_irq() - the Amiga now uses the standard + * mechanism like all other architectures - SA_INTERRUPT and SA_SHIRQ + * are your friends. + */ +#define IRQ_FLG_LOCK (0x0001) /* handler is not replaceable */ +#define IRQ_FLG_REPLACE (0x0002) /* replace existing handler */ +#define IRQ_FLG_FAST (0x0004) +#define IRQ_FLG_SLOW (0x0008) +#define IRQ_FLG_STD (0x8000) /* internally used */ + +#ifdef CONFIG_M68360 + +#define CPM_INTERRUPT IRQ4 + +/* see MC68360 User's Manual, p. 7-377 */ +#define CPM_VECTOR_BASE 0x04 /* 3 MSbits of CPM vector */ + +#endif /* CONFIG_M68360 */ + +/* + * This structure is used to chain together the ISRs for a particular + * interrupt source (if it supports chaining). + */ +typedef struct irq_node { + void (*handler)(int, void *, struct pt_regs *); + unsigned long flags; + void *dev_id; + const char *devname; + struct irq_node *next; +} irq_node_t; + +/* + * This structure has only 4 elements for speed reasons + */ +typedef struct irq_handler { + void (*handler)(int, void *, struct pt_regs *); + unsigned long flags; + void *dev_id; + const char *devname; +} irq_handler_t; + +/* count of spurious interrupts */ +extern volatile unsigned int num_spurious; + +/* + * This function returns a new irq_node_t + */ +extern irq_node_t *new_irq_node(void); + +/* + * Some drivers want these entry points + */ +#define enable_irq(x) (mach_enable_irq ? (*mach_enable_irq)(x) : 0) +#define disable_irq(x) (mach_disable_irq ? (*mach_disable_irq)(x) : 0) + +#define enable_irq_nosync(x) enable_irq(x) +#define disable_irq_nosync(x) disable_irq(x) + +#endif /* _M68K_IRQ_H_ */ diff -Nru a/include/asm-m68knommu/keyboard.h b/include/asm-m68knommu/keyboard.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/keyboard.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/kmap_types.h b/include/asm-m68knommu/kmap_types.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/kmap_types.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,19 @@ +#ifndef _ASM_KMAP_TYPES_H +#define _ASM_KMAP_TYPES_H + +enum km_type { + KM_BOUNCE_READ, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BIO_SRC_IRQ, + KM_BIO_DST_IRQ, + KM_PTE0, + KM_PTE1, + KM_IRQ0, + KM_IRQ1, + KM_TYPE_NR +}; + +#endif diff -Nru a/include/asm-m68knommu/linkage.h b/include/asm-m68knommu/linkage.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/linkage.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/linux_logo.h b/include/asm-m68knommu/linux_logo.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/linux_logo.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,13 @@ +/* + * include/asm-m68knommu/linux_logo.h: This is a linux logo + * to be displayed on boot. + */ + +#include +#include +#include + +#define linux_logo_banner "Linux/m68knommu version " UTS_RELEASE + +#include + diff -Nru a/include/asm-m68knommu/m5206sim.h b/include/asm-m68knommu/m5206sim.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/m5206sim.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,132 @@ +/****************************************************************************/ + +/* + * m5206sim.h -- ColdFire 5206 System Integration Module support. + * + * (C) Copyright 1999, Greg Ungerer (gerg@snapgear.com) + * (C) Copyright 2000, Lineo Inc. (www.lineo.com) + */ + +/****************************************************************************/ +#ifndef m5206sim_h +#define m5206sim_h +/****************************************************************************/ + +#include + +/* + * Define the 5206 SIM register set addresses. + */ +#define MCFSIM_SIMR 0x03 /* SIM Config reg (r/w) */ +#define MCFSIM_ICR1 0x14 /* Intr Ctrl reg 1 (r/w) */ +#define MCFSIM_ICR2 0x15 /* Intr Ctrl reg 2 (r/w) */ +#define MCFSIM_ICR3 0x16 /* Intr Ctrl reg 3 (r/w) */ +#define MCFSIM_ICR4 0x17 /* Intr Ctrl reg 4 (r/w) */ +#define MCFSIM_ICR5 0x18 /* Intr Ctrl reg 5 (r/w) */ +#define MCFSIM_ICR6 0x19 /* Intr Ctrl reg 6 (r/w) */ +#define MCFSIM_ICR7 0x1a /* Intr Ctrl reg 7 (r/w) */ +#define MCFSIM_ICR8 0x1b /* Intr Ctrl reg 8 (r/w) */ +#define MCFSIM_ICR9 0x1c /* Intr Ctrl reg 9 (r/w) */ +#define MCFSIM_ICR10 0x1d /* Intr Ctrl reg 10 (r/w) */ +#define MCFSIM_ICR11 0x1e /* Intr Ctrl reg 11 (r/w) */ +#define MCFSIM_ICR12 0x1f /* Intr Ctrl reg 12 (r/w) */ +#define MCFSIM_ICR13 0x20 /* Intr Ctrl reg 13 (r/w) */ +#ifdef CONFIG_M5206e +#define MCFSIM_ICR14 0x21 /* Intr Ctrl reg 14 (r/w) */ +#define MCFSIM_ICR15 0x22 /* Intr Ctrl reg 15 (r/w) */ +#endif + +#define MCFSIM_IMR 0x36 /* Interrupt Mask reg (r/w) */ +#define MCFSIM_IPR 0x3a /* Interrupt Pend reg (r/w) */ + +#define MCFSIM_RSR 0x40 /* Reset Status reg (r/w) */ +#define MCFSIM_SYPCR 0x41 /* System Protection reg (r/w)*/ + +#define MCFSIM_SWIVR 0x42 /* SW Watchdog intr reg (r/w) */ +#define MCFSIM_SWSR 0x43 /* SW Watchdog service (r/w) */ + +#define MCFSIM_DCRR 0x46 /* DRAM Refresh reg (r/w) */ +#define MCFSIM_DCTR 0x4a /* DRAM Timing reg (r/w) */ +#define MCFSIM_DCAR0 0x4c /* DRAM 0 Address reg(r/w) */ +#define MCFSIM_DCMR0 0x50 /* DRAM 0 Mask reg (r/w) */ +#define MCFSIM_DCCR0 0x57 /* DRAM 0 Control reg (r/w) */ +#define MCFSIM_DCAR1 0x58 /* DRAM 1 Address reg (r/w) */ +#define MCFSIM_DCMR1 0x5c /* DRAM 1 Mask reg (r/w) */ +#define MCFSIM_DCCR1 0x63 /* DRAM 1 Control reg (r/w) */ + +#define MCFSIM_CSAR0 0x64 /* CS 0 Address 0 reg (r/w) */ +#define MCFSIM_CSMR0 0x68 /* CS 0 Mask 0 reg (r/w) */ +#define MCFSIM_CSCR0 0x6e /* CS 0 Control reg (r/w) */ +#define MCFSIM_CSAR1 0x70 /* CS 1 Address reg (r/w) */ +#define MCFSIM_CSMR1 0x74 /* CS 1 Mask reg (r/w) */ +#define MCFSIM_CSCR1 0x7a /* CS 1 Control reg (r/w) */ +#define MCFSIM_CSAR2 0x7c /* CS 2 Address reg (r/w) */ +#define MCFSIM_CSMR2 0x80 /* CS 2 Mask reg (r/w) */ +#define MCFSIM_CSCR2 0x86 /* CS 2 Control reg (r/w) */ +#define MCFSIM_CSAR3 0x88 /* CS 3 Address reg (r/w) */ +#define MCFSIM_CSMR3 0x8c /* CS 3 Mask reg (r/w) */ +#define MCFSIM_CSCR3 0x92 /* CS 3 Control reg (r/w) */ +#define MCFSIM_CSAR4 0x94 /* CS 4 Address reg (r/w) */ +#define MCFSIM_CSMR4 0x98 /* CS 4 Mask reg (r/w) */ +#define MCFSIM_CSCR4 0x9e /* CS 4 Control reg (r/w) */ +#define MCFSIM_CSAR5 0xa0 /* CS 5 Address reg (r/w) */ +#define MCFSIM_CSMR5 0xa4 /* CS 5 Mask reg (r/w) */ +#define MCFSIM_CSCR5 0xaa /* CS 5 Control reg (r/w) */ +#define MCFSIM_CSAR6 0xac /* CS 6 Address reg (r/w) */ +#define MCFSIM_CSMR6 0xb0 /* CS 6 Mask reg (r/w) */ +#define MCFSIM_CSCR6 0xb6 /* CS 6 Control reg (r/w) */ +#define MCFSIM_CSAR7 0xb8 /* CS 7 Address reg (r/w) */ +#define MCFSIM_CSMR7 0xbc /* CS 7 Mask reg (r/w) */ +#define MCFSIM_CSCR7 0xc2 /* CS 7 Control reg (r/w) */ +#define MCFSIM_DMCR 0xc6 /* Default control */ + +#ifdef CONFIG_M5206e +#define MCFSIM_PAR 0xca /* Pin Assignment reg (r/w) */ +#else +#define MCFSIM_PAR 0xcb /* Pin Assignment reg (r/w) */ +#endif + +#define MCFSIM_PADDR 0x1c5 /* Parallel Direction (r/w) */ +#define MCFSIM_PADAT 0x1c9 /* Parallel Port Value (r/w) */ + +/* + * Some symbol defines for the Parallel Port Pin Assignment Register + */ +#ifdef CONFIG_M5206e +#define MCFSIM_PAR_DREQ0 0x100 /* Set to select DREQ0 input */ + /* Clear to select T0 input */ +#define MCFSIM_PAR_DREQ1 0x200 /* Select DREQ1 input */ + /* Clear to select T0 output */ +#endif + +/* + * Some symbol defines for the Interrupt Control Register + */ +#define MCFSIM_SWDICR MCFSIM_ICR8 /* Watchdog timer ICR */ +#define MCFSIM_TIMER1ICR MCFSIM_ICR9 /* Timer 1 ICR */ +#define MCFSIM_TIMER2ICR MCFSIM_ICR10 /* Timer 2 ICR */ +#define MCFSIM_UART1ICR MCFSIM_ICR12 /* UART 1 ICR */ +#define MCFSIM_UART2ICR MCFSIM_ICR13 /* UART 2 ICR */ +#ifdef CONFIG_M5206e +#define MCFSIM_DMA1ICR MCFSIM_ICR14 /* DMA 1 ICR */ +#define MCFSIM_DMA2ICR MCFSIM_ICR15 /* DMA 2 ICR */ +#endif + +#if defined(CONFIG_M5206e) +#define MCFSIM_IMR_MASKALL 0xfffe /* All SIM intr sources */ +#endif + +/* + * Macro to get and set IMR register. It is 16 bits on the 5206. + */ +#define mcf_getimr() \ + *((volatile unsigned short *) (MCF_MBAR + MCFSIM_IMR)) + +#define mcf_setimr(imr) \ + *((volatile unsigned short *) (MCF_MBAR + MCFSIM_IMR)) = (imr) + +#define mcf_getipr() \ + *((volatile unsigned short *) (MCF_MBAR + MCFSIM_IPR)) + +/****************************************************************************/ +#endif /* m5206sim_h */ diff -Nru a/include/asm-m68knommu/m5249sim.h b/include/asm-m68knommu/m5249sim.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/m5249sim.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,119 @@ +/****************************************************************************/ + +/* + * m5249sim.h -- ColdFire 5249 System Integration Module support. + * + * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) + */ + +/****************************************************************************/ +#ifndef m5249sim_h +#define m5249sim_h +/****************************************************************************/ + +/* + * Define the 5249 SIM register set addresses. + */ +#define MCFSIM_RSR 0x00 /* Reset Status reg (r/w) */ +#define MCFSIM_SYPCR 0x01 /* System Protection reg (r/w)*/ +#define MCFSIM_SWIVR 0x02 /* SW Watchdog intr reg (r/w) */ +#define MCFSIM_SWSR 0x03 /* SW Watchdog service (r/w) */ +#define MCFSIM_PAR 0x04 /* Pin Assignment reg (r/w) */ +#define MCFSIM_IRQPAR 0x06 /* Interrupt Assignment reg (r/w) */ +#define MCFSIM_MPARK 0x0C /* BUS Master Control Reg*/ +#define MCFSIM_IPR 0x40 /* Interrupt Pend reg (r/w) */ +#define MCFSIM_IMR 0x44 /* Interrupt Mask reg (r/w) */ +#define MCFSIM_AVR 0x4b /* Autovector Ctrl reg (r/w) */ +#define MCFSIM_ICR0 0x4c /* Intr Ctrl reg 0 (r/w) */ +#define MCFSIM_ICR1 0x4d /* Intr Ctrl reg 1 (r/w) */ +#define MCFSIM_ICR2 0x4e /* Intr Ctrl reg 2 (r/w) */ +#define MCFSIM_ICR3 0x4f /* Intr Ctrl reg 3 (r/w) */ +#define MCFSIM_ICR4 0x50 /* Intr Ctrl reg 4 (r/w) */ +#define MCFSIM_ICR5 0x51 /* Intr Ctrl reg 5 (r/w) */ +#define MCFSIM_ICR6 0x52 /* Intr Ctrl reg 6 (r/w) */ +#define MCFSIM_ICR7 0x53 /* Intr Ctrl reg 7 (r/w) */ +#define MCFSIM_ICR8 0x54 /* Intr Ctrl reg 8 (r/w) */ +#define MCFSIM_ICR9 0x55 /* Intr Ctrl reg 9 (r/w) */ +#define MCFSIM_ICR10 0x56 /* Intr Ctrl reg 10 (r/w) */ +#define MCFSIM_ICR11 0x57 /* Intr Ctrl reg 11 (r/w) */ + +#define MCFSIM_CSAR0 0x80 /* CS 0 Address 0 reg (r/w) */ +#define MCFSIM_CSMR0 0x84 /* CS 0 Mask 0 reg (r/w) */ +#define MCFSIM_CSCR0 0x8a /* CS 0 Control reg (r/w) */ +#define MCFSIM_CSAR1 0x8c /* CS 1 Address reg (r/w) */ +#define MCFSIM_CSMR1 0x90 /* CS 1 Mask reg (r/w) */ +#define MCFSIM_CSCR1 0x96 /* CS 1 Control reg (r/w) */ +#define MCFSIM_CSAR2 0x98 /* CS 2 Adress reg (r/w) */ +#define MCFSIM_CSMR2 0x9c /* CS 2 Mask reg (r/w) */ +#define MCFSIM_CSCR2 0xa2 /* CS 2 Control reg (r/w) */ +#define MCFSIM_CSAR3 0xa4 /* CS 3 Adress reg (r/w) */ +#define MCFSIM_CSMR3 0xa8 /* CS 3 Mask reg (r/w) */ +#define MCFSIM_CSCR3 0xae /* CS 3 Control reg (r/w) */ + +#define MCFSIM_DCR 0x100 /* DRAM Control reg (r/w) */ +#define MCFSIM_DACR0 0x108 /* DRAM 0 Addr and Ctrl (r/w) */ +#define MCFSIM_DMR0 0x10c /* DRAM 0 Mask reg (r/w) */ +#define MCFSIM_DACR1 0x110 /* DRAM 1 Addr and Ctrl (r/w) */ +#define MCFSIM_DMR1 0x114 /* DRAM 1 Mask reg (r/w) */ + + +/* + * Some symbol defines for the above... + */ +#define MCFSIM_SWDICR MCFSIM_ICR0 /* Watchdog timer ICR */ +#define MCFSIM_TIMER1ICR MCFSIM_ICR1 /* Timer 1 ICR */ +#define MCFSIM_TIMER2ICR MCFSIM_ICR2 /* Timer 2 ICR */ +#define MCFSIM_UART1ICR MCFSIM_ICR4 /* UART 1 ICR */ +#define MCFSIM_UART2ICR MCFSIM_ICR5 /* UART 2 ICR */ +#define MCFSIM_DMA0ICR MCFSIM_ICR6 /* DMA 0 ICR */ +#define MCFSIM_DMA1ICR MCFSIM_ICR7 /* DMA 1 ICR */ +#define MCFSIM_DMA2ICR MCFSIM_ICR8 /* DMA 2 ICR */ +#define MCFSIM_DMA3ICR MCFSIM_ICR9 /* DMA 3 ICR */ + +/* + * General purpose IO registers (in MBAR2). + */ +#define MCFSIM2_GPIOREAD 0x0 /* GPIO read values */ +#define MCFSIM2_GPIOWRITE 0x4 /* GPIO write values */ +#define MCFSIM2_GPIOENABLE 0x8 /* GPIO enabled */ +#define MCFSIM2_GPIOFUNC 0xc /* GPIO function */ +#define MCFSIM2_GPIO1READ 0xb0 /* GPIO1 read values */ +#define MCFSIM2_GPIO1WRITE 0xb4 /* GPIO1 write values */ +#define MCFSIM2_GPIO1ENABLE 0xb8 /* GPIO1 enabled */ +#define MCFSIM2_GPIO1FUNC 0xbc /* GPIO1 function */ + +#define MCFSIM2_GPIOINTSTAT 0xc0 /* GPIO interrupt status */ +#define MCFSIM2_GPIOINTCLEAR 0xc0 /* GPIO interrupt clear */ +#define MCFSIM2_GPIOINTENABLE 0xc4 /* GPIO interrupt enable */ + +#define MCFSIM2_INTLEVEL1 0x140 /* Interrupt level reg 1 */ +#define MCFSIM2_INTLEVEL2 0x144 /* Interrupt level reg 2 */ +#define MCFSIM2_INTLEVEL3 0x148 /* Interrupt level reg 3 */ +#define MCFSIM2_INTLEVEL4 0x14c /* Interrupt level reg 4 */ +#define MCFSIM2_INTLEVEL5 0x150 /* Interrupt level reg 5 */ +#define MCFSIM2_INTLEVEL6 0x154 /* Interrupt level reg 6 */ +#define MCFSIM2_INTLEVEL7 0x158 /* Interrupt level reg 7 */ +#define MCFSIM2_INTLEVEL8 0x15c /* Interrupt level reg 8 */ + +#define MCFSIM2_DMAROUTE 0x188 /* DMA routing */ + +#define MCFSIM2_IDECONFIG1 0x18c /* IDEconfig1 */ +#define MCFSIM2_IDECONFIG2 0x190 /* IDEconfig2 */ + + +/* + * Macro to set IMR register. It is 32 bits on the 5249. + */ +#define MCFSIM_IMR_MASKALL 0x7fffe /* All SIM intr sources */ + +#define mcf_getimr() \ + *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR)) + +#define mcf_setimr(imr) \ + *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR)) = (imr); + +#define mcf_getipr() \ + *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IPR)) + +/****************************************************************************/ +#endif /* m5249sim_h */ diff -Nru a/include/asm-m68knommu/m5272sim.h b/include/asm-m68knommu/m5272sim.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/m5272sim.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,79 @@ +/****************************************************************************/ + +/* + * m5272sim.h -- ColdFire 5272 System Integration Module support. + * + * (C) Copyright 1999, Greg Ungerer (gerg@snapgear.com) + * (C) Copyright 2000, Lineo Inc. (www.lineo.com) + */ + +/****************************************************************************/ +#ifndef m5272sim_h +#define m5272sim_h +/****************************************************************************/ + +#include + +/* + * Define the 5272 SIM register set addresses. + */ +#define MCFSIM_SCR 0x04 /* SIM Config reg (r/w) */ +#define MCFSIM_SPR 0x06 /* System Protection reg (r/w)*/ +#define MCFSIM_PMR 0x08 /* Power Management reg (r/w) */ +#define MCFSIM_APMR 0x0e /* Active Low Power reg (r/w) */ +#define MCFSIM_DIR 0x10 /* Device Identity reg (r/w) */ + +#define MCFSIM_ICR1 0x20 /* Intr Ctrl reg 1 (r/w) */ +#define MCFSIM_ICR2 0x24 /* Intr Ctrl reg 2 (r/w) */ +#define MCFSIM_ICR3 0x28 /* Intr Ctrl reg 3 (r/w) */ +#define MCFSIM_ICR4 0x2c /* Intr Ctrl reg 4 (r/w) */ + +#define MCFSIM_ISR 0x30 /* Interrupt Source reg (r/w) */ +#define MCFSIM_PITR 0x34 /* Interrupt Transition (r/w) */ +#define MCFSIM_PIWR 0x38 /* Interrupt Wakeup reg (r/w) */ +#define MCFSIM_PIVR 0x3f /* Interrupt Vector reg (r/w( */ + +#define MCFSIM_WRRR 0x280 /* Watchdog reference (r/w) */ +#define MCFSIM_WIRR 0x284 /* Watchdog interrupt (r/w) */ +#define MCFSIM_WCR 0x288 /* Watchdog counter (r/w) */ +#define MCFSIM_WER 0x28c /* Watchdog event (r/w) */ + +#define MCFSIM_CSBR0 0x40 /* CS0 Base Address (r/w) */ +#define MCFSIM_CSOR0 0x44 /* CS0 Option (r/w) */ +#define MCFSIM_CSBR1 0x48 /* CS1 Base Address (r/w) */ +#define MCFSIM_CSOR1 0x4c /* CS1 Option (r/w) */ +#define MCFSIM_CSBR2 0x50 /* CS2 Base Address (r/w) */ +#define MCFSIM_CSOR2 0x54 /* CS2 Option (r/w) */ +#define MCFSIM_CSBR3 0x58 /* CS3 Base Address (r/w) */ +#define MCFSIM_CSOR3 0x5c /* CS3 Option (r/w) */ +#define MCFSIM_CSBR4 0x60 /* CS4 Base Address (r/w) */ +#define MCFSIM_CSOR4 0x64 /* CS4 Option (r/w) */ +#define MCFSIM_CSBR5 0x68 /* CS5 Base Address (r/w) */ +#define MCFSIM_CSOR5 0x6c /* CS5 Option (r/w) */ +#define MCFSIM_CSBR6 0x70 /* CS6 Base Address (r/w) */ +#define MCFSIM_CSOR6 0x74 /* CS6 Option (r/w) */ +#define MCFSIM_CSBR7 0x78 /* CS7 Base Address (r/w) */ +#define MCFSIM_CSOR7 0x7c /* CS7 Option (r/w) */ + +#define MCFSIM_SDCR 0x180 /* SDRAM Configuration (r/w) */ +#define MCFSIM_SDTR 0x184 /* SDRAM Timing (r/w) */ +#define MCFSIM_DCAR0 0x4c /* DRAM 0 Address reg(r/w) */ +#define MCFSIM_DCMR0 0x50 /* DRAM 0 Mask reg (r/w) */ +#define MCFSIM_DCCR0 0x57 /* DRAM 0 Control reg (r/w) */ +#define MCFSIM_DCAR1 0x58 /* DRAM 1 Address reg (r/w) */ +#define MCFSIM_DCMR1 0x5c /* DRAM 1 Mask reg (r/w) */ +#define MCFSIM_DCCR1 0x63 /* DRAM 1 Control reg (r/w) */ + +#define MCFSIM_PACNT 0x80 /* Port A Control (r/w) */ +#define MCFSIM_PADDR 0x84 /* Port A Direction (r/w) */ +#define MCFSIM_PADAT 0x86 /* Port A Data (r/w) */ +#define MCFSIM_PBCNT 0x88 /* Port B Control (r/w) */ +#define MCFSIM_PBDDR 0x8c /* Port B Direction (r/w) */ +#define MCFSIM_PBDAT 0x8e /* Port B Data (r/w) */ +#define MCFSIM_PCDDR 0x94 /* Port C Direction (r/w) */ +#define MCFSIM_PCDAT 0x96 /* Port C Data (r/w) */ +#define MCFSIM_PDCNT 0x98 /* Port D Control (r/w) */ + + +/****************************************************************************/ +#endif /* m5272sim_h */ diff -Nru a/include/asm-m68knommu/m5307sim.h b/include/asm-m68knommu/m5307sim.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/m5307sim.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,181 @@ +/****************************************************************************/ + +/* + * m5307sim.h -- ColdFire 5307 System Integration Module support. + * + * (C) Copyright 1999, Moreton Bay Ventures Pty Ltd. + * (C) Copyright 1999, Lineo (www.lineo.com) + * + * Modified by David W. Miller for the MCF5307 Eval Board. + */ + +/****************************************************************************/ +#ifndef m5307sim_h +#define m5307sim_h +/****************************************************************************/ + +/* + * Define the 5307 SIM register set addresses. + */ +#define MCFSIM_RSR 0x00 /* Reset Status reg (r/w) */ +#define MCFSIM_SYPCR 0x01 /* System Protection reg (r/w)*/ +#define MCFSIM_SWIVR 0x02 /* SW Watchdog intr reg (r/w) */ +#define MCFSIM_SWSR 0x03 /* SW Watchdog service (r/w) */ +#define MCFSIM_PAR 0x04 /* Pin Assignment reg (r/w) */ +#define MCFSIM_IRQPAR 0x06 /* Interrupt Assignment reg (r/w) */ +#define MCFSIM_PLLCR 0x08 /* PLL Controll Reg*/ +#define MCFSIM_MPARK 0x0C /* BUS Master Control Reg*/ +#define MCFSIM_IPR 0x40 /* Interrupt Pend reg (r/w) */ +#define MCFSIM_IMR 0x44 /* Interrupt Mask reg (r/w) */ +#define MCFSIM_AVR 0x4b /* Autovector Ctrl reg (r/w) */ +#define MCFSIM_ICR0 0x4c /* Intr Ctrl reg 0 (r/w) */ +#define MCFSIM_ICR1 0x4d /* Intr Ctrl reg 1 (r/w) */ +#define MCFSIM_ICR2 0x4e /* Intr Ctrl reg 2 (r/w) */ +#define MCFSIM_ICR3 0x4f /* Intr Ctrl reg 3 (r/w) */ +#define MCFSIM_ICR4 0x50 /* Intr Ctrl reg 4 (r/w) */ +#define MCFSIM_ICR5 0x51 /* Intr Ctrl reg 5 (r/w) */ +#define MCFSIM_ICR6 0x52 /* Intr Ctrl reg 6 (r/w) */ +#define MCFSIM_ICR7 0x53 /* Intr Ctrl reg 7 (r/w) */ +#define MCFSIM_ICR8 0x54 /* Intr Ctrl reg 8 (r/w) */ +#define MCFSIM_ICR9 0x55 /* Intr Ctrl reg 9 (r/w) */ +#define MCFSIM_ICR10 0x56 /* Intr Ctrl reg 10 (r/w) */ +#define MCFSIM_ICR11 0x57 /* Intr Ctrl reg 11 (r/w) */ + +#define MCFSIM_CSAR0 0x80 /* CS 0 Address 0 reg (r/w) */ +#define MCFSIM_CSMR0 0x84 /* CS 0 Mask 0 reg (r/w) */ +#define MCFSIM_CSCR0 0x8a /* CS 0 Control reg (r/w) */ +#define MCFSIM_CSAR1 0x8c /* CS 1 Address reg (r/w) */ +#define MCFSIM_CSMR1 0x90 /* CS 1 Mask reg (r/w) */ +#define MCFSIM_CSCR1 0x96 /* CS 1 Control reg (r/w) */ + +#ifdef CONFIG_OLDMASK +#define MCFSIM_CSBAR 0x98 /* CS Base Address reg (r/w) */ +#define MCFSIM_CSBAMR 0x9c /* CS Base Mask reg (r/w) */ +#define MCFSIM_CSMR2 0x9e /* CS 2 Mask reg (r/w) */ +#define MCFSIM_CSCR2 0xa2 /* CS 2 Control reg (r/w) */ +#define MCFSIM_CSMR3 0xaa /* CS 3 Mask reg (r/w) */ +#define MCFSIM_CSCR3 0xae /* CS 3 Control reg (r/w) */ +#define MCFSIM_CSMR4 0xb6 /* CS 4 Mask reg (r/w) */ +#define MCFSIM_CSCR4 0xba /* CS 4 Control reg (r/w) */ +#define MCFSIM_CSMR5 0xc2 /* CS 5 Mask reg (r/w) */ +#define MCFSIM_CSCR5 0xc6 /* CS 5 Control reg (r/w) */ +#define MCFSIM_CSMR6 0xce /* CS 6 Mask reg (r/w) */ +#define MCFSIM_CSCR6 0xd2 /* CS 6 Control reg (r/w) */ +#define MCFSIM_CSMR7 0xda /* CS 7 Mask reg (r/w) */ +#define MCFSIM_CSCR7 0xde /* CS 7 Control reg (r/w) */ +#else +#define MCFSIM_CSAR2 0x98 /* CS 2 Adress reg (r/w) */ +#define MCFSIM_CSMR2 0x9c /* CS 2 Mask reg (r/w) */ +#define MCFSIM_CSCR2 0xa2 /* CS 2 Control reg (r/w) */ +#define MCFSIM_CSAR3 0xa4 /* CS 3 Adress reg (r/w) */ +#define MCFSIM_CSMR3 0xa8 /* CS 3 Mask reg (r/w) */ +#define MCFSIM_CSCR3 0xae /* CS 3 Control reg (r/w) */ +#define MCFSIM_CSAR4 0xb0 /* CS 4 Adress reg (r/w) */ +#define MCFSIM_CSMR4 0xb4 /* CS 4 Mask reg (r/w) */ +#define MCFSIM_CSCR4 0xba /* CS 4 Control reg (r/w) */ +#define MCFSIM_CSAR5 0xbc /* CS 5 Adress reg (r/w) */ +#define MCFSIM_CSMR5 0xc0 /* CS 5 Mask reg (r/w) */ +#define MCFSIM_CSCR5 0xc6 /* CS 5 Control reg (r/w) */ +#define MCFSIM_CSAR6 0xc8 /* CS 6 Adress reg (r/w) */ +#define MCFSIM_CSMR6 0xcc /* CS 6 Mask reg (r/w) */ +#define MCFSIM_CSCR6 0xd2 /* CS 6 Control reg (r/w) */ +#define MCFSIM_CSAR7 0xd4 /* CS 7 Adress reg (r/w) */ +#define MCFSIM_CSMR7 0xd8 /* CS 7 Mask reg (r/w) */ +#define MCFSIM_CSCR7 0xde /* CS 7 Control reg (r/w) */ +#endif /* CONFIG_OLDMASK */ + +#define MCFSIM_DCR 0x100 /* DRAM Control reg (r/w) */ +#define MCFSIM_DACR0 0x108 /* DRAM 0 Addr and Ctrl (r/w) */ +#define MCFSIM_DMR0 0x10c /* DRAM 0 Mask reg (r/w) */ +#define MCFSIM_DACR1 0x110 /* DRAM 1 Addr and Ctrl (r/w) */ +#define MCFSIM_DMR1 0x114 /* DRAM 1 Mask reg (r/w) */ + +#define MCFSIM_PADDR 0x244 /* Parallel Direction (r/w) */ +#define MCFSIM_PADAT 0x248 /* Parallel Data (r/w) */ + + +/* Definition offset address for CS2-7 -- old mask 5307 */ + +#define MCF5307_CS2 (0x400000) +#define MCF5307_CS3 (0x600000) +#define MCF5307_CS4 (0x800000) +#define MCF5307_CS5 (0xA00000) +#define MCF5307_CS6 (0xC00000) +#define MCF5307_CS7 (0xE00000) + + +/* + * Some symbol defines for the above... + */ +#define MCFSIM_SWDICR MCFSIM_ICR0 /* Watchdog timer ICR */ +#define MCFSIM_TIMER1ICR MCFSIM_ICR1 /* Timer 1 ICR */ +#define MCFSIM_TIMER2ICR MCFSIM_ICR2 /* Timer 2 ICR */ +#define MCFSIM_UART1ICR MCFSIM_ICR4 /* UART 1 ICR */ +#define MCFSIM_UART2ICR MCFSIM_ICR5 /* UART 2 ICR */ +#define MCFSIM_DMA0ICR MCFSIM_ICR6 /* DMA 0 ICR */ +#define MCFSIM_DMA1ICR MCFSIM_ICR7 /* DMA 1 ICR */ +#define MCFSIM_DMA2ICR MCFSIM_ICR8 /* DMA 2 ICR */ +#define MCFSIM_DMA3ICR MCFSIM_ICR9 /* DMA 3 ICR */ + +#if defined(CONFIG_M5307) +#define MCFSIM_IMR_MASKALL 0x3fffe /* All SIM intr sources */ +#endif + +/* + * Macro to set IMR register. It is 32 bits on the 5307. + */ +#define mcf_getimr() \ + *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR)) + +#define mcf_setimr(imr) \ + *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR)) = (imr); + +#define mcf_getipr() \ + *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IPR)) + + +/* + * Some symbol defines for the Parallel Port Pin Assignment Register + */ +#define MCFSIM_PAR_DREQ0 0x40 /* Set to select DREQ0 input */ + /* Clear to select par I/O */ +#define MCFSIM_PAR_DREQ1 0x20 /* Select DREQ1 input */ + /* Clear to select par I/O */ + +/* + * Defines for the IRQPAR Register + */ +#define IRQ5_LEVEL4 0x80 +#define IRQ3_LEVEL6 0x40 +#define IRQ1_LEVEL2 0x20 + + +/* + * Define the Cache register flags. + */ +#define CACR_EC (1<<31) +#define CACR_ESB (1<<29) +#define CACR_DPI (1<<28) +#define CACR_HLCK (1<<27) +#define CACR_CINVA (1<<24) +#define CACR_DNFB (1<<10) +#define CACR_DCM_WTHRU (0<<8) +#define CACR_DCM_WBACK (1<<8) +#define CACR_DCM_OFF_PRE (2<<8) +#define CACR_DCM_OFF_IMP (3<<8) +#define CACR_DW (1<<5) + +#define ACR_BASE_POS 24 +#define ACR_MASK_POS 16 +#define ACR_ENABLE (1<<15) +#define ACR_USER (0<<13) +#define ACR_SUPER (1<<13) +#define ACR_ANY (2<<13) +#define ACR_CM_WTHRU (0<<5) +#define ACR_CM_WBACK (1<<5) +#define ACR_CM_OFF_PRE (2<<5) +#define ACR_CM_OFF_IMP (3<<5) +#define ACR_WPROTECT (1<<2) + +/****************************************************************************/ +#endif /* m5307sim_h */ diff -Nru a/include/asm-m68knommu/m5407sim.h b/include/asm-m68knommu/m5407sim.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/m5407sim.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,157 @@ +/****************************************************************************/ + +/* + * m5407sim.h -- ColdFire 5407 System Integration Module support. + * + * (C) Copyright 2000, Lineo (www.lineo.com) + * (C) Copyright 1999, Moreton Bay Ventures Pty Ltd. + * + * Modified by David W. Miller for the MCF5307 Eval Board. + */ + +/****************************************************************************/ +#ifndef m5407sim_h +#define m5407sim_h +/****************************************************************************/ + +/* + * Define the 5407 SIM register set addresses. + */ +#define MCFSIM_RSR 0x00 /* Reset Status reg (r/w) */ +#define MCFSIM_SYPCR 0x01 /* System Protection reg (r/w)*/ +#define MCFSIM_SWIVR 0x02 /* SW Watchdog intr reg (r/w) */ +#define MCFSIM_SWSR 0x03 /* SW Watchdog service (r/w) */ +#define MCFSIM_PAR 0x04 /* Pin Assignment reg (r/w) */ +#define MCFSIM_IRQPAR 0x06 /* Interrupt Assignment reg (r/w) */ +#define MCFSIM_PLLCR 0x08 /* PLL Controll Reg*/ +#define MCFSIM_MPARK 0x0C /* BUS Master Control Reg*/ +#define MCFSIM_IPR 0x40 /* Interrupt Pend reg (r/w) */ +#define MCFSIM_IMR 0x44 /* Interrupt Mask reg (r/w) */ +#define MCFSIM_AVR 0x4b /* Autovector Ctrl reg (r/w) */ +#define MCFSIM_ICR0 0x4c /* Intr Ctrl reg 0 (r/w) */ +#define MCFSIM_ICR1 0x4d /* Intr Ctrl reg 1 (r/w) */ +#define MCFSIM_ICR2 0x4e /* Intr Ctrl reg 2 (r/w) */ +#define MCFSIM_ICR3 0x4f /* Intr Ctrl reg 3 (r/w) */ +#define MCFSIM_ICR4 0x50 /* Intr Ctrl reg 4 (r/w) */ +#define MCFSIM_ICR5 0x51 /* Intr Ctrl reg 5 (r/w) */ +#define MCFSIM_ICR6 0x52 /* Intr Ctrl reg 6 (r/w) */ +#define MCFSIM_ICR7 0x53 /* Intr Ctrl reg 7 (r/w) */ +#define MCFSIM_ICR8 0x54 /* Intr Ctrl reg 8 (r/w) */ +#define MCFSIM_ICR9 0x55 /* Intr Ctrl reg 9 (r/w) */ +#define MCFSIM_ICR10 0x56 /* Intr Ctrl reg 10 (r/w) */ +#define MCFSIM_ICR11 0x57 /* Intr Ctrl reg 11 (r/w) */ + +#define MCFSIM_CSAR0 0x80 /* CS 0 Address 0 reg (r/w) */ +#define MCFSIM_CSMR0 0x84 /* CS 0 Mask 0 reg (r/w) */ +#define MCFSIM_CSCR0 0x8a /* CS 0 Control reg (r/w) */ +#define MCFSIM_CSAR1 0x8c /* CS 1 Address reg (r/w) */ +#define MCFSIM_CSMR1 0x90 /* CS 1 Mask reg (r/w) */ +#define MCFSIM_CSCR1 0x96 /* CS 1 Control reg (r/w) */ + +#define MCFSIM_CSAR2 0x98 /* CS 2 Adress reg (r/w) */ +#define MCFSIM_CSMR2 0x9c /* CS 2 Mask reg (r/w) */ +#define MCFSIM_CSCR2 0xa2 /* CS 2 Control reg (r/w) */ +#define MCFSIM_CSAR3 0xa4 /* CS 3 Adress reg (r/w) */ +#define MCFSIM_CSMR3 0xa8 /* CS 3 Mask reg (r/w) */ +#define MCFSIM_CSCR3 0xae /* CS 3 Control reg (r/w) */ +#define MCFSIM_CSAR4 0xb0 /* CS 4 Adress reg (r/w) */ +#define MCFSIM_CSMR4 0xb4 /* CS 4 Mask reg (r/w) */ +#define MCFSIM_CSCR4 0xba /* CS 4 Control reg (r/w) */ +#define MCFSIM_CSAR5 0xbc /* CS 5 Adress reg (r/w) */ +#define MCFSIM_CSMR5 0xc0 /* CS 5 Mask reg (r/w) */ +#define MCFSIM_CSCR5 0xc6 /* CS 5 Control reg (r/w) */ +#define MCFSIM_CSAR6 0xc8 /* CS 6 Adress reg (r/w) */ +#define MCFSIM_CSMR6 0xcc /* CS 6 Mask reg (r/w) */ +#define MCFSIM_CSCR6 0xd2 /* CS 6 Control reg (r/w) */ +#define MCFSIM_CSAR7 0xd4 /* CS 7 Adress reg (r/w) */ +#define MCFSIM_CSMR7 0xd8 /* CS 7 Mask reg (r/w) */ +#define MCFSIM_CSCR7 0xde /* CS 7 Control reg (r/w) */ + +#define MCFSIM_DCR 0x100 /* DRAM Control reg (r/w) */ +#define MCFSIM_DACR0 0x108 /* DRAM 0 Addr and Ctrl (r/w) */ +#define MCFSIM_DMR0 0x10c /* DRAM 0 Mask reg (r/w) */ +#define MCFSIM_DACR1 0x110 /* DRAM 1 Addr and Ctrl (r/w) */ +#define MCFSIM_DMR1 0x114 /* DRAM 1 Mask reg (r/w) */ + +#define MCFSIM_PADDR 0x244 /* Parallel Direction (r/w) */ +#define MCFSIM_PADAT 0x248 /* Parallel Data (r/w) */ + + +/* + * Some symbol defines for the above... + */ +#define MCFSIM_SWDICR MCFSIM_ICR0 /* Watchdog timer ICR */ +#define MCFSIM_TIMER1ICR MCFSIM_ICR1 /* Timer 1 ICR */ +#define MCFSIM_TIMER2ICR MCFSIM_ICR2 /* Timer 2 ICR */ +#define MCFSIM_UART1ICR MCFSIM_ICR4 /* UART 1 ICR */ +#define MCFSIM_UART2ICR MCFSIM_ICR5 /* UART 2 ICR */ +#define MCFSIM_DMA0ICR MCFSIM_ICR6 /* DMA 0 ICR */ +#define MCFSIM_DMA1ICR MCFSIM_ICR7 /* DMA 1 ICR */ +#define MCFSIM_DMA2ICR MCFSIM_ICR8 /* DMA 2 ICR */ +#define MCFSIM_DMA3ICR MCFSIM_ICR9 /* DMA 3 ICR */ + +/* + * Macro to set IMR register. It is 32 bits on the 5407. + */ +#define mcf_getimr() \ + *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR)) + +#define mcf_setimr(imr) \ + *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IMR)) = (imr); + +#define mcf_getipr() \ + *((volatile unsigned long *) (MCF_MBAR + MCFSIM_IPR)) + + +/* + * Some symbol defines for the Parallel Port Pin Assignment Register + */ +#define MCFSIM_PAR_DREQ0 0x40 /* Set to select DREQ0 input */ + /* Clear to select par I/O */ +#define MCFSIM_PAR_DREQ1 0x20 /* Select DREQ1 input */ + /* Clear to select par I/O */ + +/* + * Defines for the IRQPAR Register + */ +#define IRQ5_LEVEL4 0x80 +#define IRQ3_LEVEL6 0x40 +#define IRQ1_LEVEL2 0x20 + + +/* + * Define the Cache register flags. + */ +#define CACR_DEC 0x80000000 /* Enable data cache */ +#define CACR_DWP 0x40000000 /* Data write protection */ +#define CACR_DESB 0x20000000 /* Enable data store buffer */ +#define CACR_DDPI 0x10000000 /* Disable CPUSHL */ +#define CACR_DHCLK 0x08000000 /* Half data cache lock mode */ +#define CACR_DDCM_WT 0x00000000 /* Write through cache*/ +#define CACR_DDCM_CP 0x02000000 /* Copyback cache */ +#define CACR_DDCM_P 0x04000000 /* No cache, precise */ +#define CACR_DDCM_IMP 0x06000000 /* No cache, imprecise */ +#define CACR_DCINVA 0x01000000 /* Invalidate data cache */ +#define CACR_BEC 0x00080000 /* Enable branch cache */ +#define CACR_BCINVA 0x00040000 /* Invalidate branch cache */ +#define CACR_IEC 0x00008000 /* Enable instruction cache */ +#define CACR_DNFB 0x00002000 /* Inhibited fill buffer */ +#define CACR_IDPI 0x00001000 /* Disable CPUSHL */ +#define CACR_IHLCK 0x00000800 /* Intruction cache half lock */ +#define CACR_IDCM 0x00000400 /* Intruction cache inhibit */ +#define CACR_ICINVA 0x00000100 /* Invalidate instr cache */ + +#define ACR_BASE_POS 24 /* Address Base */ +#define ACR_MASK_POS 16 /* Address Mask */ +#define ACR_ENABLE 0x00008000 /* Enable address */ +#define ACR_USER 0x00000000 /* User mode access only */ +#define ACR_SUPER 0x00002000 /* Supervisor mode only */ +#define ACR_ANY 0x00004000 /* Match any access mode */ +#define ACR_CM_WT 0x00000000 /* Write through mode */ +#define ACR_CM_CP 0x00000020 /* Copyback mode */ +#define ACR_CM_OFF_PRE 0x00000040 /* No cache, precise */ +#define ACR_CM_OFF_IMP 0x00000060 /* No cache, imprecise */ +#define ACR_WPROTECT 0x00000004 /* Write protect */ + +/****************************************************************************/ +#endif /* m5407sim_h */ diff -Nru a/include/asm-m68knommu/m68360.h b/include/asm-m68knommu/m68360.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/m68360.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,5 @@ +#include "m68360_regs.h" +#include "m68360_pram.h" +#include "m68360_quicc.h" +#include "m68360_enet.h" + diff -Nru a/include/asm-m68knommu/m68360_enet.h b/include/asm-m68knommu/m68360_enet.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/m68360_enet.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,177 @@ +/*********************************** + * $Id: m68360_enet.h,v 1.1 2002/03/02 15:01:07 gerg Exp $ + *********************************** + * + *************************************** + * Definitions for the ETHERNET controllers + *************************************** + */ + +#ifndef __ETHER_H +#define __ETHER_H + +#include "quicc_simple.h" + +/* + * transmit BD's + */ +#define T_R 0x8000 /* ready bit */ +#define E_T_PAD 0x4000 /* short frame padding */ +#define T_W 0x2000 /* wrap bit */ +#define T_I 0x1000 /* interrupt on completion */ +#define T_L 0x0800 /* last in frame */ +#define T_TC 0x0400 /* transmit CRC (when last) */ + +#define T_DEF 0x0200 /* defer indication */ +#define T_HB 0x0100 /* heartbeat */ +#define T_LC 0x0080 /* error: late collision */ +#define T_RL 0x0040 /* error: retransmission limit */ +#define T_RC 0x003c /* retry count */ +#define T_UN 0x0002 /* error: underrun */ +#define T_CSL 0x0001 /* carier sense lost */ +#define T_ERROR (T_HB | T_LC | T_RL | T_UN | T_CSL) + +/* + * receive BD's + */ +#define R_E 0x8000 /* buffer empty */ +#define R_W 0x2000 /* wrap bit */ +#define R_I 0x1000 /* interrupt on reception */ +#define R_L 0x0800 /* last BD in frame */ +#define R_F 0x0400 /* first BD in frame */ +#define R_M 0x0100 /* received because of promisc. mode */ + +#define R_LG 0x0020 /* frame too long */ +#define R_NO 0x0010 /* non-octet aligned */ +#define R_SH 0x0008 /* short frame */ +#define R_CR 0x0004 /* receive CRC error */ +#define R_OV 0x0002 /* receive overrun */ +#define R_CL 0x0001 /* collision */ +#define ETHER_R_ERROR (R_LG | R_NO | R_SH | R_CR | R_OV | R_CL) + + +/* + * ethernet interrupts + */ +#define ETHERNET_GRA 0x0080 /* graceful stop complete */ +#define ETHERNET_TXE 0x0010 /* transmit error */ +#define ETHERNET_RXF 0x0008 /* receive frame */ +#define ETHERNET_BSY 0x0004 /* busy condition */ +#define ETHERNET_TXB 0x0002 /* transmit buffer */ +#define ETHERNET_RXB 0x0001 /* receive buffer */ + +/* + * ethernet protocol specific mode register (PSMR) + */ +#define ETHER_HBC 0x8000 /* heartbeat checking */ +#define ETHER_FC 0x4000 /* force collision */ +#define ETHER_RSH 0x2000 /* receive short frames */ +#define ETHER_IAM 0x1000 /* individual address mode */ +#define ETHER_CRC_32 (0x2<<10) /* Enable CRC */ +#define ETHER_PRO 0x0200 /* promiscuous */ +#define ETHER_BRO 0x0100 /* broadcast address */ +#define ETHER_SBT 0x0080 /* stop backoff timer */ +#define ETHER_LPB 0x0040 /* Loop Back Mode */ +#define ETHER_SIP 0x0020 /* sample input pins */ +#define ETHER_LCW 0x0010 /* late collision window */ +#define ETHER_NIB_13 (0x0<<1) /* # of ignored bits 13 */ +#define ETHER_NIB_14 (0x1<<1) /* # of ignored bits 14 */ +#define ETHER_NIB_15 (0x2<<1) /* # of ignored bits 15 */ +#define ETHER_NIB_16 (0x3<<1) /* # of ignored bits 16 */ +#define ETHER_NIB_21 (0x4<<1) /* # of ignored bits 21 */ +#define ETHER_NIB_22 (0x5<<1) /* # of ignored bits 22 */ +#define ETHER_NIB_23 (0x6<<1) /* # of ignored bits 23 */ +#define ETHER_NIB_24 (0x7<<1) /* # of ignored bits 24 */ + +/* + * ethernet specific parameters + */ +#define CRC_WORD 4 /* Length in bytes of CRC */ +#define C_PRES 0xffffffff /* preform 32 bit CRC */ +#define C_MASK 0xdebb20e3 /* comply with 32 bit CRC */ +#define CRCEC 0x00000000 +#define ALEC 0x00000000 +#define DISFC 0x00000000 +#define PADS 0x00000000 +#define RET_LIM 0x000f /* retry 15 times to send a frame before interupt */ +#define ETH_MFLR 0x05ee /* 1518 max frame size */ +#define MINFLR 0x0040 /* Minimum frame size 64 */ +#define MAXD1 0x05ee /* Max dma count 1518 */ +#define MAXD2 0x05ee +#define GADDR1 0x00000000 /* Clear group address */ +#define GADDR2 0x00000000 +#define GADDR3 0x00000000 +#define GADDR4 0x00000000 +#define P_PER 0x00000000 /*not used */ +#define IADDR1 0x00000000 /* Individual hash table not used */ +#define IADDR2 0x00000000 +#define IADDR3 0x00000000 +#define IADDR4 0x00000000 +#define TADDR_H 0x00000000 /* clear this regs */ +#define TADDR_M 0x00000000 +#define TADDR_L 0x00000000 + +/* SCC Parameter Ram */ +#define RFCR 0x18 /* normal operation */ +#define TFCR 0x18 /* normal operation */ +#define E_MRBLR 1518 /* Max ethernet frame length */ + +/* + * ethernet specific structure + */ +typedef union { + unsigned char b[6]; + struct { + unsigned short high; + unsigned short middl; + unsigned short low; + } w; +} ETHER_ADDR; + +typedef struct { + int max_frame_length; + int promisc_mode; + int reject_broadcast; + ETHER_ADDR phys_adr; +} ETHER_SPECIFIC; + +typedef struct { + ETHER_ADDR dst_addr; + ETHER_ADDR src_addr; + unsigned short type_or_len; + unsigned char data[1]; +} ETHER_FRAME; + +#define MAX_DATALEN 1500 +typedef struct { + ETHER_ADDR dst_addr; + ETHER_ADDR src_addr; + unsigned short type_or_len; + unsigned char data[MAX_DATALEN]; + unsigned char fcs[CRC_WORD]; +} ETHER_MAX_FRAME; + + +/* + * Internal ethernet function prototypes + */ +void ether_interrupt(int scc_num); +/* mleslie: debug */ +/* static void ethernet_rx_internal(int scc_num); */ +/* static void ethernet_tx_internal(int scc_num); */ + +/* + * User callable routines prototypes (ethernet specific) + */ +void ethernet_init(int scc_number, + alloc_routine *alloc_buffer, + free_routine *free_buffer, + store_rx_buffer_routine *store_rx_buffer, + handle_tx_error_routine *handle_tx_error, + handle_rx_error_routine *handle_rx_error, + handle_lost_error_routine *handle_lost_error, + ETHER_SPECIFIC *ether_spec); +int ethernet_tx(int scc_number, void *buf, int length); + +#endif + diff -Nru a/include/asm-m68knommu/m68360_pram.h b/include/asm-m68knommu/m68360_pram.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/m68360_pram.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,431 @@ +/*********************************** + * $Id: m68360_pram.h,v 1.1 2002/03/02 15:01:07 gerg Exp $ + *********************************** + * + *************************************** + * Definitions of the parameter area RAM. + * Note that different structures are overlaid + * at the same offsets for the different modes + * of operation. + *************************************** + */ + +#ifndef __PRAM_H +#define __PRAM_H + +/* Time slot assignment table */ +#define VALID_SLOT 0x8000 +#define WRAP_SLOT 0x4000 + +/***************************************************************** + Global Multichannel parameter RAM +*****************************************************************/ +struct global_multi_pram { + /* + * Global Multichannel parameter RAM + */ + unsigned long mcbase; /* Multichannel Base pointer */ + unsigned short qmcstate; /* Multichannel Controller state */ + unsigned short mrblr; /* Maximum Receive Buffer Length */ + unsigned short tx_s_ptr; /* TSTATx Pointer */ + unsigned short rxptr; /* Current Time slot entry in TSATRx */ + unsigned short grfthr; /* Global Receive frame threshold */ + unsigned short grfcnt; /* Global Receive Frame Count */ + unsigned long intbase; /* Multichannel Base address */ + unsigned long iintptr; /* Pointer to interrupt queue */ + unsigned short rx_s_ptr; /* TSTARx Pointer */ + + unsigned short txptr; /* Current Time slot entry in TSATTx */ + unsigned long c_mask32; /* CRC Constant (debb20e3) */ + unsigned short tsatrx[32]; /* Time Slot Assignment Table Rx */ + unsigned short tsattx[32]; /* Time Slot Assignment Table Tx */ + unsigned short c_mask16; /* CRC Constant (f0b8) */ +}; + +/***************************************************************** + Quicc32 HDLC parameter RAM +*****************************************************************/ +struct quicc32_pram { + + unsigned short tbase; /* Tx Buffer Descriptors Base Address */ + unsigned short chamr; /* Channel Mode Register */ + unsigned long tstate; /* Tx Internal State */ + unsigned long txintr; /* Tx Internal Data Pointer */ + unsigned short tbptr; /* Tx Buffer Descriptor Pointer */ + unsigned short txcntr; /* Tx Internal Byte Count */ + unsigned long tupack; /* (Tx Temp) */ + unsigned long zistate; /* Zero Insertion machine state */ + unsigned long tcrc; /* Temp Transmit CRC */ + unsigned short intmask; /* Channel's interrupt mask flags */ + unsigned short bdflags; + unsigned short rbase; /* Rx Buffer Descriptors Base Address */ + unsigned short mflr; /* Max Frame Length Register */ + unsigned long rstate; /* Rx Internal State */ + unsigned long rxintr; /* Rx Internal Data Pointer */ + unsigned short rbptr; /* Rx Buffer Descriptor Pointer */ + unsigned short rxbyc; /* Rx Internal Byte Count */ + unsigned long rpack; /* (Rx Temp) */ + unsigned long zdstate; /* Zero Deletion machine state */ + unsigned long rcrc; /* Temp Transmit CRC */ + unsigned short maxc; /* Max_length counter */ + unsigned short tmp_mb; /* Temp */ +}; + + +/***************************************************************** + HDLC parameter RAM +*****************************************************************/ + +struct hdlc_pram { + /* + * SCC parameter RAM + */ + unsigned short rbase; /* RX BD base address */ + unsigned short tbase; /* TX BD base address */ + unsigned char rfcr; /* Rx function code */ + unsigned char tfcr; /* Tx function code */ + unsigned short mrblr; /* Rx buffer length */ + unsigned long rstate; /* Rx internal state */ + unsigned long rptr; /* Rx internal data pointer */ + unsigned short rbptr; /* rb BD Pointer */ + unsigned short rcount; /* Rx internal byte count */ + unsigned long rtemp; /* Rx temp */ + unsigned long tstate; /* Tx internal state */ + unsigned long tptr; /* Tx internal data pointer */ + unsigned short tbptr; /* Tx BD pointer */ + unsigned short tcount; /* Tx byte count */ + unsigned long ttemp; /* Tx temp */ + unsigned long rcrc; /* temp receive CRC */ + unsigned long tcrc; /* temp transmit CRC */ + + /* + * HDLC specific parameter RAM + */ + unsigned char RESERVED1[4]; /* Reserved area */ + unsigned long c_mask; /* CRC constant */ + unsigned long c_pres; /* CRC preset */ + unsigned short disfc; /* discarded frame counter */ + unsigned short crcec; /* CRC error counter */ + unsigned short abtsc; /* abort sequence counter */ + unsigned short nmarc; /* nonmatching address rx cnt */ + unsigned short retrc; /* frame retransmission cnt */ + unsigned short mflr; /* maximum frame length reg */ + unsigned short max_cnt; /* maximum length counter */ + unsigned short rfthr; /* received frames threshold */ + unsigned short rfcnt; /* received frames count */ + unsigned short hmask; /* user defined frm addr mask */ + unsigned short haddr1; /* user defined frm address 1 */ + unsigned short haddr2; /* user defined frm address 2 */ + unsigned short haddr3; /* user defined frm address 3 */ + unsigned short haddr4; /* user defined frm address 4 */ + unsigned short tmp; /* temp */ + unsigned short tmp_mb; /* temp */ +}; + + + +/***************************************************************** + UART parameter RAM +*****************************************************************/ + +/* + * bits in uart control characters table + */ +#define CC_INVALID 0x8000 /* control character is valid */ +#define CC_REJ 0x4000 /* don't store char in buffer */ +#define CC_CHAR 0x00ff /* control character */ + +/* UART */ +struct uart_pram { + /* + * SCC parameter RAM + */ + unsigned short rbase; /* RX BD base address */ + unsigned short tbase; /* TX BD base address */ + unsigned char rfcr; /* Rx function code */ + unsigned char tfcr; /* Tx function code */ + unsigned short mrblr; /* Rx buffer length */ + unsigned long rstate; /* Rx internal state */ + unsigned long rptr; /* Rx internal data pointer */ + unsigned short rbptr; /* rb BD Pointer */ + unsigned short rcount; /* Rx internal byte count */ + unsigned long rx_temp; /* Rx temp */ + unsigned long tstate; /* Tx internal state */ + unsigned long tptr; /* Tx internal data pointer */ + unsigned short tbptr; /* Tx BD pointer */ + unsigned short tcount; /* Tx byte count */ + unsigned long ttemp; /* Tx temp */ + unsigned long rcrc; /* temp receive CRC */ + unsigned long tcrc; /* temp transmit CRC */ + + /* + * UART specific parameter RAM + */ + unsigned char RESERVED1[8]; /* Reserved area */ + unsigned short max_idl; /* maximum idle characters */ + unsigned short idlc; /* rx idle counter (internal) */ + unsigned short brkcr; /* break count register */ + + unsigned short parec; /* Rx parity error counter */ + unsigned short frmer; /* Rx framing error counter */ + unsigned short nosec; /* Rx noise counter */ + unsigned short brkec; /* Rx break character counter */ + unsigned short brkln; /* Reaceive break length */ + + unsigned short uaddr1; /* address character 1 */ + unsigned short uaddr2; /* address character 2 */ + unsigned short rtemp; /* temp storage */ + unsigned short toseq; /* Tx out of sequence char */ + unsigned short cc[8]; /* Rx control characters */ + unsigned short rccm; /* Rx control char mask */ + unsigned short rccr; /* Rx control char register */ + unsigned short rlbc; /* Receive last break char */ +}; + + + +/***************************************************************** + BISYNC parameter RAM +*****************************************************************/ + +struct bisync_pram { + /* + * SCC parameter RAM + */ + unsigned short rbase; /* RX BD base address */ + unsigned short tbase; /* TX BD base address */ + unsigned char rfcr; /* Rx function code */ + unsigned char tfcr; /* Tx function code */ + unsigned short mrblr; /* Rx buffer length */ + unsigned long rstate; /* Rx internal state */ + unsigned long rptr; /* Rx internal data pointer */ + unsigned short rbptr; /* rb BD Pointer */ + unsigned short rcount; /* Rx internal byte count */ + unsigned long rtemp; /* Rx temp */ + unsigned long tstate; /* Tx internal state */ + unsigned long tptr; /* Tx internal data pointer */ + unsigned short tbptr; /* Tx BD pointer */ + unsigned short tcount; /* Tx byte count */ + unsigned long ttemp; /* Tx temp */ + unsigned long rcrc; /* temp receive CRC */ + unsigned long tcrc; /* temp transmit CRC */ + + /* + * BISYNC specific parameter RAM + */ + unsigned char RESERVED1[4]; /* Reserved area */ + unsigned long crcc; /* CRC Constant Temp Value */ + unsigned short prcrc; /* Preset Receiver CRC-16/LRC */ + unsigned short ptcrc; /* Preset Transmitter CRC-16/LRC */ + unsigned short parec; /* Receive Parity Error Counter */ + unsigned short bsync; /* BISYNC SYNC Character */ + unsigned short bdle; /* BISYNC DLE Character */ + unsigned short cc[8]; /* Rx control characters */ + unsigned short rccm; /* Receive Control Character Mask */ +}; + +/***************************************************************** + IOM2 parameter RAM + (overlaid on tx bd[5] of SCC channel[2]) +*****************************************************************/ +struct iom2_pram { + unsigned short ci_data; /* ci data */ + unsigned short monitor_data; /* monitor data */ + unsigned short tstate; /* transmitter state */ + unsigned short rstate; /* receiver state */ +}; + +/***************************************************************** + SPI/SMC parameter RAM + (overlaid on tx bd[6,7] of SCC channel[2]) +*****************************************************************/ + +#define SPI_R 0x8000 /* Ready bit in BD */ + +struct spi_pram { + unsigned short rbase; /* Rx BD Base Address */ + unsigned short tbase; /* Tx BD Base Address */ + unsigned char rfcr; /* Rx function code */ + unsigned char tfcr; /* Tx function code */ + unsigned short mrblr; /* Rx buffer length */ + unsigned long rstate; /* Rx internal state */ + unsigned long rptr; /* Rx internal data pointer */ + unsigned short rbptr; /* rb BD Pointer */ + unsigned short rcount; /* Rx internal byte count */ + unsigned long rtemp; /* Rx temp */ + unsigned long tstate; /* Tx internal state */ + unsigned long tptr; /* Tx internal data pointer */ + unsigned short tbptr; /* Tx BD pointer */ + unsigned short tcount; /* Tx byte count */ + unsigned long ttemp; /* Tx temp */ +}; + +struct smc_uart_pram { + unsigned short rbase; /* Rx BD Base Address */ + unsigned short tbase; /* Tx BD Base Address */ + unsigned char rfcr; /* Rx function code */ + unsigned char tfcr; /* Tx function code */ + unsigned short mrblr; /* Rx buffer length */ + unsigned long rstate; /* Rx internal state */ + unsigned long rptr; /* Rx internal data pointer */ + unsigned short rbptr; /* rb BD Pointer */ + unsigned short rcount; /* Rx internal byte count */ + unsigned long rtemp; /* Rx temp */ + unsigned long tstate; /* Tx internal state */ + unsigned long tptr; /* Tx internal data pointer */ + unsigned short tbptr; /* Tx BD pointer */ + unsigned short tcount; /* Tx byte count */ + unsigned long ttemp; /* Tx temp */ + unsigned short max_idl; /* Maximum IDLE Characters */ + unsigned short idlc; /* Temporary IDLE Counter */ + unsigned short brkln; /* Last Rx Break Length */ + unsigned short brkec; /* Rx Break Condition Counter */ + unsigned short brkcr; /* Break Count Register (Tx) */ + unsigned short r_mask; /* Temporary bit mask */ +}; + +struct smc_trnsp_pram { + unsigned short rbase; /* rx BD Base Address */ + unsigned short tbase; /* Tx BD Base Address */ + unsigned char rfcr; /* Rx function code */ + unsigned char tfcr; /* Tx function code */ + unsigned short mrblr; /* Rx buffer length */ + unsigned long rstate; /* Rx internal state */ + unsigned long rptr; /* Rx internal data pointer */ + unsigned short rbptr; /* rb BD Pointer */ + unsigned short rcount; /* Rx internal byte count */ + unsigned long rtemp; /* Rx temp */ + unsigned long tstate; /* Tx internal state */ + unsigned long tptr; /* Tx internal data pointer */ + unsigned short tbptr; /* Tx BD pointer */ + unsigned short tcount; /* Tx byte count */ + unsigned long ttemp; /* Tx temp */ + unsigned short reserved[5]; /* Reserved */ +}; + +struct idma_pram { + unsigned short ibase; /* IDMA BD Base Address */ + unsigned short ibptr; /* IDMA buffer descriptor pointer */ + unsigned long istate; /* IDMA internal state */ + unsigned long itemp; /* IDMA temp */ +}; + +struct ethernet_pram { + /* + * SCC parameter RAM + */ + unsigned short rbase; /* RX BD base address */ + unsigned short tbase; /* TX BD base address */ + unsigned char rfcr; /* Rx function code */ + unsigned char tfcr; /* Tx function code */ + unsigned short mrblr; /* Rx buffer length */ + unsigned long rstate; /* Rx internal state */ + unsigned long rptr; /* Rx internal data pointer */ + unsigned short rbptr; /* rb BD Pointer */ + unsigned short rcount; /* Rx internal byte count */ + unsigned long rtemp; /* Rx temp */ + unsigned long tstate; /* Tx internal state */ + unsigned long tptr; /* Tx internal data pointer */ + unsigned short tbptr; /* Tx BD pointer */ + unsigned short tcount; /* Tx byte count */ + unsigned long ttemp; /* Tx temp */ + unsigned long rcrc; /* temp receive CRC */ + unsigned long tcrc; /* temp transmit CRC */ + + /* + * ETHERNET specific parameter RAM + */ + unsigned long c_pres; /* preset CRC */ + unsigned long c_mask; /* constant mask for CRC */ + unsigned long crcec; /* CRC error counter */ + unsigned long alec; /* alighnment error counter */ + unsigned long disfc; /* discard frame counter */ + unsigned short pads; /* short frame PAD characters */ + unsigned short ret_lim; /* retry limit threshold */ + unsigned short ret_cnt; /* retry limit counter */ + unsigned short mflr; /* maximum frame length reg */ + unsigned short minflr; /* minimum frame length reg */ + unsigned short maxd1; /* maximum DMA1 length reg */ + unsigned short maxd2; /* maximum DMA2 length reg */ + unsigned short maxd; /* rx max DMA */ + unsigned short dma_cnt; /* rx dma counter */ + unsigned short max_b; /* max bd byte count */ + unsigned short gaddr1; /* group address filter 1 */ + unsigned short gaddr2; /* group address filter 2 */ + unsigned short gaddr3; /* group address filter 3 */ + unsigned short gaddr4; /* group address filter 4 */ + unsigned long tbuf0_data0; /* save area 0 - current frm */ + unsigned long tbuf0_data1; /* save area 1 - current frm */ + unsigned long tbuf0_rba0; + unsigned long tbuf0_crc; + unsigned short tbuf0_bcnt; + union { + unsigned char b[6]; + struct { + unsigned short high; + unsigned short middl; + unsigned short low; + } w; + } paddr; + unsigned short p_per; /* persistence */ + unsigned short rfbd_ptr; /* rx first bd pointer */ + unsigned short tfbd_ptr; /* tx first bd pointer */ + unsigned short tlbd_ptr; /* tx last bd pointer */ + unsigned long tbuf1_data0; /* save area 0 - next frame */ + unsigned long tbuf1_data1; /* save area 1 - next frame */ + unsigned long tbuf1_rba0; + unsigned long tbuf1_crc; + unsigned short tbuf1_bcnt; + unsigned short tx_len; /* tx frame length counter */ + unsigned short iaddr1; /* individual address filter 1*/ + unsigned short iaddr2; /* individual address filter 2*/ + unsigned short iaddr3; /* individual address filter 3*/ + unsigned short iaddr4; /* individual address filter 4*/ + unsigned short boff_cnt; /* back-off counter */ + unsigned short taddr_h; /* temp address (MSB) */ + unsigned short taddr_m; /* temp address */ + unsigned short taddr_l; /* temp address (LSB) */ +}; + +struct transparent_pram { + /* + * SCC parameter RAM + */ + unsigned short rbase; /* RX BD base address */ + unsigned short tbase; /* TX BD base address */ + unsigned char rfcr; /* Rx function code */ + unsigned char tfcr; /* Tx function code */ + unsigned short mrblr; /* Rx buffer length */ + unsigned long rstate; /* Rx internal state */ + unsigned long rptr; /* Rx internal data pointer */ + unsigned short rbptr; /* rb BD Pointer */ + unsigned short rcount; /* Rx internal byte count */ + unsigned long rtemp; /* Rx temp */ + unsigned long tstate; /* Tx internal state */ + unsigned long tptr; /* Tx internal data pointer */ + unsigned short tbptr; /* Tx BD pointer */ + unsigned short tcount; /* Tx byte count */ + unsigned long ttemp; /* Tx temp */ + unsigned long rcrc; /* temp receive CRC */ + unsigned long tcrc; /* temp transmit CRC */ + + /* + * TRANSPARENT specific parameter RAM + */ + unsigned long crc_p; /* CRC Preset */ + unsigned long crc_c; /* CRC constant */ +}; + +struct timer_pram { + /* + * RISC timers parameter RAM + */ + unsigned short tm_base; /* RISC timer table base adr */ + unsigned short tm_ptr; /* RISC timer table pointer */ + unsigned short r_tmr; /* RISC timer mode register */ + unsigned short r_tmv; /* RISC timer valid register */ + unsigned long tm_cmd; /* RISC timer cmd register */ + unsigned long tm_cnt; /* RISC timer internal cnt */ +}; + +#endif diff -Nru a/include/asm-m68knommu/m68360_quicc.h b/include/asm-m68knommu/m68360_quicc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/m68360_quicc.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,362 @@ +/*********************************** + * $Id: m68360_quicc.h,v 1.1 2002/03/02 15:01:07 gerg Exp $ + *********************************** + * + *************************************** + * Definitions of QUICC memory structures + *************************************** + */ + +#ifndef __M68360_QUICC_H +#define __M68360_QUICC_H + +/* + * include registers and + * parameter ram definitions files + */ +#include +#include + + + +/* Buffer Descriptors */ +typedef struct quicc_bd { + volatile unsigned short status; + volatile unsigned short length; + volatile unsigned char *buf; /* WARNING: This is only true if *char is 32 bits */ +} QUICC_BD; + + +#ifdef MOTOROLA_ORIGINAL +struct user_data { + /* BASE + 0x000: user data memory */ + volatile unsigned char udata_bd_ucode[0x400]; /*user data bd's Ucode*/ + volatile unsigned char udata_bd[0x200]; /*user data Ucode */ + volatile unsigned char ucode_ext[0x100]; /*Ucode Extention ram */ + volatile unsigned char RESERVED1[0x500]; /* Reserved area */ +}; +#else +struct user_data { + /* BASE + 0x000: user data memory */ + volatile unsigned char udata_bd_ucode[0x400]; /* user data, bds, Ucode*/ + volatile unsigned char udata_bd1[0x200]; /* user, bds */ + volatile unsigned char ucode_bd_scratch[0x100]; /* user, bds, ucode scratch */ + volatile unsigned char udata_bd2[0x100]; /* user, bds */ + volatile unsigned char RESERVED1[0x400]; /* Reserved area */ +}; +#endif + + +/* + * internal ram + */ +typedef struct quicc { + union { + struct quicc32_pram ch_pram_tbl[32]; /* 32*64(bytes) per channel */ + struct user_data u; + }ch_or_u; /* multipul or user space */ + + /* BASE + 0xc00: PARAMETER RAM */ + union { + struct scc_pram { + union { + struct hdlc_pram h; + struct uart_pram u; + struct bisync_pram b; + struct transparent_pram t; + unsigned char RESERVED66[0x70]; + } pscc; /* scc parameter area (protocol dependent) */ + union { + struct { + unsigned char RESERVED70[0x10]; + struct spi_pram spi; + unsigned char RESERVED72[0x8]; + struct timer_pram timer; + } timer_spi; + struct { + struct idma_pram idma; + unsigned char RESERVED67[0x4]; + union { + struct smc_uart_pram u; + struct smc_trnsp_pram t; + } psmc; + } idma_smc; + } pothers; + } scc; + struct ethernet_pram enet_scc; + struct global_multi_pram m; + unsigned char pr[0x100]; + } pram[4]; + + /* reserved */ + + /* BASE + 0x1000: INTERNAL REGISTERS */ + /* SIM */ + volatile unsigned long sim_mcr; /* module configuration reg */ + volatile unsigned short sim_simtr; /* module test register */ + volatile unsigned char RESERVED2[0x2]; /* Reserved area */ + volatile unsigned char sim_avr; /* auto vector reg */ + volatile unsigned char sim_rsr; /* reset status reg */ + volatile unsigned char RESERVED3[0x2]; /* Reserved area */ + volatile unsigned char sim_clkocr; /* CLCO control register */ + volatile unsigned char RESERVED62[0x3]; /* Reserved area */ + volatile unsigned short sim_pllcr; /* PLL control register */ + volatile unsigned char RESERVED63[0x2]; /* Reserved area */ + volatile unsigned short sim_cdvcr; /* Clock devider control register */ + volatile unsigned short sim_pepar; /* Port E pin assignment register */ + volatile unsigned char RESERVED64[0xa]; /* Reserved area */ + volatile unsigned char sim_sypcr; /* system protection control*/ + volatile unsigned char sim_swiv; /* software interrupt vector*/ + volatile unsigned char RESERVED6[0x2]; /* Reserved area */ + volatile unsigned short sim_picr; /* periodic interrupt control reg */ + volatile unsigned char RESERVED7[0x2]; /* Reserved area */ + volatile unsigned short sim_pitr; /* periodic interrupt timing reg */ + volatile unsigned char RESERVED8[0x3]; /* Reserved area */ + volatile unsigned char sim_swsr; /* software service */ + volatile unsigned long sim_bkar; /* breakpoint address register*/ + volatile unsigned long sim_bkcr; /* breakpoint control register*/ + volatile unsigned char RESERVED10[0x8]; /* Reserved area */ + /* MEMC */ + volatile unsigned long memc_gmr; /* Global memory register */ + volatile unsigned short memc_mstat; /* MEMC status register */ + volatile unsigned char RESERVED11[0xa]; /* Reserved area */ + volatile unsigned long memc_br0; /* base register 0 */ + volatile unsigned long memc_or0; /* option register 0 */ + volatile unsigned char RESERVED12[0x8]; /* Reserved area */ + volatile unsigned long memc_br1; /* base register 1 */ + volatile unsigned long memc_or1; /* option register 1 */ + volatile unsigned char RESERVED13[0x8]; /* Reserved area */ + volatile unsigned long memc_br2; /* base register 2 */ + volatile unsigned long memc_or2; /* option register 2 */ + volatile unsigned char RESERVED14[0x8]; /* Reserved area */ + volatile unsigned long memc_br3; /* base register 3 */ + volatile unsigned long memc_or3; /* option register 3 */ + volatile unsigned char RESERVED15[0x8]; /* Reserved area */ + volatile unsigned long memc_br4; /* base register 3 */ + volatile unsigned long memc_or4; /* option register 3 */ + volatile unsigned char RESERVED16[0x8]; /* Reserved area */ + volatile unsigned long memc_br5; /* base register 3 */ + volatile unsigned long memc_or5; /* option register 3 */ + volatile unsigned char RESERVED17[0x8]; /* Reserved area */ + volatile unsigned long memc_br6; /* base register 3 */ + volatile unsigned long memc_or6; /* option register 3 */ + volatile unsigned char RESERVED18[0x8]; /* Reserved area */ + volatile unsigned long memc_br7; /* base register 3 */ + volatile unsigned long memc_or7; /* option register 3 */ + volatile unsigned char RESERVED9[0x28]; /* Reserved area */ + /* TEST */ + volatile unsigned short test_tstmra; /* master shift a */ + volatile unsigned short test_tstmrb; /* master shift b */ + volatile unsigned short test_tstsc; /* shift count */ + volatile unsigned short test_tstrc; /* repetition counter */ + volatile unsigned short test_creg; /* control */ + volatile unsigned short test_dreg; /* destributed register */ + volatile unsigned char RESERVED58[0x404]; /* Reserved area */ + /* IDMA1 */ + volatile unsigned short idma_iccr; /* channel configuration reg*/ + volatile unsigned char RESERVED19[0x2]; /* Reserved area */ + volatile unsigned short idma1_cmr; /* dma mode reg */ + volatile unsigned char RESERVED68[0x2]; /* Reserved area */ + volatile unsigned long idma1_sapr; /* dma source addr ptr */ + volatile unsigned long idma1_dapr; /* dma destination addr ptr */ + volatile unsigned long idma1_bcr; /* dma byte count reg */ + volatile unsigned char idma1_fcr; /* function code reg */ + volatile unsigned char RESERVED20; /* Reserved area */ + volatile unsigned char idma1_cmar; /* channel mask reg */ + volatile unsigned char RESERVED21; /* Reserved area */ + volatile unsigned char idma1_csr; /* channel status reg */ + volatile unsigned char RESERVED22[0x3]; /* Reserved area */ + /* SDMA */ + volatile unsigned char sdma_sdsr; /* status reg */ + volatile unsigned char RESERVED23; /* Reserved area */ + volatile unsigned short sdma_sdcr; /* configuration reg */ + volatile unsigned long sdma_sdar; /* address reg */ + /* IDMA2 */ + volatile unsigned char RESERVED69[0x2]; /* Reserved area */ + volatile unsigned short idma2_cmr; /* dma mode reg */ + volatile unsigned long idma2_sapr; /* dma source addr ptr */ + volatile unsigned long idma2_dapr; /* dma destination addr ptr */ + volatile unsigned long idma2_bcr; /* dma byte count reg */ + volatile unsigned char idma2_fcr; /* function code reg */ + volatile unsigned char RESERVED24; /* Reserved area */ + volatile unsigned char idma2_cmar; /* channel mask reg */ + volatile unsigned char RESERVED25; /* Reserved area */ + volatile unsigned char idma2_csr; /* channel status reg */ + volatile unsigned char RESERVED26[0x7]; /* Reserved area */ + /* Interrupt Controller */ + volatile unsigned long intr_cicr; /* CP interrupt configuration reg*/ + volatile unsigned long intr_cipr; /* CP interrupt pending reg */ + volatile unsigned long intr_cimr; /* CP interrupt mask reg */ + volatile unsigned long intr_cisr; /* CP interrupt in service reg*/ + /* Parallel I/O */ + volatile unsigned short pio_padir; /* port A data direction reg */ + volatile unsigned short pio_papar; /* port A pin assignment reg */ + volatile unsigned short pio_paodr; /* port A open drain reg */ + volatile unsigned short pio_padat; /* port A data register */ + volatile unsigned char RESERVED28[0x8]; /* Reserved area */ + volatile unsigned short pio_pcdir; /* port C data direction reg*/ + volatile unsigned short pio_pcpar; /* port C pin assignment reg*/ + volatile unsigned short pio_pcso; /* port C special options */ + volatile unsigned short pio_pcdat; /* port C data register */ + volatile unsigned short pio_pcint; /* port C interrupt cntrl reg */ + volatile unsigned char RESERVED29[0x16]; /* Reserved area */ + /* Timer */ + volatile unsigned short timer_tgcr; /* timer global configuration reg */ + volatile unsigned char RESERVED30[0xe]; /* Reserved area */ + volatile unsigned short timer_tmr1; /* timer 1 mode reg */ + volatile unsigned short timer_tmr2; /* timer 2 mode reg */ + volatile unsigned short timer_trr1; /* timer 1 referance reg */ + volatile unsigned short timer_trr2; /* timer 2 referance reg */ + volatile unsigned short timer_tcr1; /* timer 1 capture reg */ + volatile unsigned short timer_tcr2; /* timer 2 capture reg */ + volatile unsigned short timer_tcn1; /* timer 1 counter reg */ + volatile unsigned short timer_tcn2; /* timer 2 counter reg */ + volatile unsigned short timer_tmr3; /* timer 3 mode reg */ + volatile unsigned short timer_tmr4; /* timer 4 mode reg */ + volatile unsigned short timer_trr3; /* timer 3 referance reg */ + volatile unsigned short timer_trr4; /* timer 4 referance reg */ + volatile unsigned short timer_tcr3; /* timer 3 capture reg */ + volatile unsigned short timer_tcr4; /* timer 4 capture reg */ + volatile unsigned short timer_tcn3; /* timer 3 counter reg */ + volatile unsigned short timer_tcn4; /* timer 4 counter reg */ + volatile unsigned short timer_ter1; /* timer 1 event reg */ + volatile unsigned short timer_ter2; /* timer 2 event reg */ + volatile unsigned short timer_ter3; /* timer 3 event reg */ + volatile unsigned short timer_ter4; /* timer 4 event reg */ + volatile unsigned char RESERVED34[0x8]; /* Reserved area */ + /* CP */ + volatile unsigned short cp_cr; /* command register */ + volatile unsigned char RESERVED35[0x2]; /* Reserved area */ + volatile unsigned short cp_rccr; /* main configuration reg */ + volatile unsigned char RESERVED37; /* Reserved area */ + volatile unsigned char cp_rmds; /* development support status reg */ + volatile unsigned long cp_rmdr; /* development support control reg */ + volatile unsigned short cp_rctr1; /* ram break register 1 */ + volatile unsigned short cp_rctr2; /* ram break register 2 */ + volatile unsigned short cp_rctr3; /* ram break register 3 */ + volatile unsigned short cp_rctr4; /* ram break register 4 */ + volatile unsigned char RESERVED59[0x2]; /* Reserved area */ + volatile unsigned short cp_rter; /* RISC timers event reg */ + volatile unsigned char RESERVED38[0x2]; /* Reserved area */ + volatile unsigned short cp_rtmr; /* RISC timers mask reg */ + volatile unsigned char RESERVED39[0x14]; /* Reserved area */ + /* BRG */ + union { + volatile unsigned long l; + struct { + volatile unsigned short BRGC_RESERV:14; + volatile unsigned short rst:1; + volatile unsigned short en:1; + volatile unsigned short extc:2; + volatile unsigned short atb:1; + volatile unsigned short cd:12; + volatile unsigned short div16:1; + } b; + } brgc[4]; /* BRG1-BRG4 configuration regs*/ + /* SCC registers */ + struct scc_regs { + union { + struct { + /* Low word. */ + volatile unsigned short GSMR_RESERV2:1; + volatile unsigned short edge:2; + volatile unsigned short tci:1; + volatile unsigned short tsnc:2; + volatile unsigned short rinv:1; + volatile unsigned short tinv:1; + volatile unsigned short tpl:3; + volatile unsigned short tpp:2; + volatile unsigned short tend:1; + volatile unsigned short tdcr:2; + volatile unsigned short rdcr:2; + volatile unsigned short renc:3; + volatile unsigned short tenc:3; + volatile unsigned short diag:2; + volatile unsigned short enr:1; + volatile unsigned short ent:1; + volatile unsigned short mode:4; + /* High word. */ + volatile unsigned short GSMR_RESERV1:14; + volatile unsigned short pri:1; + volatile unsigned short gde:1; + volatile unsigned short tcrc:2; + volatile unsigned short revd:1; + volatile unsigned short trx:1; + volatile unsigned short ttx:1; + volatile unsigned short cdp:1; + volatile unsigned short ctsp:1; + volatile unsigned short cds:1; + volatile unsigned short ctss:1; + volatile unsigned short tfl:1; + volatile unsigned short rfw:1; + volatile unsigned short txsy:1; + volatile unsigned short synl:2; + volatile unsigned short rtsm:1; + volatile unsigned short rsyn:1; + } b; + struct { + volatile unsigned long low; + volatile unsigned long high; + } w; + } scc_gsmr; /* SCC general mode reg */ + volatile unsigned short scc_psmr; /* protocol specific mode reg */ + volatile unsigned char RESERVED42[0x2]; /* Reserved area */ + volatile unsigned short scc_todr; /* SCC transmit on demand */ + volatile unsigned short scc_dsr; /* SCC data sync reg */ + volatile unsigned short scc_scce; /* SCC event reg */ + volatile unsigned char RESERVED43[0x2];/* Reserved area */ + volatile unsigned short scc_sccm; /* SCC mask reg */ + volatile unsigned char RESERVED44[0x1];/* Reserved area */ + volatile unsigned char scc_sccs; /* SCC status reg */ + volatile unsigned char RESERVED45[0x8]; /* Reserved area */ + } scc_regs[4]; + /* SMC */ + struct smc_regs { + volatile unsigned char RESERVED46[0x2]; /* Reserved area */ + volatile unsigned short smc_smcmr; /* SMC mode reg */ + volatile unsigned char RESERVED60[0x2]; /* Reserved area */ + volatile unsigned char smc_smce; /* SMC event reg */ + volatile unsigned char RESERVED47[0x3]; /* Reserved area */ + volatile unsigned char smc_smcm; /* SMC mask reg */ + volatile unsigned char RESERVED48[0x5]; /* Reserved area */ + } smc_regs[2]; + /* SPI */ + volatile unsigned short spi_spmode; /* SPI mode reg */ + volatile unsigned char RESERVED51[0x4]; /* Reserved area */ + volatile unsigned char spi_spie; /* SPI event reg */ + volatile unsigned char RESERVED52[0x3]; /* Reserved area */ + volatile unsigned char spi_spim; /* SPI mask reg */ + volatile unsigned char RESERVED53[0x2]; /* Reserved area */ + volatile unsigned char spi_spcom; /* SPI command reg */ + volatile unsigned char RESERVED54[0x4]; /* Reserved area */ + /* PIP */ + volatile unsigned short pip_pipc; /* pip configuration reg */ + volatile unsigned char RESERVED65[0x2]; /* Reserved area */ + volatile unsigned short pip_ptpr; /* pip timing parameters reg */ + volatile unsigned long pip_pbdir; /* port b data direction reg */ + volatile unsigned long pip_pbpar; /* port b pin assignment reg */ + volatile unsigned long pip_pbodr; /* port b open drain reg */ + volatile unsigned long pip_pbdat; /* port b data reg */ + volatile unsigned char RESERVED71[0x18]; /* Reserved area */ + /* Serial Interface */ + volatile unsigned long si_simode; /* SI mode register */ + volatile unsigned char si_sigmr; /* SI global mode register */ + volatile unsigned char RESERVED55; /* Reserved area */ + volatile unsigned char si_sistr; /* SI status register */ + volatile unsigned char si_sicmr; /* SI command register */ + volatile unsigned char RESERVED56[0x4]; /* Reserved area */ + volatile unsigned long si_sicr; /* SI clock routing */ + volatile unsigned long si_sirp; /* SI ram pointers */ + volatile unsigned char RESERVED57[0xc]; /* Reserved area */ + volatile unsigned short si_siram[0x80]; /* SI routing ram */ +} QUICC; + +#endif + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff -Nru a/include/asm-m68knommu/m68360_regs.h b/include/asm-m68knommu/m68360_regs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/m68360_regs.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,408 @@ +/*********************************** + * $Id: m68360_regs.h,v 1.2 2002/10/26 15:03:55 gerg Exp $ + *********************************** + * + *************************************** + * Definitions of the QUICC registers + *************************************** + */ + +#ifndef __REGISTERS_H +#define __REGISTERS_H + +#define CLEAR_BIT(x, bit) x =bit + +/***************************************************************** + Command Register +*****************************************************************/ + +/* bit fields within command register */ +#define SOFTWARE_RESET 0x8000 +#define CMD_OPCODE 0x0f00 +#define CMD_CHANNEL 0x00f0 +#define CMD_FLAG 0x0001 + +/* general command opcodes */ +#define INIT_RXTX_PARAMS 0x0000 +#define INIT_RX_PARAMS 0x0100 +#define INIT_TX_PARAMS 0x0200 +#define ENTER_HUNT_MODE 0x0300 +#define STOP_TX 0x0400 +#define GR_STOP_TX 0x0500 +#define RESTART_TX 0x0600 +#define CLOSE_RX_BD 0x0700 +#define SET_ENET_GROUP 0x0800 +#define RESET_ENET_GROUP 0x0900 + +/* quicc32 CP commands */ +#define STOP_TX_32 0x0e00 /*add chan# bits 2-6 */ +#define ENTER_HUNT_MODE_32 0x1e00 + +/* quicc32 mask/event SCC register */ +#define GOV 0x01 +#define GUN 0x02 +#define GINT 0x04 +#define IQOV 0x08 + + +/* Timer commands */ +#define SET_TIMER 0x0800 + +/* Multi channel Interrupt structure */ +#define INTR_VALID 0x8000 /* Valid interrupt entry */ +#define INTR_WRAP 0x4000 /* Wrap bit in the interrupt entry table */ +#define INTR_CH_NU 0x07c0 /* Channel Num in interrupt table */ +#define INTR_MASK_BITS 0x383f + +/* + * General SCC mode register (GSMR) + */ + +#define MODE_HDLC 0x0 +#define MODE_APPLE_TALK 0x2 +#define MODE_SS7 0x3 +#define MODE_UART 0x4 +#define MODE_PROFIBUS 0x5 +#define MODE_ASYNC_HDLC 0x6 +#define MODE_V14 0x7 +#define MODE_BISYNC 0x8 +#define MODE_DDCMP 0x9 +#define MODE_MULTI_CHANNEL 0xa +#define MODE_ETHERNET 0xc + +#define DIAG_NORMAL 0x0 +#define DIAG_LOCAL_LPB 0x1 +#define DIAG_AUTO_ECHO 0x2 +#define DIAG_LBP_ECHO 0x3 + +/* For RENC and TENC fields in GSMR */ +#define ENC_NRZ 0x0 +#define ENC_NRZI 0x1 +#define ENC_FM0 0x2 +#define ENC_MANCH 0x4 +#define ENC_DIFF_MANC 0x6 + +/* For TDCR and RDCR fields in GSMR */ +#define CLOCK_RATE_1 0x0 +#define CLOCK_RATE_8 0x1 +#define CLOCK_RATE_16 0x2 +#define CLOCK_RATE_32 0x3 + +#define TPP_00 0x0 +#define TPP_10 0x1 +#define TPP_01 0x2 +#define TPP_11 0x3 + +#define TPL_NO 0x0 +#define TPL_8 0x1 +#define TPL_16 0x2 +#define TPL_32 0x3 +#define TPL_48 0x4 +#define TPL_64 0x5 +#define TPL_128 0x6 + +#define TSNC_INFINITE 0x0 +#define TSNC_14_65 0x1 +#define TSNC_4_15 0x2 +#define TSNC_3_1 0x3 + +#define EDGE_BOTH 0x0 +#define EDGE_POS 0x1 +#define EDGE_NEG 0x2 +#define EDGE_NO 0x3 + +#define SYNL_NO 0x0 +#define SYNL_4 0x1 +#define SYNL_8 0x2 +#define SYNL_16 0x3 + +#define TCRC_CCITT16 0x0 +#define TCRC_CRC16 0x1 +#define TCRC_CCITT32 0x2 + + +/***************************************************************** + TODR (Transmit on demand) Register +*****************************************************************/ +#define TODR_TOD 0x8000 /* Transmit on demand */ + + +/***************************************************************** + CICR register settings +*****************************************************************/ + +/* note that relative irq priorities of the SCCs can be reordered + * if desired - see p. 7-377 of the MC68360UM */ +#define CICR_SCA_SCC1 ((uint)0x00000000) /* SCC1 @ SCCa */ +#define CICR_SCB_SCC2 ((uint)0x00040000) /* SCC2 @ SCCb */ +#define CICR_SCC_SCC3 ((uint)0x00200000) /* SCC3 @ SCCc */ +#define CICR_SCD_SCC4 ((uint)0x00c00000) /* SCC4 @ SCCd */ + +#define CICR_IRL_MASK ((uint)0x0000e000) /* Core interrrupt */ +#define CICR_HP_MASK ((uint)0x00001f00) /* Hi-pri int. */ +#define CICR_VBA_MASK ((uint)0x000000e0) /* Vector Base Address */ +#define CICR_SPS ((uint)0x00000001) /* SCC Spread */ + + +/***************************************************************** + Interrupt bits for CIPR and CIMR (MC68360UM p. 7-379) +*****************************************************************/ + +#define INTR_PIO_PC0 0x80000000 /* parallel I/O C bit 0 */ +#define INTR_SCC1 0x40000000 /* SCC port 1 */ +#define INTR_SCC2 0x20000000 /* SCC port 2 */ +#define INTR_SCC3 0x10000000 /* SCC port 3 */ +#define INTR_SCC4 0x08000000 /* SCC port 4 */ +#define INTR_PIO_PC1 0x04000000 /* parallel i/o C bit 1 */ +#define INTR_TIMER1 0x02000000 /* timer 1 */ +#define INTR_PIO_PC2 0x01000000 /* parallel i/o C bit 2 */ +#define INTR_PIO_PC3 0x00800000 /* parallel i/o C bit 3 */ +#define INTR_SDMA_BERR 0x00400000 /* SDMA channel bus error */ +#define INTR_DMA1 0x00200000 /* idma 1 */ +#define INTR_DMA2 0x00100000 /* idma 2 */ +#define INTR_TIMER2 0x00040000 /* timer 2 */ +#define INTR_CP_TIMER 0x00020000 /* CP timer */ +#define INTR_PIP_STATUS 0x00010000 /* PIP status */ +#define INTR_PIO_PC4 0x00008000 /* parallel i/o C bit 4 */ +#define INTR_PIO_PC5 0x00004000 /* parallel i/o C bit 5 */ +#define INTR_TIMER3 0x00001000 /* timer 3 */ +#define INTR_PIO_PC6 0x00000800 /* parallel i/o C bit 6 */ +#define INTR_PIO_PC7 0x00000400 /* parallel i/o C bit 7 */ +#define INTR_PIO_PC8 0x00000200 /* parallel i/o C bit 8 */ +#define INTR_TIMER4 0x00000080 /* timer 4 */ +#define INTR_PIO_PC9 0x00000040 /* parallel i/o C bit 9 */ +#define INTR_SCP 0x00000020 /* SCP */ +#define INTR_SMC1 0x00000010 /* SMC 1 */ +#define INTR_SMC2 0x00000008 /* SMC 2 */ +#define INTR_PIO_PC10 0x00000004 /* parallel i/o C bit 10 */ +#define INTR_PIO_PC11 0x00000002 /* parallel i/o C bit 11 */ +#define INTR_ERR 0x00000001 /* error */ + + +/***************************************************************** + CPM Interrupt vector encodings (MC68360UM p. 7-376) +*****************************************************************/ + +#define CPMVEC_NR 32 +#define CPMVEC_PIO_PC0 0x1f +#define CPMVEC_SCC1 0x1e +#define CPMVEC_SCC2 0x1d +#define CPMVEC_SCC3 0x1c +#define CPMVEC_SCC4 0x1b +#define CPMVEC_PIO_PC1 0x1a +#define CPMVEC_TIMER1 0x19 +#define CPMVEC_PIO_PC2 0x18 +#define CPMVEC_PIO_PC3 0x17 +#define CPMVEC_SDMA_CB_ERR 0x16 +#define CPMVEC_IDMA1 0x15 +#define CPMVEC_IDMA2 0x14 +#define CPMVEC_RESERVED3 0x13 +#define CPMVEC_TIMER2 0x12 +#define CPMVEC_RISCTIMER 0x11 +#define CPMVEC_RESERVED2 0x10 +#define CPMVEC_PIO_PC4 0x0f +#define CPMVEC_PIO_PC5 0x0e +#define CPMVEC_TIMER3 0x0c +#define CPMVEC_PIO_PC6 0x0b +#define CPMVEC_PIO_PC7 0x0a +#define CPMVEC_PIO_PC8 0x09 +#define CPMVEC_RESERVED1 0x08 +#define CPMVEC_TIMER4 0x07 +#define CPMVEC_PIO_PC9 0x06 +#define CPMVEC_SPI 0x05 +#define CPMVEC_SMC1 0x04 +#define CPMVEC_SMC2 0x03 +#define CPMVEC_PIO_PC10 0x02 +#define CPMVEC_PIO_PC11 0x01 +#define CPMVEC_ERROR 0x00 + +/* #define CPMVEC_PIO_PC0 ((ushort)0x1f) */ +/* #define CPMVEC_SCC1 ((ushort)0x1e) */ +/* #define CPMVEC_SCC2 ((ushort)0x1d) */ +/* #define CPMVEC_SCC3 ((ushort)0x1c) */ +/* #define CPMVEC_SCC4 ((ushort)0x1b) */ +/* #define CPMVEC_PIO_PC1 ((ushort)0x1a) */ +/* #define CPMVEC_TIMER1 ((ushort)0x19) */ +/* #define CPMVEC_PIO_PC2 ((ushort)0x18) */ +/* #define CPMVEC_PIO_PC3 ((ushort)0x17) */ +/* #define CPMVEC_SDMA_CB_ERR ((ushort)0x16) */ +/* #define CPMVEC_IDMA1 ((ushort)0x15) */ +/* #define CPMVEC_IDMA2 ((ushort)0x14) */ +/* #define CPMVEC_RESERVED3 ((ushort)0x13) */ +/* #define CPMVEC_TIMER2 ((ushort)0x12) */ +/* #define CPMVEC_RISCTIMER ((ushort)0x11) */ +/* #define CPMVEC_RESERVED2 ((ushort)0x10) */ +/* #define CPMVEC_PIO_PC4 ((ushort)0x0f) */ +/* #define CPMVEC_PIO_PC5 ((ushort)0x0e) */ +/* #define CPMVEC_TIMER3 ((ushort)0x0c) */ +/* #define CPMVEC_PIO_PC6 ((ushort)0x0b) */ +/* #define CPMVEC_PIO_PC7 ((ushort)0x0a) */ +/* #define CPMVEC_PIO_PC8 ((ushort)0x09) */ +/* #define CPMVEC_RESERVED1 ((ushort)0x08) */ +/* #define CPMVEC_TIMER4 ((ushort)0x07) */ +/* #define CPMVEC_PIO_PC9 ((ushort)0x06) */ +/* #define CPMVEC_SPI ((ushort)0x05) */ +/* #define CPMVEC_SMC1 ((ushort)0x04) */ +/* #define CPMVEC_SMC2 ((ushort)0x03) */ +/* #define CPMVEC_PIO_PC10 ((ushort)0x02) */ +/* #define CPMVEC_PIO_PC11 ((ushort)0x01) */ +/* #define CPMVEC_ERROR ((ushort)0x00) */ + + +/***************************************************************** + * PIO control registers + *****************************************************************/ + +/* Port A - See 360UM p. 7-358 + * + * Note that most of these pins have alternate functions + */ + + +/* The macros are nice, but there are all sorts of references to 1-indexed + * facilities on the 68360... */ +/* #define PA_RXD(n) ((ushort)(0x01<<(2*n))) */ +/* #define PA_TXD(n) ((ushort)(0x02<<(2*n))) */ + +#define PA_RXD1 ((ushort)0x0001) +#define PA_TXD1 ((ushort)0x0002) +#define PA_RXD2 ((ushort)0x0004) +#define PA_TXD2 ((ushort)0x0008) +#define PA_RXD3 ((ushort)0x0010) +#define PA_TXD3 ((ushort)0x0020) +#define PA_RXD4 ((ushort)0x0040) +#define PA_TXD4 ((ushort)0x0080) + +#define PA_CLK1 ((ushort)0x0100) +#define PA_CLK2 ((ushort)0x0200) +#define PA_CLK3 ((ushort)0x0400) +#define PA_CLK4 ((ushort)0x0800) +#define PA_CLK5 ((ushort)0x1000) +#define PA_CLK6 ((ushort)0x2000) +#define PA_CLK7 ((ushort)0x4000) +#define PA_CLK8 ((ushort)0x8000) + + +/* Port B - See 360UM p. 7-362 + */ + + +/* Port C - See 360UM p. 7-365 + */ + +#define PC_RTS1 ((ushort)0x0001) +#define PC_RTS2 ((ushort)0x0002) +#define PC__RTS3 ((ushort)0x0004) /* !RTS3 */ +#define PC__RTS4 ((ushort)0x0008) /* !RTS4 */ + +#define PC_CTS1 ((ushort)0x0010) +#define PC_CD1 ((ushort)0x0020) +#define PC_CTS2 ((ushort)0x0040) +#define PC_CD2 ((ushort)0x0080) +#define PC_CTS3 ((ushort)0x0100) +#define PC_CD3 ((ushort)0x0200) +#define PC_CTS4 ((ushort)0x0400) +#define PC_CD4 ((ushort)0x0800) + + + +/***************************************************************** + chip select option register +*****************************************************************/ +#define DTACK 0xe000 +#define ADR_MASK 0x1ffc +#define RDWR_MASK 0x0002 +#define FC_MASK 0x0001 + +/***************************************************************** + tbase and rbase registers +*****************************************************************/ +#define TBD_ADDR(quicc,pram) ((struct quicc_bd *) \ + (quicc->ch_or_u.u.udata_bd_ucode + pram->tbase)) +#define RBD_ADDR(quicc,pram) ((struct quicc_bd *) \ + (quicc->ch_or_u.u.udata_bd_ucode + pram->rbase)) +#define TBD_CUR_ADDR(quicc,pram) ((struct quicc_bd *) \ + (quicc->ch_or_u.u.udata_bd_ucode + pram->tbptr)) +#define RBD_CUR_ADDR(quicc,pram) ((struct quicc_bd *) \ + (quicc->ch_or_u.u.udata_bd_ucode + pram->rbptr)) +#define TBD_SET_CUR_ADDR(bd,quicc,pram) pram->tbptr = \ + ((unsigned short)((char *)(bd) - (char *)(quicc->ch_or_u.u.udata_bd_ucode))) +#define RBD_SET_CUR_ADDR(bd,quicc,pram) pram->rbptr = \ + ((unsigned short)((char *)(bd) - (char *)(quicc->ch_or_u.u.udata_bd_ucode))) +#define INCREASE_TBD(bd,quicc,pram) { \ + if((bd)->status & T_W) \ + (bd) = TBD_ADDR(quicc,pram); \ + else \ + (bd)++; \ +} +#define DECREASE_TBD(bd,quicc,pram) { \ + if ((bd) == TBD_ADDR(quicc, pram)) \ + while (!((bd)->status & T_W)) \ + (bd)++; \ + else \ + (bd)--; \ +} +#define INCREASE_RBD(bd,quicc,pram) { \ + if((bd)->status & R_W) \ + (bd) = RBD_ADDR(quicc,pram); \ + else \ + (bd)++; \ +} +#define DECREASE_RBD(bd,quicc,pram) { \ + if ((bd) == RBD_ADDR(quicc, pram)) \ + while (!((bd)->status & T_W)) \ + (bd)++; \ + else \ + (bd)--; \ +} + +/***************************************************************** + Macros for Multi channel +*****************************************************************/ +#define QMC_BASE(quicc,page) (struct global_multi_pram *)(&quicc->pram[page]) +#define MCBASE(quicc,page) (unsigned long)(quicc->pram[page].m.mcbase) +#define CHANNEL_PRAM_BASE(quicc,channel) ((struct quicc32_pram *) \ + (&(quicc->ch_or_u.ch_pram_tbl[channel]))) +#define TBD_32_ADDR(quicc,page,channel) ((struct quicc_bd *) \ + (MCBASE(quicc,page) + (CHANNEL_PRAM_BASE(quicc,channel)->tbase))) +#define RBD_32_ADDR(quicc,page,channel) ((struct quicc_bd *) \ + (MCBASE(quicc,page) + (CHANNEL_PRAM_BASE(quicc,channel)->rbase))) +#define TBD_32_CUR_ADDR(quicc,page,channel) ((struct quicc_bd *) \ + (MCBASE(quicc,page) + (CHANNEL_PRAM_BASE(quicc,channel)->tbptr))) +#define RBD_32_CUR_ADDR(quicc,page,channel) ((struct quicc_bd *) \ + (MCBASE(quicc,page) + (CHANNEL_PRAM_BASE(quicc,channel)->rbptr))) +#define TBD_32_SET_CUR_ADDR(bd,quicc,page,channel) \ + CHANNEL_PRAM_BASE(quicc,channel)->tbptr = \ + ((unsigned short)((char *)(bd) - (char *)(MCBASE(quicc,page)))) +#define RBD_32_SET_CUR_ADDR(bd,quicc,page,channel) \ + CHANNEL_PRAM_BASE(quicc,channel)->rbptr = \ + ((unsigned short)((char *)(bd) - (char *)(MCBASE(quicc,page)))) + +#define INCREASE_TBD_32(bd,quicc,page,channel) { \ + if((bd)->status & T_W) \ + (bd) = TBD_32_ADDR(quicc,page,channel); \ + else \ + (bd)++; \ +} +#define DECREASE_TBD_32(bd,quicc,page,channel) { \ + if ((bd) == TBD_32_ADDR(quicc, page,channel)) \ + while (!((bd)->status & T_W)) \ + (bd)++; \ + else \ + (bd)--; \ +} +#define INCREASE_RBD_32(bd,quicc,page,channel) { \ + if((bd)->status & R_W) \ + (bd) = RBD_32_ADDR(quicc,page,channel); \ + else \ + (bd)++; \ +} +#define DECREASE_RBD_32(bd,quicc,page,channel) { \ + if ((bd) == RBD_32_ADDR(quicc, page,channel)) \ + while (!((bd)->status & T_W)) \ + (bd)++; \ + else \ + (bd)--; \ +} + +#endif diff -Nru a/include/asm-m68knommu/machdep.h b/include/asm-m68knommu/machdep.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/machdep.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,51 @@ +#ifndef _M68KNOMMU_MACHDEP_H +#define _M68KNOMMU_MACHDEP_H + +struct pt_regs; +struct kbd_repeat; +struct mktime; +struct hwclk_time; +struct gendisk; +struct buffer_head; + +extern void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)); +/* machine dependent keyboard functions */ +extern int (*mach_keyb_init) (void); +extern int (*mach_kbdrate) (struct kbd_repeat *); +extern void (*mach_kbd_leds) (unsigned int); +/* machine dependent irq functions */ +extern void (*mach_init_IRQ) (void); +extern void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *); +extern int (*mach_request_irq) (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id); +extern void (*mach_free_irq) (unsigned int irq, void *dev_id); +extern void (*mach_get_model) (char *model); +extern int (*mach_get_hardware_list) (char *buffer); +extern int (*mach_get_irq_list) (struct seq_file *p, void *v); +extern void (*mach_process_int) (int irq, struct pt_regs *fp); +/* machine dependent timer functions */ +extern unsigned long (*mach_gettimeoffset)(void); +extern void (*mach_gettod)(int *year, int *mon, int *day, int *hour, + int *min, int *sec); +extern int (*mach_hwclk)(int, struct hwclk_time*); +extern int (*mach_set_clock_mmss)(unsigned long); +extern void (*mach_reset)( void ); +extern void (*mach_halt)( void ); +extern void (*mach_power_off)( void ); +extern unsigned long (*mach_hd_init) (unsigned long, unsigned long); +extern void (*mach_hd_setup)(char *, int *); +extern long mach_max_dma_address; +extern void (*mach_floppy_setup)(char *, int *); +extern void (*mach_floppy_eject)(void); +extern void (*mach_heartbeat) (int); +extern void (*mach_l2_flush) (int); +extern int mach_sysrq_key; +extern int mach_sysrq_shift_state; +extern int mach_sysrq_shift_mask; +extern char *mach_sysrq_xlate; + +extern void config_BSP(char *command, int len); +extern void (*mach_tick)(void); +extern void (*mach_trap_init)(void); + +#endif /* _M68KNOMMU_MACHDEP_H */ diff -Nru a/include/asm-m68knommu/math-emu.h b/include/asm-m68knommu/math-emu.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/math-emu.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/mc146818rtc.h b/include/asm-m68knommu/mc146818rtc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/mc146818rtc.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,9 @@ +/* + * Machine dependent access functions for RTC registers. + */ +#ifndef _M68KNOMMU_MC146818RTC_H +#define _M68KNOMMU_MC146818RTC_H + +/* empty include file to satisfy the include in genrtc.c/ide-geometry.c */ + +#endif /* _M68KNOMMU_MC146818RTC_H */ diff -Nru a/include/asm-m68knommu/mcfdma.h b/include/asm-m68knommu/mcfdma.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/mcfdma.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,139 @@ +/****************************************************************************/ + +/* + * mcfdma.h -- Coldfire internal DMA support defines. + * + * (C) Copyright 1999, Rob Scott (rscott@mtrob.ml.org) + */ + +/****************************************************************************/ +#ifndef mcfdma_h +#define mcfdma_h +/****************************************************************************/ + +#include + +/* + * Get address specific defines for this Coldfire member. + */ +#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) +#define MCFDMA_BASE0 0x200 /* Base address of DMA 0 */ +#define MCFDMA_BASE1 0x240 /* Base address of DMA 1 */ +#elif defined(CONFIG_M5272) +#define MCFDMA_BASE0 0x0e0 /* Base address of DMA 0 */ +#elif defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407) +#define MCFDMA_BASE0 0x300 /* Base address of DMA 0 */ +#define MCFDMA_BASE1 0x340 /* Base address of DMA 1 */ +#define MCFDMA_BASE2 0x380 /* Base address of DMA 2 */ +#define MCFDMA_BASE3 0x3C0 /* Base address of DMA 3 */ +#endif + + +#if !defined(CONFIG_M5272) + +/* + * Define the DMA register set addresses. + * Note: these are longword registers, use unsigned long as data type + */ +#define MCFDMA_SAR 0x00 /* DMA source address (r/w) */ +#define MCFDMA_DAR 0x01 /* DMA destination adr (r/w) */ +/* these are word registers, use unsigned short data type */ +#define MCFDMA_DCR 0x04 /* DMA control reg (r/w) */ +#define MCFDMA_BCR 0x06 /* DMA byte count reg (r/w) */ +/* these are byte registers, use unsiged char data type */ +#define MCFDMA_DSR 0x10 /* DMA status reg (r/w) */ +#define MCFDMA_DIVR 0x14 /* DMA interrupt vec (r/w) */ + +/* + * Bit definitions for the DMA Control Register (DCR). + */ +#define MCFDMA_DCR_INT 0x8000 /* Enable completion irq */ +#define MCFDMA_DCR_EEXT 0x4000 /* Enable external DMA req */ +#define MCFDMA_DCR_CS 0x2000 /* Enable cycle steal */ +#define MCFDMA_DCR_AA 0x1000 /* Enable auto alignment */ +#define MCFDMA_DCR_BWC_MASK 0x0E00 /* Bandwidth ctl mask */ +#define MCFDMA_DCR_BWC_512 0x0200 /* Bandwidth: 512 Bytes */ +#define MCFDMA_DCR_BWC_1024 0x0400 /* Bandwidth: 1024 Bytes */ +#define MCFDMA_DCR_BWC_2048 0x0600 /* Bandwidth: 2048 Bytes */ +#define MCFDMA_DCR_BWC_4096 0x0800 /* Bandwidth: 4096 Bytes */ +#define MCFDMA_DCR_BWC_8192 0x0a00 /* Bandwidth: 8192 Bytes */ +#define MCFDMA_DCR_BWC_16384 0x0c00 /* Bandwidth: 16384 Bytes */ +#define MCFDMA_DCR_BWC_32768 0x0e00 /* Bandwidth: 32768 Bytes */ +#define MCFDMA_DCR_SAA 0x0100 /* Single Address Access */ +#define MCFDMA_DCR_S_RW 0x0080 /* SAA read/write value */ +#define MCFDMA_DCR_SINC 0x0040 /* Source addr inc enable */ +#define MCFDMA_DCR_SSIZE_MASK 0x0030 /* Src xfer size */ +#define MCFDMA_DCR_SSIZE_LONG 0x0000 /* Src xfer size, 00 = longw */ +#define MCFDMA_DCR_SSIZE_BYTE 0x0010 /* Src xfer size, 01 = byte */ +#define MCFDMA_DCR_SSIZE_WORD 0x0020 /* Src xfer size, 10 = word */ +#define MCFDMA_DCR_SSIZE_LINE 0x0030 /* Src xfer size, 11 = line */ +#define MCFDMA_DCR_DINC 0x0008 /* Dest addr inc enable */ +#define MCFDMA_DCR_DSIZE_MASK 0x0006 /* Dest xfer size */ +#define MCFDMA_DCR_DSIZE_LONG 0x0000 /* Dest xfer size, 00 = long */ +#define MCFDMA_DCR_DSIZE_BYTE 0x0002 /* Dest xfer size, 01 = byte */ +#define MCFDMA_DCR_DSIZE_WORD 0x0004 /* Dest xfer size, 10 = word */ +#define MCFDMA_DCR_DSIZE_LINE 0x0006 /* Dest xfer size, 11 = line */ +#define MCFDMA_DCR_START 0x0001 /* Start transfer */ + +/* + * Bit definitions for the DMA Status Register (DSR). + */ +#define MCFDMA_DSR_CE 0x40 /* Config error */ +#define MCFDMA_DSR_BES 0x20 /* Bus Error on source */ +#define MCFDMA_DSR_BED 0x10 /* Bus Error on dest */ +#define MCFDMA_DSR_REQ 0x04 /* Requests remaining */ +#define MCFDMA_DSR_BSY 0x02 /* Busy */ +#define MCFDMA_DSR_DONE 0x01 /* DMA transfer complete */ + +#else /* This is an MCF5272 */ + +#define MCFDMA_DMR 0x00 /* Mode Register (r/w) */ +#define MCFDMA_DIR 0x03 /* Interrupt trigger register (r/w) */ +#define MCFDMA_DSAR 0x03 /* Source Address register (r/w) */ +#define MCFDMA_DDAR 0x04 /* Destination Address register (r/w) */ +#define MCFDMA_DBCR 0x02 /* Byte Count Register (r/w) */ + +/* Bit definitions for the DMA Mode Register (DMR) */ +#define MCFDMA_DMR_RESET 0x80000000L /* Reset bit */ +#define MCFDMA_DMR_EN 0x40000000L /* DMA enable */ +#define MCFDMA_DMR_RQM 0x000C0000L /* Request Mode Mask */ +#define MCFDMA_DMR_RQM_DUAL 0x000C0000L /* Dual address mode, the only valid mode */ +#define MCFDMA_DMR_DSTM 0x00002000L /* Destination addressing mask */ +#define MCFDMA_DMR_DSTM_SA 0x00000000L /* Destination uses static addressing */ +#define MCFDMA_DMR_DSTM_IA 0x00002000L /* Destination uses incremental addressing */ +#define MCFDMA_DMR_DSTT_UD 0x00000400L /* Destination is user data */ +#define MCFDMA_DMR_DSTT_UC 0x00000800L /* Destination is user code */ +#define MCFDMA_DMR_DSTT_SD 0x00001400L /* Destination is supervisor data */ +#define MCFDMA_DMR_DSTT_SC 0x00001800L /* Destination is supervisor code */ +#define MCFDMA_DMR_DSTS_OFF 0x8 /* offset to the destination size bits */ +#define MCFDMA_DMR_DSTS_LONG 0x00000000L /* Long destination size */ +#define MCFDMA_DMR_DSTS_BYTE 0x00000100L /* Byte destination size */ +#define MCFDMA_DMR_DSTS_WORD 0x00000200L /* Word destination size */ +#define MCFDMA_DMR_DSTS_LINE 0x00000300L /* Line destination size */ +#define MCFDMA_DMR_SRCM 0x00000020L /* Source addressing mask */ +#define MCFDMA_DMR_SRCM_SA 0x00000000L /* Source uses static addressing */ +#define MCFDMA_DMR_SRCM_IA 0x00000020L /* Source uses incremental addressing */ +#define MCFDMA_DMR_SRCT_UD 0x00000004L /* Source is user data */ +#define MCFDMA_DMR_SRCT_UC 0x00000008L /* Source is user code */ +#define MCFDMA_DMR_SRCT_SD 0x00000014L /* Source is supervisor data */ +#define MCFDMA_DMR_SRCT_SC 0x00000018L /* Source is supervisor code */ +#define MCFDMA_DMR_SRCS_OFF 0x0 /* Offset to the source size bits */ +#define MCFDMA_DMR_SRCS_LONG 0x00000000L /* Long source size */ +#define MCFDMA_DMR_SRCS_BYTE 0x00000001L /* Byte source size */ +#define MCFDMA_DMR_SRCS_WORD 0x00000002L /* Word source size */ +#define MCFDMA_DMR_SRCS_LINE 0x00000003L /* Line source size */ + +/* Bit definitions for the DMA interrupt register (DIR) */ +#define MCFDMA_DIR_INVEN 0x1000 /* Invalid Combination interrupt enable */ +#define MCFDMA_DIR_ASCEN 0x0800 /* Address Sequence Complete (Completion) interrupt enable */ +#define MCFDMA_DIR_TEEN 0x0200 /* Transfer Error interrupt enable */ +#define MCFDMA_DIR_TCEN 0x0100 /* Transfer Complete (a bus transfer, that is) interrupt enable */ +#define MCFDMA_DIR_INV 0x1000 /* Invalid Combination */ +#define MCFDMA_DIR_ASC 0x0008 /* Address Sequence Complete (DMA Completion) */ +#define MCFDMA_DIR_TE 0x0002 /* Transfer Error */ +#define MCFDMA_DIR_TC 0x0001 /* Transfer Complete */ + +#endif /* !defined(CONFIG_M5272) */ + +/****************************************************************************/ +#endif /* mcfdma_h */ diff -Nru a/include/asm-m68knommu/mcfmbus.h b/include/asm-m68knommu/mcfmbus.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/mcfmbus.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,78 @@ +/****************************************************************************/ + +/* + * mcfmbus.h -- Coldfire MBUS support defines. + * + * (C) Copyright 1999, Martin Floeer (mfloeer@axcent.de) + */ + +/****************************************************************************/ + + +#ifndef mcfmbus_h +#define mcfmbus_h +#include + + +#define MCFMBUS_BASE 0x280 +#define MCFMBUS_IRQ_VECTOR 0x19 +#define MCFMBUS_IRQ 0x1 +#define MCFMBUS_CLK 0x3f +#define MCFMBUS_IRQ_LEVEL 0x07 /*IRQ Level 1*/ +#define MCFMBUS_ADDRESS 0x01 + + +/* +* Define the 5307 MBUS register set adresses +*/ + +#define MCFMBUS_MADR 0x00 +#define MCFMBUS_MFDR 0x04 +#define MCFMBUS_MBCR 0x08 +#define MCFMBUS_MBSR 0x0C +#define MCFMBUS_MBDR 0x10 + + +#define MCFMBUS_MADR_ADDR(a) (((a)&0x7F)<<0x01) /*Slave Address*/ + +#define MCFMBUS_MFDR_MBC(a) ((a)&0x3F) /*M-Bus Clock*/ + +/* +* Define bit flags in Controll Register +*/ + +#define MCFMBUS_MBCR_MEN (0x80) /* M-Bus Enable */ +#define MCFMBUS_MBCR_MIEN (0x40) /* M-Bus Interrupt Enable */ +#define MCFMBUS_MBCR_MSTA (0x20) /* Master/Slave Mode Select Bit */ +#define MCFMBUS_MBCR_MTX (0x10) /* Transmit/Rcv Mode Select Bit */ +#define MCFMBUS_MBCR_TXAK (0x08) /* Transmit Acknowledge Enable */ +#define MCFMBUS_MBCR_RSTA (0x04) /* Repeat Start */ + +/* +* Define bit flags in Status Register +*/ + +#define MCFMBUS_MBSR_MCF (0x80) /* Data Transfer Complete */ +#define MCFMBUS_MBSR_MAAS (0x40) /* Addressed as a Slave */ +#define MCFMBUS_MBSR_MBB (0x20) /* Bus Busy */ +#define MCFMBUS_MBSR_MAL (0x10) /* Arbitration Lost */ +#define MCFMBUS_MBSR_SRW (0x04) /* Slave Transmit */ +#define MCFMBUS_MBSR_MIF (0x02) /* M-Bus Interrupt */ +#define MCFMBUS_MBSR_RXAK (0x01) /* No Acknowledge Received */ + +/* +* Define bit flags in DATA I/O Register +*/ + +#define MCFMBUS_MBDR_READ (0x01) /* 1=read 0=write MBUS */ + +#define MBUSIOCSCLOCK 1 +#define MBUSIOCGCLOCK 2 +#define MBUSIOCSADDR 3 +#define MBUSIOCGADDR 4 +#define MBUSIOCSSLADDR 5 +#define MBUSIOCGSLADDR 6 +#define MBUSIOCSSUBADDR 7 +#define MBUSIOCGSUBADDR 8 + +#endif diff -Nru a/include/asm-m68knommu/mcfne.h b/include/asm-m68knommu/mcfne.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/mcfne.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,353 @@ +/****************************************************************************/ + +/* + * mcfne.h -- NE2000 in ColdFire eval boards. + * + * (C) Copyright 1999-2000, Greg Ungerer (gerg@snapgear.com) + * (C) Copyright 2000, Lineo (www.lineo.com) + * (C) Copyright 2001, SnapGear (www.snapgear.com) + * + * 19990409 David W. Miller Converted from m5206ne.h for 5307 eval board + * + * Hacked support for m5206e Cadre III evaluation board + * Fred Stevens (fred.stevens@pemstar.com) 13 April 1999 + */ + +/****************************************************************************/ +#ifndef mcfne_h +#define mcfne_h +/****************************************************************************/ + +#include + +/* + * Support for NE2000 clones devices in ColdFire based boards. + * Not all boards address these parts the same way, some use a + * direct addressing method, others use a side-band address space + * to access odd address registers, some require byte swapping + * others do not. + */ +#define BSWAP(w) (((w) << 8) | ((w) >> 8)) +#define RSWAP(w) (w) + + +/* + * Define the basic hardware resources of NE2000 boards. + */ + +#if defined(CONFIG_M5206) && defined(CONFIG_ARNEWSH) +#define NE2000_ADDR 0x40000300 +#define NE2000_ODDOFFSET 0x00010000 +#define NE2000_IRQ_VECTOR 0xf0 +#define NE2000_IRQ_PRIORITY 2 +#define NE2000_IRQ_LEVEL 4 +#define NE2000_BYTE volatile unsigned short +#endif + +#if defined(CONFIG_M5206e) && defined(CONFIG_MOTOROLA) +#define NE2000_ADDR 0x40000300 +#define NE2000_ODDOFFSET 0x00010000 +#define NE2000_IRQ_VECTOR 0x1c +#define NE2000_IRQ_PRIORITY 2 +#define NE2000_IRQ_LEVEL 4 +#define NE2000_BYTE volatile unsigned short +#endif + +#if defined(CONFIG_M5206e) && defined(CONFIG_NETtel) +#define NE2000_ADDR 0x30000300 +#define NE2000_IRQ_VECTOR 25 +#define NE2000_IRQ_PRIORITY 1 +#define NE2000_IRQ_LEVEL 3 +#define NE2000_BYTE volatile unsigned char +#endif + +#if defined(CONFIG_M5206e) && defined(CONFIG_CFV240) +#define NE2000_ADDR 0x40010000 +#define NE2000_ADDR1 0x40010001 +#define NE2000_ODDOFFSET 0x00000000 +#define NE2000_IRQ 1 +#define NE2000_IRQ_VECTOR 0x19 +#define NE2000_IRQ_PRIORITY 2 +#define NE2000_IRQ_LEVEL 1 +#define NE2000_BYTE volatile unsigned char +#endif + +#if defined(CONFIG_M5307) && defined(CONFIG_MOTOROLA) +#define NE2000_ADDR 0x40000300 +#define NE2000_ODDOFFSET 0x00010000 +#define NE2000_IRQ_VECTOR 0x1b +#define NE2000_BYTE volatile unsigned short +#endif + +#if defined(CONFIG_M5272) && defined(CONFIG_NETtel) +#define NE2000_ADDR 0x30600300 +#define NE2000_ODDOFFSET 0x00008000 +#define NE2000_IRQ_VECTOR 67 +#undef BSWAP +#define BSWAP(w) (w) +#define NE2000_BYTE volatile unsigned short +#undef RSWAP +#define RSWAP(w) (((w) << 8) | ((w) >> 8)) +#endif + +#if defined(CONFIG_M5307) && defined(CONFIG_NETtel) +#define NE2000_ADDR0 0x30600300 +#define NE2000_ADDR1 0x30800300 +#define NE2000_ODDOFFSET 0x00008000 +#define NE2000_IRQ_VECTOR0 27 +#define NE2000_IRQ_VECTOR1 29 +#undef BSWAP +#define BSWAP(w) (w) +#define NE2000_BYTE volatile unsigned short +#undef RSWAP +#define RSWAP(w) (((w) << 8) | ((w) >> 8)) +#endif + +#if defined(CONFIG_M5307) && defined(CONFIG_SECUREEDGEMP3) +#define NE2000_ADDR 0x30600300 +#define NE2000_ODDOFFSET 0x00008000 +#define NE2000_IRQ_VECTOR 27 +#undef BSWAP +#define BSWAP(w) (w) +#define NE2000_BYTE volatile unsigned short +#undef RSWAP +#define RSWAP(w) (((w) << 8) | ((w) >> 8)) +#endif + +#if defined(CONFIG_M5307) && defined(CONFIG_ARNEWSH) +#define NE2000_ADDR 0xfe600300 +#define NE2000_ODDOFFSET 0x00010000 +#define NE2000_IRQ_VECTOR 0x1b +#define NE2000_IRQ_PRIORITY 2 +#define NE2000_IRQ_LEVEL 3 +#define NE2000_BYTE volatile unsigned short +#endif + +#if defined(CONFIG_M5407) +#define NE2000_ADDR 0x40000300 +#define NE2000_ODDOFFSET 0x00010000 +#define NE2000_IRQ_VECTOR 0x1b +#define NE2000_BYTE volatile unsigned short +#endif + +/****************************************************************************/ + +/* + * Side-band address space for odd address requires re-mapping + * many of the standard ISA access functions. + */ +#ifdef NE2000_ODDOFFSET + +#undef outb +#undef outb_p +#undef inb +#undef inb_p +#undef outsb +#undef outsw +#undef insb +#undef insw + +#define outb ne2000_outb +#define inb ne2000_inb +#define outb_p ne2000_outb +#define inb_p ne2000_inb +#define outsb ne2000_outsb +#define outsw ne2000_outsw +#define insb ne2000_insb +#define insw ne2000_insw + + +#ifndef COLDFIRE_NE2000_FUNCS + +void ne2000_outb(unsigned int val, unsigned int addr); +int ne2000_inb(unsigned int addr); +void ne2000_insb(unsigned int addr, void *vbuf, int unsigned long len); +void ne2000_insw(unsigned int addr, void *vbuf, unsigned long len); +void ne2000_outsb(unsigned int addr, void *vbuf, unsigned long len); +void ne2000_outsw(unsigned int addr, void *vbuf, unsigned long len); + +#else + +/* + * This macro converts a conventional register address into the + * real memory pointer of the mapped NE2000 device. + * On most NE2000 implementations on ColdFire boards the chip is + * mapped in kinda funny, due to its ISA heritage. + */ +#ifdef CONFIG_CFV240 +#define NE2000_PTR(addr) (NE2000_ADDR + ((addr & 0x3f) << 1) + 1) +#define NE2000_DATA_PTR(addr) (NE2000_ADDR + ((addr & 0x3f) << 1)) +#else +#define NE2000_PTR(addr) ((addr&0x1)?(NE2000_ODDOFFSET+addr-1):(addr)) +#define NE2000_DATA_PTR(addr) (addr) +#endif + + +void ne2000_outb(unsigned int val, unsigned int addr) +{ + NE2000_BYTE *rp; + + rp = (NE2000_BYTE *) NE2000_PTR(addr); + *rp = RSWAP(val); +} + +int ne2000_inb(unsigned int addr) +{ + NE2000_BYTE *rp, val; + + rp = (NE2000_BYTE *) NE2000_PTR(addr); + val = *rp; + return((int) ((NE2000_BYTE) RSWAP(val))); +} + +void ne2000_insb(unsigned int addr, void *vbuf, int unsigned long len) +{ + NE2000_BYTE *rp, val; + unsigned char *buf; + + buf = (unsigned char *) vbuf; + rp = (NE2000_BYTE *) NE2000_DATA_PTR(addr); + for (; (len > 0); len--) { + val = *rp; + *buf++ = RSWAP(val); + } +} + +void ne2000_insw(unsigned int addr, void *vbuf, unsigned long len) +{ + volatile unsigned short *rp; + unsigned short w, *buf; + + buf = (unsigned short *) vbuf; + rp = (volatile unsigned short *) NE2000_DATA_PTR(addr); + for (; (len > 0); len--) { + w = *rp; + *buf++ = BSWAP(w); + } +} + +void ne2000_outsb(unsigned int addr, const void *vbuf, unsigned long len) +{ + NE2000_BYTE *rp, val; + unsigned char *buf; + + buf = (unsigned char *) vbuf; + rp = (NE2000_BYTE *) NE2000_DATA_PTR(addr); + for (; (len > 0); len--) { + val = *buf++; + *rp = RSWAP(val); + } +} + +void ne2000_outsw(unsigned int addr, const void *vbuf, unsigned long len) +{ + volatile unsigned short *rp; + unsigned short w, *buf; + + buf = (unsigned short *) vbuf; + rp = (volatile unsigned short *) NE2000_DATA_PTR(addr); + for (; (len > 0); len--) { + w = *buf++; + *rp = BSWAP(w); + } +} + +#endif /* COLDFIRE_NE2000_FUNCS */ +#endif /* NE2000_OFFOFFSET */ + +/****************************************************************************/ + +#ifdef COLDFIRE_NE2000_FUNCS + +/* + * Lastly the interrupt set up code... + * Minor diferences between the different board types. + */ + +#if defined(CONFIG_M5206) && defined(CONFIG_ARNEWSH) +void ne2000_irqsetup(int irq) +{ + volatile unsigned char *icrp; + + icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_ICR4); + *icrp = MCFSIM_ICR_LEVEL4 | MCFSIM_ICR_PRI2; + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_EINT4); +} +#endif + +#if defined(CONFIG_M5206e) && defined(CONFIG_MOTOROLA) +void ne2000_irqsetup(int irq) +{ + volatile unsigned char *icrp; + + icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_ICR4); + *icrp = MCFSIM_ICR_LEVEL4 | MCFSIM_ICR_PRI2 | MCFSIM_ICR_AUTOVEC; + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_EINT4); +} +#endif + +#if defined(CONFIG_M5206e) && defined(CONFIG_CFV240) +void ne2000_irqsetup(int irq) +{ + volatile unsigned char *icrp; + + icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_ICR1); + *icrp = MCFSIM_ICR_LEVEL1 | MCFSIM_ICR_PRI2 | MCFSIM_ICR_AUTOVEC; + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_EINT1); +} +#endif + +#if defined(CONFIG_M5206e) && defined(CONFIG_NETtel) +void ne2000_irqsetup(int irq) +{ + mcf_autovector(irq); +} +#endif + +#if defined(CONFIG_M5272) && defined(CONFIG_NETtel) +void ne2000_irqsetup(int irq) +{ + volatile unsigned long *icrp; + volatile unsigned long *pitr; + + /* The NE2000 device uses external IRQ3 */ + icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); + *icrp = (*icrp & 0x77077777) | 0x00d00000; + + pitr = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PITR); + *pitr = *pitr | 0x20000000; +} + +void ne2000_irqack(int irq) +{ + volatile unsigned long *icrp; + + /* The NE2000 device uses external IRQ3 */ + icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1); + *icrp = (*icrp & 0x77777777) | 0x00800000; +} +#endif + +#if defined(CONFIG_M5307) || defined(CONFIG_M5407) +#if defined(CONFIG_NETtel) || defined(CONFIG_SECUREEDGEMP3) + +void ne2000_irqsetup(int irq) +{ + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_EINT3); + mcf_autovector(irq); +} + +#else + +void ne2000_irqsetup(int irq) +{ + mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_EINT3); +} + +#endif /* ! CONFIG_NETtel || CONFIG_SECUREEDGEMP3 */ +#endif /* CONFIG_M5307 || CONFIG_M5407 */ + +#endif /* COLDFIRE_NE2000_FUNCS */ + +/****************************************************************************/ +#endif /* mcfne_h */ diff -Nru a/include/asm-m68knommu/mcfpci.h b/include/asm-m68knommu/mcfpci.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/mcfpci.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,120 @@ +/****************************************************************************/ + +/* + * mcfpci.h -- PCI bridge on ColdFire eval boards. + * + * (C) Copyright 2000, Greg Ungerer (gerg@snapgear.com) + * (C) Copyright 2000, Lineo Inc. (www.lineo.com) + */ + +/****************************************************************************/ +#ifndef mcfpci_h +#define mcfpci_h +/****************************************************************************/ + +#include + +#ifdef CONFIG_PCI + +/* + * Address regions in the PCI addres space are not mapped into the + * normal memory space of the ColdFire. They must be accessed via + * handler routines. This is easy for I/O space (inb/outb/etc) but + * needs some code changes to support ordinary memory. Interrupts + * also need to be vectored through the PCI handler first, then it + * will call the actual driver sub-handlers. + */ + +/* + * Un-define all the standard I/O access routines. + */ +#undef inb +#undef inw +#undef inl +#undef inb_p +#undef inw_p +#undef insb +#undef insw +#undef insl +#undef outb +#undef outw +#undef outl +#undef outb_p +#undef outw_p +#undef outsb +#undef outsw +#undef outsl + +#undef request_irq +#undef free_irq + +#undef bus_to_virt +#undef virt_to_bus + + +/* + * Re-direct all I/O memory accesses functions to PCI specific ones. + */ +#define inb pci_inb +#define inw pci_inw +#define inl pci_inl +#define inb_p pci_inb +#define inw_p pci_inw +#define insb pci_insb +#define insw pci_insw +#define insl pci_insl + +#define outb pci_outb +#define outw pci_outw +#define outl pci_outl +#define outb_p pci_outb +#define outw_p pci_outw +#define outsb pci_outsb +#define outsw pci_outsw +#define outsl pci_outsl + +#define request_irq pci_request_irq +#define free_irq pci_free_irq + +#define virt_to_bus pci_virt_to_bus +#define bus_to_virt pci_bus_to_virt + +#define CONFIG_COMEMPCI 1 + + +/* + * Prototypes of the real PCI functions (defined in bios32.c). + */ +unsigned char pci_inb(unsigned int addr); +unsigned short pci_inw(unsigned int addr); +unsigned int pci_inl(unsigned int addr); +void pci_insb(void *addr, void *buf, int len); +void pci_insw(void *addr, void *buf, int len); +void pci_insl(void *addr, void *buf, int len); + +void pci_outb(unsigned char val, unsigned int addr); +void pci_outw(unsigned short val, unsigned int addr); +void pci_outl(unsigned int val, unsigned int addr); +void pci_outsb(void *addr, void *buf, int len); +void pci_outsw(void *addr, void *buf, int len); +void pci_outsl(void *addr, void *buf, int len); + +int pci_request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, + const char *device, + void *dev_id); +void pci_free_irq(unsigned int irq, void *dev_id); + +void *pci_bmalloc(int size); +void pci_bmfree(void *bmp, int len); +void pci_copytoshmem(unsigned long bmp, void *src, int size); +void pci_copyfromshmem(void *dst, unsigned long bmp, int size); +unsigned long pci_virt_to_bus(volatile void *address); +void *pci_bus_to_virt(unsigned long address); +void pci_bmcpyto(void *dst, void *src, int len); +void pci_bmcpyfrom(void *dst, void *src, int len); + +#endif /* CONFIG_PCI */ +/****************************************************************************/ +#endif /* mcfpci_h */ diff -Nru a/include/asm-m68knommu/mcfsim.h b/include/asm-m68knommu/mcfsim.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/mcfsim.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,104 @@ +/****************************************************************************/ + +/* + * mcfsim.h -- ColdFire System Integration Module support. + * + * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com) + * (C) Copyright 2000, Lineo Inc. (www.lineo.com) + */ + +/****************************************************************************/ +#ifndef mcfsim_h +#define mcfsim_h +/****************************************************************************/ + +#include + +/* + * Include 5204, 5206, 5249, 5272, 5307 or 5407 specific addresses. + */ +#if defined(CONFIG_M5204) +#include +#elif defined(CONFIG_M5206) || defined(CONFIG_M5206e) +#include +#elif defined(CONFIG_M5249) +#include +#elif defined(CONFIG_M5272) +#include +#elif defined(CONFIG_M5307) +#include +#elif defined(CONFIG_M5407) +#include +#endif + + +/* + * Define the base address of the SIM within the MBAR address space. + */ +#define MCFSIM_BASE 0x0 /* Base address of SIM */ + + +/* + * Bit definitions for the ICR family of registers. + */ +#define MCFSIM_ICR_AUTOVEC 0x80 /* Auto-vectored intr */ +#define MCFSIM_ICR_LEVEL0 0x00 /* Level 0 intr */ +#define MCFSIM_ICR_LEVEL1 0x04 /* Level 1 intr */ +#define MCFSIM_ICR_LEVEL2 0x08 /* Level 2 intr */ +#define MCFSIM_ICR_LEVEL3 0x0c /* Level 3 intr */ +#define MCFSIM_ICR_LEVEL4 0x10 /* Level 4 intr */ +#define MCFSIM_ICR_LEVEL5 0x14 /* Level 5 intr */ +#define MCFSIM_ICR_LEVEL6 0x18 /* Level 6 intr */ +#define MCFSIM_ICR_LEVEL7 0x1c /* Level 7 intr */ + +#define MCFSIM_ICR_PRI0 0x00 /* Priority 0 intr */ +#define MCFSIM_ICR_PRI1 0x01 /* Priority 1 intr */ +#define MCFSIM_ICR_PRI2 0x02 /* Priority 2 intr */ +#define MCFSIM_ICR_PRI3 0x03 /* Priority 3 intr */ + +/* + * Bit definitions for the Interrupt Mask register (IMR). + */ +#define MCFSIM_IMR_EINT1 0x0002 /* External intr # 1 */ +#define MCFSIM_IMR_EINT2 0x0004 /* External intr # 2 */ +#define MCFSIM_IMR_EINT3 0x0008 /* External intr # 3 */ +#define MCFSIM_IMR_EINT4 0x0010 /* External intr # 4 */ +#define MCFSIM_IMR_EINT5 0x0020 /* External intr # 5 */ +#define MCFSIM_IMR_EINT6 0x0040 /* External intr # 6 */ +#define MCFSIM_IMR_EINT7 0x0080 /* External intr # 7 */ + +#define MCFSIM_IMR_SWD 0x0100 /* Software Watchdog intr */ +#define MCFSIM_IMR_TIMER1 0x0200 /* TIMER 1 intr */ +#define MCFSIM_IMR_TIMER2 0x0400 /* TIMER 2 intr */ +#define MCFSIM_IMR_MBUS 0x0800 /* MBUS intr */ +#define MCFSIM_IMR_UART1 0x1000 /* UART 1 intr */ +#define MCFSIM_IMR_UART2 0x2000 /* UART 2 intr */ + +#if defined(CONFIG_M5206e) +#define MCFSIM_IMR_DMA1 0x4000 /* DMA 1 intr */ +#define MCFSIM_IMR_DMA2 0x8000 /* DMA 2 intr */ +#elif defined(CONFIG_M5249) || defined(CONFIG_M5307) +#define MCFSIM_IMR_DMA0 0x4000 /* DMA 0 intr */ +#define MCFSIM_IMR_DMA1 0x8000 /* DMA 1 intr */ +#define MCFSIM_IMR_DMA2 0x10000 /* DMA 2 intr */ +#define MCFSIM_IMR_DMA3 0x20000 /* DMA 3 intr */ +#endif + +/* + * Mask for all of the SIM devices. Some parts have more or less + * SIM devices. This is a catchall for the sandard set. + */ +#ifndef MCFSIM_IMR_MASKALL +#define MCFSIM_IMR_MASKALL 0x3ffe /* All intr sources */ +#endif + + +#ifndef __ASSEMBLY__ +/* + * Definition for the interrupt auto-vectoring support. + */ +extern void mcf_autovector(unsigned int vec); +#endif /* __ASSEMBLY__ */ + +/****************************************************************************/ +#endif /* mcfsim_h */ diff -Nru a/include/asm-m68knommu/mcfsmc.h b/include/asm-m68knommu/mcfsmc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/mcfsmc.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,176 @@ +/****************************************************************************/ + +/* + * mcfsmc.h -- SMC ethernet support for ColdFire environments. + * + * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com) + * (C) Copyright 2000, Lineo Inc. (www.lineo.com) + */ + +/****************************************************************************/ +#ifndef mcfsmc_h +#define mcfsmc_h +/****************************************************************************/ + +/* + * None of the current ColdFire targets that use the SMC91x111 + * allow 8 bit accesses. So this code is 16bit access only. + */ + +#include + +#undef outb +#undef inb + +/* + * Re-defines for ColdFire environment... The SMC part is + * mapped into memory space, so remap the PC-style in/out + * routines to handle that. + */ +#define outb smc_outb +#define inb smc_inb +#define outw smc_outw +#define outwd smc_outwd +#define inw smc_inw +#define outl smc_outl +#define inl smc_inl + +#define outsb smc_outsb +#define outsw smc_outsw +#define outsl smc_outsl +#define insb smc_insb +#define insw smc_insw +#define insl smc_insl + + +static inline int smc_inb(unsigned int addr) +{ + register unsigned short w; + w = *((volatile unsigned short *) (addr & ~0x1)); + return(((addr & 0x1) ? w : (w >> 8)) & 0xff); +} + +static inline void smc_outw(unsigned int val, unsigned int addr) +{ + *((volatile unsigned short *) addr) = (val << 8) | (val >> 8); +} + +static inline int smc_inw(unsigned int addr) +{ + register unsigned short w; + w = *((volatile unsigned short *) addr); + return(((w << 8) | (w >> 8)) & 0xffff); +} + +static inline void smc_outl(unsigned long val, unsigned int addr) +{ + *((volatile unsigned long *) addr) = + ((val << 8) & 0xff000000) | ((val >> 8) & 0x00ff0000) | + ((val << 8) & 0x0000ff00) | ((val >> 8) & 0x000000ff); +} + +static inline void smc_outwd(unsigned int val, unsigned int addr) +{ + *((volatile unsigned short *) addr) = val; +} + + +/* + * The rep* functions are used to feed the data port with + * raw data. So we do not byte swap them when copying. + */ + +static inline void smc_insb(unsigned int addr, void *vbuf, int unsigned long len) +{ + volatile unsigned short *rp; + unsigned short *buf, *ebuf; + + buf = (unsigned short *) vbuf; + rp = (volatile unsigned short *) addr; + + /* Copy as words for as long as possible */ + for (ebuf = buf + (len >> 1); (buf < ebuf); ) + *buf++ = *rp; + + /* Lastly, handle left over byte */ + if (len & 0x1) + *((unsigned char *) buf) = (*rp >> 8) & 0xff; +} + +static inline void smc_insw(unsigned int addr, void *vbuf, unsigned long len) +{ + volatile unsigned short *rp; + unsigned short *buf, *ebuf; + + buf = (unsigned short *) vbuf; + rp = (volatile unsigned short *) addr; + for (ebuf = buf + len; (buf < ebuf); ) + *buf++ = *rp; +} + +static inline void smc_insl(unsigned int addr, void *vbuf, unsigned long len) +{ + volatile unsigned long *rp; + unsigned long *buf, *ebuf; + + buf = (unsigned long *) vbuf; + rp = (volatile unsigned long *) addr; + for (ebuf = buf + len; (buf < ebuf); ) + *buf++ = *rp; +} + +static inline void smc_outsw(unsigned int addr, const void *vbuf, unsigned long len) +{ + volatile unsigned short *rp; + unsigned short *buf, *ebuf; + + buf = (unsigned short *) vbuf; + rp = (volatile unsigned short *) addr; + for (ebuf = buf + len; (buf < ebuf); ) + *rp = *buf++; +} + +static inline void smc_outsl(unsigned int addr, void *vbuf, unsigned long len) +{ + volatile unsigned long *rp; + unsigned long *buf, *ebuf; + + buf = (unsigned long *) vbuf; + rp = (volatile unsigned long *) addr; + for (ebuf = buf + len; (buf < ebuf); ) + *rp = *buf++; +} + + +#ifdef CONFIG_NETtel +/* + * Re-map the address space of at least one of the SMC ethernet + * parts. Both parts power up decoding the same address, so we + * need to move one of them first, before doing enything else. + * + * We also increase the number of wait states for this part by one. + */ + +void smc_remap(unsigned int ioaddr) +{ + static int once = 0; + extern unsigned short ppdata; + if (once++ == 0) { + *((volatile unsigned short *)(MCF_MBAR+MCFSIM_PADDR)) = 0x00ec; + ppdata |= 0x0080; + *((volatile unsigned short *)(MCF_MBAR+MCFSIM_PADAT)) = ppdata; + outw(0x0001, ioaddr + BANK_SELECT); + outw(0x0001, ioaddr + BANK_SELECT); + outw(0x0067, ioaddr + BASE); + + ppdata &= ~0x0080; + *((volatile unsigned short *)(MCF_MBAR+MCFSIM_PADAT)) = ppdata; + } + + *((volatile unsigned short *)(MCF_MBAR+MCFSIM_CSCR3)) = 0x1180; +} + +#endif + +/****************************************************************************/ +#endif /* mcfsmc_h */ diff -Nru a/include/asm-m68knommu/mcftimer.h b/include/asm-m68knommu/mcftimer.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/mcftimer.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,73 @@ +/****************************************************************************/ + +/* + * mcftimer.h -- ColdFire internal TIMER support defines. + * + * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com) + * (C) Copyright 2000, Lineo Inc. (www.lineo.com) + */ + +/****************************************************************************/ +#ifndef mcftimer_h +#define mcftimer_h +/****************************************************************************/ + +#include + +/* + * Get address specific defines for this ColdFire member. + */ +#if defined(CONFIG_M5204) || defined(CONFIG_M5206) || defined(CONFIG_M5206e) +#define MCFTIMER_BASE1 0x100 /* Base address of TIMER1 */ +#define MCFTIMER_BASE2 0x120 /* Base address of TIMER2 */ +#elif defined(CONFIG_M5272) +#define MCFTIMER_BASE1 0x200 /* Base address of TIMER1 */ +#define MCFTIMER_BASE2 0x220 /* Base address of TIMER2 */ +#define MCFTIMER_BASE3 0x240 /* Base address of TIMER4 */ +#define MCFTIMER_BASE4 0x260 /* Base address of TIMER3 */ +#elif defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407) +#define MCFTIMER_BASE1 0x140 /* Base address of TIMER1 */ +#define MCFTIMER_BASE2 0x180 /* Base address of TIMER2 */ +#endif + + +/* + * Define the TIMER register set addresses. + */ +#define MCFTIMER_TMR 0x00 /* Timer Mode reg (r/w) */ +#define MCFTIMER_TRR 0x02 /* Timer Reference (r/w) */ +#define MCFTIMER_TCR 0x04 /* Timer Capture reg (r/w) */ +#define MCFTIMER_TCN 0x06 /* Timer Counter reg (r/w) */ +#define MCFTIMER_TER 0x11 /* Timer Event reg (r/w) */ + + +/* + * Bit definitions for the Timer Mode Register (TMR). + * Register bit flags are common accross ColdFires. + */ +#define MCFTIMER_TMR_PREMASK 0xff00 /* Prescalar mask */ +#define MCFTIMER_TMR_DISCE 0x0000 /* Disable capture */ +#define MCFTIMER_TMR_ANYCE 0x00c0 /* Capture any edge */ +#define MCFTIMER_TMR_FALLCE 0x0080 /* Capture fallingedge */ +#define MCFTIMER_TMR_RISECE 0x0040 /* Capture rising edge */ +#define MCFTIMER_TMR_ENOM 0x0020 /* Enable output toggle */ +#define MCFTIMER_TMR_DISOM 0x0000 /* Do single output pulse */ +#define MCFTIMER_TMR_ENORI 0x0010 /* Enable ref interrupt */ +#define MCFTIMER_TMR_DISORI 0x0000 /* Disable ref interrupt */ +#define MCFTIMER_TMR_RESTART 0x0008 /* Restart counter */ +#define MCFTIMER_TMR_FREERUN 0x0000 /* Free running counter */ +#define MCFTIMER_TMR_CLKTIN 0x0006 /* Input clock is TIN */ +#define MCFTIMER_TMR_CLK16 0x0004 /* Input clock is /16 */ +#define MCFTIMER_TMR_CLK1 0x0002 /* Input clock is /1 */ +#define MCFTIMER_TMR_CLKSTOP 0x0000 /* Stop counter */ +#define MCFTIMER_TMR_ENABLE 0x0001 /* Enable timer */ +#define MCFTIMER_TMR_DISABLE 0x0000 /* Disable timer */ + +/* + * Bit definitions for the Timer Event Registers (TER). + */ +#define MCFTIMER_TER_CAP 0x01 /* Capture event */ +#define MCFTIMER_TER_REF 0x02 /* Refernece event */ + +/****************************************************************************/ +#endif /* mcftimer_h */ diff -Nru a/include/asm-m68knommu/mcfuart.h b/include/asm-m68knommu/mcfuart.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/mcfuart.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,174 @@ +/****************************************************************************/ + +/* + * mcfuart.h -- ColdFire internal UART support defines. + * + * (C) Copyright 1999-2002, Greg Ungerer (gerg@snapgear.com) + * (C) Copyright 2000, Lineo Inc. (www.lineo.com) + */ + +/****************************************************************************/ +#ifndef mcfuart_h +#define mcfuart_h +/****************************************************************************/ + +#include + +/* + * Define the base address of the UARTS within the MBAR address + * space. + */ +#if defined(CONFIG_M5272) +#define MCFUART_BASE1 0x100 /* Base address of UART1 */ +#define MCFUART_BASE2 0x140 /* Base address of UART2 */ +#elif defined(CONFIG_M5204) || defined(CONFIG_M5206) || defined(CONFIG_M5206e) +#if defined(CONFIG_NETtel) +#define MCFUART_BASE1 0x180 /* Base address of UART1 */ +#define MCFUART_BASE2 0x140 /* Base address of UART2 */ +#else +#define MCFUART_BASE1 0x140 /* Base address of UART1 */ +#define MCFUART_BASE2 0x180 /* Base address of UART2 */ +#endif +#elif defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407) +#if defined(CONFIG_NETtel) || defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) +#define MCFUART_BASE1 0x200 /* Base address of UART1 */ +#define MCFUART_BASE2 0x1c0 /* Base address of UART2 */ +#else +#define MCFUART_BASE1 0x1c0 /* Base address of UART1 */ +#define MCFUART_BASE2 0x200 /* Base address of UART2 */ +#endif +#endif + + +/* + * Define the ColdFire UART register set addresses. + */ +#define MCFUART_UMR 0x00 /* Mode register (r/w) */ +#define MCFUART_USR 0x04 /* Status register (r) */ +#define MCFUART_UCSR 0x04 /* Clock Select (w) */ +#define MCFUART_UCR 0x08 /* Command register (w) */ +#define MCFUART_URB 0x0c /* Receiver Buffer (r) */ +#define MCFUART_UTB 0x0c /* Transmit Buffer (w) */ +#define MCFUART_UIPCR 0x10 /* Input Port Change (r) */ +#define MCFUART_UACR 0x10 /* Auxiliary Control (w) */ +#define MCFUART_UISR 0x14 /* Interrup Status (r) */ +#define MCFUART_UIMR 0x14 /* Interrupt Mask (w) */ +#define MCFUART_UBG1 0x18 /* Baud Rate MSB (r/w) */ +#define MCFUART_UBG2 0x1c /* Baud Rate LSB (r/w) */ +#define MCFUART_UIVR 0x30 /* Interrupt Vector (r/w) */ +#define MCFUART_UIPR 0x34 /* Input Port (r) */ +#define MCFUART_UOP1 0x38 /* Output Port Bit Set (w) */ +#define MCFUART_UOP0 0x3c /* Output Port Bit Reset (w) */ + + +/* + * Define bit flags in Mode Register 1 (MR1). + */ +#define MCFUART_MR1_RXRTS 0x80 /* Auto RTS flow control */ +#define MCFUART_MR1_RXIRQFULL 0x40 /* RX IRQ type FULL */ +#define MCFUART_MR1_RXIRQRDY 0x00 /* RX IRQ type RDY */ +#define MCFUART_MR1_RXERRBLOCK 0x20 /* RX block error mode */ +#define MCFUART_MR1_RXERRCHAR 0x00 /* RX char error mode */ + +#define MCFUART_MR1_PARITYNONE 0x10 /* No parity */ +#define MCFUART_MR1_PARITYEVEN 0x00 /* Even parity */ +#define MCFUART_MR1_PARITYODD 0x04 /* Odd parity */ +#define MCFUART_MR1_PARITYSPACE 0x08 /* Space parity */ +#define MCFUART_MR1_PARITYMARK 0x06 /* Mark parity */ + +#define MCFUART_MR1_CS5 0x00 /* 5 bits per char */ +#define MCFUART_MR1_CS6 0x01 /* 6 bits per char */ +#define MCFUART_MR1_CS7 0x02 /* 7 bits per char */ +#define MCFUART_MR1_CS8 0x03 /* 8 bits per char */ + +/* + * Define bit flags in Mode Register 2 (MR2). + */ +#define MCFUART_MR2_LOOPBACK 0x80 /* Loopback mode */ +#define MCFUART_MR2_REMOTELOOP 0xc0 /* Remote loopback mode */ +#define MCFUART_MR2_AUTOECHO 0x40 /* Automatic echo */ +#define MCFUART_MR2_TXRTS 0x20 /* Assert RTS on TX */ +#define MCFUART_MR2_TXCTS 0x10 /* Auto CTS flow control */ + +#define MCFUART_MR2_STOP1 0x07 /* 1 stop bit */ +#define MCFUART_MR2_STOP15 0x08 /* 1.5 stop bits */ +#define MCFUART_MR2_STOP2 0x0f /* 2 stop bits */ + +/* + * Define bit flags in Status Register (USR). + */ +#define MCFUART_USR_RXBREAK 0x80 /* Received BREAK */ +#define MCFUART_USR_RXFRAMING 0x40 /* Received framing error */ +#define MCFUART_USR_RXPARITY 0x20 /* Received parity error */ +#define MCFUART_USR_RXOVERRUN 0x10 /* Received overrun error */ +#define MCFUART_USR_TXEMPTY 0x08 /* Transmitter empty */ +#define MCFUART_USR_TXREADY 0x04 /* Transmitter ready */ +#define MCFUART_USR_RXFULL 0x02 /* Receiver full */ +#define MCFUART_USR_RXREADY 0x01 /* Receiver ready */ + +#define MCFUART_USR_RXERR (MCFUART_USR_RXBREAK | MCFUART_USR_RXFRAMING | \ + MCFUART_USR_RXPARITY | MCFUART_USR_RXOVERRUN) + +/* + * Define bit flags in Clock Select Register (UCSR). + */ +#define MCFUART_UCSR_RXCLKTIMER 0xd0 /* RX clock is timer */ +#define MCFUART_UCSR_RXCLKEXT16 0xe0 /* RX clock is external x16 */ +#define MCFUART_UCSR_RXCLKEXT1 0xf0 /* RX clock is external x1 */ + +#define MCFUART_UCSR_TXCLKTIMER 0x0d /* TX clock is timer */ +#define MCFUART_UCSR_TXCLKEXT16 0x0e /* TX clock is external x16 */ +#define MCFUART_UCSR_TXCLKEXT1 0x0f /* TX clock is external x1 */ + +/* + * Define bit flags in Command Register (UCR). + */ +#define MCFUART_UCR_CMDNULL 0x00 /* No command */ +#define MCFUART_UCR_CMDRESETMRPTR 0x10 /* Reset MR pointer */ +#define MCFUART_UCR_CMDRESETRX 0x20 /* Reset receiver */ +#define MCFUART_UCR_CMDRESETTX 0x30 /* Reset transmitter */ +#define MCFUART_UCR_CMDRESETERR 0x40 /* Reset error status */ +#define MCFUART_UCR_CMDRESETBREAK 0x50 /* Reset BREAK change */ +#define MCFUART_UCR_CMDBREAKSTART 0x60 /* Start BREAK */ +#define MCFUART_UCR_CMDBREAKSTOP 0x70 /* Stop BREAK */ + +#define MCFUART_UCR_TXNULL 0x00 /* No TX command */ +#define MCFUART_UCR_TXENABLE 0x04 /* Enable TX */ +#define MCFUART_UCR_TXDISABLE 0x08 /* Disable TX */ +#define MCFUART_UCR_RXNULL 0x00 /* No RX command */ +#define MCFUART_UCR_RXENABLE 0x01 /* Enable RX */ +#define MCFUART_UCR_RXDISABLE 0x02 /* Disable RX */ + +/* + * Define bit flags in Input Port Change Register (UIPCR). + */ +#define MCFUART_UIPCR_CTSCOS 0x10 /* CTS change of state */ +#define MCFUART_UIPCR_CTS 0x01 /* CTS value */ + +/* + * Define bit flags in Input Port Register (UIP). + */ +#define MCFUART_UIPR_CTS 0x01 /* CTS value */ + +/* + * Define bit flags in Output Port Registers (UOP). + * Clear bit by writing to UOP0, set by writing to UOP1. + */ +#define MCFUART_UOP_RTS 0x01 /* RTS set or clear */ + +/* + * Define bit flags in the Auxiliary Control Register (UACR). + */ +#define MCFUART_UACR_IEC 0x01 /* Input enable control */ + +/* + * Define bit flags in Interrupt Status Register (UISR). + * These same bits are used for the Interrupt Mask Register (UIMR). + */ +#define MCFUART_UIR_COS 0x80 /* Change of state (CTS) */ +#define MCFUART_UIR_DELTABREAK 0x04 /* Break start or stop */ +#define MCFUART_UIR_RXREADY 0x02 /* Receiver ready */ +#define MCFUART_UIR_TXREADY 0x01 /* Transmitter ready */ + +/****************************************************************************/ +#endif /* mcfuart_h */ diff -Nru a/include/asm-m68knommu/mcfwdebug.h b/include/asm-m68knommu/mcfwdebug.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/mcfwdebug.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,119 @@ +/****************************************************************************/ + +/* + * mcfdebug.h -- ColdFire Debug Module support. + * + * (C) Copyright 2001, Lineo Inc. (www.lineo.com) + */ + +/****************************************************************************/ +#ifndef mcfdebug_h +#define mcfdebug_h +/****************************************************************************/ +#include + +/* Define the debug module registers */ +#define MCFDEBUG_CSR 0x0 /* Configuration status */ +#define MCFDEBUG_BAAR 0x5 /* BDM address attribute */ +#define MCFDEBUG_AATR 0x6 /* Address attribute trigger */ +#define MCFDEBUG_TDR 0x7 /* Trigger definition */ +#define MCFDEBUG_PBR 0x8 /* PC breakpoint */ +#define MCFDEBUG_PBMR 0x9 /* PC breakpoint mask */ +#define MCFDEBUG_ABHR 0xc /* High address breakpoint */ +#define MCFDEBUG_ABLR 0xd /* Low address breakpoint */ +#define MCFDEBUG_DBR 0xe /* Data breakpoint */ +#define MCFDEBUG_DBMR 0xf /* Data breakpoint mask */ + +/* Define some handy constants for the trigger definition register */ +#define MCFDEBUG_TDR_TRC_DISP 0x00000000 /* display on DDATA only */ +#define MCFDEBUG_TDR_TRC_HALT 0x40000000 /* Processor halt on BP */ +#define MCFDEBUG_TDR_TRC_INTR 0x80000000 /* Debug intr on BP */ +#define MCFDEBUG_TDR_LXT1 0x00004000 /* TDR level 1 */ +#define MCFDEBUG_TDR_LXT2 0x00008000 /* TDR level 2 */ +#define MCFDEBUG_TDR_EBL1 0x00002000 /* Enable breakpoint level 1 */ +#define MCFDEBUG_TDR_EBL2 0x20000000 /* Enable breakpoint level 2 */ +#define MCFDEBUG_TDR_EDLW1 0x00001000 /* Enable data BP longword */ +#define MCFDEBUG_TDR_EDLW2 0x10000000 +#define MCFDEBUG_TDR_EDWL1 0x00000800 /* Enable data BP lower word */ +#define MCFDEBUG_TDR_EDWL2 0x08000000 +#define MCFDEBUG_TDR_EDWU1 0x00000400 /* Enable data BP upper word */ +#define MCFDEBUG_TDR_EDWU2 0x04000000 +#define MCFDEBUG_TDR_EDLL1 0x00000200 /* Enable data BP low low byte */ +#define MCFDEBUG_TDR_EDLL2 0x02000000 +#define MCFDEBUG_TDR_EDLM1 0x00000100 /* Enable data BP low mid byte */ +#define MCFDEBUG_TDR_EDLM2 0x01000000 +#define MCFDEBUG_TDR_EDUM1 0x00000080 /* Enable data BP up mid byte */ +#define MCFDEBUG_TDR_EDUM2 0x00800000 +#define MCFDEBUG_TDR_EDUU1 0x00000040 /* Enable data BP up up byte */ +#define MCFDEBUG_TDR_EDUU2 0x00400000 +#define MCFDEBUG_TDR_DI1 0x00000020 /* Data BP invert */ +#define MCFDEBUG_TDR_DI2 0x00200000 +#define MCFDEBUG_TDR_EAI1 0x00000010 /* Enable address BP inverted */ +#define MCFDEBUG_TDR_EAI2 0x00100000 +#define MCFDEBUG_TDR_EAR1 0x00000008 /* Enable address BP range */ +#define MCFDEBUG_TDR_EAR2 0x00080000 +#define MCFDEBUG_TDR_EAL1 0x00000004 /* Enable address BP low */ +#define MCFDEBUG_TDR_EAL2 0x00040000 +#define MCFDEBUG_TDR_EPC1 0x00000002 /* Enable PC BP */ +#define MCFDEBUG_TDR_EPC2 0x00020000 +#define MCFDEBUG_TDR_PCI1 0x00000001 /* PC BP invert */ +#define MCFDEBUG_TDR_PCI2 0x00010000 + +/* Constants for the address attribute trigger register */ +#define MCFDEBUG_AAR_RESET 0x00000005 +/* Fields not yet implemented */ + +/* And some definitions for the writable sections of the CSR */ +#define MCFDEBUG_CSR_RESET 0x00100000 +#define MCFDEBUG_CSR_PSTCLK 0x00020000 /* PSTCLK disable */ +#define MCFDEBUG_CSR_IPW 0x00010000 /* Inhibit processor writes */ +#define MCFDEBUG_CSR_MAP 0x00008000 /* Processor refs in emul mode */ +#define MCFDEBUG_CSR_TRC 0x00004000 /* Emul mode on trace exception */ +#define MCFDEBUG_CSR_EMU 0x00002000 /* Force emulation mode */ +#define MCFDEBUG_CSR_DDC_READ 0x00000800 /* Debug data control */ +#define MCFDEBUG_CSR_DDC_WRITE 0x00001000 +#define MCFDEBUG_CSR_UHE 0x00000400 /* User mode halt enable */ +#define MCFDEBUG_CSR_BTB0 0x00000000 /* Branch target 0 bytes */ +#define MCFDEBUG_CSR_BTB2 0x00000100 /* Branch target 2 bytes */ +#define MCFDEBUG_CSR_BTB3 0x00000200 /* Branch target 3 bytes */ +#define MCFDEBUG_CSR_BTB4 0x00000300 /* Branch target 4 bytes */ +#define MCFDEBUG_CSR_NPL 0x00000040 /* Non-pipelined mode */ +#define MCFDEBUG_CSR_SSM 0x00000010 /* Single step mode */ + +/* Constants for the BDM address attribute register */ +#define MCFDEBUG_BAAR_RESET 0x00000005 +/* Fields not yet implemented */ + + +/* This routine wrappers up the wdebug asm instruction so that the register + * and value can be relatively easily specified. The biggest hassle here is + * that the debug module instructions (2 longs) must be long word aligned and + * some pointer fiddling is performed to ensure this. + */ +extern inline void wdebug(int reg, unsigned long data) { + unsigned short dbg_spc[6]; + unsigned short *dbg; + + // Force alignment to long word boundary + dbg = (unsigned short *)((((unsigned long)dbg_spc) + 3) & 0xfffffffc); + + // Build up the debug instruction + dbg[0] = 0x2c80 | (reg & 0xf); + dbg[1] = (data >> 16) & 0xffff; + dbg[2] = data & 0xffff; + dbg[3] = 0; + + // Perform the wdebug instruction +#if 0 + // This strain is for gas which doesn't have the wdebug instructions defined + asm( "move.l %0, %%a0\n\t" + ".word 0xfbd0\n\t" + ".word 0x0003\n\t" + :: "g" (dbg) : "a0"); +#else + // And this is for when it does + asm( "wdebug (%0)" :: "a" (dbg)); +#endif +} + +#endif diff -Nru a/include/asm-m68knommu/md.h b/include/asm-m68knommu/md.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/md.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/mman.h b/include/asm-m68knommu/mman.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/mman.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/mmu.h b/include/asm-m68knommu/mmu.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/mmu.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,22 @@ +#ifndef __M68KNOMMU_MMU_H +#define __M68KNOMMU_MMU_H + +/* Copyright (C) 2002, David McCullough */ + +struct mm_rblock_struct { + int size; + int refcount; + void *kblock; +}; + +struct mm_tblock_struct { + struct mm_rblock_struct *rblock; + struct mm_tblock_struct *next; +}; + +typedef struct { + struct mm_tblock_struct tblock; + unsigned long end_brk; +} mm_context_t; + +#endif /* __M68KNOMMU_MMU_H */ diff -Nru a/include/asm-m68knommu/mmu_context.h b/include/asm-m68knommu/mmu_context.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/mmu_context.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,31 @@ +#ifndef __M68KNOMMU_MMU_CONTEXT_H +#define __M68KNOMMU_MMU_CONTEXT_H + +#include +#include +#include +#include + +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +{ +} + +extern inline int +init_new_context(struct task_struct *tsk, struct mm_struct *mm) +{ + // mm->context = virt_to_phys(mm->pgd); + return(0); +} + +#define destroy_context(mm) do { } while(0) + +static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu) +{ +} + +extern inline void activate_mm(struct mm_struct *prev_mm, + struct mm_struct *next_mm) +{ +} + +#endif diff -Nru a/include/asm-m68knommu/module.h b/include/asm-m68knommu/module.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/module.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/movs.h b/include/asm-m68knommu/movs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/movs.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/msgbuf.h b/include/asm-m68knommu/msgbuf.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/msgbuf.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/namei.h b/include/asm-m68knommu/namei.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/namei.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/nap.h b/include/asm-m68knommu/nap.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/nap.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,96 @@ +/****************************************************************************/ + +/* + * nap.h -- Marconi/NAP support. + * + * (C) Copyright 2001, SnapGear (www.snapgear.com) + */ + +/****************************************************************************/ +#ifndef nap_h +#define nap_h +/****************************************************************************/ + +#include + +/****************************************************************************/ +#ifdef CONFIG_MARCONINAP +/****************************************************************************/ + +#ifdef CONFIG_COLDFIRE +#include +#include +#endif + +/* + * Command to support selecting RS232 or RS422 mode on the + * second COM port. + */ +#define TIOCSET422 0x4d01 /* Set port mode 232 or 422 */ +#define TIOCGET422 0x4d02 /* Get current port mode */ + +/* + * Low level control of the RS232/422 enable. + */ +#define MCFPP_PA11 0x0800 + +#ifndef __ASSEMBLY__ +/* + * RS232/422 control is via the single PA11 line. Low is the RS422 + * enable, high is RS232 mode. + */ +static __inline__ unsigned int mcf_getpa(void) +{ + volatile unsigned short *pp; + pp = (volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT); + return((unsigned int) *pp); +} + +static __inline__ void mcf_setpa(unsigned int mask, unsigned int bits) +{ + volatile unsigned short *pp; + unsigned long flags; + + pp = (volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT); + save_flags(flags); cli(); + *pp = (*pp & ~mask) | bits; + restore_flags(flags); +} +#endif /* __ASSEMBLY__ */ + +/****************************************************************************/ + +#if defined(CONFIG_M5272) +/* + * Marconi/NAP based hardware. DTR/DCD lines are wired to GPB lines. + */ +#define MCFPP_DCD0 0x0080 +#define MCFPP_DCD1 0x0020 +#define MCFPP_DTR0 0x0040 +#define MCFPP_DTR1 0x0010 + +#ifndef __ASSEMBLY__ +/* + * These functions defined to give quasi generic access to the + * PPIO bits used for DTR/DCD. + */ +static __inline__ unsigned int mcf_getppdata(void) +{ + volatile unsigned short *pp; + pp = (volatile unsigned short *) (MCF_MBAR + MCFSIM_PBDAT); + return((unsigned int) *pp); +} + +static __inline__ void mcf_setppdata(unsigned int mask, unsigned int bits) +{ + volatile unsigned short *pp; + pp = (volatile unsigned short *) (MCF_MBAR + MCFSIM_PBDAT); + *pp = (*pp & ~mask) | bits; +} +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_M5272 */ + +/****************************************************************************/ +#endif /* CONFIG_MARCONINAP */ +/****************************************************************************/ +#endif /* nap_h */ diff -Nru a/include/asm-m68knommu/nettel.h b/include/asm-m68knommu/nettel.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/nettel.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,109 @@ +/****************************************************************************/ + +/* + * nettel.h -- Lineo (formerly Moreton Bay) NETtel support. + * + * (C) Copyright 1999-2000, Moreton Bay (www.moretonbay.com) + * (C) Copyright 2000-2001, Lineo Inc. (www.lineo.com) + * (C) Copyright 2001-2002, SnapGear Inc., (www.snapgear.com) + */ + +/****************************************************************************/ +#ifndef nettel_h +#define nettel_h +/****************************************************************************/ + +#include + +/****************************************************************************/ +#ifdef CONFIG_NETtel +/****************************************************************************/ + +#ifdef CONFIG_COLDFIRE +#include +#include +#endif + +/*---------------------------------------------------------------------------*/ +#if defined(CONFIG_M5307) +/* + * NETtel/5307 based hardware first. DTR/DCD lines are wired to + * GPIO lines. Most of the LED's are driver through a latch + * connected to CS2. + */ +#define MCFPP_DCD1 0x0001 +#define MCFPP_DCD0 0x0002 +#define MCFPP_DTR1 0x0004 +#define MCFPP_DTR0 0x0008 + +#define NETtel_LEDADDR 0x30400000 + +#ifndef __ASSEMBLY__ + +extern volatile unsigned short ppdata; + +/* + * These functions defined to give quasi generic access to the + * PPIO bits used for DTR/DCD. + */ +static __inline__ unsigned int mcf_getppdata(void) +{ + volatile unsigned short *pp; + pp = (volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT); + return((unsigned int) *pp); +} + +static __inline__ void mcf_setppdata(unsigned int mask, unsigned int bits) +{ + volatile unsigned short *pp; + pp = (volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT); + ppdata = (ppdata & ~mask) | bits; + *pp = ppdata; +} +#endif + +/*---------------------------------------------------------------------------*/ +#elif defined(CONFIG_M5206e) +/* + * NETtel/5206e based hardware has leds on latch on CS3. + * No support modem for lines?? + */ +#define NETtel_LEDADDR 0x50000000 + +/*---------------------------------------------------------------------------*/ +#elif defined(CONFIG_M5272) +/* + * NETtel/5272 based hardware. DTR/DCD lines are wired to GPB lines. + */ +#define MCFPP_DCD0 0x0080 +#define MCFPP_DCD1 0x0000 /* Port 1 no DCD support */ +#define MCFPP_DTR0 0x0040 +#define MCFPP_DTR1 0x0000 /* Port 1 no DTR support */ + +#ifndef __ASSEMBLY__ +/* + * These functions defined to give quasi generic access to the + * PPIO bits used for DTR/DCD. + */ +static __inline__ unsigned int mcf_getppdata(void) +{ + volatile unsigned short *pp; + pp = (volatile unsigned short *) (MCF_MBAR + MCFSIM_PBDAT); + return((unsigned int) *pp); +} + +static __inline__ void mcf_setppdata(unsigned int mask, unsigned int bits) +{ + volatile unsigned short *pp; + pp = (volatile unsigned short *) (MCF_MBAR + MCFSIM_PBDAT); + *pp = (*pp & ~mask) | bits; +} +#endif + +#endif +/*---------------------------------------------------------------------------*/ + +/****************************************************************************/ +#endif /* CONFIG_NETtel */ +/****************************************************************************/ +#endif /* nettel_h */ diff -Nru a/include/asm-m68knommu/openprom.h b/include/asm-m68knommu/openprom.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/openprom.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/oplib.h b/include/asm-m68knommu/oplib.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/oplib.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/page.h b/include/asm-m68knommu/page.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/page.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,123 @@ +#ifndef _M68KNOMMU_PAGE_H +#define _M68KNOMMU_PAGE_H + +#include + +/* PAGE_SHIFT determines the page size */ + +#define PAGE_SHIFT (12) +#define PAGE_SIZE (4096) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#ifdef __KERNEL__ + +#include + +#if !defined(CONFIG_SMALL_TASKS) && PAGE_SHIFT < 13 +#define KTHREAD_SIZE (8192) +#else +#define KTHREAD_SIZE PAGE_SIZE +#endif + +#ifndef __ASSEMBLY__ + +#define get_user_page(vaddr) __get_free_page(GFP_KERNEL) +#define free_user_page(page, addr) free_page(addr) + +#define clear_page(page) memset((page), 0, PAGE_SIZE) +#define copy_page(to,from) memcpy((to), (from), PAGE_SIZE) + +#define clear_user_page(page, vaddr, pg) clear_page(page) +#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) + +/* + * These are used to make use of C type-checking.. + */ +typedef struct { unsigned long pte; } pte_t; +typedef struct { unsigned long pmd[16]; } pmd_t; +typedef struct { unsigned long pgd; } pgd_t; +typedef struct { unsigned long pgprot; } pgprot_t; + +#define pte_val(x) ((x).pte) +#define pmd_val(x) ((&x)->pmd[0]) +#define pgd_val(x) ((x).pgd) +#define pgprot_val(x) ((x).pgprot) + +#define __pte(x) ((pte_t) { (x) } ) +#define __pmd(x) ((pmd_t) { (x) } ) +#define __pgd(x) ((pgd_t) { (x) } ) +#define __pgprot(x) ((pgprot_t) { (x) } ) + +/* to align the pointer to the (next) page boundary */ +#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) + +/* 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; +} + +extern unsigned long memory_start; +extern unsigned long memory_end; + +#endif /* !__ASSEMBLY__ */ + +#include + +#define PAGE_OFFSET (PAGE_OFFSET_RAW) + +#ifndef __ASSEMBLY__ + +#define __pa(vaddr) virt_to_phys((void *)vaddr) +#define __va(paddr) phys_to_virt((unsigned long)paddr) + +#define MAP_NR(addr) (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT) + +#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) +#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) + +#define virt_to_page(addr) (mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)) +#define page_to_virt(page) ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET) +#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) + +#define pfn_to_page(pfn) virt_to_page(pfn_to_virt(pfn)) +#define page_to_pfn(page) virt_to_pfn(page_to_virt(page)) + +#define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \ + ((void *)(kaddr) < (void *)memory_end)) + + +#ifdef CONFIG_NO_KERNEL_MSG +#define BUG_PRINT() +#else +#define BUG_PRINT() printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__) +#endif + + +// #define BUG_PANIC() asm volatile ("halt") /* drop to debugger */ +// #define BUG_PANIC() while(1) +#define BUG_PANIC() panic("BUG!") + + +#define BUG() do { \ + BUG_PRINT(); \ + BUG_PANIC(); \ +} while (0) + +#define PAGE_BUG(page) do { \ + BUG(); \ +} while (0) + +#endif /* __ASSEMBLY__ */ + +#endif /* __KERNEL__ */ + +#endif /* _M68KNOMMU_PAGE_H */ diff -Nru a/include/asm-m68knommu/page_offset.h b/include/asm-m68knommu/page_offset.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/page_offset.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,51 @@ + +#include +#include + +/* This handles the memory map.. */ + +#ifdef CONFIG_COLDFIRE +#if defined(CONFIG_SMALL) +#define PAGE_OFFSET_RAW 0x30020000 +#elif defined(CONFIG_CFV240) +#define PAGE_OFFSET_RAW 0x02000000 +#else +#define PAGE_OFFSET_RAW 0x00000000 +#endif +#endif + +#ifdef CONFIG_M68360 +#define PAGE_OFFSET_RAW 0x00000000 +#endif + +#ifdef CONFIG_PILOT +#ifdef CONFIG_M68328 +#define PAGE_OFFSET_RAW 0x10000000 +#endif +#ifdef CONFIG_M68EZ328 +#define PAGE_OFFSET_RAW 0x00000000 +#endif +#endif +#ifdef CONFIG_UCSIMM +#define PAGE_OFFSET_RAW 0x00000000 +#endif + +#if defined(CONFIG_UCDIMM) || defined(CONFIG_DRAGEN2) +#ifdef CONFIG_M68VZ328 +#define PAGE_OFFSET_RAW 0x00000000 +#endif /* CONFIG_M68VZ328 */ +#endif /* CONFIG_UCDIMM */ + +#ifdef CONFIG_M68EZ328ADS +#define PAGE_OFFSET_RAW 0x00000000 +#endif +#ifdef CONFIG_ALMA_ANS +#define PAGE_OFFSET_RAW 0x00000000 +#endif +#ifdef CONFIG_M68EN302 +#define PAGE_OFFSET_RAW 0x00000000 +#endif +#ifdef CONFIG_SHGLCORE +#define PAGE_OFFSET_RAW SHGLCORE_RAM_BANK_0_ADDR +#endif + diff -Nru a/include/asm-m68knommu/param.h b/include/asm-m68knommu/param.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/param.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,57 @@ +#ifndef _M68KNOMMU_PARAM_H +#define _M68KNOMMU_PARAM_H + +#include + +#ifndef HZ +#ifdef CONFIG_COLDFIRE +#if defined(CONFIG_CLEOPATRA) +#define HZ 1000 +#else +#define HZ 100 +#endif +#endif +#ifdef CONFIG_M68EN302 +#define HZ 100 +#endif +#ifdef CONFIG_M68328 +#define HZ 100 +#endif +#ifdef CONFIG_M68EZ328 +#define HZ 100 +#endif +#ifdef CONFIG_UCSIMM +#define HZ 100 +#endif + +#ifdef CONFIG_M68VZ328 +#define HZ 100 +#endif + +#ifdef CONFIG_SHGLCORE +#define HZ 50 +#endif +#ifdef CONFIG_M68360 +#define HZ 100 +#endif + +#endif + +#ifdef __KERNEL__ +#define USER_HZ HZ +#define CLOCKS_PER_SEC (USER_HZ) +#endif + +#define EXEC_PAGESIZE 4096 + +#ifndef NGROUPS +#define NGROUPS 32 +#endif + +#ifndef NOGROUP +#define NOGROUP (-1) +#endif + +#define MAXHOSTNAMELEN 64 /* max length of hostname */ + +#endif /* _M68KNOMMU_PARAM_H */ diff -Nru a/include/asm-m68knommu/pci.h b/include/asm-m68knommu/pci.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/pci.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/percpu.h b/include/asm-m68knommu/percpu.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/percpu.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,6 @@ +#ifndef __ARCH_M68KNOMMU_PERCPU__ +#define __ARCH_M68KNOMMU_PERCPU__ + +#include + +#endif /* __ARCH_M68KNOMMU_PERCPU__ */ diff -Nru a/include/asm-m68knommu/pgalloc.h b/include/asm-m68knommu/pgalloc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/pgalloc.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,8 @@ +#ifndef _M68KNOMMU_PGALLOC_H +#define _M68KNOMMU_PGALLOC_H + +#include + +#define check_pgt_cache() do { } while (0) + +#endif /* _M68KNOMMU_PGALLOC_H */ diff -Nru a/include/asm-m68knommu/pgtable.h b/include/asm-m68knommu/pgtable.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/pgtable.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,59 @@ +#ifndef _M68KNOMMU_PGTABLE_H +#define _M68KNOMMU_PGTABLE_H + +/* + * (C) Copyright 2000-2002, Greg Ungerer + */ + +#include +#include +#include +#include +#include + +typedef pte_t *pte_addr_t; + +/* + * Trivial page table functions. + */ +#define pgd_present(pgd) (1) +#define pgd_none(pgd) (0) +#define pgd_bad(pgd) (0) +#define pgd_clear(pgdp) +#define kern_addr_valid(addr) (1) +#define pmd_offset(a, b) ((void *)0) + +#define PAGE_NONE __pgprot(0) +#define PAGE_SHARED __pgprot(0) +#define PAGE_COPY __pgprot(0) +#define PAGE_READONLY __pgprot(0) +#define PAGE_KERNEL __pgprot(0) + +extern void paging_init(void); +#define swapper_pg_dir ((pgd_t *) 0) + +#define __swp_type(x) (0) +#define __swp_offset(x) (0) +#define __swp_entry(typ,off) ((swp_entry_t) { ((typ) | ((off) << 7)) }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) + +/* + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. + */ +#define ZERO_PAGE(vaddr) (virt_to_page(0)) + +/* + * These would be in other places but having them here reduces the diffs. + */ +extern unsigned int kobjsize(const void *objp); +extern int is_in_rom(unsigned long); + +/* + * No page table caches to initialise. + */ +#define pgtable_cache_init() do { } while (0) +#define io_remap_page_range remap_page_range + +#endif /* _M68KNOMMU_PGTABLE_H */ diff -Nru a/include/asm-m68knommu/poll.h b/include/asm-m68knommu/poll.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/poll.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/posix_types.h b/include/asm-m68knommu/posix_types.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/posix_types.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/processor.h b/include/asm-m68knommu/processor.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/processor.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,128 @@ +/* + * include/asm-m68k/processor.h + * + * Copyright (C) 1995 Hamish Macdonald + */ + +#ifndef __ASM_M68K_PROCESSOR_H +#define __ASM_M68K_PROCESSOR_H + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +#define current_text_addr() ({ __label__ _l; _l: &&_l;}) + +#include +#include +#include +#include +#include +#include +#include + +extern inline unsigned long rdusp(void) +{ +#ifdef CONFIG_COLDFIRE + extern unsigned int sw_usp; + return(sw_usp); +#else + unsigned long usp; + __asm__ __volatile__("move %/usp,%0" : "=a" (usp)); + return usp; +#endif +} + +extern inline void wrusp(unsigned long usp) +{ +#ifdef CONFIG_COLDFIRE + extern unsigned int sw_usp; + sw_usp = usp; +#else + __asm__ __volatile__("move %0,%/usp" : : "a" (usp)); +#endif +} + +/* + * User space process size: 3.75GB. This is hardcoded into a few places, + * so don't change it unless you know what you are doing. + */ +#define TASK_SIZE (0xF0000000UL) + +/* + * Bus types + */ +#define EISA_bus 0 +#define MCA_bus 0 + +/* + * if you change this structure, you must change the code and offsets + * in m68k/machasm.S + */ + +struct thread_struct { + unsigned long ksp; /* kernel stack pointer */ + unsigned long usp; /* user stack pointer */ + unsigned short sr; /* saved status register */ + unsigned short fs; /* saved fs (sfc, dfc) */ + unsigned long crp[2]; /* cpu root pointer */ + unsigned long esp0; /* points to SR of stack frame */ + unsigned long fp[8*3]; + unsigned long fpcntl[3]; /* fp control regs */ + unsigned char fpstate[FPSTATESIZE]; /* floating point state */ +}; + +#define INIT_THREAD { \ + sizeof(init_stack) + (unsigned long) init_stack, 0, \ + PS_S, __KERNEL_DS, \ + {0, 0}, 0, {0,}, {0, 0, 0}, {0,}, \ +} + +/* + * Do necessary setup to start up a newly executed thread. + * + * pass the data segment into user programs if it exists, + * it can't hurt anything as far as I can tell + */ +#define start_thread(_regs, _pc, _usp) \ +do { \ + set_fs(USER_DS); /* reads from user space */ \ + (_regs)->pc = (_pc); \ + if (current->mm) \ + (_regs)->d5 = current->mm->start_data; \ + (_regs)->sr &= ~0x2000; \ + wrusp(_usp); \ +} while(0) + +/* Forward declaration, a strange C thing */ +struct task_struct; + +/* Free all resources held by a thread. */ +static inline void release_thread(struct task_struct *dead_task) +{ +} + +extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); + +/* + * Free current thread data structures etc.. + */ +static inline void exit_thread(void) +{ +} + +unsigned long thread_saved_pc(struct task_struct *tsk); +unsigned long get_wchan(struct task_struct *p); + +#define KSTK_EIP(tsk) \ + ({ \ + unsigned long eip = 0; \ + if ((tsk)->thread.esp0 > PAGE_SIZE && \ + MAP_NR((tsk)->thread.esp0) < max_mapnr) \ + eip = ((struct pt_regs *) (tsk)->thread.esp0)->pc; \ + eip; }) +#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp) + +#define cpu_relax() do { } while (0) + +#endif diff -Nru a/include/asm-m68knommu/ptrace.h b/include/asm-m68knommu/ptrace.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/ptrace.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,90 @@ +#ifndef _M68K_PTRACE_H +#define _M68K_PTRACE_H + +#define PT_D1 0 +#define PT_D2 1 +#define PT_D3 2 +#define PT_D4 3 +#define PT_D5 4 +#define PT_D6 5 +#define PT_D7 6 +#define PT_A0 7 +#define PT_A1 8 +#define PT_A2 9 +#define PT_A3 10 +#define PT_A4 11 +#define PT_A5 12 +#define PT_A6 13 +#define PT_D0 14 +#define PT_USP 15 +#define PT_ORIG_D0 16 +#define PT_SR 17 +#define PT_PC 18 + +#ifndef __ASSEMBLY__ + +/* this struct defines the way the registers are stored on the + stack during a system call. */ + +struct pt_regs { + long d1; + long d2; + long d3; + long d4; + long d5; + long a0; + long a1; + long a2; + long d0; + long orig_d0; + long stkadj; +#ifdef CONFIG_COLDFIRE + unsigned format : 4; /* frame format specifier */ + unsigned vector : 12; /* vector offset */ + unsigned short sr; + unsigned long pc; +#else + unsigned short sr; + unsigned long pc; +#ifndef NO_FORMAT_VEC + unsigned format : 4; /* frame format specifier */ + unsigned vector : 12; /* vector offset */ +#endif +#endif +}; + +/* + * This is the extended stack used by signal handlers and the context + * switcher: it's pushed after the normal "struct pt_regs". + */ +struct switch_stack { + unsigned long d6; + unsigned long d7; + unsigned long a3; + unsigned long a4; + unsigned long a5; + unsigned long a6; + unsigned long retpc; +}; + +/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#ifdef COFNIG_FPU +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 +#endif + +#ifdef __KERNEL__ + +#ifndef PS_S +#define PS_S (0x2000) +#define PS_M (0x1000) +#endif + +#define user_mode(regs) (!((regs)->sr & PS_S)) +#define instruction_pointer(regs) ((regs)->pc) +extern void show_regs(struct pt_regs *); +#endif /* __KERNEL__ */ +#endif /* __ASSEMBLY__ */ +#endif /* _M68K_PTRACE_H */ diff -Nru a/include/asm-m68knommu/quicc_simple.h b/include/asm-m68knommu/quicc_simple.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/quicc_simple.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,52 @@ +/*********************************** + * $Id: quicc_simple.h,v 1.1 2002/03/02 15:01:10 gerg Exp $ + *********************************** + * + *************************************** + * Simple drivers common header + *************************************** + */ + +#ifndef __SIMPLE_H +#define __SIMPLE_H + +/* #include "quicc.h" */ + +#define GLB_SCC_0 0 +#define GLB_SCC_1 1 +#define GLB_SCC_2 2 +#define GLB_SCC_3 3 + +typedef void (int_routine)(unsigned short interrupt_event); +typedef int_routine *int_routine_ptr; +typedef void *(alloc_routine)(int length); +typedef void (free_routine)(int scc_num, int channel_num, void *buf); +typedef void (store_rx_buffer_routine)(int scc_num, int channel_num, void *buff, int length); +typedef int (handle_tx_error_routine)(int scc_num, int channel_num, QUICC_BD *tbd); +typedef void (handle_rx_error_routine)(int scc_num, int channel_num, QUICC_BD *rbd); +typedef void (handle_lost_error_routine)(int scc_num, int channel_num); + +/* user defined functions for global errors */ +typedef void (handle_glob_overrun_routine)(int scc_number); +typedef void (handle_glob_underrun_routine)(int scc_number); +typedef void (glob_intr_q_overflow_routine)(int scc_number); + +/* + * General initialization and command routines + */ +void quicc_issue_cmd (unsigned short cmd, int scc_num); +void quicc_init(void); +void quicc_scc_init(int scc_number, int number_of_rx_buf, int number_of_tx_buf); +void quicc_smc_init(int smc_number, int number_of_rx_buf, int number_of_tx_buf); +void quicc_scc_start(int scc_num); +void quicc_scc_loopback(int scc_num); + +/* Interrupt enable/disable routines for critical pieces of code*/ +unsigned short IntrDis(void); +void IntrEna(unsigned short old_sr); + +/* For debugging */ +void print_rbd(int scc_num); +void print_tbd(int scc_num); + +#endif diff -Nru a/include/asm-m68knommu/resource.h b/include/asm-m68knommu/resource.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/resource.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/rmap.h b/include/asm-m68knommu/rmap.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/rmap.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,2 @@ +/* Do not need anything here */ + diff -Nru a/include/asm-m68knommu/scatterlist.h b/include/asm-m68knommu/scatterlist.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/scatterlist.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,13 @@ +#ifndef _M68KNOMMU_SCATTERLIST_H +#define _M68KNOMMU_SCATTERLIST_H + +struct scatterlist { + struct page *page; + unsigned int offset; + dma_addr_t dma_address; + unsigned int length; +}; + +#define ISA_DMA_THRESHOLD (0xffffffff) + +#endif /* !(_M68KNOMMU_SCATTERLIST_H) */ diff -Nru a/include/asm-m68knommu/segment.h b/include/asm-m68knommu/segment.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/segment.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,51 @@ +#ifndef _M68K_SEGMENT_H +#define _M68K_SEGMENT_H + +/* define constants */ +/* Address spaces (FC0-FC2) */ +#define USER_DATA (1) +#ifndef __USER_DS +#define __USER_DS (USER_DATA) +#endif +#define USER_PROGRAM (2) +#define SUPER_DATA (5) +#ifndef __KERNEL_DS +#define __KERNEL_DS (SUPER_DATA) +#endif +#define SUPER_PROGRAM (6) +#define CPU_SPACE (7) + +#ifndef __ASSEMBLY__ + +typedef struct { + unsigned long seg; +} mm_segment_t; + +#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) +#define USER_DS MAKE_MM_SEG(__USER_DS) +#define KERNEL_DS MAKE_MM_SEG(__KERNEL_DS) + +/* + * Get/set the SFC/DFC registers for MOVES instructions + */ + +static inline mm_segment_t get_fs(void) +{ + return USER_DS; +} + +static inline mm_segment_t get_ds(void) +{ + /* return the supervisor data space code */ + return KERNEL_DS; +} + +static inline void set_fs(mm_segment_t val) +{ +} + +#define segment_eq(a,b) ((a).seg == (b).seg) + +#endif /* __ASSEMBLY__ */ + +#endif /* _M68K_SEGMENT_H */ diff -Nru a/include/asm-m68knommu/semaphore-helper.h b/include/asm-m68knommu/semaphore-helper.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/semaphore-helper.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,83 @@ +#ifndef _M68K_SEMAPHORE_HELPER_H +#define _M68K_SEMAPHORE_HELPER_H + +/* + * SMP- and interrupt-safe semaphores helper functions. + * + * (C) Copyright 1996 Linus Torvalds + * + * m68k version by Andreas Schwab + */ + +#include + +/* + * These two _must_ execute atomically wrt each other. + */ +static inline void wake_one_more(struct semaphore * sem) +{ + atomic_inc(&sem->waking); +} + +static inline int waking_non_zero(struct semaphore *sem) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&semaphore_wake_lock, flags); + ret = 0; + if (atomic_read(&sem->waking) > 0) { + atomic_dec(&sem->waking); + ret = 1; + } + spin_unlock_irqrestore(&semaphore_wake_lock, flags); + return ret; +} + +/* + * waking_non_zero_interruptible: + * 1 got the lock + * 0 go to sleep + * -EINTR interrupted + */ +static inline int waking_non_zero_interruptible(struct semaphore *sem, + struct task_struct *tsk) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&semaphore_wake_lock, flags); + ret = 0; + if (atomic_read(&sem->waking) > 0) { + atomic_dec(&sem->waking); + ret = 1; + } else if (signal_pending(tsk)) { + atomic_inc(&sem->count); + ret = -EINTR; + } + spin_unlock_irqrestore(&semaphore_wake_lock, flags); + return ret; +} + +/* + * waking_non_zero_trylock: + * 1 failed to lock + * 0 got the lock + */ +static inline int waking_non_zero_trylock(struct semaphore *sem) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&semaphore_wake_lock, flags); + ret = 1; + if (atomic_read(&sem->waking) > 0) { + atomic_dec(&sem->waking); + ret = 0; + } else + atomic_inc(&sem->count); + spin_unlock_irqrestore(&semaphore_wake_lock, flags); + return ret; +} + +#endif diff -Nru a/include/asm-m68knommu/semaphore.h b/include/asm-m68knommu/semaphore.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/semaphore.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,178 @@ +#ifndef _M68K_SEMAPHORE_H +#define _M68K_SEMAPHORE_H + +#define RW_LOCK_BIAS 0x01000000 + +#ifndef __ASSEMBLY__ + +#include +#include +#include +#include + +#include +#include + +/* + * Interrupt-safe semaphores.. + * + * (C) Copyright 1996 Linus Torvalds + * + * m68k version by Andreas Schwab + */ + + +struct semaphore { + atomic_t count; + atomic_t waking; + wait_queue_head_t wait; +#if WAITQUEUE_DEBUG + long __magic; +#endif +}; + +#if WAITQUEUE_DEBUG +# define __SEM_DEBUG_INIT(name) \ + , (long)&(name).__magic +#else +# define __SEM_DEBUG_INIT(name) +#endif + +#define __SEMAPHORE_INITIALIZER(name,count) \ +{ ATOMIC_INIT(count), ATOMIC_INIT(0), __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ + __SEM_DEBUG_INIT(name) } + +#define __MUTEX_INITIALIZER(name) \ + __SEMAPHORE_INITIALIZER(name,1) + +#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ + struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) + +#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) +#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0) + +extern inline void sema_init (struct semaphore *sem, int val) +{ + *sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val); +} + +static inline void init_MUTEX (struct semaphore *sem) +{ + sema_init(sem, 1); +} + +static inline void init_MUTEX_LOCKED (struct semaphore *sem) +{ + sema_init(sem, 0); +} + +asmlinkage void __down_failed(void /* special register calling convention */); +asmlinkage int __down_failed_interruptible(void /* params in registers */); +asmlinkage int __down_failed_trylock(void /* params in registers */); +asmlinkage void __up_wakeup(void /* special register calling convention */); + +asmlinkage void __down(struct semaphore * sem); +asmlinkage int __down_interruptible(struct semaphore * sem); +asmlinkage int __down_trylock(struct semaphore * sem); +asmlinkage void __up(struct semaphore * sem); + +extern spinlock_t semaphore_wake_lock; + +/* + * This is ugly, but we want the default case to fall through. + * "down_failed" is a special asm handler that calls the C + * routine that actually waits. See arch/m68k/lib/semaphore.S + */ +extern inline void down(struct semaphore * sem) +{ +#if WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + + __asm__ __volatile__( + "| atomic down operation\n\t" + "movel %0, %%a1\n\t" + "lea %%pc@(1f), %%a0\n\t" + "subql #1, %%a1@\n\t" + "jmi __down_failed\n" + "1:" + : /* no outputs */ + : "g" (sem) + : "cc", "%a0", "%a1", "memory"); +} + +extern inline int down_interruptible(struct semaphore * sem) +{ + int ret; + +#if WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + + __asm__ __volatile__( + "| atomic down operation\n\t" + "movel %1, %%a1\n\t" + "lea %%pc@(1f), %%a0\n\t" + "subql #1, %%a1@\n\t" + "jmi __down_failed_interruptible\n\t" + "clrl %%d0\n" + "1: movel %%d0, %0\n" + : "=d" (ret) + : "g" (sem) + : "cc", "%d0", "%a0", "%a1", "memory"); + return(ret); +} + +extern inline int down_trylock(struct semaphore * sem) +{ + register struct semaphore *sem1 __asm__ ("%a1") = sem; + register int result __asm__ ("%d0"); + +#if WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + + __asm__ __volatile__( + "| atomic down trylock operation\n\t" + "subql #1,%1@\n\t" + "jmi 2f\n\t" + "clrl %0\n" + "1:\n" + ".section .text.lock,\"ax\"\n" + ".even\n" + "2:\tpea 1b\n\t" + "jbra __down_failed_trylock\n" + ".previous" + : "=d" (result) + : "a" (sem1) + : "%d0", "memory"); + return result; +} + +/* + * Note! This is subtle. We jump to wake people up only if + * the semaphore was negative (== somebody was waiting on it). + * The default case (no contention) will result in NO + * jumps for both down() and up(). + */ +extern inline void up(struct semaphore * sem) +{ +#if WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + + __asm__ __volatile__( + "| atomic up operation\n\t" + "movel %0, %%a1\n\t" + "lea %%pc@(1f), %%a0\n\t" + "addql #1, %%a1@\n\t" + "jle __up_wakeup\n" + "1:" + : /* no outputs */ + : "g" (sem) + : "cc", "%a0", "%a1", "memory"); +} + +#endif /* __ASSEMBLY__ */ + +#endif diff -Nru a/include/asm-m68knommu/sembuf.h b/include/asm-m68knommu/sembuf.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/sembuf.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/semp3.h b/include/asm-m68knommu/semp3.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/semp3.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,60 @@ +/****************************************************************************/ + +/* + * semp.h -- SecureEdge MP3 hardware platform support. + * + * (C) Copyright 2001-2002, Greg Ungerer (gerg@snapgear.com). + */ + +/****************************************************************************/ +#ifndef semp3_h +#define semp3_h +/****************************************************************************/ + +#include + +/****************************************************************************/ +#ifdef CONFIG_SECUREEDGEMP3 +/****************************************************************************/ + +#include +#include + +/* + * The ColdFire UARTs do not have any support for DTR/DCD lines. + * We have wired them onto some of the parallel IO lines. + */ +#define MCFPP_DCD1 0x0004 +#define MCFPP_DCD0 0x0000 /* No DCD line on port 0 */ +#define MCFPP_DTR1 0x0080 +#define MCFPP_DTR0 0x0000 /* No DTR line on port 0 */ + + +#ifndef __ASSEMBLY__ + +extern volatile unsigned short ppdata; + +/* + * These functions defined to give quasi generic access to the + * PPIO bits used for DTR/DCD. + */ +static __inline__ unsigned int mcf_getppdata(void) +{ + volatile unsigned short *pp; + pp = (volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT); + return((unsigned int) *pp); +} + +static __inline__ void mcf_setppdata(unsigned int mask, unsigned int bits) +{ + volatile unsigned short *pp; + pp = (volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT); + ppdata = (ppdata & ~mask) | bits; + *pp = ppdata; +} +#endif + +/****************************************************************************/ +#endif /* CONFIG_SECUREEDGEMP3 */ +/****************************************************************************/ +#endif /* semp3_h */ diff -Nru a/include/asm-m68knommu/setup.h b/include/asm-m68knommu/setup.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/setup.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/shglcore.h b/include/asm-m68knommu/shglcore.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/shglcore.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,65 @@ + +/* Copyright (C) 1998 Kenneth Albanowski , + */ + +#ifndef _M68K_SHGLCORE_H +#define _M68K_SHGLCORE_H + +#include + +#ifdef CONFIG_SHGLCORE + +#include + +#ifdef CONFIG_SHGLCORE_2MEG + +#define SHGLCORE_ROM_BANK_0_ADDR 0x000000 +#define SHGLCORE_ROM_BANK_1_ADDR 0x100000 +#define SHGLCORE_RAM_BANK_0_ADDR 0x200000 +#define SHGLCORE_RAM_BANK_1_ADDR 0x300000 +#define SHGLCORE_FLASH_BANK_0_ADDR 0x400000 + +#define SHGLCORE_ROM_BANK_0_LENGTH 0x100000 +#define SHGLCORE_ROM_BANK_1_LENGTH 0x100000 +#define SHGLCORE_RAM_BANK_0_LENGTH 0x100000 +#define SHGLCORE_RAM_BANK_1_LENGTH 0x100000 +#define SHGLCORE_FLASH_BANK_0_LENGTH 0x80000 + +#define SHGLCORE_ACC_ADDR 0x600000 +#define SHGLCORE_LANCE_ADDR 0x700000 + +#else + +#define SHGLCORE_ROM_BANK_0_ADDR 0x000000 +#define SHGLCORE_RAM_BANK_0_ADDR 0x100000 +#define SHGLCORE_FLASH_BANK_0_ADDR 0x300000 + +#define SHGLCORE_ROM_BANK_0_LENGTH 0x100000 +#define SHGLCORE_RAM_BANK_0_LENGTH 0x100000 +#define SHGLCORE_FLASH_BANK_0_LENGTH 0x80000 + +#define SHGLCORE_ACC_ADDR 0x400000 +#define SHGLCORE_LANCE_ADDR 0x500000 + +#endif + +#define MAX_DMA_ADDRESS SHGLCORE_RAM_BANK_0_ADDR + SHGLCORE_RAM_BANK_0_LENGTH + +#define SHGLCORE_LATCH_ADDR (SHGLCORE_ACC_ADDR+0x100) +#define SHGLCORE_1865_0_ADDR (SHGLCORE_ACC_ADDR+0x600) +#define SHGLCORE_1865_1_ADDR (SHGLCORE_ACC_ADDR+0x700) + +#define SHGLCORE_LATCH_BIT(x) BYTE_REF(SHGLCORE_LATCH_ADDR+x) + +#define SHGLCORE_LATCH_STATUS_LED 0 +#define SHGLCORE_LATCH_ERROR_LED 1 +#define SHGLCORE_LATCH_ALARM_LED 2 + +#define SHGLCORE_LATCH_1865 4 + +#define SHGLCORE_LATCH_RELAY_1 6 +#define SHGLCORE_LATCH_RELAY_2 7 + +#endif /* SHGLCORE */ + +#endif /* _M68K_SHGLCORE_H */ diff -Nru a/include/asm-m68knommu/shglports.h b/include/asm-m68knommu/shglports.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/shglports.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,76 @@ + +/* Copyright (C) 1998 Kenneth Albanowski , + * 1997, 1998 D. Jeff Dionne , + */ + +#ifndef _M68K_SHGLPORTS_H +#define _M68K_SHGLPORTS_H + +#include +#include + +#ifdef CONFIG_SHGLCORE + +extern struct semaphore porte_interlock; + +struct SHGLCORE_PORT_QS { + unsigned char + nullqs:1, /* COM1TX */ + sbin:1, /* PQS6 (PCS3) */ + sbclk:1, /* PQS5 (PCS2) */ + sbout:1, /* PQS4 (PCS1) */ + null4:4; /* MISO, MOSI, SCLK, /SS=PCS0 */ +}; + +#define PORT_QS ((volatile struct SHGLCORE_PORT_QS*)PORTQS_ADDR) + +struct SHGLCORE_PORT_E { + unsigned char + dead:1, /* LED */ + sbirigb:1, /* PE6 */ + ds:1, /* /DS */ + nulle1:1, /* na */ + sbpll:1, /* PE3 */ + avec:1, /* /AVEC */ + sbsrom:1, /* PE1 */ + sbpanel:1; /* PE0 */ +}; + +#define PORT_E ((volatile struct SHGLCORE_PORT_E*)PORTE_ADDR) + +struct SHGLCORE_PORT_F { + unsigned char + nullf1:4, + nullf2:4; +}; + +#define PORT_F ((volatile struct SHGLCORE_PORT_F*)PORTF_ADDR) + +extern int comm_status_led, comm_error_led, alarm_led; + +static inline void SET_COMM_STATUS_LED(int value) { + BYTE_REF(SHGLCORE_ACC_ADDR+0x100+0) = comm_status_led = value; +} +static inline int GET_COMM_STATUS_LED(void) { + return comm_status_led; +} + + +static inline void SET_COMM_ERROR_LED(int value) { + BYTE_REF(SHGLCORE_ACC_ADDR+0x100+1) = comm_error_led = value; +} +static inline int GET_COMM_ERROR_LED(void) { + return comm_error_led; +} + + +static inline void SET_ALARM_LED(int value) { + BYTE_REF(SHGLCORE_ACC_ADDR+0x100+2) = alarm_led = value; +} +static inline int GET_ALARM_LED(void) { + return alarm_led; +} + +#endif + +#endif /* _M68K_SHGLPORTS_H */ diff -Nru a/include/asm-m68knommu/shm.h b/include/asm-m68knommu/shm.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/shm.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/shmbuf.h b/include/asm-m68knommu/shmbuf.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/shmbuf.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/shmparam.h b/include/asm-m68knommu/shmparam.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/shmparam.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/sigcontext.h b/include/asm-m68knommu/sigcontext.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/sigcontext.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,16 @@ +#ifndef _ASM_M68KNOMMU_SIGCONTEXT_H +#define _ASM_M68KNOMMU_SIGCONTEXT_H + +struct sigcontext { + unsigned long sc_mask; /* old sigmask */ + unsigned long sc_usp; /* old user stack pointer */ + unsigned long sc_d0; + unsigned long sc_d1; + unsigned long sc_a0; + unsigned long sc_a1; + unsigned short sc_sr; + unsigned long sc_pc; + unsigned short sc_formatvec; +}; + +#endif diff -Nru a/include/asm-m68knommu/siginfo.h b/include/asm-m68knommu/siginfo.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/siginfo.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/signal.h b/include/asm-m68knommu/signal.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/signal.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,181 @@ +#ifndef _M68KNOMMU_SIGNAL_H +#define _M68KNOMMU_SIGNAL_H + +#include + +/* Avoid too many header ordering problems. */ +struct siginfo; + +#ifdef __KERNEL__ +/* Most things should be clean enough to redefine this at will, if care + is taken to make libc match. */ + +#define _NSIG 64 +#define _NSIG_BPW 32 +#define _NSIG_WORDS (_NSIG / _NSIG_BPW) + +typedef unsigned long old_sigset_t; /* at least 32 bits */ + +typedef struct { + unsigned long sig[_NSIG_WORDS]; +} sigset_t; + +#else +/* Here we must cater to libcs that poke about in kernel headers. */ + +#define NSIG 32 +typedef unsigned long sigset_t; + +#endif /* __KERNEL__ */ + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL SIGIO +/* +#define SIGLOST 29 +*/ +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGUNUSED 31 + +/* These should not be considered constants from userland. */ +#define SIGRTMIN 32 +#define SIGRTMAX (_NSIG-1) + +/* + * SA_FLAGS values: + * + * SA_ONSTACK indicates that a registered stack_t will be used. + * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the + * SA_RESTART flag to get restarting signals (which were the default long ago) + * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. + * SA_RESETHAND clears the handler when the signal is delivered. + * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. + * SA_NODEFER prevents the current signal from being masked in the handler. + * + * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single + * Unix names RESETHAND and NODEFER respectively. + */ +#define SA_NOCLDSTOP 0x00000001 +#define SA_NOCLDWAIT 0x00000002 /* not supported yet */ +#define SA_SIGINFO 0x00000004 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 + +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND +#define SA_INTERRUPT 0x20000000 /* dummy -- ignored */ + +/* + * sigaltstack controls + */ +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 + +#ifdef __KERNEL__ +/* + * These values of sa_flags are used only by the kernel as part of the + * irq handling routines. + * + * SA_INTERRUPT is also used by the irq handling routines. + * SA_SHIRQ is for shared interrupt support on PCI and EISA. + */ +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x04000000 +#endif + +#define SIG_BLOCK 0 /* for blocking signals */ +#define SIG_UNBLOCK 1 /* for unblocking signals */ +#define SIG_SETMASK 2 /* for setting the signal mask */ + +/* Type of a signal handler. */ +typedef void (*__sighandler_t)(int); + +#define SIG_DFL ((__sighandler_t)0) /* default signal handling */ +#define SIG_IGN ((__sighandler_t)1) /* ignore signal */ +#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */ + +#ifdef __KERNEL__ +struct old_sigaction { + __sighandler_t sa_handler; + old_sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +struct sigaction { + __sighandler_t sa_handler; + unsigned long sa_flags; + void (*sa_restorer)(void); + sigset_t sa_mask; /* mask last for extensibility */ +}; + +struct k_sigaction { + struct sigaction sa; +}; +#else +/* Here we must cater to libcs that poke about in kernel headers. */ + +struct sigaction { + union { + __sighandler_t _sa_handler; + void (*_sa_sigaction)(int, struct siginfo *, void *); + } _u; + sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +#define sa_handler _u._sa_handler +#define sa_sigaction _u._sa_sigaction + +#endif /* __KERNEL__ */ + +typedef struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; + +#ifdef __KERNEL__ + +#include +#undef __HAVE_ARCH_SIG_BITOPS + +#endif /* __KERNEL__ */ + +#endif /* _M68KNOMMU_SIGNAL_H */ diff -Nru a/include/asm-m68knommu/smp.h b/include/asm-m68knommu/smp.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/smp.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +/* nothing required here yet */ diff -Nru a/include/asm-m68knommu/socket.h b/include/asm-m68knommu/socket.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/socket.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/sockios.h b/include/asm-m68knommu/sockios.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/sockios.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/softirq.h b/include/asm-m68knommu/softirq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/softirq.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,20 @@ +#ifndef __ASM_SOFTIRQ_H +#define __ASM_SOFTIRQ_H + +#include +#include + +#define local_bh_disable() \ + do { preempt_count() += SOFTIRQ_OFFSET; barrier(); } while (0) +#define __local_bh_enable() \ + do { barrier(); preempt_count() -= SOFTIRQ_OFFSET; } while (0) + +#define local_bh_enable() \ +do { \ + __local_bh_enable(); \ + if (unlikely(!in_interrupt() && softirq_pending(smp_processor_id()))) \ + do_softirq(); \ + preempt_check_resched(); \ +} while (0) + +#endif /* __ASM_SOFTIRQ_H */ diff -Nru a/include/asm-m68knommu/spinlock.h b/include/asm-m68knommu/spinlock.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/spinlock.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/stat.h b/include/asm-m68knommu/stat.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/stat.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/statfs.h b/include/asm-m68knommu/statfs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/statfs.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/string.h b/include/asm-m68knommu/string.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/string.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,126 @@ +#ifndef _M68KNOMMU_STRING_H_ +#define _M68KNOMMU_STRING_H_ + +#ifdef __KERNEL__ /* only set these up for kernel code */ + +#include +#include + +#define __HAVE_ARCH_STRCPY +static inline char * strcpy(char * dest,const char *src) +{ + char *xdest = dest; + + __asm__ __volatile__ + ("1:\tmoveb %1@+,%0@+\n\t" + "jne 1b" + : "=a" (dest), "=a" (src) + : "0" (dest), "1" (src) : "memory"); + return xdest; +} + +#define __HAVE_ARCH_STRNCPY +static inline char * strncpy(char *dest, const char *src, size_t n) +{ + char *xdest = dest; + + if (n == 0) + return xdest; + + __asm__ __volatile__ + ("1:\tmoveb %1@+,%0@+\n\t" + "jeq 2f\n\t" + "subql #1,%2\n\t" + "jne 1b\n\t" + "2:" + : "=a" (dest), "=a" (src), "=d" (n) + : "0" (dest), "1" (src), "2" (n) + : "memory"); + return xdest; +} + + +#ifndef CONFIG_COLDFIRE + +#define __HAVE_ARCH_STRCMP +static inline int strcmp(const char * cs,const char * ct) +{ + char __res; + + __asm__ + ("1:\tmoveb %0@+,%2\n\t" /* get *cs */ + "cmpb %1@+,%2\n\t" /* compare a byte */ + "jne 2f\n\t" /* not equal, break out */ + "tstb %2\n\t" /* at end of cs? */ + "jne 1b\n\t" /* no, keep going */ + "jra 3f\n\t" /* strings are equal */ + "2:\tsubb %1@-,%2\n\t" /* *cs - *ct */ + "3:" + : "=a" (cs), "=a" (ct), "=d" (__res) + : "0" (cs), "1" (ct)); + + return __res; +} + +#define __HAVE_ARCH_STRNCMP +static inline int strncmp(const char * cs,const char * ct,size_t count) +{ + char __res; + + if (!count) + return 0; + __asm__ + ("1:\tmovb %0@+,%3\n\t" /* get *cs */ + "cmpb %1@+,%3\n\t" /* compare a byte */ + "jne 3f\n\t" /* not equal, break out */ + "tstb %3\n\t" /* at end of cs? */ + "jeq 4f\n\t" /* yes, all done */ + "subql #1,%2\n\t" /* no, adjust count */ + "jne 1b\n\t" /* more to do, keep going */ + "2:\tmoveq #0,%3\n\t" /* strings are equal */ + "jra 4f\n\t" + "3:\tsubb %1@-,%3\n\t" /* *cs - *ct */ + "4:" + : "=a" (cs), "=a" (ct), "=d" (count), "=d" (__res) + : "0" (cs), "1" (ct), "2" (count)); + return __res; +} + +#endif /* CONFIG_COLDFIRE */ + +#define __HAVE_ARCH_MEMSET +extern void * memset(void * s, int c, size_t count); + +#define __HAVE_ARCH_MEMCPY +extern void * memcpy(void *d, const void *s, size_t count); + +#else /* KERNEL */ + +/* + * let user libraries deal with these, + * IMHO the kernel has no place defining these functions for user apps + */ + +#define __HAVE_ARCH_STRCPY 1 +#define __HAVE_ARCH_STRNCPY 1 +#define __HAVE_ARCH_STRCAT 1 +#define __HAVE_ARCH_STRNCAT 1 +#define __HAVE_ARCH_STRCMP 1 +#define __HAVE_ARCH_STRNCMP 1 +#define __HAVE_ARCH_STRNICMP 1 +#define __HAVE_ARCH_STRCHR 1 +#define __HAVE_ARCH_STRRCHR 1 +#define __HAVE_ARCH_STRSTR 1 +#define __HAVE_ARCH_STRLEN 1 +#define __HAVE_ARCH_STRNLEN 1 +#define __HAVE_ARCH_MEMSET 1 +#define __HAVE_ARCH_MEMCPY 1 +#define __HAVE_ARCH_MEMMOVE 1 +#define __HAVE_ARCH_MEMSCAN 1 +#define __HAVE_ARCH_MEMCMP 1 +#define __HAVE_ARCH_MEMCHR 1 +#define __HAVE_ARCH_STRTOK 1 + +#endif /* KERNEL */ + +#endif /* _M68K_STRING_H_ */ diff -Nru a/include/asm-m68knommu/system.h b/include/asm-m68knommu/system.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/system.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,270 @@ +#ifndef _M68KNOMMU_SYSTEM_H +#define _M68KNOMMU_SYSTEM_H + +#include /* get configuration macros */ +#include +#include +#include + +/* + * switch_to(n) should switch tasks to task ptr, first checking that + * ptr isn't the current task, in which case it does nothing. This + * also clears the TS-flag if the task we switched to has used the + * math co-processor latest. + */ +/* + * switch_to() saves the extra registers, that are not saved + * automatically by SAVE_SWITCH_STACK in resume(), ie. d0-d5 and + * a0-a1. Some of these are used by schedule() and its predecessors + * and so we might get see unexpected behaviors when a task returns + * with unexpected register values. + * + * syscall stores these registers itself and none of them are used + * by syscall after the function in the syscall has been called. + * + * Beware that resume now expects *next to be in d1 and the offset of + * tss to be in a1. This saves a few instructions as we no longer have + * to push them onto the stack and read them back right after. + * + * 02/17/96 - Jes Sorensen (jds@kom.auc.dk) + * + * Changed 96/09/19 by Andreas Schwab + * pass prev in a0, next in a1, offset of tss in d1, and whether + * the mm structures are shared in d2 (to avoid atc flushing). + */ +asmlinkage void resume(void); +#define switch_to(prev,next,last) \ +{ \ + void *_last; \ + __asm__ __volatile__( \ + "movel %1, %%a0\n\t" \ + "movel %2, %%a1\n\t" \ + "jbsr resume\n\t" \ + "movel %%d1, %0\n\t" \ + : "=d" (_last) \ + : "d" (prev), "d" (next) \ + : "cc", "d0", "d1", "d2", "d3", "d4", "d5", "a0", "a1"); \ + (last) = _last; \ +} + +#ifdef CONFIG_COLDFIRE +#define local_irq_enable() __asm__ __volatile__ ( \ + "move %/sr,%%d0\n\t" \ + "andi.l #0xf8ff,%%d0\n\t" \ + "move %%d0,%/sr\n" \ + : /* no outputs */ \ + : \ + : "cc", "%d0", "memory") +#define local_irq_disable() __asm__ __volatile__ ( \ + "move %/sr,%%d0\n\t" \ + "ori.l #0x0700,%%d0\n\t" \ + "move %%d0,%/sr\n" \ + : /* no inputs */ \ + : \ + : "cc", "%d0", "memory") +#else + +/* portable version */ /* FIXME - see entry.h*/ +#define ALLOWINT 0xf8ff + +#define local_irq_enable() asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory") +#define local_irq_disable() asm volatile ("oriw #0x0700,%%sr": : : "memory") +#endif + +#define local_save_flags(x) asm volatile ("movew %%sr,%0":"=d" (x) : : "memory") +#define local_irq_restore(x) asm volatile ("movew %0,%%sr": :"d" (x) : "memory") + +/* For spinlocks etc */ +#define local_irq_save(x) do { local_save_flags(x); local_irq_disable(); } while (0) + +#define irqs_disabled() \ +({ \ + unsigned long flags; \ + local_save_flags(flags); \ + ((flags & 0x0700) == 0x0700); \ +}) + +#define iret() __asm__ __volatile__ ("rte": : :"memory", "sp", "cc") + +/* + * Force strict CPU ordering. + * Not really required on m68k... + */ +#define nop() asm volatile ("nop"::) +#define mb() asm volatile ("" : : :"memory") +#define rmb() asm volatile ("" : : :"memory") +#define wmb() asm volatile ("" : : :"memory") +#define set_rmb(var, value) do { xchg(&var, value); } while (0) +#define set_mb(var, value) set_rmb(var, value) +#define set_wmb(var, value) do { var = value; wmb(); } while (0) + +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() wmb() +#else +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() +#endif + +#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) +#define tas(ptr) (xchg((ptr),1)) + +struct __xchg_dummy { unsigned long a[100]; }; +#define __xg(x) ((volatile struct __xchg_dummy *)(x)) + +#ifndef CONFIG_RMW_INSNS +static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) +{ + unsigned long tmp, flags; + + local_irq_save(flags); + + switch (size) { + case 1: + __asm__ __volatile__ + ("moveb %2,%0\n\t" + "moveb %1,%2" + : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory"); + break; + case 2: + __asm__ __volatile__ + ("movew %2,%0\n\t" + "movew %1,%2" + : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory"); + break; + case 4: + __asm__ __volatile__ + ("movel %2,%0\n\t" + "movel %1,%2" + : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory"); + break; + } + local_irq_restore(flags); + return tmp; +} +#else +static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) +{ + switch (size) { + case 1: + __asm__ __volatile__ + ("moveb %2,%0\n\t" + "1:\n\t" + "casb %0,%1,%2\n\t" + "jne 1b" + : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory"); + break; + case 2: + __asm__ __volatile__ + ("movew %2,%0\n\t" + "1:\n\t" + "casw %0,%1,%2\n\t" + "jne 1b" + : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory"); + break; + case 4: + __asm__ __volatile__ + ("movel %2,%0\n\t" + "1:\n\t" + "casl %0,%1,%2\n\t" + "jne 1b" + : "=&d" (x) : "d" (x), "m" (*__xg(ptr)) : "memory"); + break; + } + return x; +} +#endif + +/* + * Atomic compare and exchange. Compare OLD with MEM, if identical, + * store NEW in MEM. Return the initial value in MEM. Success is + * indicated by comparing RETURN with OLD. + */ +#define __HAVE_ARCH_CMPXCHG 1 + +static __inline__ unsigned long +cmpxchg(volatile int *p, int old, int new) +{ + unsigned long flags; + int prev; + + local_irq_save(flags); + if ((prev = *p) == old) + *p = new; + local_irq_restore(flags); + return(prev); +} + + +#ifdef CONFIG_M68332 +#define HARD_RESET_NOW() ({ \ + local_irq_disable(); \ + asm(" \ + movew #0x0000, 0xfffa6a; \ + reset; \ + /*movew #0x1557, 0xfffa44;*/ \ + /*movew #0x0155, 0xfffa46;*/ \ + moveal #0, %a0; \ + movec %a0, %vbr; \ + moveal 0, %sp; \ + moveal 4, %a0; \ + jmp (%a0); \ + "); \ +}) +#endif + +#if defined( CONFIG_M68328 ) || defined( CONFIG_M68EZ328 ) || \ + defined (CONFIG_M68360) || defined( CONFIG_M68VZ328 ) +#define HARD_RESET_NOW() ({ \ + local_irq_disable(); \ + asm(" \ + moveal #0x10c00000, %a0; \ + moveb #0, 0xFFFFF300; \ + moveal 0(%a0), %sp; \ + moveal 4(%a0), %a0; \ + jmp (%a0); \ + "); \ +}) +#endif + +#ifdef CONFIG_COLDFIRE +#if defined(CONFIG_M5272) && defined(CONFIG_NETtel) +/* + * Need to account for broken early mask of 5272 silicon. So don't + * jump through the original start address. Jump strait into the + * known start of the FLASH code. + */ +#define HARD_RESET_NOW() ({ \ + asm(" \ + movew #0x2700, %sr; \ + jmp 0xf0000400; \ + "); \ +}) +#elif defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) || defined(CONFIG_CLEOPATRA) +#define HARD_RESET_NOW() ({ \ + asm(" \ + movew #0x2700, %sr; \ + moveal #0x10000044, %a0; \ + movel #0xffffffff, (%a0); \ + moveal #0x10000001, %a0; \ + moveb #0x00, (%a0); \ + moveal #0xf0000004, %a0; \ + moveal (%a0), %a0; \ + jmp (%a0); \ + "); \ +}) +#else +#define HARD_RESET_NOW() ({ \ + asm(" \ + movew #0x2700, %sr; \ + moveal #0x4, %a0; \ + moveal (%a0), %a0; \ + jmp (%a0); \ + "); \ +}) +#endif +#endif + +#endif /* _M68KNOMMU_SYSTEM_H */ diff -Nru a/include/asm-m68knommu/termbits.h b/include/asm-m68knommu/termbits.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/termbits.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/termios.h b/include/asm-m68knommu/termios.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/termios.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/thread_info.h b/include/asm-m68knommu/thread_info.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/thread_info.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,100 @@ +/* thread_info.h: m68knommu low-level thread information + * adapted from the i386 and PPC versions by Greg Ungerer (gerg@snapgear.com) + * + * Copyright (C) 2002 David Howells (dhowells@redhat.com) + * - Incorporating suggestions made by Linus Torvalds and Dave Miller + */ + +#ifndef _ASM_THREAD_INFO_H +#define _ASM_THREAD_INFO_H + +#ifdef __KERNEL__ + +#ifndef __ASSEMBLY__ + +/* + * low level task data. + * If you change this, change the TI_* offsets below to match. + */ +struct thread_info { + struct task_struct *task; /* main task structure */ + struct exec_domain *exec_domain; /* execution domain */ + unsigned long flags; /* low level flags */ + int cpu; /* cpu we're on */ + int preempt_count; /* 0 => preemptable, <0 => BUG*/ +}; + +/* + * macros/functions for gaining access to the thread information structure + */ +#define INIT_THREAD_INFO(tsk) \ +{ \ + task: &tsk, \ + exec_domain: &default_exec_domain, \ + flags: 0, \ + cpu: 0, \ +} + +#define init_thread_info (init_thread_union.thread_info) +#define init_stack (init_thread_union.stack) + + +/* + * Size of kernel stack for each process. This must be a power of 2... + */ +#define THREAD_SIZE 8192 /* 2 pages */ + + +/* how to get the thread information struct from C */ +static inline struct thread_info *current_thread_info(void) +{ + struct thread_info *ti; + __asm__( + "move.l %%sp, %0 \n\t" + "and.l %1, %0" + : "=&d"(ti) + : "d" (~(THREAD_SIZE-1)) + ); + return ti; +} + +/* thread information allocation */ +#define alloc_thread_info() ((struct thread_info *) \ + __get_free_pages(GFP_KERNEL, 1)) +#define free_thread_info(ti) free_pages((unsigned long) (ti), 1) +#define get_thread_info(ti) get_task_struct((ti)->task) +#define put_thread_info(ti) put_task_struct((ti)->task) +#endif /* __ASSEMBLY__ */ + +/* + * Offsets in thread_info structure, used in assembly code + */ +#define TI_TASK 0 +#define TI_EXECDOMAIN 4 +#define TI_FLAGS 8 +#define TI_CPU 12 + +#define PREEMPT_ACTIVE 0x4000000 + +/* + * thread information flag bit numbers + */ +#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ +#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ +#define TIF_SIGPENDING 2 /* signal pending */ +#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ +#define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling + TIF_NEED_RESCHED */ + +/* as above, but as bit values */ +#define _TIF_SYSCALL_TRACE (1< diff -Nru a/include/asm-m68knommu/tlb.h b/include/asm-m68knommu/tlb.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/tlb.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-m68knommu/tlbflush.h b/include/asm-m68knommu/tlbflush.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/tlbflush.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,61 @@ +#ifndef _M68KNOMMU_TLBFLUSH_H +#define _M68KNOMMU_TLBFLUSH_H + +/* + * Copyright (C) 2000 Lineo, David McCullough + * Copyright (C) 2000-2002, Greg Ungerer + */ + +#include + +/* + * flush all user-space atc entries. + */ +static inline void __flush_tlb(void) +{ + BUG(); +} + +static inline void __flush_tlb_one(unsigned long addr) +{ + BUG(); +} + +#define flush_tlb() __flush_tlb() + +/* + * flush all atc entries (both kernel and user-space entries). + */ +static inline void flush_tlb_all(void) +{ + BUG(); +} + +static inline void flush_tlb_mm(struct mm_struct *mm) +{ + BUG(); +} + +static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) +{ + BUG(); +} + +static inline void flush_tlb_range(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + BUG(); +} + +extern inline void flush_tlb_kernel_page(unsigned long addr) +{ + BUG(); +} + +extern inline void flush_tlb_pgtables(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + BUG(); +} + +#endif /* _M68KNOMMU_TLBFLUSH_H */ diff -Nru a/include/asm-m68knommu/topology.h b/include/asm-m68knommu/topology.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/topology.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,6 @@ +#ifndef _ASM_M68K_TOPOLOGY_H +#define _ASM_M68K_TOPOLOGY_H + +#include + +#endif /* _ASM_M68K_TOPOLOGY_H */ diff -Nru a/include/asm-m68knommu/traps.h b/include/asm-m68knommu/traps.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/traps.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,150 @@ +/* + * linux/include/asm/traps.h + * + * Copyright (C) 1993 Hamish Macdonald + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#ifndef _M68KNOMMU_TRAPS_H +#define _M68KNOMMU_TRAPS_H + +#ifndef __ASSEMBLY__ + +typedef void (*e_vector)(void); + +extern e_vector vectors[]; + +#endif + +#define VEC_BUSERR (2) +#define VEC_ADDRERR (3) +#define VEC_ILLEGAL (4) +#define VEC_ZERODIV (5) +#define VEC_CHK (6) +#define VEC_TRAP (7) +#define VEC_PRIV (8) +#define VEC_TRACE (9) +#define VEC_LINE10 (10) +#define VEC_LINE11 (11) +#define VEC_RESV1 (12) +#define VEC_COPROC (13) +#define VEC_FORMAT (14) +#define VEC_UNINT (15) +#define VEC_SPUR (24) +#define VEC_INT1 (25) +#define VEC_INT2 (26) +#define VEC_INT3 (27) +#define VEC_INT4 (28) +#define VEC_INT5 (29) +#define VEC_INT6 (30) +#define VEC_INT7 (31) +#define VEC_SYS (32) +#define VEC_TRAP1 (33) +#define VEC_TRAP2 (34) +#define VEC_TRAP3 (35) +#define VEC_TRAP4 (36) +#define VEC_TRAP5 (37) +#define VEC_TRAP6 (38) +#define VEC_TRAP7 (39) +#define VEC_TRAP8 (40) +#define VEC_TRAP9 (41) +#define VEC_TRAP10 (42) +#define VEC_TRAP11 (43) +#define VEC_TRAP12 (44) +#define VEC_TRAP13 (45) +#define VEC_TRAP14 (46) +#define VEC_TRAP15 (47) +#define VEC_FPBRUC (48) +#define VEC_FPIR (49) +#define VEC_FPDIVZ (50) +#define VEC_FPUNDER (51) +#define VEC_FPOE (52) +#define VEC_FPOVER (53) +#define VEC_FPNAN (54) +#define VEC_FPUNSUP (55) +#define VEC_UNIMPEA (60) +#define VEC_UNIMPII (61) +#define VEC_USER (64) + +#define VECOFF(vec) ((vec)<<2) + +#ifndef __ASSEMBLY__ + +/* Status register bits */ +#define PS_T (0x8000) +#define PS_S (0x2000) +#define PS_M (0x1000) +#define PS_C (0x0001) + +/* structure for stack frames */ + +struct frame { + struct pt_regs ptregs; + union { + struct { + unsigned long iaddr; /* instruction address */ + } fmt2; + struct { + unsigned long effaddr; /* effective address */ + } fmt3; + struct { + unsigned long effaddr; /* effective address */ + unsigned long pc; /* pc of faulted instr */ + } fmt4; + struct { + unsigned long effaddr; /* effective address */ + unsigned short ssw; /* special status word */ + unsigned short wb3s; /* write back 3 status */ + unsigned short wb2s; /* write back 2 status */ + unsigned short wb1s; /* write back 1 status */ + unsigned long faddr; /* fault address */ + unsigned long wb3a; /* write back 3 address */ + unsigned long wb3d; /* write back 3 data */ + unsigned long wb2a; /* write back 2 address */ + unsigned long wb2d; /* write back 2 data */ + unsigned long wb1a; /* write back 1 address */ + unsigned long wb1dpd0; /* write back 1 data/push data 0*/ + unsigned long pd1; /* push data 1*/ + unsigned long pd2; /* push data 2*/ + unsigned long pd3; /* push data 3*/ + } fmt7; + struct { + unsigned long iaddr; /* instruction address */ + unsigned short int1[4]; /* internal registers */ + } fmt9; + struct { + unsigned short int1; + unsigned short ssw; /* special status word */ + unsigned short isc; /* instruction stage c */ + unsigned short isb; /* instruction stage b */ + unsigned long daddr; /* data cycle fault address */ + unsigned short int2[2]; + unsigned long dobuf; /* data cycle output buffer */ + unsigned short int3[2]; + } fmta; + struct { + unsigned short int1; + unsigned short ssw; /* special status word */ + unsigned short isc; /* instruction stage c */ + unsigned short isb; /* instruction stage b */ + unsigned long daddr; /* data cycle fault address */ + unsigned short int2[2]; + unsigned long dobuf; /* data cycle output buffer */ + unsigned short int3[4]; + unsigned long baddr; /* stage B address */ + unsigned short int4[2]; + unsigned long dibuf; /* data cycle input buffer */ + unsigned short int5[3]; + unsigned ver : 4; /* stack frame version # */ + unsigned int6:12; + unsigned short int7[18]; + } fmtb; + } un; +}; + +#endif /* __ASSEMBLY__ */ + +#endif /* _M68KNOMMU_TRAPS_H */ diff -Nru a/include/asm-m68knommu/types.h b/include/asm-m68knommu/types.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/types.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,58 @@ +#ifndef _M68K_TYPES_H +#define _M68K_TYPES_H + +/* + * This file is never included by application software unless + * explicitly requested (e.g., via linux/types.h) in which case the + * application is Linux specific so (user-) name space pollution is + * not a major issue. However, for interoperability, libraries still + * need to be careful to avoid a name clashes. + */ + +typedef unsigned short umode_t; + +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +#define BITS_PER_LONG 32 + +/* Dma addresses are 32-bits wide. */ + +typedef u32 dma_addr_t; + +#endif /* __KERNEL__ */ + +#endif /* _M68K_TYPES_H */ diff -Nru a/include/asm-m68knommu/uaccess.h b/include/asm-m68knommu/uaccess.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/uaccess.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,184 @@ +#ifndef __M68KNOMMU_UACCESS_H +#define __M68KNOMMU_UACCESS_H + +/* + * User space memory access functions + */ +#include +#include +#include + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +/* We let the MMU do all checking */ +extern inline int access_ok(int type, const void * addr, unsigned long size) +{ +#define RANGE_CHECK_OK(addr, size, lower, upper) \ + (((addr) >= (lower)) && (((addr) + (size)) < (upper))) + +#ifdef CONFIG_COLDFIRE + extern unsigned long _ramend; + return(RANGE_CHECK_OK((unsigned long) addr, size, 0L, _ramend) || + (is_in_rom((unsigned long) addr) && + is_in_rom((unsigned long) addr + size))); +#else + /* DAVIDM - this could be restricted a lot more */ + return(RANGE_CHECK_OK((unsigned long)addr, size, 0, 0x10f00000)); +#endif +} + +extern inline int verify_area(int type, const void * addr, unsigned long size) +{ + return access_ok(type,addr,size)?0:-EFAULT; +} + +/* + * The exception table consists of pairs of addresses: the first is the + * address of an instruction that is allowed to fault, and the second is + * the address at which the program should continue. No registers are + * modified, so it is entirely up to the continuation code to figure out + * what to do. + * + * All the routines below use bits of fixup code that are out of line + * with the main instruction path. This means when everything is well, + * we don't even have to jump over them. Further, they do not intrude + * on our cache or tlb entries. + */ + +struct exception_table_entry +{ + unsigned long insn, fixup; +}; + +/* Returns 0 if exception not found and fixup otherwise. */ +extern unsigned long search_exception_table(unsigned long); + + +/* + * These are the main single-value transfer routines. They automatically + * use the right size if we just have the right pointer type. + */ + +#define put_user(x, ptr) \ +({ \ + int __pu_err = 0; \ + typeof(*(ptr)) __pu_val = (x); \ + switch (sizeof (*(ptr))) { \ + case 1: \ + __put_user_asm(__pu_err, __pu_val, ptr, b); \ + break; \ + case 2: \ + __put_user_asm(__pu_err, __pu_val, ptr, w); \ + break; \ + case 4: \ + __put_user_asm(__pu_err, __pu_val, ptr, l); \ + break; \ + case 8: \ + memcpy(ptr, &__pu_val, sizeof (*(ptr))); \ + break; \ + default: \ + __pu_err = __put_user_bad(); \ + break; \ + } \ + __pu_err; \ +}) +#define __put_user(x, ptr) put_user(x, ptr) + +extern int __put_user_bad(void); + +/* + * Tell gcc we read from memory instead of writing: this is because + * we do not write to any memory gcc knows about, so there are no + * aliasing issues. + */ + +#define __ptr(x) ((unsigned long *)(x)) + +#define __put_user_asm(err,x,ptr,bwl) \ + __asm__ ("move" #bwl " %0,%1" \ + : /* no outputs */ \ + :"d" (x),"m" (*__ptr(ptr)) : "memory") + +#define get_user(x, ptr) \ +({ \ + int __gu_err = 0; \ + typeof(*(ptr)) __gu_val = 0; \ + switch (sizeof(*(ptr))) { \ + case 1: \ + __get_user_asm(__gu_err, __gu_val, ptr, b, "=d"); \ + break; \ + case 2: \ + __get_user_asm(__gu_err, __gu_val, ptr, w, "=r"); \ + break; \ + case 4: \ + __get_user_asm(__gu_err, __gu_val, ptr, l, "=r"); \ + break; \ + case 8: \ + memcpy(&__gu_val, ptr, sizeof (*(ptr))); \ + break; \ + default: \ + __gu_val = 0; \ + __gu_err = __get_user_bad(); \ + break; \ + } \ + (x) = __gu_val; \ + __gu_err; \ +}) +#define __get_user(x, ptr) get_user(x, ptr) + +extern int __get_user_bad(void); + +#define __get_user_asm(err,x,ptr,bwl,reg) \ + __asm__ ("move" #bwl " %1,%0" \ + : "=d" (x) \ + : "m" (*__ptr(ptr))) + +#define copy_from_user(to, from, n) (memcpy(to, from, n), 0) +#define copy_to_user(to, from, n) (memcpy(to, from, n), 0) + +#define __copy_from_user(to, from, n) copy_from_user(to, from, n) +#define __copy_to_user(to, from, n) copy_to_user(to, from, n) + +#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; }) + +#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; }) + +/* + * Copy a null terminated string from userspace. + */ + +static inline long +strncpy_from_user(char *dst, const char *src, long count) +{ + char *tmp; + strncpy(dst, src, count); + for (tmp = dst; *tmp && count > 0; tmp++, count--) + ; + return(tmp - dst); /* DAVIDM should we count a NUL ? check getname */ +} + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 on exception, a value greater than N if too long + */ +static inline long strnlen_user(const char *src, long n) +{ + return(strlen(src) + 1); /* DAVIDM make safer */ +} + +#define strlen_user(str) strnlen_user(str, 32767) + +/* + * Zero Userspace + */ + +static inline unsigned long +clear_user(void *to, unsigned long n) +{ + memset(to, 0, n); + return(0); +} + +#endif /* _M68KNOMMU_UACCESS_H */ diff -Nru a/include/asm-m68knommu/ucontext.h b/include/asm-m68knommu/ucontext.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/ucontext.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,38 @@ +#ifndef _M68KNOMMU_UCONTEXT_H +#define _M68KNOMMU_UCONTEXT_H + +typedef int greg_t; +#define NGREG 18 +typedef greg_t gregset_t[NGREG]; + +#ifdef CONFIG_FPU +typedef struct fpregset { + int f_pcr; + int f_psr; + int f_fpiaddr; + int f_fpregs[8][3]; +} fpregset_t; +#endif + +struct mcontext { + int version; + gregset_t gregs; +#ifdef CONFIG_FPU + fpregset_t fpregs; +#endif +}; + +#define MCONTEXT_VERSION 2 + +struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + struct mcontext uc_mcontext; +#ifdef CONFIG_FPU + unsigned long uc_filler[80]; +#endif + sigset_t uc_sigmask; /* mask last for extensibility */ +}; + +#endif diff -Nru a/include/asm-m68knommu/unaligned.h b/include/asm-m68knommu/unaligned.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/unaligned.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,32 @@ +#ifndef __M68K_UNALIGNED_H +#define __M68K_UNALIGNED_H + +#include + +#ifdef CONFIG_COLDFIRE + +/* Use memmove here, so gcc does not insert a __builtin_memcpy. */ + +#define get_unaligned(ptr) \ + ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; }) + +#define put_unaligned(val, ptr) \ + ({ __typeof__(*(ptr)) __tmp = (val); \ + memmove((ptr), &__tmp, sizeof(*(ptr))); \ + (void)0; }) + +#else +/* + * The m68k can do unaligned accesses itself. + * + * The strange macros are there to make sure these can't + * be misused in a way that makes them not work on other + * architectures where unaligned accesses aren't as simple. + */ + +#define get_unaligned(ptr) (*(ptr)) +#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) )) + +#endif + +#endif diff -Nru a/include/asm-m68knommu/unistd.h b/include/asm-m68knommu/unistd.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/unistd.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,418 @@ +#ifndef _ASM_M68K_UNISTD_H_ +#define _ASM_M68K_UNISTD_H_ + +/* + * This file contains the system call numbers. + */ + +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_chown 16 +#define __NR_break 17 +#define __NR_oldstat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_oldfstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_stty 31 +#define __NR_gtty 32 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_ftime 35 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_prof 44 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_umount2 52 +#define __NR_lock 53 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_mpx 56 +#define __NR_setpgid 57 +#define __NR_ulimit 58 +#define __NR_oldolduname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 +#define __NR_sigsuspend 72 +#define __NR_sigpending 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_old_getrlimit 76 +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_select 82 +#define __NR_symlink 83 +#define __NR_oldlstat 84 +#define __NR_readlink 85 +#define __NR_uselib 86 +#define __NR_swapon 87 +#define __NR_reboot 88 +#define __NR_readdir 89 +#define __NR_mmap 90 +#define __NR_munmap 91 +#define __NR_truncate 92 +#define __NR_ftruncate 93 +#define __NR_fchmod 94 +#define __NR_fchown 95 +#define __NR_getpriority 96 +#define __NR_setpriority 97 +#define __NR_profil 98 +#define __NR_statfs 99 +#define __NR_fstatfs 100 +#define __NR_ioperm 101 +#define __NR_socketcall 102 +#define __NR_syslog 103 +#define __NR_setitimer 104 +#define __NR_getitimer 105 +#define __NR_stat 106 +#define __NR_lstat 107 +#define __NR_fstat 108 +#define __NR_olduname 109 +#define __NR_iopl /* 110 */ not supported +#define __NR_vhangup 111 +#define __NR_idle /* 112 */ Obsolete +#define __NR_vm86 /* 113 */ not supported +#define __NR_wait4 114 +#define __NR_swapoff 115 +#define __NR_sysinfo 116 +#define __NR_ipc 117 +#define __NR_fsync 118 +#define __NR_sigreturn 119 +#define __NR_clone 120 +#define __NR_setdomainname 121 +#define __NR_uname 122 +#define __NR_cacheflush 123 +#define __NR_adjtimex 124 +#define __NR_mprotect 125 +#define __NR_sigprocmask 126 +#define __NR_create_module 127 +#define __NR_init_module 128 +#define __NR_delete_module 129 +#define __NR_get_kernel_syms 130 +#define __NR_quotactl 131 +#define __NR_getpgid 132 +#define __NR_fchdir 133 +#define __NR_bdflush 134 +#define __NR_sysfs 135 +#define __NR_personality 136 +#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define __NR_setfsuid 138 +#define __NR_setfsgid 139 +#define __NR__llseek 140 +#define __NR_getdents 141 +#define __NR__newselect 142 +#define __NR_flock 143 +#define __NR_msync 144 +#define __NR_readv 145 +#define __NR_writev 146 +#define __NR_getsid 147 +#define __NR_fdatasync 148 +#define __NR__sysctl 149 +#define __NR_mlock 150 +#define __NR_munlock 151 +#define __NR_mlockall 152 +#define __NR_munlockall 153 +#define __NR_sched_setparam 154 +#define __NR_sched_getparam 155 +#define __NR_sched_setscheduler 156 +#define __NR_sched_getscheduler 157 +#define __NR_sched_yield 158 +#define __NR_sched_get_priority_max 159 +#define __NR_sched_get_priority_min 160 +#define __NR_sched_rr_get_interval 161 +#define __NR_nanosleep 162 +#define __NR_mremap 163 +#define __NR_setresuid 164 +#define __NR_getresuid 165 +#define __NR_query_module 167 +#define __NR_poll 168 +#define __NR_nfsservctl 169 +#define __NR_setresgid 170 +#define __NR_getresgid 171 +#define __NR_prctl 172 +#define __NR_rt_sigreturn 173 +#define __NR_rt_sigaction 174 +#define __NR_rt_sigprocmask 175 +#define __NR_rt_sigpending 176 +#define __NR_rt_sigtimedwait 177 +#define __NR_rt_sigqueueinfo 178 +#define __NR_rt_sigsuspend 179 +#define __NR_pread 180 +#define __NR_pwrite 181 +#define __NR_lchown 182 +#define __NR_getcwd 183 +#define __NR_capget 184 +#define __NR_capset 185 +#define __NR_sigaltstack 186 +#define __NR_sendfile 187 +#define __NR_getpmsg 188 /* some people actually want streams */ +#define __NR_putpmsg 189 /* some people actually want streams */ +#define __NR_vfork 190 +#define __NR_getrlimit 191 +#define __NR_mmap2 192 +#define __NR_truncate64 193 +#define __NR_ftruncate64 194 +#define __NR_stat64 195 +#define __NR_lstat64 196 +#define __NR_fstat64 197 +#define __NR_chown32 198 +#define __NR_getuid32 199 +#define __NR_getgid32 200 +#define __NR_geteuid32 201 +#define __NR_getegid32 202 +#define __NR_setreuid32 203 +#define __NR_setregid32 204 +#define __NR_getgroups32 205 +#define __NR_setgroups32 206 +#define __NR_fchown32 207 +#define __NR_setresuid32 208 +#define __NR_getresuid32 209 +#define __NR_setresgid32 210 +#define __NR_getresgid32 211 +#define __NR_lchown32 212 +#define __NR_setuid32 213 +#define __NR_setgid32 214 +#define __NR_setfsuid32 215 +#define __NR_setfsgid32 216 + +/* user-visible error numbers are in the range -1 - -122: see + */ + +#define __syscall_return(type, res) \ +do { \ + if ((unsigned long)(res) >= (unsigned long)(-125)) { \ + /* avoid using res which is declared to be in register d0; \ + errno might expand to a function call and clobber it. */ \ + int __err = -(res); \ + errno = __err; \ + res = -1; \ + } \ + return (type) (res); \ +} while (0) + +#define _syscall0(type, name) \ +type name(void) \ +{ \ + long __res; \ + __asm__ __volatile__ ("movel %1, %%d0\n\t" \ + "trap #0\n\t" \ + "movel %%d0, %0" \ + : "=g" (__res) \ + : "i" (__NR_##name) \ + : "cc", "%d0"); \ + if ((unsigned long)(__res) >= (unsigned long)(-125)) { \ + errno = -__res; \ + __res = -1; \ + } \ + return (type)__res; \ +} + +#define _syscall1(type, name, atype, a) \ +type name(atype a) \ +{ \ + long __res; \ + __asm__ __volatile__ ("movel %2, %%d1\n\t" \ + "movel %1, %%d0\n\t" \ + "trap #0\n\t" \ + "movel %%d0, %0" \ + : "=g" (__res) \ + : "i" (__NR_##name), \ + "g" ((long)a) \ + : "cc", "%d0", "%d1"); \ + if ((unsigned long)(__res) >= (unsigned long)(-125)) { \ + errno = -__res; \ + __res = -1; \ + } \ + return (type)__res; \ +} + +#define _syscall2(type, name, atype, a, btype, b) \ +type name(atype a, btype b) \ +{ \ + long __res; \ + __asm__ __volatile__ ("movel %3, %%d2\n\t" \ + "movel %2, %%d1\n\t" \ + "movel %1, %%d0\n\t" \ + "trap #0\n\t" \ + "movel %%d0, %0" \ + : "=g" (__res) \ + : "i" (__NR_##name), \ + "a" ((long)a), \ + "g" ((long)b) \ + : "cc", "%d0", "%d1", "%d2"); \ + if ((unsigned long)(__res) >= (unsigned long)(-125)) { \ + errno = -__res; \ + __res = -1; \ + } \ + return (type)__res; \ +} + +#define _syscall3(type, name, atype, a, btype, b, ctype, c) \ +type name(atype a, btype b, ctype c) \ +{ \ + long __res; \ + __asm__ __volatile__ ("movel %4, %%d3\n\t" \ + "movel %3, %%d2\n\t" \ + "movel %2, %%d1\n\t" \ + "movel %1, %%d0\n\t" \ + "trap #0\n\t" \ + "movel %%d0, %0" \ + : "=g" (__res) \ + : "i" (__NR_##name), \ + "a" ((long)a), \ + "a" ((long)b), \ + "g" ((long)c) \ + : "cc", "%d0", "%d1", "%d2", "%d3"); \ + if ((unsigned long)(__res) >= (unsigned long)(-125)) { \ + errno = -__res; \ + __res = -1; \ + } \ + return (type)__res; \ +} + +#define _syscall4(type, name, atype, a, btype, b, ctype, c, dtype, d) \ +type name(atype a, btype b, ctype c, dtype d) \ +{ \ + long __res; \ + __asm__ __volatile__ ("movel %5, %%d4\n\t" \ + "movel %4, %%d3\n\t" \ + "movel %3, %%d2\n\t" \ + "movel %2, %%d1\n\t" \ + "movel %1, %%d0\n\t" \ + "trap #0\n\t" \ + "movel %%d0, %0" \ + : "=g" (__res) \ + : "i" (__NR_##name), \ + "a" ((long)a), \ + "a" ((long)b), \ + "a" ((long)c), \ + "g" ((long)d) \ + : "cc", "%d0", "%d1", "%d2", "%d3", \ + "%d4"); \ + if ((unsigned long)(__res) >= (unsigned long)(-125)) { \ + errno = -__res; \ + __res = -1; \ + } \ + return (type)__res; \ +} + +#define _syscall5(type, name, atype, a, btype, b, ctype, c, dtype, d, etype, e) \ +type name(atype a, btype b, ctype c, dtype d, etype e) \ +{ \ + long __res; \ + __asm__ __volatile__ ("movel %6, %%d5\n\t" \ + "movel %5, %%d4\n\t" \ + "movel %4, %%d3\n\t" \ + "movel %3, %%d2\n\t" \ + "movel %2, %%d1\n\t" \ + "movel %1, %%d0\n\t" \ + "trap #0\n\t" \ + "movel %%d0, %0" \ + : "=g" (__res) \ + : "i" (__NR_##name), \ + "a" ((long)a), \ + "a" ((long)b), \ + "a" ((long)c), \ + "a" ((long)d), \ + "g" ((long)e) \ + : "cc", "%d0", "%d1", "%d2", "%d3", \ + "%d4", "%d5"); \ + if ((unsigned long)(__res) >= (unsigned long)(-125)) { \ + errno = -__res; \ + __res = -1; \ + } \ + return (type)__res; \ +} + + +#ifdef __KERNEL_SYSCALLS__ + +/* + * we need this inline - forking from kernel space will result + * in NO COPY ON WRITE (!!!), until an execve is executed. This + * is no problem, but for the stack. This is handled by not letting + * main() use the stack at all after fork(). Thus, no function + * calls - which means inline code for fork too, as otherwise we + * would use the stack upon exit from 'fork()'. + * + * Actually only pause and fork are needed inline, so that there + * won't be any messing with the stack from main(), but we define + * some others too. + */ +#define __NR__exit __NR_exit +static inline _syscall0(int,pause) +static inline _syscall0(int,sync) +static inline _syscall0(pid_t,setsid) +static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) +static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) +static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) +static inline _syscall1(int,dup,int,fd) +static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) +static inline _syscall3(int,open,const char *,file,int,flag,int,mode) +static inline _syscall1(int,close,int,fd) +static inline _syscall1(int,_exit,int,exitcode) +static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) +static inline _syscall1(int,delete_module,const char *,name) + +static inline pid_t wait(int * wait_stat) +{ + return waitpid(-1,wait_stat,0); +} + +#endif + +/* + * "Conditional" syscalls + * + * What we want is __attribute__((weak,alias("sys_ni_syscall"))), + * but it doesn't work on all toolchains, so we just do it by hand + */ +#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall"); + +#endif /* _ASM_M68K_UNISTD_H_ */ diff -Nru a/include/asm-m68knommu/user.h b/include/asm-m68knommu/user.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-m68knommu/user.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-mips/processor.h b/include/asm-mips/processor.h --- a/include/asm-mips/processor.h Mon Nov 4 14:31:00 2002 +++ b/include/asm-mips/processor.h Mon Nov 4 14:31:00 2002 @@ -210,10 +210,6 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); -/* Copy and release all segment info associated with a VM */ -#define copy_segments(p, mm) do { } while(0) -#define release_segments(mm) do { } while(0) - /* * Return saved PC of a blocked thread. */ diff -Nru a/include/asm-mips/ptrace.h b/include/asm-mips/ptrace.h --- a/include/asm-mips/ptrace.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-mips/ptrace.h Mon Nov 4 14:31:02 2002 @@ -59,10 +59,7 @@ /* #define PTRACE_GETFPXREGS 18 */ /* #define PTRACE_SETFPXREGS 19 */ -#define PTRACE_SETOPTIONS 21 - -/* options set using PTRACE_SETOPTIONS */ -#define PTRACE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_OLDSETOPTIONS 21 #ifdef _LANGUAGE_ASSEMBLY #include diff -Nru a/include/asm-mips64/processor.h b/include/asm-mips64/processor.h --- a/include/asm-mips64/processor.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-mips64/processor.h Mon Nov 4 14:31:02 2002 @@ -233,10 +233,6 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); -/* Copy and release all segment info associated with a VM */ -#define copy_segments(p, mm) do { } while(0) -#define release_segments(mm) do { } while(0) - /* * Return saved PC of a blocked thread. */ diff -Nru a/include/asm-mips64/ptrace.h b/include/asm-mips64/ptrace.h --- a/include/asm-mips64/ptrace.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-mips64/ptrace.h Mon Nov 4 14:31:02 2002 @@ -64,10 +64,7 @@ /* #define PTRACE_GETFPXREGS 18 */ /* #define PTRACE_SETFPXREGS 19 */ -#define PTRACE_SETOPTIONS 21 - -/* options set using PTRACE_SETOPTIONS */ -#define PTRACE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_OLDSETOPTIONS 21 #ifdef _LANGUAGE_ASSEMBLY #include diff -Nru a/include/asm-parisc/dma.h b/include/asm-parisc/dma.h --- a/include/asm-parisc/dma.h Mon Nov 4 14:31:03 2002 +++ b/include/asm-parisc/dma.h Mon Nov 4 14:31:03 2002 @@ -1,4 +1,4 @@ -/* $Id: dma.h,v 1.1 2002/07/20 15:52:25 rhirst Exp $ +/* $Id: dma.h,v 1.2 1999/04/27 00:46:18 deller Exp $ * linux/include/asm/dma.h: Defines for using and allocating dma channels. * Written by Hennus Bergman, 1992. * High DMA channel support & info by Hannu Savolainen @@ -177,11 +177,7 @@ } - -/* These are in kernel/dma.c: */ -extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ -extern void free_dma(unsigned int dmanr); /* release it again */ -extern int get_dma_list(char *buf); /* proc/dma support */ +#define free_dma(dmanr) #ifdef CONFIG_PCI extern int isa_dma_bridge_buggy; diff -Nru a/include/asm-parisc/gsc.h b/include/asm-parisc/gsc.h --- a/include/asm-parisc/gsc.h Mon Nov 4 14:31:02 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,31 +0,0 @@ -#ifndef ASM_PARISC_GSC_H -#define ASM_PARISC_GSC_H -#ifdef __KERNEL__ - -#include -#include /* temporary for __raw_{read,write} */ - -/* Please, call ioremap and use {read,write}[bwl] instead. These functions - * are not very fast. - */ -#define gsc_readb(x) __raw_readb((unsigned long)x) -#define gsc_readw(x) __raw_readw((unsigned long)x) -#define gsc_readl(x) __raw_readl((unsigned long)x) -#define gsc_writeb(x, y) __raw_writeb(x, (unsigned long)y) -#define gsc_writew(x, y) __raw_writew(x, (unsigned long)y) -#define gsc_writel(x, y) __raw_writel(x, (unsigned long)y) - -struct gsc_irq { - unsigned long txn_addr; /* IRQ "target" */ - int txn_data; /* HW "IRQ" */ - int irq; /* virtual IRQ */ -}; - -/* PA I/O Architected devices support at least 5 bits in the EIM register. */ -#define GSC_EIM_WIDTH 5 - -extern int gsc_alloc_irq(struct gsc_irq *dev); /* dev needs an irq */ -extern int gsc_claim_irq(struct gsc_irq *dev, int irq); /* dev needs this irq */ - -#endif /* __KERNEL__ */ -#endif /* LINUX_GSC_H */ diff -Nru a/include/asm-parisc/io.h b/include/asm-parisc/io.h --- a/include/asm-parisc/io.h Mon Nov 4 14:31:00 2002 +++ b/include/asm-parisc/io.h Mon Nov 4 14:31:00 2002 @@ -182,6 +182,18 @@ #define isa_memcpy_fromio(a,b,c) memcpy_fromio((a), EISA_BASE | (b), (c)) #define isa_memcpy_toio(a,b,c) memcpy_toio(EISA_BASE | (a), (b), (c)) +/* + * These functions support PA-RISC drivers which don't yet call ioremap(). + * They will disappear once the last of these drivers is gone. + */ +#define gsc_readb(x) __raw_readb((unsigned long)x) +#define gsc_readw(x) __raw_readw((unsigned long)x) +#define gsc_readl(x) __raw_readl((unsigned long)x) +#define gsc_writeb(x, y) __raw_writeb(x, (unsigned long)y) +#define gsc_writew(x, y) __raw_writew(x, (unsigned long)y) +#define gsc_writel(x, y) __raw_writel(x, (unsigned long)y) + + /* * XXX - We don't have csum_partial_copy_fromio() yet, so we cheat here and * just copy it. The net code will then do the checksum later. Presently diff -Nru a/include/asm-parisc/poll.h b/include/asm-parisc/poll.h --- a/include/asm-parisc/poll.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-parisc/poll.h Mon Nov 4 14:31:01 2002 @@ -15,6 +15,7 @@ #define POLLWRNORM 0x0100 #define POLLWRBAND 0x0200 #define POLLMSG 0x0400 +#define POLLREMOVE 0x1000 struct pollfd { int fd; diff -Nru a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h --- a/include/asm-parisc/processor.h Mon Nov 4 14:31:03 2002 +++ b/include/asm-parisc/processor.h Mon Nov 4 14:31:03 2002 @@ -73,10 +73,8 @@ ** Per CPU data structure - ie varies per CPU. */ struct cpuinfo_parisc { - - struct irq_region *region; - unsigned long it_value; /* Interval Timer value at last timer Intr */ - unsigned long it_delta; /* Interval Timer delta (tic_10ms / HZ * 100) */ + unsigned long it_value; /* Interval Timer at last timer Intr */ + unsigned long it_delta; /* Interval delta (tic_10ms / HZ * 100) */ unsigned long irq_count; /* number of IRQ's since boot */ unsigned long irq_max_cr16; /* longest time to handle a single IRQ */ unsigned long cpuid; /* aka slot_number or set to NO_PROC_ID */ @@ -296,12 +294,6 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); extern void map_hpux_gateway_page(struct task_struct *tsk, struct mm_struct *mm); - -#define copy_segments(tsk, mm) do { \ - if (tsk->personality == PER_HPUX) \ - map_hpux_gateway_page(tsk,mm); \ - } while (0) -#define release_segments(mm) do { } while (0) static inline unsigned long get_wchan(struct task_struct *p) { diff -Nru a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h --- a/include/asm-ppc/processor.h Mon Nov 4 14:31:00 2002 +++ b/include/asm-ppc/processor.h Mon Nov 4 14:31:00 2002 @@ -736,9 +736,6 @@ #define thread_saved_pc(tsk) \ ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0) -#define copy_segments(tsk, mm) do { } while (0) -#define release_segments(mm) do { } while (0) - unsigned long get_wchan(struct task_struct *p); #define KSTK_EIP(tsk) ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0) diff -Nru a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h --- a/include/asm-ppc64/processor.h Mon Nov 4 14:31:00 2002 +++ b/include/asm-ppc64/processor.h Mon Nov 4 14:31:00 2002 @@ -682,10 +682,6 @@ #define thread_saved_pc(tsk) \ ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0) -#define copy_segments(tsk, mm) do { } while (0) -#define release_segments(mm) do { } while (0) -#define forget_segments() do { } while (0) - unsigned long get_wchan(struct task_struct *p); #define KSTK_EIP(tsk) ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0) diff -Nru a/include/asm-s390/processor.h b/include/asm-s390/processor.h --- a/include/asm-s390/processor.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-s390/processor.h Mon Nov 4 14:31:01 2002 @@ -114,10 +114,6 @@ extern void release_thread(struct task_struct *); extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); -/* Copy and release all segment info associated with a VM */ -#define copy_segments(nr, mm) do { } while (0) -#define release_segments(mm) do { } while (0) - /* * Return saved PC of a blocked thread. */ diff -Nru a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h --- a/include/asm-s390/ptrace.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-s390/ptrace.h Mon Nov 4 14:31:02 2002 @@ -105,10 +105,7 @@ #define STACK_FRAME_OVERHEAD 96 /* size of minimum stack frame */ -#define PTRACE_SETOPTIONS 21 - -/* options set using PTRACE_SETOPTIONS */ -#define PTRACE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_OLDSETOPTIONS 21 #ifndef __ASSEMBLY__ #include diff -Nru a/include/asm-s390x/processor.h b/include/asm-s390x/processor.h --- a/include/asm-s390x/processor.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-s390x/processor.h Mon Nov 4 14:31:02 2002 @@ -131,10 +131,6 @@ extern void release_thread(struct task_struct *); extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); -/* Copy and release all segment info associated with a VM */ -#define copy_segments(nr, mm) do { } while (0) -#define release_segments(mm) do { } while (0) - /* * Return saved PC of a blocked thread. */ diff -Nru a/include/asm-s390x/ptrace.h b/include/asm-s390x/ptrace.h --- a/include/asm-s390x/ptrace.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-s390x/ptrace.h Mon Nov 4 14:31:01 2002 @@ -85,10 +85,7 @@ #define STACK_FRAME_OVERHEAD 160 /* size of minimum stack frame */ -#define PTRACE_SETOPTIONS 21 - -/* options set using PTRACE_SETOPTIONS */ -#define PTRACE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_OLDSETOPTIONS 21 #ifndef __ASSEMBLY__ #include diff -Nru a/include/asm-sh/processor.h b/include/asm-sh/processor.h --- a/include/asm-sh/processor.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-sh/processor.h Mon Nov 4 14:31:01 2002 @@ -147,11 +147,6 @@ #define MCA_bus 0 #define MCA_bus__is_a_macro /* for versions in ksyms.c */ - -/* Copy and release all segment info associated with a VM */ -#define copy_segments(p, mm) do { } while(0) -#define release_segments(mm) do { } while(0) - /* * FPU lazy state save handling. */ diff -Nru a/include/asm-sh/ptrace.h b/include/asm-sh/ptrace.h --- a/include/asm-sh/ptrace.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-sh/ptrace.h Mon Nov 4 14:31:02 2002 @@ -44,10 +44,7 @@ #define REG_XDREG14 47 #define REG_FPSCR 48 -#define PTRACE_SETOPTIONS 21 - -/* options set using PTRACE_SETOPTIONS */ -#define PTRACE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_OLDSETOPTIONS 21 /* * This struct defines the way the registers are stored on the diff -Nru a/include/asm-sparc/mman.h b/include/asm-sparc/mman.h --- a/include/asm-sparc/mman.h Mon Nov 4 14:31:02 2002 +++ b/include/asm-sparc/mman.h Mon Nov 4 14:31:02 2002 @@ -32,6 +32,9 @@ #define MCL_CURRENT 0x2000 /* lock all currently mapped pages */ #define MCL_FUTURE 0x4000 /* lock all additions to address space */ +#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ +#define MAP_NONBLOCK 0x10000 /* do not block on IO */ + /* XXX Need to add flags to SunOS's mctl, mlockall, and madvise system * XXX calls. */ diff -Nru a/include/asm-sparc/processor.h b/include/asm-sparc/processor.h --- a/include/asm-sparc/processor.h Mon Nov 4 14:31:03 2002 +++ b/include/asm-sparc/processor.h Mon Nov 4 14:31:03 2002 @@ -140,10 +140,6 @@ #define release_thread(tsk) do { } while(0) extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); - -#define copy_segments(tsk, mm) do { } while (0) -#define release_segments(mm) do { } while (0) - #define get_wchan(__TSK) \ ({ extern void scheduling_functions_start_here(void); \ extern void scheduling_functions_end_here(void); \ diff -Nru a/include/asm-sparc64/mman.h b/include/asm-sparc64/mman.h --- a/include/asm-sparc64/mman.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-sparc64/mman.h Mon Nov 4 14:31:01 2002 @@ -32,6 +32,9 @@ #define MCL_CURRENT 0x2000 /* lock all currently mapped pages */ #define MCL_FUTURE 0x4000 /* lock all additions to address space */ +#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ +#define MAP_NONBLOCK 0x10000 /* do not block on IO */ + /* XXX Need to add flags to SunOS's mctl, mlockall, and madvise system * XXX calls. */ diff -Nru a/include/asm-sparc64/processor.h b/include/asm-sparc64/processor.h --- a/include/asm-sparc64/processor.h Mon Nov 4 14:31:00 2002 +++ b/include/asm-sparc64/processor.h Mon Nov 4 14:31:00 2002 @@ -188,9 +188,6 @@ extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); -#define copy_segments(tsk, mm) do { } while (0) -#define release_segments(mm) do { } while (0) - #define get_wchan(__TSK) \ ({ extern void scheduling_functions_start_here(void); \ extern void scheduling_functions_end_here(void); \ diff -Nru a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h --- a/include/asm-um/processor-generic.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-um/processor-generic.h Mon Nov 4 14:31:01 2002 @@ -92,17 +92,6 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); extern void dump_thread(struct pt_regs *regs, struct user *u); -static inline void release_segments(struct mm_struct *mm) -{ -} - -static inline void copy_segments(struct task_struct *p, - struct mm_struct *new_mm) -{ -} - -#define forget_segments() do ; while(0) - extern unsigned long thread_saved_pc(struct task_struct *t); #define init_stack (init_thread_union.stack) diff -Nru a/include/asm-v850/a.out.h b/include/asm-v850/a.out.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/a.out.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,21 @@ +#ifndef __V850_A_OUT_H__ +#define __V850_A_OUT_H__ + +struct exec +{ + unsigned long a_info; /* Use macros N_MAGIC, etc for access */ + unsigned a_text; /* length of text, in bytes */ + unsigned a_data; /* length of data, in bytes */ + unsigned a_bss; /* length of uninitialized data area for file, in bytes */ + unsigned a_syms; /* length of symbol table data in file, in bytes */ + unsigned a_entry; /* start address */ + unsigned a_trsize; /* length of relocation info for text, in bytes */ + unsigned a_drsize; /* length of relocation info for data, in bytes */ +}; + +#define N_TRSIZE(a) ((a).a_trsize) +#define N_DRSIZE(a) ((a).a_drsize) +#define N_SYMSIZE(a) ((a).a_syms) + + +#endif /* __V850_A_OUT_H__ */ diff -Nru a/include/asm-v850/anna.h b/include/asm-v850/anna.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/anna.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,150 @@ +/* + * include/asm-v850/anna.h -- Anna V850E2 evaluation cpu chip/board + * + * Copyright (C) 2001,2002 NEC Corporation + * Copyright (C) 2001,2002 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_ANNA_H__ +#define __V850_ANNA_H__ + + +#define CPU_ARCH "v850e2" +#define CPU_MODEL "v850e2/anna" +#define CPU_MODEL_LONG "NEC V850E2/Anna" +#define PLATFORM "anna" +#define PLATFORM_LONG "NEC/Midas lab V850E2/Anna evaluation board" + +#define CPU_CLOCK_FREQ 200000000 /* 200MHz */ +#define SYS_CLOCK_FREQ 33300000 /* 33.3MHz */ + + +/* 1MB of static RAM. This memory is mirrored 64 times. */ +#define SRAM_ADDR 0x04000000 +#define SRAM_SIZE 0x00100000 /* 1MB */ +/* 64MB of DRAM. */ +#define SDRAM_ADDR 0x08000000 +#define SDRAM_SIZE 0x04000000 /* 64MB */ + + +/* For */ +#define PAGE_OFFSET SRAM_ADDR + +/* We use on-chip RAM, for a few miscellaneous variables that must be + accessible using a load instruction relative to R0. The Anna chip has + 128K of `dLB' ram nominally located at 0xFFF00000, but it's mirrored + every 128K, so we can use the `last mirror' (except for the portion at + the top which is overridden by I/O space). In addition, the early + sample chip we're using has lots of memory errors in the dLB ram, so we + use a specially chosen location that has at least 20 bytes of contiguous + valid memory (xxxF0020 - xxxF003F). */ +#define R0_RAM_ADDR 0xFFFF8020 + + +/* Anna specific control registers. */ +#define ANNA_CSC_ADDR(n) (0xFFFFF060 + (n) * 2) +#define ANNA_CSC(n) (*(volatile u16 *)ANNA_CSC_ADDR(n)) +#define ANNA_BPC_ADDR 0xFFFFF064 +#define ANNA_BPC (*(volatile u16 *)ANNA_BPC_ADDR) +#define ANNA_BSC_ADDR 0xFFFFF066 +#define ANNA_BSC (*(volatile u16 *)ANNA_BSC_ADDR) +#define ANNA_BEC_ADDR 0xFFFFF068 +#define ANNA_BEC (*(volatile u16 *)ANNA_BEC_ADDR) +#define ANNA_BHC_ADDR 0xFFFFF06A +#define ANNA_BHC (*(volatile u16 *)ANNA_BHC_ADDR) +#define ANNA_BCT_ADDR(n) (0xFFFFF480 + (n) * 2) +#define ANNA_BCT(n) (*(volatile u16 *)ANNA_BCT_ADDR(n)) +#define ANNA_DWC_ADDR(n) (0xFFFFF484 + (n) * 2) +#define ANNA_DWC(n) (*(volatile u16 *)ANNA_DWC_ADDR(n)) +#define ANNA_BCC_ADDR 0xFFFFF488 +#define ANNA_BCC (*(volatile u16 *)ANNA_BCC_ADDR) +#define ANNA_ASC_ADDR 0xFFFFF48A +#define ANNA_ASC (*(volatile u16 *)ANNA_ASC_ADDR) +#define ANNA_LBS_ADDR 0xFFFFF48E +#define ANNA_LBS (*(volatile u16 *)ANNA_LBS_ADDR) +#define ANNA_SCR3_ADDR 0xFFFFF4AC +#define ANNA_SCR3 (*(volatile u16 *)ANNA_SCR3_ADDR) +#define ANNA_RFS3_ADDR 0xFFFFF4AE +#define ANNA_RFS3 (*(volatile u16 *)ANNA_RFS3_ADDR) +#define ANNA_ILBEN_ADDR 0xFFFFF7F2 +#define ANNA_ILBEN (*(volatile u16 *)ANNA_ILBEN_ADDR) + + +/* I/O port P0-P3. */ +/* Direct I/O. Bits 0-7 are pins Pn0-Pn7. */ +#define ANNA_PORT_IO_ADDR(n) (0xFFFFF400 + (n) * 2) +#define ANNA_PORT_IO(n) (*(volatile u8 *)ANNA_PORT_IO_ADDR(n)) +/* Port mode (for direct I/O, 0 = output, 1 = input). */ +#define ANNA_PORT_PM_ADDR(n) (0xFFFFF410 + (n) * 2) +#define ANNA_PORT_PM(n) (*(volatile u8 *)ANNA_PORT_PM_ADDR(n)) + + +/* NB85E-style interrupt system. */ +#include + +/* Hardware-specific interrupt numbers (in the kernel IRQ namespace). */ +#define IRQ_INTP(n) (n) /* Pnnn (pin) interrupts 0-15 */ +#define IRQ_INTP_NUM 16 +#define IRQ_INTOV(n) (0x10 + (n)) /* 0-2 */ +#define IRQ_INTOV_NUM 2 +#define IRQ_INTCCC(n) (0x12 + (n)) +#define IRQ_INTCCC_NUM 4 +#define IRQ_INTCMD(n) (0x16 + (n)) /* interval timer interrupts 0-5 */ +#define IRQ_INTCMD_NUM 6 +#define IRQ_INTDMA(n) (0x1C + (n)) /* DMA interrupts 0-3 */ +#define IRQ_INTDMA_NUM 4 +#define IRQ_INTDMXER 0x20 +#define IRQ_INTSRE(n) (0x21 + (n)*3) /* UART 0-1 reception error */ +#define IRQ_INTSRE_NUM 2 +#define IRQ_INTSR(n) (0x22 + (n)*3) /* UART 0-1 reception completion */ +#define IRQ_INTSR_NUM 2 +#define IRQ_INTST(n) (0x23 + (n)*3) /* UART 0-1 transmission completion */ +#define IRQ_INTST_NUM 2 + +#define NUM_CPU_IRQS 64 + +#ifndef __ASSEMBLY__ +/* Initialize chip interrupts. */ +extern void anna_init_irqs (void); +#endif + + +/* Anna UART details (basically the same as the V850E/MA1, but 2 channels). */ +#define NB85E_UART_NUM_CHANNELS 2 +#define NB85E_UART_BASE_FREQ (SYS_CLOCK_FREQ / 2) +#define NB85E_UART_CHIP_NAME "V850E2/NA85E2A" + +/* This is a function that gets called before configuring the UART. */ +#define NB85E_UART_PRE_CONFIGURE anna_uart_pre_configure +#ifndef __ASSEMBLY__ +extern void anna_uart_pre_configure (unsigned chan, + unsigned cflags, unsigned baud); +#endif + + +/* Timer C details. */ +#define NB85E_TIMER_C_BASE_ADDR 0xFFFFF600 + +/* Timer D details (the Anna actually has 5 of these; should change later). */ +#define NB85E_TIMER_D_BASE_ADDR 0xFFFFF540 +#define NB85E_TIMER_D_TMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x0) +#define NB85E_TIMER_D_CMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x2) +#define NB85E_TIMER_D_TMCD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x4) + +#define NB85E_TIMER_D_BASE_FREQ SYS_CLOCK_FREQ +#define NB85E_TIMER_D_TMCD_CS_MIN 1 /* min 2^1 divider */ + + +/* For */ +#ifndef HZ +#define HZ 100 +#endif + + +#endif /* __V850_ANNA_H__ */ diff -Nru a/include/asm-v850/asm.h b/include/asm-v850/asm.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/asm.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,25 @@ +/* + * include/asm-v850/asm.h -- Macros for writing assembly code + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#define G_ENTRY(name) \ + .align 4; \ + .globl name; \ + .type name,@function; \ + name +#define END(name) \ + .size name,.-name + +#define L_ENTRY(name) \ + .align 4; \ + .type name,@function; \ + name diff -Nru a/include/asm-v850/atomic.h b/include/asm-v850/atomic.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/atomic.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,89 @@ +/* + * include/asm-v850/atomic.h -- Atomic operations + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_ATOMIC_H__ +#define __V850_ATOMIC_H__ + +#include + +#include + +#ifdef CONFIG_SMP +#error SMP not supported +#endif + +typedef struct { int counter; } atomic_t; + +#define ATOMIC_INIT(i) { (i) } + +#ifdef __KERNEL__ + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v,i) (((v)->counter) = (i)) + +extern __inline__ int atomic_add_return (int i, volatile atomic_t *v) +{ + unsigned long flags; + int res; + + local_irq_save (flags); + res = v->counter + i; + v->counter = res; + local_irq_restore (flags); + + return res; +} + +static __inline__ int atomic_sub_return (int i, volatile atomic_t *v) +{ + unsigned long flags; + int res; + + local_irq_save (flags); + res = v->counter - i; + v->counter = res; + local_irq_restore (flags); + + return res; +} + +static __inline__ void atomic_clear_mask (unsigned long mask, unsigned long *addr) +{ + unsigned long flags; + + local_irq_save (flags); + *addr &= ~mask; + local_irq_restore (flags); +} + +#endif + +#define atomic_add(i, v) atomic_add_return ((i), (v)) +#define atomic_sub(i, v) atomic_sub_return ((i), (v)) + +#define atomic_dec_return(v) atomic_sub_return (1, (v)) +#define atomic_inc_return(v) atomic_add_return (1, (v)) +#define atomic_inc(v) atomic_inc_return (v) +#define atomic_dec(v) atomic_dec_return (v) + +#define atomic_sub_and_test(i,v) (atomic_sub_return ((i), (v)) == 0) +#define atomic_dec_and_test(v) (atomic_sub_return (1, (v)) == 0) +#define atomic_add_negative(i,v) (atomic_add_return ((i), (v)) < 0) + +/* Atomic operations are already serializing on ARM */ +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() + +#endif /* __V850_ATOMIC_H__ */ diff -Nru a/include/asm-v850/bitops.h b/include/asm-v850/bitops.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/bitops.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,269 @@ +/* + * include/asm-v850/bitops.h -- Bit operations + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * Copyright (C) 1992 Linus Torvalds. + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ + +#ifndef __V850_BITOPS_H__ +#define __V850_BITOPS_H__ + + +#include +#include /* unlikely */ +#include /* swab32 */ +#include /* interrupt enable/disable */ + + +#ifdef __KERNEL__ + +/* + * The __ functions are not atomic + */ + +/* + * ffz = Find First Zero in word. Undefined if no zero exists, + * so code should check against ~0UL first.. + */ +extern __inline__ unsigned long ffz (unsigned long word) +{ + unsigned long result = 0; + + while (word & 1) { + result++; + word >>= 1; + } + return result; +} + + +/* In the following constant-bit-op macros, a "g" constraint is used when + we really need an integer ("i" constraint). This is to avoid + warnings/errors from the compiler in the case where the associated + operand _isn't_ an integer, and shouldn't produce bogus assembly because + use of that form is protected by a guard statement that checks for + constants, and should otherwise be removed by the optimizer. This + _usually_ works -- however, __builtin_constant_p returns true for a + variable with a known constant value too, and unfortunately gcc will + happily put the variable in a register and use the register for the "g" + constraint'd asm operand. To avoid the latter problem, we add a + constant offset to the operand and subtract it back in the asm code; + forcing gcc to do arithmetic on the value is usually enough to get it + to use a real constant value. This is horrible, and ultimately + unreliable too, but it seems to work for now (hopefully gcc will offer + us more control in the future, so we can do a better job). */ + +#define __const_bit_op(op, nr, addr) \ + ({ __asm__ (op " (%0 - 0x123), %1" \ + :: "g" (((nr) & 0x7) + 0x123), \ + "m" (*((char *)(addr) + ((nr) >> 3))) \ + : "memory"); }) +#define __var_bit_op(op, nr, addr) \ + ({ int __nr = (nr); \ + __asm__ (op " %0, [%1]" \ + :: "r" (__nr & 0x7), \ + "r" ((char *)(addr) + (__nr >> 3)) \ + : "memory"); }) +#define __bit_op(op, nr, addr) \ + ((__builtin_constant_p (nr) && (unsigned)(nr) <= 0x7FFFF) \ + ? __const_bit_op (op, nr, addr) \ + : __var_bit_op (op, nr, addr)) + +#define __set_bit(nr, addr) __bit_op ("set1", nr, addr) +#define __clear_bit(nr, addr) __bit_op ("clr1", nr, addr) +#define __change_bit(nr, addr) __bit_op ("not1", nr, addr) + +/* The bit instructions used by `non-atomic' variants are actually atomic. */ +#define set_bit __set_bit +#define clear_bit __clear_bit +#define change_bit __change_bit + + +#define __const_tns_bit_op(op, nr, addr) \ + ({ int __tns_res; \ + __asm__ ("tst1 (%1 - 0x123), %2; setf nz, %0; " op " (%1 - 0x123), %2" \ + : "=&r" (__tns_res) \ + : "g" (((nr) & 0x7) + 0x123), \ + "m" (*((char *)(addr) + ((nr) >> 3))) \ + : "memory"); \ + __tns_res; \ + }) +#define __var_tns_bit_op(op, nr, addr) \ + ({ int __nr = (nr); \ + int __tns_res; \ + __asm__ ("tst1 %1, [%2]; setf nz, %0; " op " %1, [%2]" \ + : "=&r" (__tns_res) \ + : "r" (__nr & 0x7), \ + "r" ((char *)(addr) + (__nr >> 3)) \ + : "memory"); \ + __tns_res; \ + }) +#define __tns_bit_op(op, nr, addr) \ + ((__builtin_constant_p (nr) && (unsigned)(nr) <= 0x7FFFF) \ + ? __const_tns_bit_op (op, nr, addr) \ + : __var_tns_bit_op (op, nr, addr)) +#define __tns_atomic_bit_op(op, nr, addr) \ + ({ int __tns_atomic_res, __tns_atomic_flags; \ + local_irq_save (__tns_atomic_flags); \ + __tns_atomic_res = __tns_bit_op (op, nr, addr); \ + local_irq_restore (__tns_atomic_flags); \ + __tns_atomic_res; \ + }) + +#define __test_and_set_bit(nr, addr) __tns_bit_op ("set1", nr, addr) +#define test_and_set_bit(nr, addr) __tns_atomic_bit_op ("set1", nr, addr) + +#define __test_and_clear_bit(nr, addr) __tns_bit_op ("clr1", nr, addr) +#define test_and_clear_bit(nr, addr) __tns_atomic_bit_op ("clr1", nr, addr) + +#define __test_and_change_bit(nr, addr) __tns_bit_op ("not1", nr, addr) +#define test_and_change_bit(nr, addr) __tns_atomic_bit_op ("not1", nr, addr) + + +#define __const_test_bit(nr, addr) \ + ({ int __test_bit_res; \ + __asm__ ("tst1 (%1 - 0x123), %2; setf nz, %0" \ + : "=r" (__test_bit_res) \ + : "g" (((nr) & 0x7) + 0x123), \ + "m" (*((const char *)(addr) + ((nr) >> 3)))); \ + __test_bit_res; \ + }) +extern __inline__ int __test_bit (int nr, void *addr) +{ + int res; + __asm__ ("tst1 %1, [%2]; setf nz, %0" + : "=r" (res) + : "r" (nr & 0x7), "r" (addr + (nr >> 3))); + return res; +} +#define test_bit(nr,addr) \ + ((__builtin_constant_p (nr) && (unsigned)(nr) <= 0x7FFFF) \ + ? __const_test_bit ((nr), (addr)) \ + : __test_bit ((nr), (addr))) + + +/* clear_bit doesn't provide any barrier for the compiler. */ +#define smp_mb__before_clear_bit() barrier () +#define smp_mb__after_clear_bit() barrier () + + +#define find_first_zero_bit(addr, size) \ + find_next_zero_bit ((addr), (size), 0) + +extern __inline__ int find_next_zero_bit (void *addr, int size, int offset) +{ + unsigned long *p = ((unsigned long *) addr) + (offset >> 5); + unsigned long result = offset & ~31UL; + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset &= 31UL; + if (offset) { + tmp = * (p++); + tmp |= ~0UL >> (32-offset); + if (size < 32) + goto found_first; + if (~tmp) + goto found_middle; + size -= 32; + result += 32; + } + while (size & ~31UL) { + if (~ (tmp = * (p++))) + goto found_middle; + result += 32; + size -= 32; + } + if (!size) + return result; + tmp = *p; + + found_first: + tmp |= ~0UL >> size; + found_middle: + return result + ffz (tmp); +} + +#define ffs(x) generic_ffs (x) +#define fls(x) generic_fls (x) +#define __ffs(x) ffs(x) + +/* + * This is just `generic_ffs' from , except that it assumes + * that at least one bit is set, and returns the real index of the bit + * (rather than the bit index + 1, like ffs does). + */ +static inline int sched_ffs(int x) +{ + int r = 0; + + if (!(x & 0xffff)) { + x >>= 16; + r += 16; + } + if (!(x & 0xff)) { + x >>= 8; + r += 8; + } + if (!(x & 0xf)) { + x >>= 4; + r += 4; + } + if (!(x & 3)) { + x >>= 2; + r += 2; + } + if (!(x & 1)) { + x >>= 1; + r += 1; + } + return r; +} + +/* + * Every architecture must define this function. It's the fastest + * way of searching a 140-bit bitmap where the first 100 bits are + * unlikely to be set. It's guaranteed that at least one of the 140 + * bits is set. + */ +static inline int sched_find_first_bit(unsigned long *b) +{ + unsigned offs = 0; + while (! *b) { + b++; + offs += 32; + } + return sched_ffs (*b) + offs; +} + +/* + * hweightN: returns the hamming weight (i.e. the number + * of bits set) of a N-bit word + */ +#define hweight32(x) generic_hweight32 (x) +#define hweight16(x) generic_hweight16 (x) +#define hweight8(x) generic_hweight8 (x) + +#define ext2_set_bit test_and_set_bit +#define ext2_clear_bit test_and_clear_bit +#define ext2_test_bit test_bit +#define ext2_find_first_zero_bit find_first_zero_bit +#define ext2_find_next_zero_bit find_next_zero_bit + +/* Bitmap functions for the minix filesystem. */ +#define minix_test_and_set_bit test_and_set_bit +#define minix_set_bit set_bit +#define minix_test_and_clear_bit test_and_clear_bit +#define minix_test_bit test_bit +#define minix_find_first_zero_bit find_first_zero_bit + +#endif /* __KERNEL__ */ + +#endif /* __V850_BITOPS_H__ */ diff -Nru a/include/asm-v850/bugs.h b/include/asm-v850/bugs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/bugs.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,16 @@ +/* + * include/asm-v850e/bugs.h + * + * Copyright (C) 1994 Linus Torvalds + */ + +/* + * This is included by init/main.c to check for architecture-dependent bugs. + * + * Needs: + * void check_bugs(void); + */ + +static void check_bugs(void) +{ +} diff -Nru a/include/asm-v850/byteorder.h b/include/asm-v850/byteorder.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/byteorder.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,47 @@ +/* + * include/asm-v850/byteorder.h -- Endian id and conversion ops + * + * Copyright (C) 2001 NEC Corporation + * Copyright (C) 2001 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_BYTEORDER_H__ +#define __V850_BYTEORDER_H__ + +#include + +#ifdef __GNUC__ + +static __inline__ __const__ __u32 ___arch__swab32 (__u32 word) +{ + __u32 res; + __asm__ ("bsw %1, %0" : "=r" (res) : "r" (word)); + return res; +} + +static __inline__ __const__ __u16 ___arch__swab16 (__u16 half_word) +{ + __u16 res; + __asm__ ("bsh %1, %0" : "=r" (res) : "r" (half_word)); + return res; +} + +#define __arch__swab32(x) ___arch__swab32(x) +#define __arch__swab16(x) ___arch__swab16(x) + +#if !defined(__STRICT_ANSI__) || defined(__KERNEL__) +# define __BYTEORDER_HAS_U64__ +# define __SWAB_64_THRU_32__ +#endif + +#endif /* __GNUC__ */ + +#include + +#endif /* __V850_BYTEORDER_H__ */ diff -Nru a/include/asm-v850/cache.h b/include/asm-v850/cache.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/cache.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,25 @@ +/* + * include/asm-v850/cache.h -- Cache operations + * + * Copyright (C) 2001 NEC Corporation + * Copyright (C) 2001 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_CACHE_H__ +#define __V850_CACHE_H__ + +/* All cache operations are machine-dependent. */ +#include + +#ifndef L1_CACHE_BYTES +/* This processor has no cache, so just choose an arbitrary value. */ +#define L1_CACHE_BYTES 16 +#endif + +#endif /* __V850_CACHE_H__ */ diff -Nru a/include/asm-v850/cacheflush.h b/include/asm-v850/cacheflush.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/cacheflush.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,42 @@ +/* + * include/asm-v850/cacheflush.h + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_CACHEFLUSH_H__ +#define __V850_CACHEFLUSH_H__ + +/* Somebody depends on this; sigh... */ +#include + +#include +#include + + +#ifndef flush_cache_all +/* If there's no flush_cache_all macro defined by , then + this processor has no cache, so just define these as nops. */ + +#define flush_cache_all() ((void)0) +#define flush_cache_mm(mm) ((void)0) +#define flush_cache_range(vma, start, end) ((void)0) +#define flush_cache_page(vma, vmaddr) ((void)0) +#define flush_page_to_ram(page) ((void)0) +#define flush_dcache_page(page) ((void)0) +#define flush_icache() ((void)0) +#define flush_icache_range(start, end) ((void)0) +#define flush_icache_page(vma,pg) ((void)0) +#define flush_icache_user_range(vma,pg,adr,len) ((void)0) +#define flush_cache_sigtramp(vaddr) ((void)0) + +#endif /* !flush_cache_all */ + +#endif /* __V850_CACHEFLUSH_H__ */ diff -Nru a/include/asm-v850/checksum.h b/include/asm-v850/checksum.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/checksum.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,115 @@ +/* + * include/asm-v850/checksum.h -- Checksum ops + * + * Copyright (C) 2001 NEC Corporation + * Copyright (C) 2001 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_CHECKSUM_H__ +#define __V850_CHECKSUM_H__ + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +extern unsigned int csum_partial (const unsigned char * buff, int len, + unsigned int sum); + +/* + * the same as csum_partial, but copies from src while it + * checksums + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ +extern unsigned csum_partial_copy (const char *src, char *dst, int len, + unsigned sum); + + +/* + * the same as csum_partial_copy, but copies from user space. + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ +extern unsigned csum_partial_copy_from_user (const char *src, char *dst, + int len, unsigned sum, + int *csum_err); + +#define csum_partial_copy_nocheck(src, dst, len, sum) \ + csum_partial_copy ((src), (dst), (len), (sum)) + +unsigned short ip_fast_csum (unsigned char *iph, unsigned int ihl); + +/* + * Fold a partial checksum + */ +static inline unsigned int csum_fold (unsigned long sum) +{ + unsigned int result; + /* + %0 %1 + hsw %1, %0 H L L H + add %1, %0 H L H+L+C H+L + */ + asm ("hsw %1, %0; add %1, %0" : "=&r" (result) : "r" (sum)); + return (~result) >> 16; +} + + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ +static inline unsigned int +csum_tcpudp_nofold (unsigned long saddr, unsigned long daddr, + unsigned short len, + unsigned short proto, unsigned int sum) +{ + int __carry; + __asm__ ("add %2, %0;" + "setf c, %1;" + "add %1, %0;" + "add %3, %0;" + "setf c, %1;" + "add %1, %0;" + "add %4, %0;" + "setf c, %1;" + "add %1, %0" + : "=&r" (sum), "=&r" (__carry) + : "r" (daddr), "r" (saddr), + "r" (ntohs (len) + (proto << 8)), + "0" (sum)); + return sum; +} + +static inline unsigned short int +csum_tcpudp_magic (unsigned long saddr, unsigned long daddr, + unsigned short len, + unsigned short proto, unsigned int sum) +{ + return csum_fold (csum_tcpudp_nofold (saddr, daddr, len, proto, sum)); +} + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ +extern unsigned short ip_compute_csum (const unsigned char * buff, int len); + + +#endif /* __V850_CHECKSUM_H__ */ diff -Nru a/include/asm-v850/clinkage.h b/include/asm-v850/clinkage.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/clinkage.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,25 @@ +/* + * include/asm-v850/clinkage.h -- Macros to reflect C symbol-naming conventions + * + * Copyright (C) 2001,02 NEC Corporatione + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __CLINKAGE_H__ +#define __V850_CLINKAGE_H__ + +#include +#include + +#define C_SYMBOL_NAME(name) macrology_paste(_, name) +#define C_SYMBOL_STRING(name) macrology_stringify(C_SYMBOL_NAME(name)) +#define C_ENTRY(name) G_ENTRY(C_SYMBOL_NAME(name)) +#define C_END(name) END(C_SYMBOL_NAME(name)) + +#endif /* __V850_CLINKAGE_H__ */ diff -Nru a/include/asm-v850/current.h b/include/asm-v850/current.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/current.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,44 @@ +/* + * include/asm-v850/current.h -- Current task + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_CURRENT_H__ +#define __V850_CURRENT_H__ + +#include +#include + + +/* Register used to hold the current task pointer while in the kernel. + Any `call clobbered' register without a special meaning should be OK, + but check asm/v850/kernel/entry.S to be sure. */ +#define CURRENT_TASK_REGNUM 16 +#define CURRENT_TASK macrology_paste (r, CURRENT_TASK_REGNUM) + + +#ifdef __ASSEMBLY__ + +/* Put a pointer to the current task structure into REG. */ +#define GET_CURRENT_TASK(reg) \ + GET_CURRENT_THREAD(reg); \ + ld.w TI_TASK[reg], reg + +#else /* !__ASSEMBLY__ */ + +/* A pointer to the current task. */ +register struct task_struct *current \ + __asm__ (macrology_stringify (CURRENT_TASK)); + +#endif /* __ASSEMBLY__ */ + + +#endif /* _V850_CURRENT_H */ diff -Nru a/include/asm-v850/delay.h b/include/asm-v850/delay.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/delay.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,46 @@ +/* + * include/asm-v850/delay.h -- Delay routines, using a pre-computed + * "loops_per_second" value + * + * Copyright (C) 2001 NEC Corporation + * Copyright (C) 2001 Miles Bader + * Copyright (C) 1994 Hamish Macdonald + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ + +#ifndef __V850_DELAY_H__ +#define __V850_DELAY_H__ + +#include + +extern __inline__ void __delay(unsigned long loops) +{ + __asm__ __volatile__ ("1: add -1, %0; bnz 1b" + : "=r" (loops) : "0" (loops)); +} + +/* + * Use only for very small delays ( < 1 msec). Should probably use a + * lookup table, really, as the multiplications take much too long with + * short delays. This is a "reasonable" implementation, though (and the + * first constant multiplications gets optimized away if the delay is + * a constant) + */ + +extern unsigned long loops_per_jiffy; + +extern __inline__ void udelay(unsigned long usecs) +{ + register unsigned long full_loops, part_loops; + + full_loops = ((usecs * HZ) / 1000000) * loops_per_jiffy; + usecs %= (1000000 / HZ); + part_loops = (usecs * HZ * loops_per_jiffy) / 1000000; + + __delay(full_loops + part_loops); +} + +#endif /* __V850_DELAY_H__ */ diff -Nru a/include/asm-v850/div64.h b/include/asm-v850/div64.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/div64.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,11 @@ +#ifndef __V850_DIV64_H__ +#define __V850_DIV64_H__ + +/* We're not 64-bit, but... */ +#define do_div(n,base) ({ \ + int __res; \ + __res = ((unsigned long) n) % (unsigned) base; \ + n = ((unsigned long) n) / (unsigned) base; \ + __res; }) + +#endif /* __V850_DIV64_H__ */ diff -Nru a/include/asm-v850/dma.h b/include/asm-v850/dma.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/dma.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,18 @@ +#ifndef __V850_DMA_H__ +#define __V850_DMA_H__ + +/* What should this be? */ +#define MAX_DMA_ADDRESS 0xFFFFFFFF + +/* reserve a DMA channel */ +extern int request_dma (unsigned int dmanr, const char * device_id); +/* release it again */ +extern void free_dma (unsigned int dmanr); + +#ifdef CONFIG_PCI +extern int isa_dma_bridge_buggy; +#else +#define isa_dma_bridge_buggy (0) +#endif + +#endif /* __V850_DMA_H__ */ diff -Nru a/include/asm-v850/elf.h b/include/asm-v850/elf.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/elf.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,75 @@ +#ifndef __V850_ELF_H__ +#define __V850_ELF_H__ + +/* + * ELF register definitions.. + */ + +#include +#include +#include + +typedef unsigned long elf_greg_t; + +#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct user_fpu_struct elf_fpregset_t; + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ( (x)->e_machine == EM_CYGNUS_V850 ) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#ifdef __LITTLE_ENDIAN__ +#define ELF_DATA ELFDATA2LSB +#else +#define ELF_DATA ELFDATA2MSB +#endif +#define ELF_ARCH EM_V850 + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + + +#define ELF_CORE_COPY_REGS(_dest,_regs) \ + memcpy((char *) &_dest, (char *) _regs, \ + sizeof(struct pt_regs)); + +/* This yields a mask that user programs can use to figure out what + instruction set this CPU supports. This could be done in user space, + but it's not easy, and we've already done it here. */ + +#define ELF_HWCAP (0) + +/* This yields a string that ld.so will use to load implementation + specific libraries for optimization. This is more specific in + intent than poking at uname or /proc/cpuinfo. + + For the moment, we have only optimizations for the Intel generations, + but that could change... */ + +#define ELF_PLATFORM (NULL) + +#define ELF_PLAT_INIT(_r) \ + do { \ + _r->gpr[0] = _r->gpr[1] = _r->gpr[2] = _r->gpr[3] = \ + _r->gpr[4] = _r->gpr[5] = _r->gpr[6] = _r->gpr[7] = \ + _r->gpr[8] = _r->gpr[9] = _r->gpr[10] = _r->gpr[11] = \ + _r->gpr[12] = _r->gpr[13] = _r->gpr[14] = _r->gpr[15] = \ + _r->gpr[16] = _r->gpr[17] = _r->gpr[18] = _r->gpr[19] = \ + _r->gpr[20] = _r->gpr[21] = _r->gpr[22] = _r->gpr[23] = \ + _r->gpr[24] = _r->gpr[25] = _r->gpr[26] = _r->gpr[27] = \ + _r->gpr[28] = _r->gpr[29] = _r->gpr[30] = _r->gpr[31] = \ + 0; \ + } while (0) + +#ifdef __KERNEL__ +#define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT) +#endif + +#endif /* __V850_ELF_H__ */ diff -Nru a/include/asm-v850/entry.h b/include/asm-v850/entry.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/entry.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,128 @@ +/* + * include/asm-v850/entry.h -- Definitions used by low-level trap handlers + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_ENTRY_H__ +#define __V850_ENTRY_H__ + + +#include +#include + + +/* If true, system calls save and restore all registers (except result + registers, of course). If false, then `call clobbered' registers + will not be preserved, on the theory that system calls are basically + function calls anyway, and the caller should be able to deal with it. + This is a security risk, of course, as `internal' values may leak out + after a system call, but that certainly doesn't matter very much for + a processor with no MMU protection! For a protected-mode kernel, it + would be faster to just zero those registers before returning. */ +#define TRAPS_PRESERVE_CALL_CLOBBERED_REGS 0 + +/* If TRAPS_PRESERVE_CALL_CLOBBERED_REGS is false, then zero `call + clobbered' registers before returning from a system call. */ +#define TRAPS_ZERO_CALL_CLOBBERED_REGS 0 + + +/* These are special variables using by the kernel trap/interrupt code + to save registers in, at a time when there are no spare registers we + can use to do so, and we can't depend on the value of the stack + pointer. This means that they must be within a signed 16-bit + displacement of 0x00000000. */ + +#define KERNEL_VAR_SPACE_ADDR R0_RAM_ADDR + +#ifdef __ASSEMBLY__ +#define KERNEL_VAR(addr) addr[r0] +#else +#define KERNEL_VAR(addr) (*(volatile unsigned long *)(addr)) +#endif + +/* Kernel stack pointer, 4 bytes. */ +#define KSP_ADDR (KERNEL_VAR_SPACE_ADDR + 0) +#define KSP KERNEL_VAR (KSP_ADDR) +/* 1 if in kernel-mode, 0 if in user mode, 1 byte. */ +#define KM_ADDR (KERNEL_VAR_SPACE_ADDR + 4) +#define KM KERNEL_VAR (KM_ADDR) +/* Temporary storage for interrupt handlers, 4 bytes. */ +#define INT_SCRATCH_ADDR (KERNEL_VAR_SPACE_ADDR + 8) +#define INT_SCRATCH KERNEL_VAR (INT_SCRATCH_ADDR) +/* Where the stack-pointer is saved when jumping to various sorts of + interrupt handlers. ENTRY_SP is used by everything except NMIs, + which have their own location. Higher-priority NMIs can clobber the + value written by a lower priority NMI, since they can't be disabled, + but that's OK, because only NMI0 (the lowest-priority one) is allowed + to return. */ +#define ENTRY_SP_ADDR (KERNEL_VAR_SPACE_ADDR + 12) +#define ENTRY_SP KERNEL_VAR (ENTRY_SP_ADDR) +#define NMI_ENTRY_SP_ADDR (KERNEL_VAR_SPACE_ADDR + 16) +#define NMI_ENTRY_SP KERNEL_VAR (NMI_ENTRY_SP_ADDR) + +#ifdef CONFIG_RESET_GUARD +/* Used to detect unexpected resets (since the v850 has no MMU, any call + through a null pointer will jump to the reset vector). We detect + such resets by checking for a magic value, RESET_GUARD_ACTIVE, in + this location. Properly resetting the machine stores zero there, so + it shouldn't trigger the guard; the power-on value is uncertain, but + it's unlikely to be RESET_GUARD_ACTIVE. */ +#define RESET_GUARD_ADDR (KERNEL_VAR_SPACE_ADDR + 28) +#define RESET_GUARD KERNEL_VAR (RESET_GUARD_ADDR) +#define RESET_GUARD_ACTIVE 0xFAB4BEEF +#endif /* CONFIG_RESET_GUARD */ + +#ifdef CONFIG_V850E_MA1_HIGHRES_TIMER +#define HIGHRES_TIMER_SLOW_TICKS_ADDR (KERNEL_VAR_SPACE_ADDR + 32) +#define HIGHRES_TIMER_SLOW_TICKS KERNEL_VAR (HIGHRES_TIMER_SLOW_TICKS_ADDR) +#endif /* CONFIG_V850E_MA1_HIGHRES_TIMER */ + +#ifndef __ASSEMBLY__ + +#ifdef CONFIG_RESET_GUARD +/* Turn off reset guard, so that resetting the machine works normally. + This should be called in the various machine_halt, etc., functions. */ +static inline void disable_reset_guard (void) +{ + RESET_GUARD = 0; +} +#endif /* CONFIG_RESET_GUARD */ + +#endif /* !__ASSEMBLY__ */ + + +/* A `state save frame' is a struct pt_regs preceded by some extra space + suitable for a function call stack frame. */ + +/* Amount of room on the stack reserved for arguments and to satisfy the + C calling conventions, in addition to the space used by the struct + pt_regs that actually holds saved values. */ +#define STATE_SAVE_ARG_SPACE (6*4) /* Up to six arguments. */ + + +#ifdef __ASSEMBLY__ + +/* The size of a state save frame. */ +#define STATE_SAVE_SIZE (PT_SIZE + STATE_SAVE_ARG_SPACE) + +#else /* !__ASSEMBLY__ */ + +/* The size of a state save frame. */ +#define STATE_SAVE_SIZE (sizeof (struct pt_regs) + STATE_SAVE_ARG_SPACE) + +#endif /* __ASSEMBLY__ */ + + +/* Offset of the struct pt_regs in a state save frame. */ +#define STATE_SAVE_PT_OFFSET STATE_SAVE_ARG_SPACE + + +#endif /* __V850_ENTRY_H__ */ diff -Nru a/include/asm-v850/errno.h b/include/asm-v850/errno.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/errno.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,6 @@ +#ifndef __V850_ERRNO_H__ +#define __V850_ERRNO_H__ + +#include + +#endif /* __V850_ERRNO_H__ */ diff -Nru a/include/asm-v850/fcntl.h b/include/asm-v850/fcntl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/fcntl.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,86 @@ +#ifndef __V850_FCNTL_H__ +#define __V850_FCNTL_H__ + +/* open/fcntl - O_SYNC is only implemented on blocks devices and on files + located on an ext2 file system */ +#define O_ACCMODE 0003 +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 +#define O_CREAT 0100 /* not fcntl */ +#define O_EXCL 0200 /* not fcntl */ +#define O_NOCTTY 0400 /* not fcntl */ +#define O_TRUNC 01000 /* not fcntl */ +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_NDELAY O_NONBLOCK +#define O_SYNC 010000 +#define FASYNC 020000 /* fcntl, for BSD compatibility */ +#define O_DIRECTORY 040000 /* must be a directory */ +#define O_NOFOLLOW 0100000 /* don't follow links */ +#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */ +#define O_LARGEFILE 0400000 + +#define F_DUPFD 0 /* dup */ +#define F_GETFD 1 /* get close_on_exec */ +#define F_SETFD 2 /* set/clear close_on_exec */ +#define F_GETFL 3 /* get file->f_flags */ +#define F_SETFL 4 /* set file->f_flags */ +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLKW 7 + +#define F_SETOWN 8 /* for sockets. */ +#define F_GETOWN 9 /* for sockets. */ +#define F_SETSIG 10 /* for sockets. */ +#define F_GETSIG 11 /* for sockets. */ + +#define F_GETLK64 12 /* using 'struct flock64' */ +#define F_SETLK64 13 +#define F_SETLKW64 14 + +/* for F_[GET|SET]FL */ +#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ + +/* for posix fcntl() and lockf() */ +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +/* for old implementation of bsd flock () */ +#define F_EXLCK 4 /* or 3 */ +#define F_SHLCK 8 /* or 4 */ + +/* for leases */ +#define F_INPROGRESS 16 + +/* operations for bsd flock(), also used by the kernel implementation */ +#define LOCK_SH 1 /* shared lock */ +#define LOCK_EX 2 /* exclusive lock */ +#define LOCK_NB 4 /* or'd with one of the above to prevent + blocking */ +#define LOCK_UN 8 /* remove lock */ + +#define LOCK_MAND 32 /* This is a mandatory flock */ +#define LOCK_READ 64 /* ... Which allows concurrent read operations */ +#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */ +#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */ + +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +struct flock64 { + short l_type; + short l_whence; + loff_t l_start; + loff_t l_len; + pid_t l_pid; +}; + +#define F_LINUX_SPECIFIC_BASE 1024 +#endif /* __V850_FCNTL_H__ */ diff -Nru a/include/asm-v850/fpga85e2c.h b/include/asm-v850/fpga85e2c.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/fpga85e2c.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,107 @@ +/* + * include/asm-v850/fpga85e2c.h -- Machine-dependent defs for + * FPGA implementation of V850E2/NA85E2C + * + * Copyright (C) 2002 NEC Corporation + * Copyright (C) 2002 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_FPGA85E2C_H__ +#define __V850_FPGA85E2C_H__ + + +#include + + +#define CPU_ARCH "v850e2" +#define CPU_MODEL "FPGA NA85E2C/V850E2" + + +/* `external ram'. */ +#define ERAM_ADDR 0 +#define ERAM_SIZE 0x00100000 /* 1MB */ + + +/* FPGA specific control registers. */ + +/* Writing a non-zero value to FLGREG(0) will signal the controlling CPU + to stop execution. */ +#define FLGREG_ADDR(n) (0xFFE80100 + 2*(n)) +#define FLGREG(n) (*(volatile unsigned char *)FLGREG_ADDR (n)) +#define FLGREG_NUM 2 + +#define CSDEV_ADDR(n) (0xFFE80110 + 2*(n)) +#define CSDEV(n) (*(volatile unsigned char *)CSDEV_ADDR (n)) + +/* The BSC register controls bus-sizing. Each memory area CSn uses a pair + of bits N*2 and N*2+1, where 00 means an 8-bit bus size, 01 16-bit, and + 10 32-bit. */ +#define BSC_ADDR 0xFFFFF066 +#define BSC (*(volatile unsigned short *)BSC_ADDR) + +#define DWC_ADDR(n) (0xFFFFF484 + 2*(n)) +#define DWC(n) (*(volatile unsigned short *)DWC_ADDR (n)) + +#define ASC_ADDR 0xFFFFF48A +#define ASC (*(volatile unsigned short *)ASC_ADDR) + +#define BTSC_ADDR 0xFFFFF070 +#define BTSC (*(volatile unsigned short *)BTSC_ADDR) + +#define BHC_ADDR 0xFFFFF06A +#define BHC (*(volatile unsigned short *)BHC_ADDR) + + +/* NB85E-style interrupt system. */ +#include + +/* Timer interrupts 0-3, interrupt at intervals from CLK/4096 to CLK/16384. */ +#define IRQ_RPU(n) (60 + (n)) +#define IRQ_RPU_NUM 4 + +/* For */ +#define NUM_CPU_IRQS 64 + + +/* General-purpose timer. */ +/* control/status register (can only be read/written via bit insns) */ +#define RPU_GTMC_ADDR 0xFFFFFB00 +#define RPU_GTMC (*(volatile unsigned char *)RPU_GTMC_ADDR) +#define RPU_GTMC_CE_BIT 7 /* clock enable (control) */ +#define RPU_GTMC_OV_BIT 6 /* overflow (status) */ +#define RPU_GTMC_CLK_BIT 1 /* 0 = .5 MHz CLK, 1 = 1 Mhz (control) */ +/* 32-bit count (8 least-significant bits are always zero). */ +#define RPU_GTM_ADDR 0xFFFFFB28 +#define RPU_GTM (*(volatile unsigned long *)RPU_GTMC_ADDR) + + +/* For */ +#define PAGE_OFFSET ERAM_ADDR /* minimum allocatable address */ + + +/* For */ +/* `R0 RAM', used for a few miscellaneous variables that must be accessible + using a load instruction relative to R0. The FPGA implementation + actually has no on-chip RAM, so we use part of main ram just after the + interrupt vectors. */ +#ifdef __ASSEMBLY__ +#define R0_RAM_ADDR lo(C_SYMBOL_NAME(_r0_ram)) +#else +extern char _r0_ram; +#define R0_RAM_ADDR ((unsigned long)&_r0_ram); +#endif + + +/* For */ +#ifndef HZ +#define HZ 122 /* actually, 8.192ms ticks =~ 122.07 */ +#endif + + +#endif /* __V850_FPGA85E2C_H__ */ diff -Nru a/include/asm-v850/gbus_int.h b/include/asm-v850/gbus_int.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/gbus_int.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,97 @@ +/* + * include/asm-v850/gbus_int.h -- Midas labs GBUS interrupt support + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_GBUS_INT_H__ +#define __V850_GBUS_INT_H__ + + +/* The GBUS interrupt interface has 32 interrupts shared among 4 + processor interrupts. The 32 GBUS interrupts are divided into two + sets of 16 each, for allocating among control registers, etc (there + are two of each control register, with bits 0-15 controlling an + interrupt each). */ + +/* The GBUS interrupts themselves. */ +#define IRQ_GBUS_INT(n) (GBUS_INT_BASE_IRQ + (n)) +#define IRQ_GBUS_INT_NUM 32 + +/* Control registers. */ +#define GBUS_INT_STATUS_ADDR(w) (GBUS_INT_BASE_ADDR + (w)*0x40) +#define GBUS_INT_STATUS(w) (*(volatile u16 *)GBUS_INT_STATUS_ADDR(w)) +#define GBUS_INT_CLEAR_ADDR(w) (GBUS_INT_BASE_ADDR + 0x10 + (w)*0x40) +#define GBUS_INT_CLEAR(w) (*(volatile u16 *)GBUS_INT_CLEAR_ADDR(w)) +#define GBUS_INT_EDGE_ADDR(w) (GBUS_INT_BASE_ADDR + 0x20 + (w)*0x40) +#define GBUS_INT_EDGE(w) (*(volatile u16 *)GBUS_INT_EDGE_ADDR(w)) +#define GBUS_INT_POLARITY_ADDR(w) (GBUS_INT_BASE_ADDR + 0x30 + (w)*0x40) +#define GBUS_INT_POLARITY(w) (*(volatile u16 *)GBUS_INT_POLARITY_ADDR(w)) +/* This allows enabling interrupt bits in word W for interrupt GINTn. */ +#define GBUS_INT_ENABLE_ADDR(w, n) \ + (GBUS_INT_BASE_ADDR + 0x100 + (w)*0x10 + (n)*0x20) +#define GBUS_INT_ENABLE(w, n) (*(volatile u16 *)GBUS_INT_ENABLE_ADDR(w, n)) + +/* Mapping between kernel interrupt numbers and hardware control regs/bits. */ +#define GBUS_INT_BITS_PER_WORD 16 +#define GBUS_INT_NUM_WORDS (IRQ_GBUS_INT_NUM / GBUS_INT_BITS_PER_WORD) +#define GBUS_INT_IRQ_WORD(irq) (((irq) - GBUS_INT_BASE_IRQ) >> 4) +#define GBUS_INT_IRQ_BIT(irq) (((irq) - GBUS_INT_BASE_IRQ) & 0xF) +#define GBUS_INT_IRQ_MASK(irq) (1 << GBUS_INT_IRQ_BIT(irq)) + + +/* Possible priorities for GBUS interrupts. */ +#define GBUS_INT_PRIORITY_HIGH 2 +#define GBUS_INT_PRIORITY_MEDIUM 4 +#define GBUS_INT_PRIORITY_LOW 6 + + +#ifndef __ASSEMBLY__ + +/* Enable interrupt handling for interrupt IRQ. */ +extern void gbus_int_enable_irq (unsigned irq); +/* Disable interrupt handling for interrupt IRQ. Note that any + interrupts received while disabled will be delivered once the + interrupt is enabled again, unless they are explicitly cleared using + `gbus_int_clear_pending_irq'. */ +extern void gbus_int_disable_irq (unsigned irq); +/* Return true if interrupt handling for interrupt IRQ is enabled. */ +extern int gbus_int_irq_enabled (unsigned irq); +/* Disable all GBUS irqs. */ +extern int gbus_int_disable_irqs (void); +/* Clear any pending interrupts for IRQ. */ +extern void gbus_int_clear_pending_irq (unsigned irq); +/* Return true if interrupt IRQ is pending (but disabled). */ +extern int gbus_int_irq_pending (unsigned irq); + + +struct gbus_int_irq_init { + const char *name; /* name of interrupt type */ + + /* Range of kernel irq numbers for this type: + BASE, BASE+INTERVAL, ..., BASE+INTERVAL*NUM */ + unsigned base, num, interval; + + unsigned priority; /* interrupt priority to assign */ +}; +struct hw_interrupt_type; /* fwd decl */ + +/* Initialize HW_IRQ_TYPES for GBUS irqs described in array + INITS (which is terminated by an entry with the name field == 0). */ +extern void gbus_int_init_irq_types (struct gbus_int_irq_init *inits, + struct hw_interrupt_type *hw_irq_types); + +/* Initialize GBUS interrupts. */ +extern void gbus_int_init_irqs (void); + +#endif /* !__ASSEMBLY__ */ + + +#endif /* __V850_GBUS_INT_H__ */ diff -Nru a/include/asm-v850/hardirq.h b/include/asm-v850/hardirq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/hardirq.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,96 @@ +#ifndef __V850_HARDIRQ_H__ +#define __V850_HARDIRQ_H__ + +#include +#include + +typedef struct { + unsigned int __softirq_pending; + unsigned int __syscall_count; + struct task_struct * __ksoftirqd_task; +} ____cacheline_aligned irq_cpustat_t; + +#include /* Standard mappings for irq_cpustat_t above */ + +/* + * We put the hardirq and softirq counter into the preemption + * counter. The bitmask has the following meaning: + * + * - bits 0-7 are the preemption count (max preemption depth: 256) + * - bits 8-15 are the softirq count (max # of softirqs: 256) + * - bits 16-23 are the hardirq count (max # of hardirqs: 256) + * + * - ( bit 26 is the PREEMPT_ACTIVE flag. ) + * + * PREEMPT_MASK: 0x000000ff + * HARDIRQ_MASK: 0x0000ff00 + * SOFTIRQ_MASK: 0x00ff0000 + */ + +#define PREEMPT_BITS 8 +#define SOFTIRQ_BITS 8 +#define HARDIRQ_BITS 8 + +#define PREEMPT_SHIFT 0 +#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS) +#define HARDIRQ_SHIFT (SOFTIRQ_SHIFT + SOFTIRQ_BITS) + +#define __MASK(x) ((1UL << (x))-1) + +#define PREEMPT_MASK (__MASK(PREEMPT_BITS) << PREEMPT_SHIFT) +#define HARDIRQ_MASK (__MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT) +#define SOFTIRQ_MASK (__MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT) + +#define hardirq_count() (preempt_count() & HARDIRQ_MASK) +#define softirq_count() (preempt_count() & SOFTIRQ_MASK) +#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK)) + +#define PREEMPT_OFFSET (1UL << PREEMPT_SHIFT) +#define SOFTIRQ_OFFSET (1UL << SOFTIRQ_SHIFT) +#define HARDIRQ_OFFSET (1UL << HARDIRQ_SHIFT) + +/* + * The hardirq mask has to be large enough to have + * space for potentially all IRQ sources in the system + * nesting on a single CPU: + */ +#if (1 << HARDIRQ_BITS) < NR_IRQS +# error HARDIRQ_BITS is too low! +#endif + +/* + * Are we doing bottom half or hardware interrupt processing? + * Are we in a softirq context? Interrupt context? + */ +#define in_irq() (hardirq_count()) +#define in_softirq() (softirq_count()) +#define in_interrupt() (irq_count()) + +#define hardirq_trylock() (!in_interrupt()) +#define hardirq_endlock() do { } while (0) + +#define irq_enter() (preempt_count() += HARDIRQ_OFFSET) + +#if CONFIG_PREEMPT +# define in_atomic() (preempt_count() != kernel_locked()) +# define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) +#else +# define in_atomic() (preempt_count() != 0) +# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET +#endif + +#define irq_exit() \ +do { \ + preempt_count() -= IRQ_EXIT_OFFSET; \ + if (!in_interrupt() && softirq_pending(smp_processor_id())) \ + do_softirq(); \ + preempt_enable_no_resched(); \ +} while (0) + +#ifndef CONFIG_SMP +# define synchronize_irq(irq) barrier() +#else +# error v850nommu SMP is not available +#endif /* CONFIG_SMP */ + +#endif /* __V850_HARDIRQ_H__ */ diff -Nru a/include/asm-v850/highres_timer.h b/include/asm-v850/highres_timer.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/highres_timer.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,44 @@ +/* + * include/asm-v850/highres_timer.h -- High resolution timing routines + * + * Copyright (C) 2001 NEC Corporation + * Copyright (C) 2001 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_HIGHRES_TIMER_H__ +#define __V850_HIGHRES_TIMER_H__ + +#ifndef __ASSEMBLY__ +#include +#endif + +#include + + +/* Frequency of the `slow ticks' (one tick each time the fast-tick + counter overflows). */ +#define HIGHRES_TIMER_SLOW_TICK_RATE 25 + +/* Which timer in the nb85e `Timer D' we use. */ +#define HIGHRES_TIMER_TIMER_D_UNIT 3 + + +#ifndef __ASSEMBLY__ + +extern void highres_timer_start (void), highres_timer_stop (void); +extern void highres_timer_reset (void); +extern void highres_timer_read_ticks (u32 *slow_ticks, u32 *fast_ticks); +extern void highres_timer_ticks_to_timeval (u32 slow_ticks, u32 fast_ticks, + struct timeval *tv); +extern void highres_timer_read (struct timeval *tv); + +#endif /* !__ASSEMBLY__ */ + + +#endif /* __V850_HIGHRES_TIMER_H__ */ diff -Nru a/include/asm-v850/hw_irq.h b/include/asm-v850/hw_irq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/hw_irq.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,8 @@ +#ifndef __V850_HW_IRQ_H__ +#define __V850_HW_IRQ_H__ + +extern inline void hw_resend_irq (struct hw_interrupt_type *h, unsigned int i) +{ +} + +#endif /* __V850_HW_IRQ_H__ */ diff -Nru a/include/asm-v850/io.h b/include/asm-v850/io.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/io.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,106 @@ +/* + * include/asm-v850/io.h -- Misc I/O operations + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_IO_H__ +#define __V850_IO_H__ + +#define IO_SPACE_LIMIT 0xFFFFFFFF + +#define readb(addr) \ + ({ unsigned char __v = (*(volatile unsigned char *) (addr)); __v; }) +#define readw(addr) \ + ({ unsigned short __v = (*(volatile unsigned short *) (addr)); __v; }) +#define readl(addr) \ + ({ unsigned long __v = (*(volatile unsigned long *) (addr)); __v; }) + +#define writeb(b, addr) \ + (void)((*(volatile unsigned char *) (addr)) = (b)) +#define writew(b, addr) \ + (void)((*(volatile unsigned short *) (addr)) = (b)) +#define writel(b, addr) \ + (void)((*(volatile unsigned int *) (addr)) = (b)) + +#define inb(addr) readb (addr) +#define inw(addr) readw (addr) +#define inl(addr) readl (addr) +#define outb(x, addr) ((void) writeb (x, addr)) +#define outw(x, addr) ((void) writew (x, addr)) +#define outl(x, addr) ((void) writel (x, addr)) + +#define inb_p(port) inb((port)) +#define outb_p(val, port) outb((val), (port)) +#define inw_p(port) inw((port)) +#define outw_p(val, port) outw((val), (port)) +#define inl_p(port) inl((port)) +#define outl_p(val, port) outl((val), (port)) + +static inline void insb (unsigned long port, void *dst, unsigned long count) +{ + unsigned char *p = dst; + while (count--) + *p++ = inb (port); +} +static inline void insw (unsigned long port, void *dst, unsigned long count) +{ + unsigned short *p = dst; + while (count--) + *p++ = inw (port); +} +static inline void insl (unsigned long port, void *dst, unsigned long count) +{ + unsigned long *p = dst; + while (count--) + *p++ = inl (port); +} + +static inline void +outsb (unsigned long port, const void *src, unsigned long count) +{ + const unsigned char *p = src; + while (count--) + outb (*p++, port); +} +static inline void +outsw (unsigned long port, const void *src, unsigned long count) +{ + const unsigned short *p = src; + while (count--) + outw (*p++, port); +} +static inline void +outsl (unsigned long port, const void *src, unsigned long count) +{ + const unsigned long *p = src; + while (count--) + outl (*p++, port); +} + +#define iounmap(addr) ((void)0) +#define ioremap(physaddr, size) (physaddr) +#define ioremap_nocache(physaddr, size) (physaddr) +#define ioremap_writethrough(physaddr, size) (physaddr) +#define ioremap_fullcache(physaddr, size) (physaddr) + +#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT) +#if 0 +/* This is really stupid; don't define it. */ +#define page_to_bus(page) page_to_phys (page) +#endif + +/* Conversion between virtual and physical mappings. */ +#define mm_ptov(addr) ((void *)__phys_to_virt (addr)) +#define mm_vtop(addr) ((unsigned long)__virt_to_phys (addr)) +#define phys_to_virt(addr) ((void *)__phys_to_virt (addr)) +#define virt_to_phys(addr) ((unsigned long)__virt_to_phys (addr)) + +#endif /* __V850_IO_H__ */ diff -Nru a/include/asm-v850/ioctl.h b/include/asm-v850/ioctl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/ioctl.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,80 @@ +/* $Id: ioctl.h,v 1.1 2002/09/28 14:58:41 gerg Exp $ + * + * linux/ioctl.h for Linux by H.H. Bergman. + */ + +#ifndef _V850_IOCTL_H +#define _V850_IOCTL_H + +/* ioctl command encoding: 32 bits total, command in lower 16 bits, + * size of the parameter structure in the lower 14 bits of the + * upper 16 bits. + * Encoding the size of the parameter structure in the ioctl request + * is useful for catching programs compiled with old versions + * and to avoid overwriting user space outside the user buffer area. + * The highest 2 bits are reserved for indicating the ``access mode''. + * NOTE: This limits the max parameter size to 16kB -1 ! + */ + +/* + * I don't really have any idea about what this should look like, so + * for the time being, this is heavily based on the PC definitions. + */ + +/* + * The following is for compatibility across the various Linux + * platforms. The i386 ioctl numbering scheme doesn't really enforce + * a type field. De facto, however, the top 8 bits of the lower 16 + * bits are indeed used as a type field, so we might just as well make + * this explicit here. Please be sure to use the decoding macros + * below from now on. + */ +#define _IOC_NRBITS 8 +#define _IOC_TYPEBITS 8 +#define _IOC_SIZEBITS 14 +#define _IOC_DIRBITS 2 + +#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) +#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) +#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) +#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) + +#define _IOC_NRSHIFT 0 +#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) +#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) +#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) + +/* + * Direction bits. + */ +#define _IOC_NONE 0U +#define _IOC_WRITE 1U +#define _IOC_READ 2U + +#define _IOC(dir,type,nr,size) \ + (((dir) << _IOC_DIRSHIFT) | \ + ((type) << _IOC_TYPESHIFT) | \ + ((nr) << _IOC_NRSHIFT) | \ + ((size) << _IOC_SIZESHIFT)) + +/* used to create numbers */ +#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) +#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) +#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) +#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) + +/* used to decode ioctl numbers.. */ +#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) +#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) +#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) +#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) + +/* ...and for the drivers/sound files... */ + +#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT) +#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT) +#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT) +#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT) +#define IOCSIZE_SHIFT (_IOC_SIZESHIFT) + +#endif /* __V850_IOCTL_H__ */ diff -Nru a/include/asm-v850/ioctls.h b/include/asm-v850/ioctls.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/ioctls.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,81 @@ +#ifndef __V850_IOCTLS_H__ +#define __V850_IOCTLS_H__ + +#include + +/* 0x54 is just a magic number to make these relatively unique ('T') */ + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C +#define TIOCCONS 0x541D +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TIOCPKT 0x5420 +#define FIONBIO 0x5421 +#define TIOCNOTTY 0x5422 +#define TIOCSETD 0x5423 +#define TIOCGETD 0x5424 +#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define TIOCSBRK 0x5427 /* BSD compatibility */ +#define TIOCCBRK 0x5428 /* BSD compatibility */ +#define TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define FIOCLEX 0x5451 +#define FIOASYNC 0x5452 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define FIOQSIZE 0x545E + +/* Used for packet mode */ +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 + +#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + +#endif /* __V850_IOCTLS_H__ */ diff -Nru a/include/asm-v850/ipc.h b/include/asm-v850/ipc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/ipc.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,31 @@ +#ifndef __V850_IPC_H__ +#define __V850_IPC_H__ + +/* + * These are used to wrap system calls on v850. + * + * See arch/v850/kernel/syscalls.c for ugly details.. + */ +struct ipc_kludge { + struct msgbuf *msgp; + long msgtyp; +}; + +#define SEMOP 1 +#define SEMGET 2 +#define SEMCTL 3 +#define MSGSND 11 +#define MSGRCV 12 +#define MSGGET 13 +#define MSGCTL 14 +#define SHMAT 21 +#define SHMDT 22 +#define SHMGET 23 +#define SHMCTL 24 + +/* Used by the DIPC package, try and avoid reusing it */ +#define DIPC 25 + +#define IPCCALL(version,op) ((version)<<16 | (op)) + +#endif /* __V850_IPC_H__ */ diff -Nru a/include/asm-v850/ipcbuf.h b/include/asm-v850/ipcbuf.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/ipcbuf.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,29 @@ +#ifndef __V850E_IPCBUF_H__ +#define __V850E_IPCBUF_H__ + +/* + * The user_ipc_perm structure for v850e architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 32-bit mode_t and seq + * - 2 miscellaneous 32-bit values + */ + +struct ipc64_perm +{ + __kernel_key_t key; + __kernel_uid32_t uid; + __kernel_gid32_t gid; + __kernel_uid32_t cuid; + __kernel_gid32_t cgid; + __kernel_mode_t mode; + unsigned short __pad1; + unsigned short seq; + unsigned short __pad2; + unsigned long __unused1; + unsigned long __unused2; +}; + +#endif /* __V850E_IPCBUF_H__ */ diff -Nru a/include/asm-v850/irq.h b/include/asm-v850/irq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/irq.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,57 @@ +/* + * include/asm-v850/irq.h -- Machine interrupt handling + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_IRQ_H__ +#define __V850_IRQ_H__ + +#include + +/* Default NUM_MACH_IRQS. */ +#ifndef NUM_MACH_IRQS +#define NUM_MACH_IRQS NUM_CPU_IRQS +#endif + +/* NMIs have IRQ numbers from FIRST_NMI to FIRST_NMI+NUM_NMIS-1. */ +#define FIRST_NMI NUM_MACH_IRQS +#define IRQ_NMI(n) (FIRST_NMI + (n)) +/* v850 processors have 3 non-maskable interrupts. */ +#define NUM_NMIS 3 + +/* Includes both maskable and non-maskable irqs. */ +#define NR_IRQS (NUM_MACH_IRQS + NUM_NMIS) + + +#ifndef __ASSEMBLY__ + +struct pt_regs; +struct hw_interrupt_type; +struct irqaction; + +#define irq_cannonicalize(irq) (irq) + +/* Initialize irq handling for IRQs. + BASE_IRQ, BASE_IRQ+INTERVAL, ..., BASE_IRQ+NUM*INTERVAL + to IRQ_TYPE. An IRQ_TYPE of 0 means to use a generic interrupt type. */ +extern void +init_irq_handlers (int base_irq, int num, int interval, + struct hw_interrupt_type *irq_type); + +typedef void (*irq_handler_t)(int irq, void *data, struct pt_regs *regs); + +/* Handle interrupt IRQ. REGS are the registers at the time of ther + interrupt. */ +extern unsigned int handle_irq (int irq, struct pt_regs *regs); + +#endif /* !__ASSEMBLY__ */ + +#endif /* __V850_IRQ_H__ */ diff -Nru a/include/asm-v850/kmap_types.h b/include/asm-v850/kmap_types.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/kmap_types.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,19 @@ +#ifndef __V850_KMAP_TYPES_H__ +#define __V850_KMAP_TYPES_H__ + +enum km_type { + KM_BOUNCE_READ, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BIO_SRC_IRQ, + KM_BIO_DST_IRQ, + KM_PTE0, + KM_PTE1, + KM_IRQ0, + KM_IRQ1, + KM_TYPE_NR +}; + +#endif /* __V850_KMAP_TYPES_H__ */ diff -Nru a/include/asm-v850/linkage.h b/include/asm-v850/linkage.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/linkage.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,6 @@ +#ifndef __ASM_LINKAGE_H +#define __ASM_LINKAGE_H + +/* Nothing to see here... */ + +#endif diff -Nru a/include/asm-v850/ma.h b/include/asm-v850/ma.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/ma.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,102 @@ +/* + * include/asm-v850/ma.h -- V850E/MA series of cpu chips + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_MA_H__ +#define __V850_MA_H__ + + +/* The MA series uses the NB85E cpu core. */ +#include + + +/* For */ +/* We use on-chip RAM, for a few miscellaneous variables that must be + accessible using a load instruction relative to R0. The amount + varies between chip models, but there's always at least 4K, and it + should always start at FFFFC000. */ +#define R0_RAM_ADDR 0xFFFFC000 + + +/* MA series UART details. */ +#define NB85E_UART_BASE_FREQ CPU_CLOCK_FREQ + +/* This is a function that gets called before configuring the UART. */ +#define NB85E_UART_PRE_CONFIGURE ma_uart_pre_configure +#ifndef __ASSEMBLY__ +extern void ma_uart_pre_configure (unsigned chan, + unsigned cflags, unsigned baud); +#endif + + +/* MA series timer C details. */ +#define NB85E_TIMER_C_BASE_ADDR 0xFFFFF600 + + +/* MA series timer D details. */ +#define NB85E_TIMER_D_BASE_ADDR 0xFFFFF540 +#define NB85E_TIMER_D_TMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x0) +#define NB85E_TIMER_D_CMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x2) +#define NB85E_TIMER_D_TMCD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x4) + +#define NB85E_TIMER_D_BASE_FREQ CPU_CLOCK_FREQ + + +/* Port 0 */ +/* Direct I/O. Bits 0-7 are pins P00-P07. */ +#define MA_PORT0_IO_ADDR 0xFFFFF400 +#define MA_PORT0_IO (*(volatile u8 *)MA_PORT0_IO_ADDR) +/* Port mode (for direct I/O, 0 = output, 1 = input). */ +#define MA_PORT0_PM_ADDR 0xFFFFF420 +#define MA_PORT0_PM (*(volatile u8 *)MA_PORT0_PM_ADDR) +/* Port mode control (0 = direct I/O mode, 1 = alternative I/O mode). */ +#define MA_PORT0_PMC_ADDR 0xFFFFF440 +#define MA_PORT0_PMC (*(volatile u8 *)MA_PORT0_PMC_ADDR) +/* Port function control (for P04-P07, 0 = IRQ, 1 = DMARQ). */ +#define MA_PORT0_PFC_ADDR 0xFFFFF460 +#define MA_PORT0_PFC (*(volatile u8 *)MA_PORT0_PFC_ADDR) + +/* Port 1 */ +/* Direct I/O. Bits 0-3 are pins P10-P13. */ +#define MA_PORT1_IO_ADDR 0xFFFFF402 +#define MA_PORT1_IO (*(volatile u8 *)MA_PORT1_IO_ADDR) +/* Port mode (for direct I/O, 0 = output, 1 = input). */ +#define MA_PORT1_PM_ADDR 0xFFFFF420 +#define MA_PORT1_PM (*(volatile u8 *)MA_PORT1_PM_ADDR) +/* Port mode control (0 = direct I/O mode, 1 = alternative I/O mode). */ +#define MA_PORT1_PMC_ADDR 0xFFFFF442 +#define MA_PORT1_PMC (*(volatile u8 *)MA_PORT1_PMC_ADDR) + +/* Port 4 */ +/* Direct I/O. Bits 0-5 are pins P40-P45. */ +#define MA_PORT4_IO_ADDR 0xFFFFF408 +#define MA_PORT4_IO (*(volatile u8 *)MA_PORT4_IO_ADDR) +/* Port mode (for direct I/O, 0 = output, 1 = input). */ +#define MA_PORT4_PM_ADDR 0xFFFFF428 +#define MA_PORT4_PM (*(volatile u8 *)MA_PORT4_PM_ADDR) +/* Port mode control (0 = direct I/O mode, 1 = alternative I/O mode). */ +#define MA_PORT4_PMC_ADDR 0xFFFFF448 +#define MA_PORT4_PMC (*(volatile u8 *)MA_PORT4_PMC_ADDR) +/* Port function control (for serial interfaces, 0 = CSI, 1 = UART). */ +#define MA_PORT4_PFC_ADDR 0xFFFFF468 +#define MA_PORT4_PFC (*(volatile u8 *)MA_PORT4_PFC_ADDR) + + +#ifndef __ASSEMBLY__ + +/* Initialize MA chip interrupts. */ +extern void ma_init_irqs (void); + +#endif /* !__ASSEMBLY__ */ + + +#endif /* __V850_MA_H__ */ diff -Nru a/include/asm-v850/ma1.h b/include/asm-v850/ma1.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/ma1.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,51 @@ +/* + * include/asm-v850/ma1.h -- V850E/MA1 cpu chip + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_MA1_H__ +#define __V850_MA1_H__ + +/* Inherit more generic details from MA series. */ +#include + + +#define CPU_MODEL "v850e/ma1" +#define CPU_MODEL_LONG "NEC V850E/MA1" + + +/* Hardware-specific interrupt numbers (in the kernel IRQ namespace). */ +#define IRQ_INTOV(n) (n) /* 0-3 */ +#define IRQ_INTOV_NUM 4 +#define IRQ_INTP(n) (0x4 + (n)) /* Pnnn (pin) interrupts */ +#define IRQ_INTP_NUM 24 +#define IRQ_INTCMD(n) (0x1c + (n)) /* interval timer interrupts 0-3 */ +#define IRQ_INTCMD_NUM 4 +#define IRQ_INTDMA(n) (0x20 + (n)) /* DMA interrupts 0-3 */ +#define IRQ_INTDMA_NUM 4 +#define IRQ_INTCSI(n) (0x24 + (n)*4)/* CSI 0-2 transmit/receive completion */ +#define IRQ_INTCSI_NUM 3 +#define IRQ_INTSER(n) (0x25 + (n)*4) /* UART 0-2 reception error */ +#define IRQ_INTSER_NUM 3 +#define IRQ_INTSR(n) (0x26 + (n)*4) /* UART 0-2 reception completion */ +#define IRQ_INTSR_NUM 3 +#define IRQ_INTST(n) (0x27 + (n)*4) /* UART 0-2 transmission completion */ +#define IRQ_INTST_NUM 3 + +/* For */ +#define NUM_CPU_IRQS 0x30 + + +/* The MA1 has a UART with 3 channels. */ +#define NB85E_UART_NUM_CHANNELS 3 + + +#endif /* __V850_MA1_H__ */ diff -Nru a/include/asm-v850/machdep.h b/include/asm-v850/machdep.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/machdep.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,49 @@ +/* + * include/asm-v850/machdep.h -- Machine-dependent definitions + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_MACHDEP_H__ +#define __V850_MACHDEP_H__ + +#include + +/* chips */ +#ifdef CONFIG_V850E_MA1 +#include +#endif +#ifdef CONFIG_V850E_TEG +#include +#endif + +/* Anna is both a chip _and_ a platform, so put it in the middle... */ +#ifdef CONFIG_V850E2_ANNA +#include +#endif + +/* platforms */ +#ifdef CONFIG_RTE_CB_MA1 +#include +#endif +#ifdef CONFIG_RTE_CB_NB85E +#include +#endif +#ifdef CONFIG_V850E_SIM +#include +#endif +#ifdef CONFIG_V850E2_SIM85E2C +#include +#endif +#ifdef CONFIG_V850E2_FPGA85E2C +#include +#endif + +#endif /* __V850_MACHDEP_H__ */ diff -Nru a/include/asm-v850/macrology.h b/include/asm-v850/macrology.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/macrology.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,17 @@ +/* + * include/asm-v850/macrology.h -- Various useful CPP macros + * + * Copyright (C) 2001 NEC Corporation + * Copyright (C) 2001 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#define macrology_paste(arg1, arg2) macrology_paste_1(arg1, arg2) +#define macrology_paste_1(arg1, arg2) arg1 ## arg2 +#define macrology_stringify(sym) macrology_stringify_1(sym) +#define macrology_stringify_1(sym) #sym diff -Nru a/include/asm-v850/mman.h b/include/asm-v850/mman.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/mman.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,38 @@ +#ifndef __V850_MMAN_H__ +#define __V850_MMAN_H__ + +#define PROT_READ 0x1 /* page can be read */ +#define PROT_WRITE 0x2 /* page can be written */ +#define PROT_EXEC 0x4 /* page can be executed */ +#define PROT_NONE 0x0 /* page can not be accessed */ + +#define MAP_SHARED 0x01 /* Share changes */ +#define MAP_PRIVATE 0x02 /* Changes are private */ +#define MAP_TYPE 0x0f /* Mask for type of mapping */ +#define MAP_FIXED 0x10 /* Interpret addr exactly */ +#define MAP_ANONYMOUS 0x20 /* don't use a file */ + +#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ +#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ +#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ +#define MAP_LOCKED 0x2000 /* pages are locked */ +#define MAP_NORESERVE 0x4000 /* don't check for reservations */ + +#define MS_ASYNC 1 /* sync memory asynchronously */ +#define MS_INVALIDATE 2 /* invalidate the caches */ +#define MS_SYNC 4 /* synchronous memory sync */ + +#define MCL_CURRENT 1 /* lock all current mappings */ +#define MCL_FUTURE 2 /* lock all future mappings */ + +#define MADV_NORMAL 0x0 /* default page-in behavior */ +#define MADV_RANDOM 0x1 /* page-in minimum required */ +#define MADV_SEQUENTIAL 0x2 /* read-ahead aggressively */ +#define MADV_WILLNEED 0x3 /* pre-fault pages */ +#define MADV_DONTNEED 0x4 /* discard these pages */ + +/* compatibility flags */ +#define MAP_ANON MAP_ANONYMOUS +#define MAP_FILE 0 + +#endif /* __V850_MMAN_H__ */ diff -Nru a/include/asm-v850/mmu.h b/include/asm-v850/mmu.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/mmu.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,22 @@ +/* Copyright (C) 2002, David McCullough */ + +#ifndef __V850_MMU_H__ +#define __V850_MMU_H__ + +struct mm_rblock_struct { + int size; + int refcount; + void *kblock; +}; + +struct mm_tblock_struct { + struct mm_rblock_struct *rblock; + struct mm_tblock_struct *next; +}; + +typedef struct { + struct mm_tblock_struct tblock; + unsigned long end_brk; +} mm_context_t; + +#endif /* __V850_MMU_H__ */ diff -Nru a/include/asm-v850/mmu_context.h b/include/asm-v850/mmu_context.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/mmu_context.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,12 @@ +#ifndef __V850_MMU_CONTEXT_H__ +#define __V850_MMU_CONTEXT_H__ + +#include + +#define destroy_context(mm) ((void)0) +#define init_new_context(tsk,mm) 0 +#define switch_mm(prev,next,tsk,cpu) ((void)0) +#define activate_mm(prev,next) ((void)0) +#define enter_lazy_tlb(mm,tsk,cpu) ((void)0) + +#endif /* __V850_MMU_CONTEXT_H__ */ diff -Nru a/include/asm-v850/module.h b/include/asm-v850/module.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/module.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,22 @@ +/* + * include/asm-v850/module.h -- Architecture-specific module hooks + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_MODULE_H__ +#define __V850_MODULE_H__ + +#define arch_init_modules(x) ((void)0) +#define module_arch_init(x) (0) +#define module_map(sz) vmalloc (sz) +#define module_unmap(sz) vfree (sz) + +#endif /* __V850_MODULE_H__ */ diff -Nru a/include/asm-v850/msgbuf.h b/include/asm-v850/msgbuf.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/msgbuf.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,31 @@ +#ifndef __V850_MSGBUF_H__ +#define __V850_MSGBUF_H__ + +/* + * The msqid64_ds structure for v850 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct msqid64_ds { + struct ipc64_perm msg_perm; + __kernel_time_t msg_stime; /* last msgsnd time */ + unsigned long __unused1; + __kernel_time_t msg_rtime; /* last msgrcv time */ + unsigned long __unused2; + __kernel_time_t msg_ctime; /* last change time */ + unsigned long __unused3; + unsigned long msg_cbytes; /* current number of bytes on queue */ + unsigned long msg_qnum; /* number of messages in queue */ + unsigned long msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + unsigned long __unused4; + unsigned long __unused5; +}; + +#endif /* __V850_MSGBUF_H__ */ diff -Nru a/include/asm-v850/namei.h b/include/asm-v850/namei.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/namei.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,17 @@ +/* + * linux/include/asm-v850/namei.h + * + * Included from linux/fs/namei.c + */ + +#ifndef __V850_NAMEI_H__ +#define __V850_NAMEI_H__ + +/* This dummy routine maybe changed to something useful + * for /usr/gnemul/ emulation stuff. + * Look at asm-sparc/namei.h for details. + */ + +#define __emul_prefix() NULL + +#endif /* __V850_NAMEI_H__ */ diff -Nru a/include/asm-v850/nb85e.h b/include/asm-v850/nb85e.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/nb85e.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,21 @@ +/* + * include/asm-v850/nb85e.h -- NB85E cpu core + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_NB85E_H__ +#define __V850_NB85E_H__ + +#include + +#define CPU_ARCH "v850e" + +#endif /* __V850_NB85E_H__ */ diff -Nru a/include/asm-v850/nb85e_cache.h b/include/asm-v850/nb85e_cache.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/nb85e_cache.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,106 @@ +/* + * include/asm-v850/nb85e_cache_cache.h -- Cache control for NB85E_CACHE212 and + * NB85E_CACHE213 cache memories + * + * Copyright (C) 2001 NEC Corporation + * Copyright (C) 2001 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_NB85E_CACHE_H__ +#define __V850_NB85E_CACHE_H__ + +/* Cache control registers. */ +#define NB85E_CACHE_ICC_ADDR 0xFFFFF070 +#define NB85E_CACHE_DCC_ADDR 0xFFFFF078 + +/* Size of a cache line in bytes. */ +#define NB85E_CACHE_LINE_SIZE 16 + + +#ifndef __ASSEMBLY__ + +extern inline void nb85e_cache_flush_cache (unsigned long cache_control_addr) +{ + /* + From the NB85E Instruction/Data Cache manual, how to flush + the instruction cache (ICC is the `Instruction Cache Control + Register'): + + mov 0x3, r2 + LOP0: + ld.h ICC[r0], r1 + cmp r0, r1 + bnz LOP0 + st.h r2, ICC[r0] + LOP1: - First TAG clear + ld.h ICC[r0], r1 + cmp r0, r1 + bnz LOP1 + st.h r2, ICC[r0] + LOP2: - Second TAG clear + ld.h ICC[r0], r1 + cmp r0, r1 + bnz LOP2 + */ + int cache_flush_bits, ccr_contents; + __asm__ __volatile__ ( + " mov 0x3, %1;" + "1: ld.h 0[%2], %0;" + " cmp r0, %0;" + " bnz 1b;" + " st.h %1, 0[%2];" + "2: ld.h 0[%2], %0;" + " cmp r0, %0;" + " bnz 2b;" + " st.h %1, 0[%2];" + "3: ld.h 0[%2], %0;" + " cmp r0, %0;" + " bnz 3b" + : "=&r" (ccr_contents), "=&r" (cache_flush_bits) + : "r" (cache_control_addr) + : "memory"); +} + +extern inline void nb85e_cache_flush_icache (void) +{ + nb85e_cache_flush_cache (NB85E_CACHE_ICC_ADDR); +} + +extern inline void nb85e_cache_flush_dcache (void) +{ + nb85e_cache_flush_cache (NB85E_CACHE_DCC_ADDR); +} + +extern inline void nb85e_cache_flush (void) +{ + nb85e_cache_flush_icache (); + nb85e_cache_flush_dcache (); +} + +#endif /* !__ASSEMBLY__ */ + + +/* Define standard definitions in terms of processor-specific ones. */ + +/* For */ +#define L1_CACHE_BYTES NB85E_CACHE_LINE_SIZE + +/* For */ +#define flush_cache_all() nb85e_cache_flush () +#define flush_cache_mm(mm) nb85e_cache_flush () +#define flush_cache_range(mm, start, end) nb85e_cache_flush () +#define flush_cache_page(vma, vmaddr) nb85e_cache_flush () +#define flush_page_to_ram(page) nb85e_cache_flush () +#define flush_dcache_page(page) nb85e_cache_flush_dcache () +#define flush_icache_range(start, end) nb85e_cache_flush_icache () +#define flush_icache_page(vma,pg) nb85e_cache_flush_icache () +#define flush_icache() nb85e_cache_flush_icache () +#define flush_cache_sigtramp(vaddr) nb85e_cache_flush_icache () + +#endif /* __V850_NB85E_CACHE_H__ */ diff -Nru a/include/asm-v850/nb85e_intc.h b/include/asm-v850/nb85e_intc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/nb85e_intc.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,126 @@ +/* + * include/asm-v850/nb85e_intc.h -- NB85E cpu core interrupt controller (INTC) + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_NB85E_INTC_H__ +#define __V850_NB85E_INTC_H__ + + +/* There are 4 16-bit `Interrupt Mask Registers' located contiguously + starting from this base. Each interrupt uses a single bit to + indicated enabled/disabled status. */ +#define NB85E_INTC_IMR_BASE_ADDR 0xFFFFF100 +#define NB85E_INTC_IMR_ADDR(irq) (NB85E_INTC_IMR_BASE_ADDR + ((irq) >> 3)) +#define NB85E_INTC_IMR_BIT(irq) ((irq) & 0x7) + +/* Each maskable interrupt has a single-byte control register at this + address. */ +#define NB85E_INTC_IC_BASE_ADDR 0xFFFFF110 +#define NB85E_INTC_IC_ADDR(irq) (NB85E_INTC_IC_BASE_ADDR + ((irq) << 1)) +#define NB85E_INTC_IC(irq) (*(char *)NB85E_INTC_IC_ADDR(irq)) +/* Encode priority PR for storing in an interrupt control register. */ +#define NB85E_INTC_IC_PR(pr) (pr) +/* Interrupt disable bit in an interrupt control register. */ +#define NB85E_INTC_IC_MK_BIT 6 +#define NB85E_INTC_IC_MK (1 << NB85E_INTC_IC_MK_BIT) +/* Interrupt pending flag in an interrupt control register. */ +#define NB85E_INTC_IC_IF_BIT 7 +#define NB85E_INTC_IC_IF (1 << NB85E_INTC_IC_IF_BIT) + +#ifndef __ASSEMBLY__ + +/* Enable interrupt handling for interrupt IRQ. */ +static inline void nb85e_intc_enable_irq (unsigned irq) +{ + __asm__ __volatile__ ("clr1 %0, [%1]" + :: "r" (NB85E_INTC_IMR_BIT (irq)), + "r" (NB85E_INTC_IMR_ADDR (irq)) + : "memory"); +} + +/* Disable interrupt handling for interrupt IRQ. Note that any + interrupts received while disabled will be delivered once the + interrupt is enabled again, unless they are explicitly cleared using + `nb85e_intc_clear_pending_irq'. */ +static inline void nb85e_intc_disable_irq (unsigned irq) +{ + __asm__ __volatile__ ("set1 %0, [%1]" + :: "r" (NB85E_INTC_IMR_BIT (irq)), + "r" (NB85E_INTC_IMR_ADDR (irq)) + : "memory"); +} + +/* Return true if interrupt handling for interrupt IRQ is enabled. */ +static inline int nb85e_intc_irq_enabled (unsigned irq) +{ + int rval; + __asm__ __volatile__ ("tst1 %1, [%2]; setf z, %0" + : "=r" (rval) + : "r" (NB85E_INTC_IMR_BIT (irq)), + "r" (NB85E_INTC_IMR_ADDR (irq))); + return rval; +} + +/* Disable irqs from 0 until LIMIT. LIMIT must be a multiple of 8. */ +static inline void _nb85e_intc_disable_irqs (unsigned limit) +{ + unsigned long addr; + for (addr = NB85E_INTC_IMR_BASE_ADDR; limit >= 8; addr++, limit -= 8) + *(char *)addr = 0xFF; +} + +/* Disable all irqs. This is purposely a macro, because NUM_MACH_IRQS + will be only be defined later. */ +#define nb85e_intc_disable_irqs() _nb85e_intc_disable_irqs (NUM_MACH_IRQS) + +/* Clear any pending interrupts for IRQ. */ +static inline void nb85e_intc_clear_pending_irq (unsigned irq) +{ + __asm__ __volatile__ ("clr1 %0, 0[%1]" + :: "i" (NB85E_INTC_IC_IF_BIT), + "r" (NB85E_INTC_IC_ADDR (irq)) + : "memory"); +} + +/* Return true if interrupt IRQ is pending (but disabled). */ +static inline int nb85e_intc_irq_pending (unsigned irq) +{ + int rval; + __asm__ __volatile__ ("tst1 %1, 0[%2]; setf nz, %0" + : "=r" (rval) + : "i" (NB85E_INTC_IC_IF_BIT), + "r" (NB85E_INTC_IC_ADDR (irq))); + return rval; +} + + +struct nb85e_intc_irq_init { + const char *name; /* name of interrupt type */ + + /* Range of kernel irq numbers for this type: + BASE, BASE+INTERVAL, ..., BASE+INTERVAL*NUM */ + unsigned base, num, interval; + + unsigned priority; /* interrupt priority to assign */ +}; +struct hw_interrupt_type; /* fwd decl */ + +/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array + INITS (which is terminated by an entry with the name field == 0). */ +extern void nb85e_intc_init_irq_types (struct nb85e_intc_irq_init *inits, + struct hw_interrupt_type *hw_irq_types); + + +#endif /* !__ASSEMBLY__ */ + + +#endif /* __V850_NB85E_INTC_H__ */ diff -Nru a/include/asm-v850/nb85e_timer_c.h b/include/asm-v850/nb85e_timer_c.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/nb85e_timer_c.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,48 @@ +/* + * include/asm-v850/nb85e_timer_c.h -- `Timer C' component often used + * with the NB85E cpu core + * + * Copyright (C) 2001 NEC Corporation + * Copyright (C) 2001 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +/* NOTE: this include file currently contains only enough to allow us to + use timer C as an interrupt pass-through. */ + +#ifndef __V850_NB85E_TIMER_C_H__ +#define __V850_NB85E_TIMER_C_H__ + +#include +#include /* Pick up chip-specific defs. */ + + +/* Timer C (16-bit interval timers). */ + +/* Control register 0 for timer C. */ +#define NB85E_TIMER_C_TMCC0_ADDR(n) (NB85E_TIMER_C_BASE_ADDR + 0x6 + 0x10 *(n)) +#define NB85E_TIMER_C_TMCC0(n) (*(volatile u8 *)NB85E_TIMER_C_TMCC0_ADDR(n)) +#define NB85E_TIMER_C_TMCC0_CAE 0x01 /* clock action enable */ +#define NB85E_TIMER_C_TMCC0_CE 0x02 /* count enable */ +/* ... */ + +/* Control register 1 for timer C. */ +#define NB85E_TIMER_C_TMCC1_ADDR(n) (NB85E_TIMER_C_BASE_ADDR + 0x8 + 0x10 *(n)) +#define NB85E_TIMER_C_TMCC1(n) (*(volatile u8 *)NB85E_TIMER_C_TMCC1_ADDR(n)) +#define NB85E_TIMER_C_TMCC1_CMS0 0x01 /* capture/compare mode select (ccc0) */ +#define NB85E_TIMER_C_TMCC1_CMS1 0x02 /* capture/compare mode select (ccc1) */ +/* ... */ + +/* Interrupt edge-sensitivity control for timer C. */ +#define NB85E_TIMER_C_SESC_ADDR(n) (NB85E_TIMER_C_BASE_ADDR + 0x9 + 0x10 *(n)) +#define NB85E_TIMER_C_SESC(n) (*(volatile u8 *)NB85E_TIMER_C_SESC_ADDR(n)) + +/* ...etc... */ + + +#endif /* __V850_NB85E_TIMER_C_H__ */ diff -Nru a/include/asm-v850/nb85e_timer_d.h b/include/asm-v850/nb85e_timer_d.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/nb85e_timer_d.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,62 @@ +/* + * include/asm-v850/nb85e_timer_d.h -- `Timer D' component often used + * with the NB85E cpu core + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_NB85E_TIMER_D_H__ +#define __V850_NB85E_TIMER_D_H__ + +#include +#include /* Pick up chip-specific defs. */ + + +/* Timer D (16-bit interval timers). */ + +/* Count registers for timer D. */ +#define NB85E_TIMER_D_TMD_ADDR(n) (NB85E_TIMER_D_TMD_BASE_ADDR + 0x10 * (n)) +#define NB85E_TIMER_D_TMD(n) (*(volatile u16 *)NB85E_TIMER_D_TMD_ADDR(n)) + +/* Count compare registers for timer D. */ +#define NB85E_TIMER_D_CMD_ADDR(n) (NB85E_TIMER_D_CMD_BASE_ADDR + 0x10 * (n)) +#define NB85E_TIMER_D_CMD(n) (*(u16 *)NB85E_TIMER_D_CMD_ADDR(n)) + +/* Control registers for timer D. */ +#define NB85E_TIMER_D_TMCD_ADDR(n) (NB85E_TIMER_D_TMCD_BASE_ADDR + 0x10 * (n)) +#define NB85E_TIMER_D_TMCD(n) (*(volatile u8 *)NB85E_TIMER_D_TMCD_ADDR(n)) +/* Control bits for timer D. */ +#define NB85E_TIMER_D_TMCD_CE 0x2 /* count enable */ +#define NB85E_TIMER_D_TMCD_CAE 0x1 /* clock action enable */ +/* Clock divider setting (log2). */ +#define NB85E_TIMER_D_TMCD_CS(divlog2) (((divlog2) - NB85E_TIMER_D_TMCD_CS_MIN) << 4) +/* Minimum clock divider setting (log2). */ +#ifndef NB85E_TIMER_D_TMCD_CS_MIN /* Can be overridden by mach-specific hdrs */ +#define NB85E_TIMER_D_TMCD_CS_MIN 2 /* Default is correct for the v850e/ma1 */ +#endif +/* Maximum clock divider setting (log2). */ +#define NB85E_TIMER_D_TMCD_CS_MAX (NB85E_TIMER_D_TMCD_CS_MIN + 7) + +/* Return the clock-divider (log2) of timer D unit N. */ +#define NB85E_TIMER_D_DIVLOG2(n) \ + (((NB85E_TIMER_D_TMCD(n) >> 4) & 0x7) + NB85E_TIMER_D_TMCD_CS_MIN) + + +#ifndef __ASSEMBLY__ + +/* Start interval timer TIMER (0-3). The timer will issue the + corresponding INTCMD interrupt RATE times per second. This function + does not enable the interrupt. */ +extern void nb85e_timer_d_configure (unsigned timer, unsigned rate); + +#endif /* !__ASSEMBLY__ */ + + +#endif /* __V850_NB85E_TIMER_D_H__ */ diff -Nru a/include/asm-v850/nb85e_uart.h b/include/asm-v850/nb85e_uart.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/nb85e_uart.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,142 @@ +/* + * include/asm-v850/nb85e_uart.h -- On-chip UART often used with the + * NB85E cpu core + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +/* There's not actually a single UART implementation used by nb85e + derivatives, but rather a series of implementations that are all + `close' to one another. This file attempts to capture some + commonality between them. */ + +#ifndef __V850_NB85E_UART_H__ +#define __V850_NB85E_UART_H__ + +#include +#include /* Pick up chip-specific defs. */ + + +/* The base address of the UART control registers for channel N. + The default is the address used on the V850E/MA1. */ +#ifndef NB85E_UART_BASE_ADDR +#define NB85E_UART_BASE_ADDR(n) (0xFFFFFA00 + 0x10 * (n)) +#endif + +/* Addresses of specific UART control registers for channel N. + The defaults are the addresses used on the V850E/MA1; if a platform + wants to redefine any of these, it must redefine them all. */ +#ifndef NB85E_UART_ASIM_ADDR +#define NB85E_UART_ASIM_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x0) +#define NB85E_UART_RXB_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x2) +#define NB85E_UART_ASIS_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x3) +#define NB85E_UART_TXB_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x4) +#define NB85E_UART_ASIF_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x5) +#define NB85E_UART_CKSR_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x6) +#define NB85E_UART_BRGC_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x7) +#endif + + +/* UART config registers. */ +#define NB85E_UART_ASIM(n) (*(volatile u8 *)NB85E_UART_ASIM_ADDR(n)) +/* Control bits for config registers. */ +#define NB85E_UART_ASIM_CAE 0x80 /* clock enable */ +#define NB85E_UART_ASIM_TXE 0x40 /* transmit enable */ +#define NB85E_UART_ASIM_RXE 0x20 /* receive enable */ +#define NB85E_UART_ASIM_PS_MASK 0x18 /* mask covering parity-select bits */ +#define NB85E_UART_ASIM_PS_NONE 0x00 /* no parity */ +#define NB85E_UART_ASIM_PS_ZERO 0x08 /* zero parity */ +#define NB85E_UART_ASIM_PS_ODD 0x10 /* odd parity */ +#define NB85E_UART_ASIM_PS_EVEN 0x18 /* even parity */ +#define NB85E_UART_ASIM_CL_8 0x04 /* char len is 8 bits (otherwise, 7) */ +#define NB85E_UART_ASIM_SL_2 0x02 /* 2 stop bits (otherwise, 1) */ +#define NB85E_UART_ASIM_ISRM 0x01 /* generate INTSR interrupt on errors + (otherwise, generate INTSER) */ + +/* UART serial interface status registers. */ +#define NB85E_UART_ASIS(n) (*(volatile u8 *)NB85E_UART_ASIS_ADDR(n)) +/* Control bits for status registers. */ +#define NB85E_UART_ASIS_PE 0x04 /* parity error */ +#define NB85E_UART_ASIS_FE 0x02 /* framing error */ +#define NB85E_UART_ASIS_OVE 0x01 /* overrun error */ + +/* UART serial interface transmission status registers. */ +#define NB85E_UART_ASIF(n) (*(volatile u8 *)NB85E_UART_ASIF_ADDR(n)) +#define NB85E_UART_ASIF_TXBF 0x02 /* transmit buffer flag (data in TXB) */ +#define NB85E_UART_ASIF_TXSF 0x01 /* transmit shift flag (sending data) */ + +/* UART receive buffer register. */ +#define NB85E_UART_RXB(n) (*(volatile u8 *)NB85E_UART_RXB_ADDR(n)) + +/* UART transmit buffer register. */ +#define NB85E_UART_TXB(n) (*(volatile u8 *)NB85E_UART_TXB_ADDR(n)) + +/* UART baud-rate generator control registers. */ +#define NB85E_UART_CKSR(n) (*(volatile u8 *)NB85E_UART_CKSR_ADDR(n)) +#define NB85E_UART_CKSR_MAX 11 +#define NB85E_UART_CKSR_MAX_FREQ (25*1000*1000) +#define NB85E_UART_BRGC(n) (*(volatile u8 *)NB85E_UART_BRGC_ADDR(n)) + + +/* This UART doesn't implement RTS/CTS by default, but some platforms + implement them externally, so check to see if defined + anything. */ +#ifdef NB85E_UART_CTS +#define nb85e_uart_cts(n) NB85E_UART_CTS(n) +#else +#define nb85e_uart_cts(n) (1) +#endif + +/* Do the same for RTS. */ +#ifdef NB85E_UART_SET_RTS +#define nb85e_uart_set_rts(n,v) NB85E_UART_SET_RTS(n,v) +#else +#define nb85e_uart_set_rts(n,v) ((void)0) +#endif + +/* Return true if all characters awaiting transmission on uart channel N + have been transmitted. */ +#define nb85e_uart_xmit_done(n) \ + (! (NB85E_UART_ASIF(n) & NB85E_UART_ASIF_TXBF)) +/* Wait for this to be true. */ +#define nb85e_uart_wait_for_xmit_done(n) \ + do { } while (! nb85e_uart_xmit_done (n)) + +/* Return true if uart channel N is ready to transmit a character. */ +#define nb85e_uart_xmit_ok(n) \ + (nb85e_uart_xmit_done(n) && nb85e_uart_cts(n)) +/* Wait for this to be true. */ +#define nb85e_uart_wait_for_xmit_ok(n) \ + do { } while (! nb85e_uart_xmit_ok (n)) + +/* Write character CH to uart channel N. */ +#define nb85e_uart_putc(n, ch) (NB85E_UART_TXB(n) = (ch)) + + +#define NB85E_UART_MINOR_BASE 64 + + +#ifndef __ASSEMBLY__ + +/* Setup a console using channel 0 of the builtin uart. */ +extern void nb85e_uart_cons_init (unsigned chan); + +/* Configure and turn on uart channel CHAN, using the termios `control + modes' bits in CFLAGS, and a baud-rate of BAUD. */ +void nb85e_uart_configure (unsigned chan, unsigned cflags, unsigned baud); + +/* If the macro NB85E_UART_PRE_CONFIGURE is defined (presumably by a + ), it is called from nb85e_uart_pre_configure before + anything else is done, with interrupts disabled. */ + +#endif /* !__ASSEMBLY__ */ + + +#endif /* __V850_NB85E_UART_H__ */ diff -Nru a/include/asm-v850/nb85e_utils.h b/include/asm-v850/nb85e_utils.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/nb85e_utils.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,35 @@ +/* + * include/asm-v850/nb85e_utils.h -- Utility functions associated with + * the NB85E cpu core + * + * Copyright (C) 2001 NEC Corporation + * Copyright (C) 2001 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_NB85E_UTILS_H__ +#define __V850_NB85E_UTILS_H__ + +/* Calculate counter clock-divider and count values to attain the + desired frequency RATE from the base frequency BASE_FREQ. The + counter is expected to have a clock-divider, which can divide the + system cpu clock by a power of two value from MIN_DIVLOG2 to + MAX_DIV_LOG2, and a word-size of COUNTER_SIZE bits (the counter + counts up and resets whenever it's equal to the compare register, + generating an interrupt or whatever when it does so). The returned + values are: *DIVLOG2 -- log2 of the desired clock divider and *COUNT + -- the counter compare value to use. Returns true if it was possible + to find a reasonable value, otherwise false (and the other return + values will be set to be as good as possible). */ +extern int calc_counter_params (unsigned long base_freq, + unsigned long rate, + unsigned min_divlog2, unsigned max_divlog2, + unsigned counter_size, + unsigned *divlog2, unsigned *count); + +#endif /* __V850_NB85E_UTILS_H__ */ diff -Nru a/include/asm-v850/page.h b/include/asm-v850/page.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/page.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,144 @@ +/* + * include/asm-v850/page.h -- VM ops + * + * Copyright (C) 2001, 2002 NEC Corporation + * Copyright (C) 2001, 2002 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_PAGE_H__ +#define __V850_PAGE_H__ + +#include + + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + + +/* + * PAGE_OFFSET -- the first address of the first page of memory. For archs with + * no MMU this corresponds to the first free page in physical memory (aligned + * on a page boundary). + */ +#ifndef PAGE_OFFSET +#define PAGE_OFFSET 0x0000000 +#endif + + +#ifdef __KERNEL__ +#ifndef __ASSEMBLY__ + +#define STRICT_MM_TYPECHECKS + +#define clear_page(page) memset ((void *)(page), 0, PAGE_SIZE) +#define copy_page(to, from) memcpy ((void *)(to), (void *)from, PAGE_SIZE) + +#define clear_user_page(page, vaddr, pg) clear_page (page) +#define copy_user_page(to, from, vaddr,pg) copy_page (to, from) + +#ifdef STRICT_MM_TYPECHECKS +/* + * These are used to make use of C type-checking.. + */ + +typedef struct { unsigned long pte; } pte_t; +typedef struct { unsigned long pmd; } pmd_t; +typedef struct { unsigned long pgd; } pgd_t; +typedef struct { unsigned long pgprot; } pgprot_t; + +#define pte_val(x) ((x).pte) +#define pmd_val(x) ((x).pmd) +#define pgd_val(x) ((x).pgd) +#define pgprot_val(x) ((x).pgprot) + +#define __pte(x) ((pte_t) { (x) } ) +#define __pmd(x) ((pmd_t) { (x) } ) +#define __pgd(x) ((pgd_t) { (x) } ) +#define __pgprot(x) ((pgprot_t) { (x) } ) + +#else /* !STRICT_MM_TYPECHECKS */ +/* + * .. while these make it easier on the compiler + */ + +typedef unsigned long pte_t; +typedef unsigned long pmd_t; +typedef unsigned long pgd_t; +typedef unsigned long pgprot_t; + +#define pte_val(x) (x) +#define pmd_val(x) (x) +#define pgd_val(x) (x) +#define pgprot_val(x) (x) + +#define __pte(x) (x) +#define __pmd(x) (x) +#define __pgd(x) (x) +#define __pgprot(x) (x) + +#endif /* STRICT_MM_TYPECHECKS */ + +#endif /* !__ASSEMBLY__ */ + + +/* to align the pointer to the (next) page boundary */ +#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) + + +#ifndef __ASSEMBLY__ + +extern void __bug (void) __attribute__ ((noreturn)); +#define BUG() __bug() +#define PAGE_BUG(page) __bug() + +/* 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; +} + +#endif /* !__ASSEMBLY__ */ + + +/* No current v850 processor has virtual memory. */ +#define __virt_to_phys(addr) (addr) +#define __phys_to_virt(addr) (addr) + +#define virt_to_pfn(kaddr) (__virt_to_phys (kaddr) >> PAGE_SHIFT) +#define pfn_to_virt(pfn) __phys_to_virt ((pfn) << PAGE_SHIFT) + +#define MAP_NR(kaddr) \ + (((unsigned long)(kaddr) - PAGE_OFFSET) >> PAGE_SHIFT) +#define virt_to_page(kaddr) (mem_map + MAP_NR (kaddr)) +#define page_to_virt(page) \ + ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET) + +#define pfn_to_page(pfn) virt_to_page (pfn_to_virt (pfn)) +#define page_to_pfn(page) virt_to_pfn (page_to_virt (page)) + +#define virt_addr_valid(kaddr) \ + (((void *)(kaddr) >= (void *)PAGE_OFFSET) && MAP_NR (kaddr) < max_mapnr) + + +#define __pa(x) __virt_to_phys ((unsigned long)(x)) +#define __va(x) ((void *)__phys_to_virt ((unsigned long)(x))) + + +#endif /* KERNEL */ + +#endif /* __V850_PAGE_H__ */ diff -Nru a/include/asm-v850/param.h b/include/asm-v850/param.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/param.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,36 @@ +/* + * include/asm-v850/param.h -- Varions kernel parameters + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_PARAM_H__ +#define __V850_PARAM_H__ + +#include /* For HZ */ + +#define EXEC_PAGESIZE 4096 + +#ifndef NGROUPS +#define NGROUPS 32 +#endif + +#ifndef NOGROUP +#define NOGROUP (-1) +#endif + +#define MAXHOSTNAMELEN 64 /* max length of hostname */ + +#ifdef __KERNEL__ +# define USER_HZ 100 +# define CLOCKS_PER_SEC USER_HZ +#endif + +#endif /* __V850_PARAM_H__ */ diff -Nru a/include/asm-v850/pci.h b/include/asm-v850/pci.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/pci.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,77 @@ +/* + * include/asm-v850/pci.h -- PCI support + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_PCI_H__ +#define __V850_PCI_H__ + +/* Get any platform-dependent definitions. */ +#include + +/* Generic declarations. */ + +struct scatterlist; + +extern void pcibios_set_master (struct pci_dev *dev); + +/* `Grant' to PDEV the memory block at CPU_ADDR, for doing DMA. The + 32-bit PCI bus mastering address to use is returned. the device owns + this memory until either pci_unmap_single or pci_dma_sync_single is + performed. */ +extern dma_addr_t +pci_map_single (struct pci_dev *pdev, void *cpu_addr, size_t size, int dir); + +/* Return to the CPU the PCI DMA memory block previously `granted' to + PDEV, at DMA_ADDR. */ +extern void +pci_unmap_single (struct pci_dev *pdev, dma_addr_t dma_addr, size_t size, + int dir); + +/* Make physical memory consistant for a single streaming mode DMA + translation after a transfer. + + If you perform a pci_map_single() but wish to interrogate the + buffer using the cpu, yet do not wish to teardown the PCI dma + mapping, you must call this function before doing so. At the next + point you give the PCI dma address back to the card, the device + again owns the buffer. */ +extern void +pci_dma_sync_single (struct pci_dev *dev, dma_addr_t dma_addr, size_t size, + int dir); + + +/* Do multiple DMA mappings at once. */ +extern int +pci_map_sg (struct pci_dev *pdev, struct scatterlist *sg, int sg_len, int dir); + +/* Unmap multiple DMA mappings at once. */ +extern void +pci_unmap_sg (struct pci_dev *pdev, struct scatterlist *sg, int sg_len, + int dir); + +/* Allocate and map kernel buffer using consistent mode DMA for PCI + device. Returns non-NULL cpu-view pointer to the buffer if + successful and sets *DMA_ADDR to the pci side dma address as well, + else DMA_ADDR is undefined. */ +extern void * +pci_alloc_consistent (struct pci_dev *pdev, size_t size, dma_addr_t *dma_addr); + +/* Free and unmap a consistent DMA buffer. CPU_ADDR and DMA_ADDR must + be values that were returned from pci_alloc_consistent. SIZE must be + the same as what as passed into pci_alloc_consistent. References to + the memory and mappings assosciated with CPU_ADDR or DMA_ADDR past + this call are illegal. */ +extern void +pci_free_consistent (struct pci_dev *pdev, size_t size, void *cpu_addr, + dma_addr_t dma_addr); + +#endif /* __V850_PCI_H__ */ diff -Nru a/include/asm-v850/percpu.h b/include/asm-v850/percpu.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/percpu.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,6 @@ +#ifndef __V850_PERCPU_H__ +#define __V850_PERCPU_H__ + +#include + +#endif /* __V850_PERCPU_H__ */ diff -Nru a/include/asm-v850/pgalloc.h b/include/asm-v850/pgalloc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/pgalloc.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,22 @@ +/* + * include/asm-v850/pgalloc.h + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_PGALLOC_H__ +#define __V850_PGALLOC_H__ + +#include /* some crap code expects this */ + +/* ... and then, there was one. */ +#define check_pgt_cache() ((void)0) + +#endif /* __V850_PGALLOC_H__ */ diff -Nru a/include/asm-v850/pgtable.h b/include/asm-v850/pgtable.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/pgtable.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,58 @@ +#ifndef __V850_PGTABLE_H__ +#define __V850_PGTABLE_H__ + +#include +#include + + +typedef pte_t *pte_addr_t; + +#define pgd_present(pgd) (1) /* pages are always present on NO_MM */ +#define pgd_none(pgd) (0) +#define pgd_bad(pgd) (0) +#define pgd_clear(pgdp) ((void)0) + +#define pmd_offset(a, b) ((void *)0) + +#define kern_addr_valid(addr) (1) + + +#define __swp_type(x) (0) +#define __swp_offset(x) (0) +#define __swp_entry(typ,off) ((swp_entry_t) { ((typ) | ((off) << 7)) }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) + + +/* These mean nothing to !CONFIG_MMU. */ +#define PAGE_NONE __pgprot(0) +#define PAGE_SHARED __pgprot(0) +#define PAGE_COPY __pgprot(0) +#define PAGE_READONLY __pgprot(0) +#define PAGE_KERNEL __pgprot(0) + + +/* + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc. When CONFIG_MMU is not defined, this + * should never actually be used, so just define it to something that's + * will hopefully cause a bus error if it is. + */ +#define ZERO_PAGE(vaddr) ((void *)0x87654321) + + +/* Some bogus code in procfs uses these; whatever. */ +#define VMALLOC_START 0 +#define VMALLOC_END (~0) + + +extern void paging_init (void); +#define swapper_pg_dir ((pgd_t *) 0) + +#define pgtable_cache_init() ((void)0) + + +extern unsigned int kobjsize(const void *objp); + + +#endif /* __V850_PGTABLE_H__ */ diff -Nru a/include/asm-v850/poll.h b/include/asm-v850/poll.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/poll.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,23 @@ +#ifndef __V850_POLL_H__ +#define __V850_POLL_H__ + +#define POLLIN 0x0001 +#define POLLPRI 0x0002 +#define POLLOUT 0x0004 +#define POLLERR 0x0008 +#define POLLHUP 0x0010 +#define POLLNVAL 0x0020 +#define POLLRDNORM 0x0040 +#define POLLWRNORM POLLOUT +#define POLLRDBAND 0x0080 +#define POLLWRBAND 0x0100 +#define POLLMSG 0x0400 +#define POLLREMOVE 0x1000 + +struct pollfd { + int fd; + short events; + short revents; +}; + +#endif /* __V850_POLL_H__ */ diff -Nru a/include/asm-v850/posix_types.h b/include/asm-v850/posix_types.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/posix_types.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,73 @@ +/* + * include/asm-v850/posix_types.h -- Kernel versions of standard types + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_POSIX_TYPES_H__ +#define __V850_POSIX_TYPES_H__ + +typedef unsigned int __kernel_dev_t; +typedef unsigned long __kernel_ino_t; +typedef unsigned long long __kernel_ino64_t; +typedef unsigned int __kernel_mode_t; +typedef unsigned int __kernel_nlink_t; +typedef long __kernel_off_t; +typedef long long __kernel_loff_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned int __kernel_uid_t; +typedef unsigned int __kernel_gid_t; +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; + +/* Some bogus code depends on this; we don't care. */ +typedef __kernel_uid_t __kernel_old_uid_t; + + +typedef struct { +#if defined(__KERNEL__) || defined(__USE_ALL) + int val[2]; +#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ + int __val[2]; +#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ +} __kernel_fsid_t; + + +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) + +#include + +#undef __FD_SET +#define __FD_SET(fd, fd_set) \ + __set_bit (fd, (void *)&((__kernel_fd_set *)fd_set)->fds_bits) +#undef __FD_CLR +#define __FD_CLR(fd, fd_set) \ + __clear_bit (fd, (void *)&((__kernel_fd_set *)fd_set)->fds_bits) +#undef __FD_ISSET +#define __FD_ISSET(fd, fd_set) \ + __test_bit (fd, (void *)&((__kernel_fd_set *)fd_set)->fds_bits) +#undef __FD_ZERO +#define __FD_ZERO(fd_set) \ + memset (fd_set, 0, sizeof (*(fd_set *)fd_set)) + +#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ + +#endif /* __V850_POSIX_TYPES_H__ */ diff -Nru a/include/asm-v850/processor.h b/include/asm-v850/processor.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/processor.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,116 @@ +/* + * include/asm-v850/processor.h + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_PROCESSOR_H__ +#define __V850_PROCESSOR_H__ + +#include + +#include +#include +#include + +/* Some code expects `segment' stuff to be defined here. */ +#include + + +/* + * The only places this is used seem to be horrible bletcherous kludges, + * so we just define it to be as large as possible. + */ +#define TASK_SIZE (0xFFFFFFFF) + + +#ifndef __ASSEMBLY__ + + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +#define current_text_addr() ({ __label__ _l; _l: &&_l;}) + + +/* + * Bus types + */ +#define EISA_bus 0 +#define EISA_bus__is_a_macro /* for versions in ksyms.c */ +#define MCA_bus 0 +#define MCA_bus__is_a_macro /* for versions in ksyms.c */ + +/* If you change this, you must change the associated assembly-languages + constants defined below, THREAD_*. */ +struct thread_struct { + /* kernel stack pointer (must be first field in structure) */ + unsigned long ksp; +}; + +#define INIT_THREAD { sizeof init_stack + (unsigned long)init_stack } + + +/* Do necessary setup to start up a newly executed thread. */ +extern inline void start_thread (struct pt_regs *regs, + unsigned long pc, unsigned long usp) +{ + regs->pc = pc; + regs->gpr[GPR_SP] = usp; + regs->kernel_mode = 0; +} + +/* Free all resources held by a thread. */ +extern inline void release_thread (struct task_struct *dead_task) +{ +} + +extern int kernel_thread (int (*fn)(void *), void * arg, unsigned long flags); + +/* Free current thread data structures etc. */ +static inline void exit_thread (void) +{ +} + +/* Return saved (kernel) PC of a blocked thread. */ +extern inline unsigned long thread_saved_pc (struct thread_struct *t) +{ + struct pt_regs *r = (struct pt_regs *)(t->ksp + STATE_SAVE_PT_OFFSET); + /* Actually, we return the LP register, because the thread is + actually blocked in switch_thread, and we're interested in + the PC it will _return_ to. */ + return r->gpr[GPR_LP]; +} + +unsigned long get_wchan (struct task_struct *p); + + +/* Return some info about the user process TASK. */ +#define task_tos(task) ((unsigned long)(task)->thread_info + THREAD_SIZE) +#define task_regs(task) ((struct pt_regs *)task_tos (task) - 1) +#define task_sp(task) (task_regs (task)->gpr[GPR_SP]) +#define task_pc(task) (task_regs (task)->pc) +/* Grotty old names for some. */ +#define KSTK_EIP(task) task_pc (task) +#define KSTK_ESP(task) task_sp (task) + + +#define cpu_relax() ((void)0) + + +#else /* __ASSEMBLY__ */ + +#define THREAD_KSP 0 + +#endif /* !__ASSEMBLY__ */ + + +#endif /* __V850_PROCESSOR_H__ */ diff -Nru a/include/asm-v850/ptrace.h b/include/asm-v850/ptrace.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/ptrace.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,111 @@ +/* + * include/asm-v850/ptrace.h -- Access to CPU registers + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_PTRACE_H__ +#define __V850_PTRACE_H__ + + +/* v850 general purpose registers with special meanings. */ +#define GPR_ZERO 0 /* constant zero */ +#define GPR_ASM 1 /* reserved for assembler */ +#define GPR_SP 3 /* stack pointer */ +#define GPR_GP 4 /* global data pointer */ +#define GPR_TP 5 /* `text pointer' */ +#define GPR_EP 30 /* `element pointer' */ +#define GPR_LP 31 /* link pointer (current return address) */ + +/* These aren't official names, but they make some code more descriptive. */ +#define GPR_ARG0 6 +#define GPR_ARG1 7 +#define GPR_ARG2 8 +#define GPR_ARG3 9 +#define GPR_RVAL0 10 +#define GPR_RVAL1 11 +#define GPR_RVAL GPR_RVAL0 + +#define NUM_GPRS 32 + +/* v850 `system' registers. */ +#define SR_EIPC 0 +#define SR_EIPSW 1 +#define SR_FEPC 2 +#define SR_FEPSW 3 +#define SR_ECR 4 +#define SR_PSW 5 +#define SR_CTPC 16 +#define SR_CTPSW 17 +#define SR_DBPC 18 +#define SR_DBPSW 19 +#define SR_CTBP 20 +#define SR_DIR 21 +#define SR_ASID 23 + + +#ifndef __ASSEMBLY__ + +typedef unsigned long v850_reg_t; + +/* How processor state is stored on the stack during a syscall/signal. + If you change this structure, change the associated assembly-language + macros below too (PT_*)! */ +struct pt_regs +{ + /* General purpose registers. */ + v850_reg_t gpr[NUM_GPRS]; + + v850_reg_t pc; /* program counter */ + v850_reg_t psw; /* program status word */ + + /* Registers used by `callt' instruction: */ + v850_reg_t ctpc; /* saved program counter */ + v850_reg_t ctpsw; /* saved psw */ + v850_reg_t ctbp; /* base pointer for callt table */ + + char kernel_mode; /* 1 if in `kernel mode', 0 if user mode */ +}; + + +#define instruction_pointer(regs) ((regs)->pc) +#define user_mode(regs) (!(regs)->kernel_mode) + +/* When a struct pt_regs is used to save user state for a system call in + the kernel, the system call is stored in the space for R0 (since it's + never used otherwise, R0 being a constant 0). Non-system-calls + simply store 0 there. */ +#define PT_REGS_SYSCALL(regs) (regs)->gpr[0] +#define PT_REGS_SET_SYSCALL(regs, val) ((regs)->gpr[0] = (val)) + +#endif /* !__ASSEMBLY__ */ + + +/* The number of bytes used to store each register. */ +#define _PT_REG_SIZE 4 + +/* Offset of a general purpose register in a stuct pt_regs. */ +#define PT_GPR(num) ((num) * _PT_REG_SIZE) + +/* Offsets of various special registers & fields in a struct pt_regs. */ +#define PT_PC ((NUM_GPRS + 0) * _PT_REG_SIZE) +#define PT_PSW ((NUM_GPRS + 1) * _PT_REG_SIZE) +#define PT_CTPC ((NUM_GPRS + 2) * _PT_REG_SIZE) +#define PT_CTPSW ((NUM_GPRS + 3) * _PT_REG_SIZE) +#define PT_CTBP ((NUM_GPRS + 4) * _PT_REG_SIZE) +#define PT_KERNEL_MODE ((NUM_GPRS + 5) * _PT_REG_SIZE) + +#define PT_SYSCALL PT_GPR(0) + +/* Size of struct pt_regs, including alignment. */ +#define PT_SIZE ((NUM_GPRS + 6) * _PT_REG_SIZE) + + +#endif /* __V850_PTRACE_H__ */ diff -Nru a/include/asm-v850/resource.h b/include/asm-v850/resource.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/resource.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,47 @@ +#ifndef __V850_RESOURCE_H__ +#define __V850_RESOURCE_H__ + +/* + * Resource limits + */ + +#define RLIMIT_CPU 0 /* CPU time in ms */ +#define RLIMIT_FSIZE 1 /* Maximum filesize */ +#define RLIMIT_DATA 2 /* max data size */ +#define RLIMIT_STACK 3 /* max stack size */ +#define RLIMIT_CORE 4 /* max core file size */ +#define RLIMIT_RSS 5 /* max resident set size */ +#define RLIMIT_NPROC 6 /* max number of processes */ +#define RLIMIT_NOFILE 7 /* max number of open files */ +#define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ +#define RLIMIT_AS 9 /* address space limit */ +#define RLIMIT_LOCKS 10 /* maximum file locks held */ + +#define RLIM_NLIMITS 11 + +/* + * SuS says limits have to be unsigned. + * Which makes a ton more sense anyway. + */ +#define RLIM_INFINITY (~0UL) + +#ifdef __KERNEL__ + +#define INIT_RLIMITS \ +{ \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { _STK_LIM, RLIM_INFINITY }, \ + { 0, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ + { INR_OPEN, INR_OPEN }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ +} + +#endif /* __KERNEL__ */ + +#endif /* __V850_RESOURCE_H__ */ diff -Nru a/include/asm-v850/rmap.h b/include/asm-v850/rmap.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/rmap.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1 @@ +/* Do not need anything here */ diff -Nru a/include/asm-v850/rte_cb.h b/include/asm-v850/rte_cb.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/rte_cb.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,87 @@ +/* + * include/asm-v850/rte_cb.h -- Midas labs RTE-CB series of evaluation boards + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_RTE_CB_H__ +#define __V850_RTE_CB_H__ + + +/* CPU addresses of GBUS memory spaces. */ +#define GCS0_ADDR 0x05000000 /* GCS0 - Common SRAM (2MB) */ +#define GCS0_SIZE 0x00200000 /* 2MB */ +#define GCS1_ADDR 0x06000000 /* GCS1 - Flash ROM (8MB) */ +#define GCS1_SIZE 0x00800000 /* 8MB */ +#define GCS2_ADDR 0x07900000 /* GCS2 - I/O registers */ +#define GCS2_SIZE 0x00400000 /* 4MB */ +#define GCS5_ADDR 0x04000000 /* GCS5 - PCI bus space */ +#define GCS5_SIZE 0x01000000 /* 16MB */ +#define GCS6_ADDR 0x07980000 /* GCS6 - PCI control registers */ +#define GCS6_SIZE 0x00000200 /* 512B */ + +/* The SRAM on the Mother-A motherboard. */ +#define MB_A_SRAM_ADDR GCS0_ADDR +#define MB_A_SRAM_SIZE 0x00200000 /* 2MB */ + + +/* GBUS interrupt support. */ +#define GBUS_INT_BASE_IRQ NUM_CPU_IRQS +#define GBUS_INT_BASE_ADDR (GCS2_ADDR + 0x00006000) +#include + +/* We define NUM_MACH_IRQS to include extra interrupts from the GBUS. */ +#define NUM_MACH_IRQS (NUM_CPU_IRQS + IRQ_GBUS_INT_NUM) + +/* Some specific interrupts. */ +#define IRQ_MB_A_LAN IRQ_GBUS_INT(10) +#define IRQ_MB_A_PCI1(n) (IRQ_GBUS_INT(16) + (n)) +#define IRQ_MB_A_PCI1_NUM 4 +#define IRQ_MB_A_PCI2(n) (IRQ_GBUS_INT(20) + (n)) +#define IRQ_MB_A_PCI2_NUM 4 +#define IRQ_MB_A_EXT(n) (IRQ_GBUS_INT(24) + (n)) +#define IRQ_MB_A_EXT_NUM 4 +#define IRQ_MB_A_USB_OC(n) (IRQ_GBUS_INT(28) + (n)) +#define IRQ_MB_A_USB_OC_NUM 2 +#define IRQ_MB_A_PCMCIA_OC IRQ_GBUS_INT(30) + + +/* Mother-A PCI bus support. */ +#include + +/* These are the base addresses used for allocating device address + space. 512K of the motherboard SRAM is in the same space, so we have + to be careful not to let it be allocated. */ +#define PCIBIOS_MIN_MEM (MB_A_PCI_MEM_ADDR + 0x80000) +#define PCIBIOS_MIN_IO MB_A_PCI_IO_ADDR + +/* As we don't really support PCI DMA to cpu memory, and use bounce-buffers + instead, perversely enough, this becomes always true! */ +#define pci_dma_supported(dev, mask) 1 +#define pci_dac_dma_supported(dev, mask) 0 +#define pci_controller_num(dev) 0 +#define pcibios_assign_all_busses() 1 + + + +/* For */ +#ifndef HZ +#define HZ 100 +#endif + + +#ifndef __ASSEMBLY__ + +extern void rte_cb_init_irqs (void); + +#endif /* !__ASSEMBLY__ */ + + +#endif /* __V850_RTE_CB_H__ */ diff -Nru a/include/asm-v850/rte_ma1_cb.h b/include/asm-v850/rte_ma1_cb.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/rte_ma1_cb.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,112 @@ +/* + * include/asm-v850/rte_ma1_cb.h -- Midas labs RTE-V850/MA1-CB board + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_RTE_MA1_CB_H__ +#define __V850_RTE_MA1_CB_H__ + +#include /* Common defs for Midas RTE-CB boards. */ + + +/* The GBUS GINT0 - GINT4 interrupts are connected to the INTP000 - INTP011 + pins on the CPU. These are shared among the GBUS interrupts. */ +#define IRQ_GINT(n) IRQ_INTP(n) +#define IRQ_GINT_NUM 4 + + +#define PLATFORM "rte-v850e/ma1-cb" +#define PLATFORM_LONG "Midas lab RTE-V850E/MA1-CB" + +#define CPU_CLOCK_FREQ 50000000 /* 50MHz */ + +/* 1MB of onboard SRAM. Note that the monitor ROM uses parts of this + for its own purposes, so care must be taken. Some address lines are + not decoded, so the SRAM area is mirrored every 1MB from 0x400000 to + 0x800000 (exclusive). */ +#define SRAM_ADDR 0x00400000 +#define SRAM_SIZE 0x00100000 /* 1MB */ + +/* 32MB of onbard SDRAM. */ +#define SDRAM_ADDR 0x00800000 +#define SDRAM_SIZE 0x02000000 /* 32MB */ + + +/* For */ +#define PAGE_OFFSET SRAM_ADDR + + +#ifdef CONFIG_ROM_KERNEL +/* Kernel is in ROM, starting at address 0. */ + +#define INTV_BASE 0 + +#else /* !CONFIG_ROM_KERNEL */ + +#ifdef CONFIG_RTE_CB_MULTI +/* Using RAM kernel with ROM monitor for Multi debugger. */ + +/* The chip's real interrupt vectors are in ROM, but they jump to a + secondary interrupt vector table in RAM. */ +#define INTV_BASE 0x004F8000 + +/* Scratch memory used by the ROM monitor, which shouldn't be used by + linux (except for the alternate interrupt vector area, defined + above). */ +#define MON_SCRATCH_ADDR 0x004F8000 +#define MON_SCRATCH_SIZE 0x00008000 /* 32KB */ + +#else /* !CONFIG_RTE_CB_MULTI */ +/* Using RAM-kernel. Assume some sort of boot-loader got us loaded at + address 0. */ + +#define INTV_BASE 0 + +#endif /* CONFIG_RTE_CB_MULTI */ + +#endif /* CONFIG_ROM_KERNEL */ + + +/* Some misc. on-board devices. */ + +/* Seven-segment LED display (two digits). Write-only. */ +#define LED_ADDR(n) (0x07802000 + (n)) +#define LED(n) (*(volatile unsigned char *)LED_ADDR(n)) +#define LED_NUM_DIGITS 2 + + +/* Override the basic MA uart pre-initialization so that we can + initialize extra stuff. */ +#undef NB85E_UART_PRE_CONFIGURE /* should be defined by */ +#define NB85E_UART_PRE_CONFIGURE rte_ma1_cb_uart_pre_configure +#ifndef __ASSEMBLY__ +extern void rte_ma1_cb_uart_pre_configure (unsigned chan, + unsigned cflags, unsigned baud); +#endif + +/* This board supports RTS/CTS for the on-chip UART, but only for channel 0. */ + +/* CTS for UART channel 0 is pin P43 (bit 3 of port 4). */ +#define NB85E_UART_CTS(chan) ((chan) == 0 ? !(MA_PORT4_IO & 0x8) : 1) +/* RTS for UART channel 0 is pin P42 (bit 2 of port 4). */ +#define NB85E_UART_SET_RTS(chan, val) \ + do { \ + if (chan == 0) { \ + unsigned old = MA_PORT4_IO; \ + if (val) \ + MA_PORT4_IO = old & ~0x4; \ + else \ + MA_PORT4_IO = old | 0x4; \ + } \ + } while (0) + + +#endif /* __V850_RTE_MA1_CB_H__ */ diff -Nru a/include/asm-v850/rte_mb_a_pci.h b/include/asm-v850/rte_mb_a_pci.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/rte_mb_a_pci.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,56 @@ +/* + * include/asm-v850/mb_a_pci.h -- PCI support for Midas lab RTE-MOTHER-A board + * + * Copyright (C) 2001 NEC Corporation + * Copyright (C) 2001 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_MB_A_PCI_H__ +#define __V850_MB_A_PCI_H__ + + +#define MB_A_PCI_MEM_ADDR GCS5_ADDR +#define MB_A_PCI_MEM_SIZE (GCS5_SIZE / 2) +#define MB_A_PCI_IO_ADDR (GCS5_ADDR + MB_A_PCI_MEM_SIZE) +#define MB_A_PCI_IO_SIZE (GCS5_SIZE / 2) +#define MB_A_PCI_REG_BASE_ADDR GCS6_ADDR + +#define MB_A_PCI_PCICR_ADDR (MB_A_PCI_REG_BASE_ADDR + 0x4) +#define MB_A_PCI_PCICR (*(volatile u16 *)MB_A_PCI_PCICR_ADDR) +#define MB_A_PCI_PCISR_ADDR (MB_A_PCI_REG_BASE_ADDR + 0x6) +#define MB_A_PCI_PCISR (*(volatile u16 *)MB_A_PCI_PCISR_ADDR) +#define MB_A_PCI_PCILTR_ADDR (MB_A_PCI_REG_BASE_ADDR + 0xD) +#define MB_A_PCI_PCILTR (*(volatile u8 *)MB_A_PCI_PCILTR_ADDR) +#define MB_A_PCI_PCIBAR0_ADDR (MB_A_PCI_REG_BASE_ADDR + 0x10) +#define MB_A_PCI_PCIBAR0 (*(volatile u32 *)MB_A_PCI_PCIBAR0_ADDR) +#define MB_A_PCI_PCIBAR1_ADDR (MB_A_PCI_REG_BASE_ADDR + 0x14) +#define MB_A_PCI_PCIBAR1 (*(volatile u32 *)MB_A_PCI_PCIBAR1_ADDR) +#define MB_A_PCI_PCIBAR2_ADDR (MB_A_PCI_REG_BASE_ADDR + 0x18) +#define MB_A_PCI_PCIBAR2 (*(volatile u32 *)MB_A_PCI_PCIBAR2_ADDR) +#define MB_A_PCI_VENDOR_ID_ADDR (MB_A_PCI_REG_BASE_ADDR + 0x2C) +#define MB_A_PCI_VENDOR_ID (*(volatile u16 *)MB_A_PCI_VENDOR_ID_ADDR) +#define MB_A_PCI_DEVICE_ID_ADDR (MB_A_PCI_REG_BASE_ADDR + 0x2E) +#define MB_A_PCI_DEVICE_ID (*(volatile u16 *)MB_A_PCI_DEVICE_ID_ADDR) +#define MB_A_PCI_DMRR_ADDR (MB_A_PCI_REG_BASE_ADDR + 0x9C) +#define MB_A_PCI_DMRR (*(volatile u32 *)MB_A_PCI_DMRR_ADDR) +#define MB_A_PCI_DMLBAM_ADDR (MB_A_PCI_REG_BASE_ADDR + 0xA0) +#define MB_A_PCI_DMLBAM (*(volatile u32 *)MB_A_PCI_DMLBAM_ADDR) +#define MB_A_PCI_DMLBAI_ADDR (MB_A_PCI_REG_BASE_ADDR + 0xA4) +#define MB_A_PCI_DMLBAI (*(volatile u32 *)MB_A_PCI_DMLBAI_ADDR) +#define MB_A_PCI_PCIPBAM_ADDR (MB_A_PCI_REG_BASE_ADDR + 0xA8) +#define MB_A_PCI_PCIPBAM (*(volatile u32 *)MB_A_PCI_PCIPBAM_ADDR) +/* `PCI Configuration Address Register for Direct Master to PCI IO/CFG' */ +#define MB_A_PCI_DMCFGA_ADDR (MB_A_PCI_REG_BASE_ADDR + 0xAC) +#define MB_A_PCI_DMCFGA (*(volatile u32 *)MB_A_PCI_DMCFGA_ADDR) +/* `PCI Permanent Configuration ID Register' */ +#define MB_A_PCI_PCIHIDR_ADDR (MB_A_PCI_REG_BASE_ADDR + 0xF0) +#define MB_A_PCI_PCIHIDR (*(volatile u32 *)MB_A_PCI_PCIHIDR_ADDR) + + +#endif /* __V850_MB_A_PCI_H__ */ diff -Nru a/include/asm-v850/rte_nb85e_cb.h b/include/asm-v850/rte_nb85e_cb.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/rte_nb85e_cb.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,63 @@ +/* + * include/asm-v850/rte_nb85e_cb.h -- Midas labs RTE-V850/NB85E-CB board + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_RTE_NB85E_CB_H__ +#define __V850_RTE_NB85E_CB_H__ + +#include /* Common defs for Midas RTE-CB boards. */ + +#define PLATFORM "rte-v850e/nb85e-cb" +#define PLATFORM_LONG "Midas lab RTE-V850E/NB85E-CB" + +#define CPU_CLOCK_FREQ 50000000 /* 50MHz */ + +/* 1MB of onboard SRAM. Note that the monitor ROM uses parts of this + for its own purposes, so care must be taken. */ +#define SRAM_ADDR 0x03C00000 +#define SRAM_SIZE 0x00100000 /* 1MB */ + +/* 16MB of onbard SDRAM. */ +#define SDRAM_ADDR 0x01000000 +#define SDRAM_SIZE 0x01000000 /* 16MB */ + + +#ifdef CONFIG_ROM_KERNEL +/* Kernel is in ROM, starting at address 0. */ + +#define INTV_BASE 0 + +#else /* !CONFIG_ROM_KERNEL */ +/* We're using the ROM monitor. */ + +/* The chip's real interrupt vectors are in ROM, but they jump to a + secondary interrupt vector table in RAM. */ +#define INTV_BASE 0x004F8000 + +/* Scratch memory used by the ROM monitor, which shouldn't be used by + linux (except for the alternate interrupt vector area, defined + above). */ +#define MON_SCRATCH_ADDR 0x03CE8000 +#define MON_SCRATCH_SIZE 0x00008000 /* 32KB */ + +#endif /* CONFIG_ROM_KERNEL */ + + +/* Some misc. on-board devices. */ + +/* Seven-segment LED display (two digits). Write-only. */ +#define LED_ADDR(n) (0x03802000 + (n)) +#define LED(n) (*(volatile unsigned char *)LED_ADDR(n)) +#define LED_NUM_DIGITS 4 + + +#endif /* __V850_RTE_NB85E_CB_H__ */ diff -Nru a/include/asm-v850/scatterlist.h b/include/asm-v850/scatterlist.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/scatterlist.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,26 @@ +/* + * include/asm-v850/scatterlist.h + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_SCATTERLIST_H__ +#define __V850_SCATTERLIST_H__ + +struct scatterlist { + struct page *page; + unsigned offset; + dma_addr_t dma_address; + unsigned length; +}; + +#define ISA_DMA_THRESHOLD (~0UL) + +#endif /* __V850_SCATTERLIST_H__ */ diff -Nru a/include/asm-v850/segment.h b/include/asm-v850/segment.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/segment.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,36 @@ +#ifndef __V850_SEGMENT_H__ +#define __V850_SEGMENT_H__ + + +#ifndef __ASSEMBLY__ + +typedef unsigned long mm_segment_t; /* domain register */ + +#endif /* !__ASSEMBLY__ */ + + +#define __KERNEL_CS 0x0 +#define __KERNEL_DS 0x0 + +#define __USER_CS 0x1 +#define __USER_DS 0x1 + +#define KERNEL_DS __KERNEL_DS +#define KERNEL_CS __KERNEL_CS +#define USER_DS __USER_DS +#define USER_CS __USER_CS + +#define segment_eq(a,b) ((a) == (b)) + +#define get_ds() (KERNEL_DS) +#define get_fs() (USER_DS) + +#define set_fs(seg) ((void)(seg)) + + +#define copy_segments(task, mm) ((void)((void)(task), (mm))) +#define release_segments(mm) ((void)(mm)) +#define forget_segments() ((void)0) + + +#endif /* __V850_SEGMENT_H__ */ diff -Nru a/include/asm-v850/semaphore.h b/include/asm-v850/semaphore.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/semaphore.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,86 @@ +#ifndef __V850_SEMAPHORE_H__ +#define __V850_SEMAPHORE_H__ + +#include +#include +#include +#include + +#include + +struct semaphore { + atomic_t count; + int sleepers; + wait_queue_head_t wait; +}; + +#define __SEMAPHORE_INITIALIZER(name,count) \ + { ATOMIC_INIT (count), 0, \ + __WAIT_QUEUE_HEAD_INITIALIZER ((name).wait) } + +#define __MUTEX_INITIALIZER(name) \ + __SEMAPHORE_INITIALIZER (name,1) + +#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ + struct semaphore name = __SEMAPHORE_INITIALIZER (name,count) + +#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC (name,1) +#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC (name,0) + +extern inline void sema_init (struct semaphore *sem, int val) +{ + *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); +} + +static inline void init_MUTEX (struct semaphore *sem) +{ + sema_init (sem, 1); +} + +static inline void init_MUTEX_LOCKED (struct semaphore *sem) +{ + sema_init (sem, 0); +} + +/* + * special register calling convention + */ +asmlinkage void __down_failed (void); +asmlinkage int __down_interruptible_failed (void); +asmlinkage int __down_trylock_failed (void); +asmlinkage void __up_wakeup (void); + +extern void __down (struct semaphore * sem); +extern int __down_interruptible (struct semaphore * sem); +extern int __down_trylock (struct semaphore * sem); +extern void __up (struct semaphore * sem); + +extern inline void down (struct semaphore * sem) +{ + if (atomic_dec_return (&sem->count) < 0) + __down (sem); +} + +extern inline int down_interruptible (struct semaphore * sem) +{ + int ret = 0; + if (atomic_dec_return (&sem->count) < 0) + ret = __down_interruptible (sem); + return ret; +} + +extern inline int down_trylock (struct semaphore *sem) +{ + int ret = 0; + if (atomic_dec_return (&sem->count) < 0) + ret = __down_trylock (sem); + return ret; +} + +extern inline void up (struct semaphore * sem) +{ + if (atomic_inc_return (&sem->count) <= 0) + __up (sem); +} + +#endif /* __V850_SEMAPHORE_H__ */ diff -Nru a/include/asm-v850/sembuf.h b/include/asm-v850/sembuf.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/sembuf.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,25 @@ +#ifndef __V850_SEMBUF_H__ +#define __V850_SEMBUF_H__ + +/* + * The semid64_ds structure for v850 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct semid64_ds { + struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ + __kernel_time_t sem_otime; /* last semop time */ + unsigned long __unused1; + __kernel_time_t sem_ctime; /* last change time */ + unsigned long __unused2; + unsigned long sem_nsems; /* no. of semaphores in array */ + unsigned long __unused3; + unsigned long __unused4; +}; + +#endif /* __V850_SEMBUF_H__ */ diff -Nru a/include/asm-v850/setup.h b/include/asm-v850/setup.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/setup.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,37 @@ +/* + * include/asm-v850/setup.h + * + * Copyright (C) 2001 NEC Corporation + * Copyright (C) 2001 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_SETUP_H__ +#define __V850_SETUP_H__ + +/* Linux/v850 platforms. This corresponds roughly to what the outside + the CPU looks like. */ +#define MACH_SIM 1 /* GDB architectural simulator */ + +/* v850 cpu architectures. This is what a user-program would be + concerned with. */ +#define CPU_ARCH_V850E 1 +#define CPU_ARCH_V850E2 2 + +/* v850 cpu `cores'. These are system-level extensions to the basic CPU, + defining such things as interrupt-handling. */ +#define CPU_CORE_NB85E 1 +#define CPU_CORE_NB85ET 2 +#define CPU_CORE_NU85E 3 +#define CPU_CORE_NU85ET 4 + +/* Specific v850 cpu chips. These each incorporate a `core', and add + varions peripheral services. */ +#define CPU_CHIP_MA1 1 + +#endif /* __V850_SETUP_H__ */ diff -Nru a/include/asm-v850/shmbuf.h b/include/asm-v850/shmbuf.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/shmbuf.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,42 @@ +#ifndef __V850_SHMBUF_H__ +#define __V850_SHMBUF_H__ + +/* + * The shmid64_ds structure for v850 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ + size_t shm_segsz; /* size of segment (bytes) */ + __kernel_time_t shm_atime; /* last attach time */ + unsigned long __unused1; + __kernel_time_t shm_dtime; /* last detach time */ + unsigned long __unused2; + __kernel_time_t shm_ctime; /* last change time */ + unsigned long __unused3; + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + unsigned long shm_nattch; /* no. of current attaches */ + unsigned long __unused4; + unsigned long __unused5; +}; + +struct shminfo64 { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused1; + unsigned long __unused2; + unsigned long __unused3; + unsigned long __unused4; +}; + +#endif /* __V850_SHMBUF_H__ */ diff -Nru a/include/asm-v850/shmparam.h b/include/asm-v850/shmparam.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/shmparam.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,6 @@ +#ifndef __V850_SHMPARAM_H__ +#define __V850_SHMPARAM_H__ + +#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */ + +#endif /* __V850_SHMPARAM_H__ */ diff -Nru a/include/asm-v850/sigcontext.h b/include/asm-v850/sigcontext.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/sigcontext.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,25 @@ +/* + * include/asm-v850/sigcontext.h -- Signal contexts + * + * Copyright (C) 2001 NEC Corporation + * Copyright (C) 2001 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_SIGCONTEXT_H__ +#define __V850_SIGCONTEXT_H__ + +#include + +struct sigcontext +{ + struct pt_regs regs; + unsigned long oldmask; +}; + +#endif /* __V850_SIGCONTEXT_H__ */ diff -Nru a/include/asm-v850/siginfo.h b/include/asm-v850/siginfo.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/siginfo.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,6 @@ +#ifndef __V850_SIGINFO_H__ +#define __V850_SIGINFO_H__ + +#include + +#endif /* __V850_SIGINFO_H__ */ diff -Nru a/include/asm-v850/signal.h b/include/asm-v850/signal.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/signal.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,193 @@ +#ifndef __V850_SIGNAL_H__ +#define __V850_SIGNAL_H__ + +#include + +/* Avoid too many header ordering problems. */ +struct siginfo; + + +#ifdef __KERNEL__ + +/* Most things should be clean enough to redefine this at will, if care + is taken to make libc match. */ +#define _NSIG 64 +#define _NSIG_BPW 32 +#define _NSIG_WORDS (_NSIG / _NSIG_BPW) + +typedef unsigned long old_sigset_t; /* at least 32 bits */ + +typedef struct { + unsigned long sig[_NSIG_WORDS]; +} sigset_t; + +#else /* !__KERNEL__ */ + +/* Here we must cater to libcs that poke about in kernel headers. */ + +#define NSIG 32 +typedef unsigned long sigset_t; + +#endif /* __KERNEL__ */ + + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL SIGIO +/* +#define SIGLOST 29 +*/ +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGUNUSED 31 + +/* These should not be considered constants from userland. */ +#define SIGRTMIN 32 +#define SIGRTMAX (_NSIG-1) + +/* + * SA_FLAGS values: + * + * SA_ONSTACK indicates that a registered stack_t will be used. + * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the + * SA_RESTART flag to get restarting signals (which were the default long ago) + * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. + * SA_RESETHAND clears the handler when the signal is delivered. + * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. + * SA_NODEFER prevents the current signal from being masked in the handler. + * + * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single + * Unix names RESETHAND and NODEFER respectively. + */ +#define SA_NOCLDSTOP 0x00000001 +#define SA_NOCLDWAIT 0x00000002 /* not supported yet */ +#define SA_SIGINFO 0x00000004 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 + +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND +#define SA_INTERRUPT 0x20000000 /* dummy -- ignored */ + +#define SA_RESTORER 0x04000000 + +/* + * sigaltstack controls + */ +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 + + +#ifdef __KERNEL__ +/* + * These values of sa_flags are used only by the kernel as part of the + * irq handling routines. + * + * SA_INTERRUPT is also used by the irq handling routines. + * SA_SHIRQ is for shared interrupt support on PCI and EISA. + */ +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x04000000 +#endif /* __KERNEL__ */ + + +#define SIG_BLOCK 0 /* for blocking signals */ +#define SIG_UNBLOCK 1 /* for unblocking signals */ +#define SIG_SETMASK 2 /* for setting the signal mask */ + +/* Type of a signal handler. */ +typedef void (*__sighandler_t)(int); + +#define SIG_DFL ((__sighandler_t)0) /* default signal handling */ +#define SIG_IGN ((__sighandler_t)1) /* ignore signal */ +#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */ + + +#ifdef __KERNEL__ + +struct old_sigaction { + __sighandler_t sa_handler; + old_sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +struct sigaction { + __sighandler_t sa_handler; + unsigned long sa_flags; + void (*sa_restorer)(void); + sigset_t sa_mask; /* mask last for extensibility */ +}; + +struct k_sigaction { + struct sigaction sa; +}; + +#else /* !__KERNEL__ */ + +/* Here we must cater to libcs that poke about in kernel headers. */ + +struct sigaction { + union { + __sighandler_t _sa_handler; + void (*_sa_sigaction)(int, struct siginfo *, void *); + } _u; + sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +#define sa_handler _u._sa_handler +#define sa_sigaction _u._sa_sigaction + +#endif /* __KERNEL__ */ + + +typedef struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; + +#ifdef __KERNEL__ + +#include +#undef __HAVE_ARCH_SIG_BITOPS + +#endif /* __KERNEL__ */ + +#endif /* __V850_SIGNAL_H__ */ diff -Nru a/include/asm-v850/sim.h b/include/asm-v850/sim.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/sim.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,49 @@ +/* + * include/asm-v850/sim.h -- Machine-dependent defs for GDB v850e simulator + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_SIM_H__ +#define __V850_SIM_H__ + + +#define CPU_ARCH "v850e" +#define CPU_MODEL "GDB/v850e simulator" + + +/* We use a wierd value for RAM, not just 0, for testing purposes. + These must match the values used in the linker script. */ +#define RAM_ADDR 0x8F000000 +#define RAM_SIZE 0x01000000 + + +/* For */ +#define PAGE_OFFSET RAM_ADDR + + +/* For */ +/* `R0 RAM', used for a few miscellaneous variables that must be + accessible using a load instruction relative to R0. On real + processors, this usually is on-chip RAM, but here we just + choose an arbitrary address that meets the above constraint. */ +#define R0_RAM_ADDR 0xFFFFF000 + + +/* For */ +#ifndef HZ +#define HZ 24 /* Minimum supported frequency. */ +#endif + +/* For */ +#define NUM_CPU_IRQS 6 + + +#endif /* __V850_SIM_H__ */ diff -Nru a/include/asm-v850/sim85e2c.h b/include/asm-v850/sim85e2c.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/sim85e2c.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,89 @@ +/* + * include/asm-v850/sim85e2c.h -- Machine-dependent defs for + * V850E2 RTL simulator + * + * Copyright (C) 2002 NEC Corporation + * Copyright (C) 2002 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_SIM85E2C_H__ +#define __V850_SIM85E2C_H__ + + +#define CPU_ARCH "v850e2" +#define CPU_MODEL "sim85e2c simulator" + + +/* Various memory areas supported by the simulator. + These should match the corresponding definitions in the linker script. */ + +/* `instruction RAM'; instruction fetches are much faster from IRAM than + from DRAM. */ +#define IRAM_ADDR 0 +#define IRAM_SIZE 0x00100000 /* 1MB */ +/* `data RAM', below and contiguous with the I/O space. + Data fetches are much faster from DRAM than from IRAM. */ +#define DRAM_ADDR 0xfff00000 +#define DRAM_SIZE 0x000ff000 /* 1020KB */ +/* `external ram'. Unlike the above RAM areas, this memory is cached, + so both instruction and data fetches should be (mostly) fast -- + however, currently only write-through caching is supported, so writes + to ERAM will be slow. */ +#define ERAM_ADDR 0x00100000 +#define ERAM_SIZE 0x07f00000 /* 127MB (max) */ + + +/* CPU core control registers; these should be expanded and moved into + separate header files when we support some other processors based on + the same E2 core. */ +/* Bus Transaction Control Register */ +#define NA85E2C_CACHE_BTSC_ADDR 0xfffff070 +#define NA85E2C_CACHE_BTSC (*(volatile unsigned short *)NA85E2C_CACHE_BTSC_ADDR) +#define NA85E2C_CACHE_BTSC_ICM 0x1 /* icache enable */ +#define NA85E2C_CACHE_BTSC_DCM0 0x4 /* dcache enable, bit 0 */ +#define NA85E2C_CACHE_BTSC_DCM1 0x8 /* dcache enable, bit 1 */ +/* Cache Configuration Register */ +#define NA85E2C_BUSM_BHC_ADDR 0xfffff06a +#define NA85E2C_BUSM_BHC (*(volatile unsigned short *)NA85E2C_BUSM_BHC_ADDR) + +/* Simulator specific control registers. */ +/* NOTHAL controls whether the simulator will stop at a `halt' insn. */ +#define NOTHAL_ADDR 0xffffff22 +#define NOTHAL (*(volatile unsigned char *)NOTHAL_ADDR) +/* The simulator will stop N cycles after N is written to SIMFIN. */ +#define SIMFIN_ADDR 0xffffff24 +#define SIMFIN (*(volatile unsigned short *)SIMFIN_ADDR) + + +/* The simulator has an nb85e-style interrupt system. */ +#include + +/* For */ +#define NUM_CPU_IRQS 64 + + +/* For */ +#define PAGE_OFFSET DRAM_ADDR + + +/* For */ +/* `R0 RAM', used for a few miscellaneous variables that must be accessible + using a load instruction relative to R0. The sim85e2c simulator + actually puts 1020K of RAM from FFF00000 to FFFFF000, so we arbitarily + choose a small portion at the end of that. */ +#define R0_RAM_ADDR 0xFFFFE000 + + +/* For */ +#ifndef HZ +#define HZ 24 /* Minimum supported frequency. */ +#endif + + +#endif /* __V850_SIM85E2C_H__ */ diff -Nru a/include/asm-v850/simsyscall.h b/include/asm-v850/simsyscall.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/simsyscall.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,99 @@ +/* + * include/asm-v850/simsyscall.h -- `System calls' under the v850e emulator + * + * Copyright (C) 2001 NEC Corporation + * Copyright (C) 2001 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_SIMSYSCALL_H__ +#define __V850_SIMSYSCALL_H__ + +#define V850_SIM_SYS_exit(a...) V850_SIM_SYSCALL_1 (1 , ##a) +#define V850_SIM_SYS_fork(a...) V850_SIM_SYSCALL_0 (2 , ##a) +#define V850_SIM_SYS_read(a...) V850_SIM_SYSCALL_3 (3 , ##a) +#define V850_SIM_SYS_write(a...) V850_SIM_SYSCALL_3 (4 , ##a) +#define V850_SIM_SYS_open(a...) V850_SIM_SYSCALL_2 (5 , ##a) +#define V850_SIM_SYS_close(a...) V850_SIM_SYSCALL_1 (6 , ##a) +#define V850_SIM_SYS_wait4(a...) V850_SIM_SYSCALL_4 (7 , ##a) +/* #define V850_SIM_SYS_creat(a...) V850_SIM_SYSCALL_1 (8 , ##a) */ +/* #define V850_SIM_SYS_link(a...) V850_SIM_SYSCALL_1 (9 , ##a) */ +/* #define V850_SIM_SYS_unlink(a...) V850_SIM_SYSCALL_1 (10 , ##a) */ +#define V850_SIM_SYS_execv(a...) V850_SIM_SYSCALL_2 (11 , ##a) +/* #define V850_SIM_SYS_chdir(a...) V850_SIM_SYSCALL_1 (12 , ##a) */ +/* #define V850_SIM_SYS_mknod(a...) V850_SIM_SYSCALL_1 (14 , ##a) */ +#define V850_SIM_SYS_chmod(a...) V850_SIM_SYSCALL_2 (15 , ##a) +#define V850_SIM_SYS_chown(a...) V850_SIM_SYSCALL_2 (16 , ##a) +#define V850_SIM_SYS_lseek(a...) V850_SIM_SYSCALL_3 (19 , ##a) +/* #define V850_SIM_SYS_getpid(a...) V850_SIM_SYSCALL_1 (20 , ##a) */ +/* #define V850_SIM_SYS_isatty(a...) V850_SIM_SYSCALL_1 (21 , ##a) */ +/* #define V850_SIM_SYS_fstat(a...) V850_SIM_SYSCALL_1 (22 , ##a) */ +#define V850_SIM_SYS_time(a...) V850_SIM_SYSCALL_1 (23 , ##a) +#define V850_SIM_SYS_poll(a...) V850_SIM_SYSCALL_3 (24 , ##a) +#define V850_SIM_SYS_stat(a...) V850_SIM_SYSCALL_2 (38 , ##a) +#define V850_SIM_SYS_pipe(a...) V850_SIM_SYSCALL_1 (42 , ##a) +#define V850_SIM_SYS_times(a...) V850_SIM_SYSCALL_1 (43 , ##a) +#define V850_SIM_SYS_execve(a...) V850_SIM_SYSCALL_3 (59 , ##a) +#define V850_SIM_SYS_gettimeofday(a...) V850_SIM_SYSCALL_2 (116 , ##a) +/* #define V850_SIM_SYS_utime(a...) V850_SIM_SYSCALL_2 (201 , ##a) */ +/* #define V850_SIM_SYS_wait(a...) V850_SIM_SYSCALL_1 (202 , ##a) */ + +#define V850_SIM_SYS_make_raw(a...) V850_SIM_SYSCALL_1 (1024 , ##a) + + +#define V850_SIM_SYSCALL_0(_call) \ +({ \ + register int call __asm__ ("r6") = _call; \ + register int rval __asm__ ("r10"); \ + __asm__ __volatile__ ("trap 31" \ + : "=r" (rval) \ + : "r" (call) \ + : "r11", "memory"); \ + rval; \ +}) +#define V850_SIM_SYSCALL_1(_call, _arg0) \ +({ \ + register int call __asm__ ("r6") = _call; \ + register long arg0 __asm__ ("r7") = (long)_arg0; \ + register int rval __asm__ ("r10"); \ + __asm__ __volatile__ ("trap 31" \ + : "=r" (rval) \ + : "r" (call), "r" (arg0) \ + : "r11", "memory"); \ + rval; \ +}) +#define V850_SIM_SYSCALL_2(_call, _arg0, _arg1) \ +({ \ + register int call __asm__ ("r6") = _call; \ + register long arg0 __asm__ ("r7") = (long)_arg0; \ + register long arg1 __asm__ ("r8") = (long)_arg1; \ + register int rval __asm__ ("r10"); \ + __asm__ __volatile__ ("trap 31" \ + : "=r" (rval) \ + : "r" (call), "r" (arg0), "r" (arg1) \ + : "r11", "memory"); \ + rval; \ +}) +#define V850_SIM_SYSCALL_3(_call, _arg0, _arg1, _arg2) \ +({ \ + register int call __asm__ ("r6") = _call; \ + register long arg0 __asm__ ("r7") = (long)_arg0; \ + register long arg1 __asm__ ("r8") = (long)_arg1; \ + register long arg2 __asm__ ("r9") = (long)_arg2; \ + register int rval __asm__ ("r10"); \ + __asm__ __volatile__ ("trap 31" \ + : "=r" (rval) \ + : "r" (call), "r" (arg0), "r" (arg1), "r" (arg2)\ + : "r11", "memory"); \ + rval; \ +}) + +#define V850_SIM_SYSCALL(call, args...) \ + V850_SIM_SYS_##call (args) + +#endif /* __V850_SIMSYSCALL_H__ */ diff -Nru a/include/asm-v850/socket.h b/include/asm-v850/socket.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/socket.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,64 @@ +#ifndef __V850_SOCKET_H__ +#define __V850_SOCKET_H__ + +#include + +/* For setsockoptions(2) */ +#define SOL_SOCKET 1 + +#define SO_DEBUG 1 +#define SO_REUSEADDR 2 +#define SO_TYPE 3 +#define SO_ERROR 4 +#define SO_DONTROUTE 5 +#define SO_BROADCAST 6 +#define SO_SNDBUF 7 +#define SO_RCVBUF 8 +#define SO_KEEPALIVE 9 +#define SO_OOBINLINE 10 +#define SO_NO_CHECK 11 +#define SO_PRIORITY 12 +#define SO_LINGER 13 +#define SO_BSDCOMPAT 14 +/* To add :#define SO_REUSEPORT 15 */ +#define SO_PASSCRED 16 +#define SO_PEERCRED 17 +#define SO_RCVLOWAT 18 +#define SO_SNDLOWAT 19 +#define SO_RCVTIMEO 20 +#define SO_SNDTIMEO 21 + +/* Security levels - as per NRL IPv6 - don't actually do anything */ +#define SO_SECURITY_AUTHENTICATION 22 +#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 +#define SO_SECURITY_ENCRYPTION_NETWORK 24 + +#define SO_BINDTODEVICE 25 + +/* Socket filtering */ +#define SO_ATTACH_FILTER 26 +#define SO_DETACH_FILTER 27 + +#define SO_PEERNAME 28 +#define SO_TIMESTAMP 29 +#define SCM_TIMESTAMP SO_TIMESTAMP + +#define SO_ACCEPTCONN 30 + +/* Nast libc5 fixup - bletch */ +#if defined(__KERNEL__) +/* Socket types. */ +#define SOCK_STREAM 1 /* stream (connection) socket */ +#define SOCK_DGRAM 2 /* datagram (conn.less) socket */ +#define SOCK_RAW 3 /* raw socket */ +#define SOCK_RDM 4 /* reliably-delivered message */ +#define SOCK_SEQPACKET 5 /* sequential packet socket */ +#define SOCK_PACKET 10 /* linux specific way of */ + /* getting packets at the dev */ + /* level. For writing rarp and */ + /* other similar things on the */ + /* user level. */ +#define SOCK_MAX (SOCK_PACKET+1) +#endif + +#endif /* __V850_SOCKET_H__ */ diff -Nru a/include/asm-v850/sockios.h b/include/asm-v850/sockios.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/sockios.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,12 @@ +#ifndef __V850_SOCKIOS_H__ +#define __V850_SOCKIOS_H__ + +/* Socket-level I/O control calls. */ +#define FIOSETOWN 0x8901 +#define SIOCSPGRP 0x8902 +#define FIOGETOWN 0x8903 +#define SIOCGPGRP 0x8904 +#define SIOCATMARK 0x8905 +#define SIOCGSTAMP 0x8906 /* Get stamp */ + +#endif /* __V850_SOCKIOS_H__ */ diff -Nru a/include/asm-v850/softirq.h b/include/asm-v850/softirq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/softirq.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,20 @@ +#ifndef __V850_SOFTIRQ_H__ +#define __V850_SOFTIRQ_H__ + +#include +#include + +#define local_bh_disable() \ + do { preempt_count() += SOFTIRQ_OFFSET; barrier(); } while (0) +#define __local_bh_enable() \ + do { barrier(); preempt_count() -= SOFTIRQ_OFFSET; } while (0) + +#define local_bh_enable() \ +do { \ + __local_bh_enable(); \ + if (unlikely(!in_interrupt() && softirq_pending(smp_processor_id()))) \ + do_softirq(); \ + preempt_check_resched(); \ +} while (0) + +#endif /* __V850_SOFTIRQ_H__ */ diff -Nru a/include/asm-v850/stat.h b/include/asm-v850/stat.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/stat.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,60 @@ +#ifndef __V850_STAT_H__ +#define __V850_STAT_H__ + +struct stat { + __kernel_dev_t st_dev; + __kernel_ino_t st_ino; + __kernel_mode_t st_mode; + __kernel_nlink_t st_nlink; + __kernel_uid_t st_uid; + __kernel_gid_t st_gid; + __kernel_dev_t st_rdev; + __kernel_off_t st_size; + unsigned long st_blksize; + unsigned long st_blocks; + unsigned long st_atime; + unsigned long __unused1; + unsigned long st_mtime; + unsigned long __unused2; + unsigned long st_ctime; + unsigned long __unused3; + unsigned long __unused4; + unsigned long __unused5; +}; + +struct stat64 { + __kernel_dev_t st_dev; + unsigned long __unused0; + unsigned long __unused1; + + __kernel_ino64_t st_ino; + + __kernel_mode_t st_mode; + __kernel_nlink_t st_nlink; + + __kernel_uid_t st_uid; + __kernel_gid_t st_gid; + + __kernel_dev_t st_rdev; + unsigned long __unused2; + unsigned long __unused3; + + __kernel_loff_t st_size; + unsigned long st_blksize; + + unsigned long st_blocks; /* No. of 512-byte blocks allocated */ + unsigned long __unused4; /* future possible st_blocks high bits */ + + unsigned long st_atime; + unsigned long __unused5; + + unsigned long st_mtime; + unsigned long __unused6; + + unsigned long st_ctime; + unsigned long __unused7; /* high 32 bits of ctime someday */ + + unsigned long __unused8; +}; + +#endif /* __V850_STAT_H__ */ diff -Nru a/include/asm-v850/statfs.h b/include/asm-v850/statfs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/statfs.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,25 @@ +#ifndef __V850_STATFS_H__ +#define __V850_STATFS_H__ + +#ifndef __KERNEL_STRICT_NAMES + +#include + +typedef __kernel_fsid_t fsid_t; + +#endif + +struct statfs { + long f_type; + long f_bsize; + long f_blocks; + long f_bfree; + long f_bavail; + long f_files; + long f_ffree; + __kernel_fsid_t f_fsid; + long f_namelen; + long f_spare[6]; +}; + +#endif /* __V850_STATFS_H__ */ diff -Nru a/include/asm-v850/string.h b/include/asm-v850/string.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/string.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,27 @@ +/* + * include/asm-v850/string.h -- Architecture specific string routines + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_STRING_H__ +#define __V850_STRING_H__ + +#define __HAVE_ARCH_BCOPY +#define __HAVE_ARCH_MEMCPY +#define __HAVE_ARCH_MEMSET +#define __HAVE_ARCH_MEMMOVE + +extern void *memcpy (void *, const void *, __kernel_size_t); +extern void bcopy (const char *, char *, int); +extern void *memset (void *, int, __kernel_size_t); +extern void *memmove (void *, const void *, __kernel_size_t); + +#endif /* __V850_STRING_H__ */ diff -Nru a/include/asm-v850/system.h b/include/asm-v850/system.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/system.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,115 @@ +/* + * include/asm-v850/system.h -- Low-level interrupt/thread ops + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_SYSTEM_H__ +#define __V850_SYSTEM_H__ + +#include +#include + + +#define prepare_to_switch() do { } while (0) + +/* + * switch_to(n) should switch tasks to task ptr, first checking that + * ptr isn't the current task, in which case it does nothing. + */ +struct thread_struct; +extern void *switch_thread (struct thread_struct *last, + struct thread_struct *next); +#define switch_to(prev,next,last) \ + do { \ + if (prev != next) { \ + (last) = switch_thread (&prev->thread, &next->thread); \ + } \ + } while (0) + + +/* Enable/disable interrupts. */ +#define local_irq_enable() __asm__ __volatile__ ("ei") +#define local_irq_disable() __asm__ __volatile__ ("di") + +#define local_save_flags(flags) \ + __asm__ __volatile__ ("stsr %1, %0" : "=r" (flags) : "i" (SR_PSW)) +#define local_restore_flags(flags) \ + __asm__ __volatile__ ("ldsr %0, %1" :: "r" (flags), "i" (SR_PSW)) + +/* For spinlocks etc */ +#define local_irq_save(flags) \ + do { local_save_flags (flags); local_irq_disable (); } while (0) +#define local_irq_restore(flags) \ + local_restore_flags (flags); + + +static inline int irqs_disabled (void) +{ + unsigned flags; + local_save_flags (flags); + return !!(flags & 0x20); +} + + +/* + * Force strict CPU ordering. + * Not really required on v850... + */ +#define nop() __asm__ __volatile__ ("nop") +#define mb() __asm__ __volatile__ ("" ::: "memory") +#define rmb() mb () +#define wmb() mb () +#define set_rmb(var, value) do { xchg (&var, value); } while (0) +#define set_mb(var, value) set_rmb (var, value) +#define set_wmb(var, value) do { var = value; wmb (); } while (0) + +#ifdef CONFIG_SMP +#define smp_mb() mb () +#define smp_rmb() rmb () +#define smp_wmb() wmb () +#else +#define smp_mb() barrier () +#define smp_rmb() barrier () +#define smp_wmb() barrier () +#endif + +#define xchg(ptr, with) \ + ((__typeof__ (*(ptr)))__xchg ((unsigned long)(with), (ptr), sizeof (*(ptr)))) +#define tas(ptr) (xchg ((ptr), 1)) + +extern inline unsigned long __xchg (unsigned long with, + __volatile__ void *ptr, int size) +{ + unsigned long tmp, flags; + + local_irq_save (flags); + + switch (size) { + case 1: + tmp = *(unsigned char *)ptr; + *(unsigned char *)ptr = with; + break; + case 2: + tmp = *(unsigned short *)ptr; + *(unsigned short *)ptr = with; + break; + case 4: + tmp = *(unsigned long *)ptr; + *(unsigned long *)ptr = with; + break; + } + + local_irq_restore (flags); + + return tmp; +} + +#endif /* __V850_SYSTEM_H__ */ diff -Nru a/include/asm-v850/teg.h b/include/asm-v850/teg.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/teg.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,58 @@ +/* + * include/asm-v850/nb85e_teg.h -- NB85E-TEG cpu chip + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_NB85E_TEG_H__ +#define __V850_NB85E_TEG_H__ + +/* The NB85E_TEG uses the NB85E cpu core. */ +#include + +#define CHIP "v850e/nb85e-teg" +#define CHIP_LONG "NEC V850E/NB85E TEG" + +/* Hardware-specific interrupt numbers (in the kernel IRQ namespace). */ +#define IRQ_INTOV(n) (n) /* 0-3 */ +#define IRQ_INTOV_NUM 4 +#define IRQ_INTCMD(n) (0x1c + (n)) /* interval timer interrupts 0-3 */ +#define IRQ_INTCMD_NUM 4 +#define IRQ_INTDMA(n) (0x20 + (n)) /* DMA interrupts 0-3 */ +#define IRQ_INTDMA_NUM 4 +#define IRQ_INTCSI(n) (0x24 + (n)) /* CSI 0-2 transmit/receive completion */ +#define IRQ_INTCSI_NUM 3 +#define IRQ_INTSER(n) (0x25 + (n)) /* UART 0-2 reception error */ +#define IRQ_INTSER_NUM 3 +#define IRQ_INTSR(n) (0x26 + (n)) /* UART 0-2 reception completion */ +#define IRQ_INTSR_NUM 3 +#define IRQ_INTST(n) (0x27 + (n)) /* UART 0-2 transmission completion */ +#define IRQ_INTST_NUM 3 + +/* For */ +#define NUM_MACH_IRQS 0x30 + +/* TEG UART details. */ +#define NB85E_UART_BASE_ADDR(n) (0xFFFFF600 + 0x10 * (n)) +#define NB85E_UART_ASIM_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x0) +#define NB85E_UART_ASIS_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x2) +#define NB85E_UART_ASIF_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x4) +#define NB85E_UART_CKSR_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x6) +#define NB85E_UART_BRGC_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x8) +#define NB85E_UART_TXB_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0xA) +#define NB85E_UART_RXB_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0xC) +#define NB85E_UART_NUM_CHANNELS 1 +#define NB85E_UART_BASE_FREQ CPU_CLOCK_FREQ + +/* The TEG RTPU. */ +#define NB85E_RTPU_BASE_ADDR 0xFFFFF210 + + +#endif /* __V850_NB85E_TEG_H__ */ diff -Nru a/include/asm-v850/termbits.h b/include/asm-v850/termbits.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/termbits.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,174 @@ +#ifndef __V850_TERMBITS_H__ +#define __V850_TERMBITS_H__ + +#include + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define NCCS 19 +struct termios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + + +/* c_iflag bits */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 + +/* c_oflag bits */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 +#define XTABS 0014000 +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 +#define FFDLY 0100000 +#define FF0 0000000 +#define FF1 0100000 + +/* c_cflag bit meaning */ +#define CBAUD 0010017 +#define B0 0000000 /* hang up */ +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 +#define CBAUDEX 0010000 +#define B57600 0010001 +#define B115200 0010002 +#define B230400 0010003 +#define B460800 0010004 +#define B500000 0010005 +#define B576000 0010006 +#define B921600 0010007 +#define B1000000 0010010 +#define B1152000 0010011 +#define B1500000 0010012 +#define B2000000 0010013 +#define B2500000 0010014 +#define B3000000 0010015 +#define B3500000 0010016 +#define B4000000 0010017 +#define CIBAUD 002003600000 /* input baud rate (not used) */ +#define CMSPAR 010000000000 /* mark or space (stick) parity */ +#define CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define ISIG 0000001 +#define ICANON 0000002 +#define XCASE 0000004 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define IEXTEN 0100000 + + +/* tcflow() and TCXONC use these */ +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +#endif /* __V850_TERMBITS_H__ */ diff -Nru a/include/asm-v850/termios.h b/include/asm-v850/termios.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/termios.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,106 @@ +#ifndef __V850_TERMIOS_H__ +#define __V850_TERMIOS_H__ + +#include +#include + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control characters */ +}; + +/* modem lines */ +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG +#define TIOCM_OUT1 0x2000 +#define TIOCM_OUT2 0x4000 +#define TIOCM_LOOP 0x8000 + +/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ + +/* line disciplines */ +#define N_TTY 0 +#define N_SLIP 1 +#define N_MOUSE 2 +#define N_PPP 3 +#define N_STRIP 4 +#define N_AX25 5 +#define N_X25 6 /* X.25 async */ +#define N_6PACK 7 +#define N_MASC 8 /* Reserved for Mobitex module */ +#define N_R3964 9 /* Reserved for Simatic R3964 module */ +#define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ +#define N_IRDA 11 /* Linux IR - http://irda.sourceforge.net/ */ +#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ +#define N_HDLC 13 /* synchronous HDLC */ +#define N_SYNC_PPP 14 /* synchronous PPP */ +#define N_HCI 15 /* Bluetooth HCI UART */ + +#ifdef __KERNEL__ + +/* intr=^C quit=^\ erase=del kill=^U + eof=^D vtime=\0 vmin=\1 sxtc=\0 + start=^Q stop=^S susp=^Z eol=\0 + reprint=^R discard=^U werase=^W lnext=^V + eol2=\0 +*/ +#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" + +/* + * Translate a "termio" structure into a "termios". Ugh. + */ +#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \ + unsigned short __tmp; \ + get_user(__tmp,&(termio)->x); \ + *(unsigned short *) &(termios)->x = __tmp; \ +} + +#define user_termio_to_kernel_termios(termios, termio) \ +({ \ + SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \ + SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \ + SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \ + SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \ + copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ +}) + +/* + * Translate a "termios" structure into a "termio". Ugh. + */ +#define kernel_termios_to_user_termio(termio, termios) \ +({ \ + put_user((termios)->c_iflag, &(termio)->c_iflag); \ + put_user((termios)->c_oflag, &(termio)->c_oflag); \ + put_user((termios)->c_cflag, &(termio)->c_cflag); \ + put_user((termios)->c_lflag, &(termio)->c_lflag); \ + put_user((termios)->c_line, &(termio)->c_line); \ + copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ +}) + +#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios)) +#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios)) + +#endif /* __KERNEL__ */ + +#endif /* __V850_TERMIOS_H__ */ diff -Nru a/include/asm-v850/thread_info.h b/include/asm-v850/thread_info.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/thread_info.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,129 @@ +/* + * include/asm-v850/thread_info.h -- v850 low-level thread information + * + * Copyright (C) 2002 NEC Corporation + * Copyright (C) 2002 Miles Bader + * Copyright (C) 2002 David Howells (dhowells@redhat.com) + * - Incorporating suggestions made by Linus Torvalds and Dave Miller + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * This file was derived from the PPC version, include/asm-ppc/thread_info.h + * which was adapted from the i386 version by Paul Mackerras + */ + +#ifndef __V850_THREAD_INFO_H__ +#define __V850_THREAD_INFO_H__ + +#ifdef __KERNEL__ + +#ifndef __ASSEMBLY__ + +/* + * low level task data. + * If you change this, change the TI_* offsets below to match. + */ +struct thread_info { + struct task_struct *task; /* main task structure */ + struct exec_domain *exec_domain; /* execution domain */ + unsigned long flags; /* low level flags */ + int cpu; /* cpu we're on */ + int preempt_count; +}; + +#define INIT_THREAD_INFO(tsk) \ +{ \ + .task = &tsk, \ + .exec_domain = &default_exec_domain, \ + .flags = 0, \ + .cpu = 0, \ + .preempt_count = 1 \ +} + +#define init_thread_info (init_thread_union.thread_info) +#define init_stack (init_thread_union.stack) + +/* + * macros/functions for gaining access to the thread information structure + */ + +/* thread information allocation */ +#define alloc_thread_info() ((struct thread_info *) \ + __get_free_pages(GFP_KERNEL, 1)) +#define free_thread_info(ti) free_pages((unsigned long) (ti), 1) +#define get_thread_info(ti) get_task_struct((ti)->task) +#define put_thread_info(ti) put_task_struct((ti)->task) + +#endif /* __ASSEMBLY__ */ + + +/* + * Offsets in thread_info structure, used in assembly code + */ +#define TI_TASK 0 +#define TI_EXECDOMAIN 4 +#define TI_FLAGS 8 +#define TI_CPU 12 +#define TI_PREEMPT 16 +#define TI_SOFTIRQ 20 +#define TI_HARDIRQ 24 + +#define PREEMPT_ACTIVE 0x4000000 + +/* + * thread information flag bit numbers + */ +#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ +#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ +#define TIF_SIGPENDING 2 /* signal pending */ +#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ +#define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling + TIF_NEED_RESCHED */ + +/* as above, but as bit values */ +#define _TIF_SYSCALL_TRACE (1< + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_TLB_H__ +#define __V850_TLB_H__ + +#define tlb_flush(tlb) ((void)0) + +#include + +#endif /* __V850_TLB_H__ */ diff -Nru a/include/asm-v850/tlbflush.h b/include/asm-v850/tlbflush.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/tlbflush.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,71 @@ +/* + * include/asm-v850/tlbflush.h + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_TLBFLUSH_H__ +#define __V850_TLBFLUSH_H__ + +#include +#include + + +/* + * flush all user-space atc entries. + */ +static inline void __flush_tlb(void) +{ + BUG (); +} + +static inline void __flush_tlb_one(unsigned long addr) +{ + BUG (); +} + +#define flush_tlb() __flush_tlb() + +/* + * flush all atc entries (both kernel and user-space entries). + */ +static inline void flush_tlb_all(void) +{ + BUG (); +} + +static inline void flush_tlb_mm(struct mm_struct *mm) +{ + BUG (); +} + +static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) +{ + BUG (); +} + +static inline void flush_tlb_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) +{ + BUG (); +} + +extern inline void flush_tlb_kernel_page(unsigned long addr) +{ + BUG (); +} + +extern inline void flush_tlb_pgtables(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + BUG (); +} + +#endif /* __V850_TLBFLUSH_H__ */ diff -Nru a/include/asm-v850/topology.h b/include/asm-v850/topology.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/topology.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,6 @@ +#ifndef __V850_TOPOLOGY_H__ +#define __V850_TOPOLOGY_H__ + +#include + +#endif /* __V850_TOPOLOGY_H__ */ diff -Nru a/include/asm-v850/types.h b/include/asm-v850/types.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/types.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,62 @@ +#ifndef __V850_TYPES_H__ +#define __V850_TYPES_H__ + +#ifndef __ASSEMBLY__ + +/* + * This file is never included by application software unless + * explicitly requested (e.g., via linux/types.h) in which case the + * application is Linux specific so (user-) name space pollution is + * not a major issue. However, for interoperability, libraries still + * need to be careful to avoid a name clashes. + */ + +typedef unsigned short umode_t; + +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +#define BITS_PER_LONG 32 + +/* Dma addresses are 32-bits wide. */ + +typedef u32 dma_addr_t; + +#endif /* __KERNEL__ */ + +#endif /* !__ASSEMBLY__ */ + +#endif /* __V850_TYPES_H__ */ diff -Nru a/include/asm-v850/uaccess.h b/include/asm-v850/uaccess.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/uaccess.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,159 @@ +#ifndef __V850_UACCESS_H__ +#define __V850_UACCESS_H__ + +/* + * User space memory access functions + */ +#include + +#include +#include + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +extern inline int access_ok (int type, const void *addr, unsigned long size) +{ + /* XXX I guess we should check against real ram bounds at least, and + possibly make sure ADDR is not within the kernel. + For now we just check to make sure it's not a small positive + or negative value, as that will at least catch some kinds of + error. In particular, we make sure that ADDR's not within the + interrupt vector area, which we know starts at zero, or within the + peripheral-I/O area, which is located just _before_ zero. */ + unsigned long val = (unsigned long)addr; + return val >= (0x80 + NUM_CPU_IRQS*16) && val < 0xFFFFF000; +} + +extern inline int verify_area (int type, const void *addr, unsigned long size) +{ + return access_ok (type, addr, size) ? 0 : -EFAULT; +} + +/* + * The exception table consists of pairs of addresses: the first is the + * address of an instruction that is allowed to fault, and the second is + * the address at which the program should continue. No registers are + * modified, so it is entirely up to the continuation code to figure out + * what to do. + * + * All the routines below use bits of fixup code that are out of line + * with the main instruction path. This means when everything is well, + * we don't even have to jump over them. Further, they do not intrude + * on our cache or tlb entries. + */ + +struct exception_table_entry +{ + unsigned long insn, fixup; +}; + +/* Returns 0 if exception not found and fixup otherwise. */ +extern unsigned long search_exception_table (unsigned long); + + +/* + * These are the main single-value transfer routines. They automatically + * use the right size if we just have the right pointer type. + */ + +extern int bad_user_access_length (void); + +#define __get_user(var, ptr) \ + ({ \ + int __gu_err = 0; \ + typeof(*(ptr)) __gu_val = 0; \ + switch (sizeof (*(ptr))) { \ + case 1: \ + case 2: \ + case 4: \ + __gu_val = *(ptr); \ + break; \ + case 8: \ + memcpy(&__gu_val, ptr, sizeof(__gu_val)); \ + break; \ + default: \ + __gu_val = 0; \ + __gu_err = __get_user_bad (); \ + break; \ + } \ + (var) = __gu_val; \ + __gu_err; \ + }) +#define __get_user_bad() (bad_user_access_length (), (-EFAULT)) + +#define __put_user(var, ptr) \ + ({ \ + int __pu_err = 0; \ + switch (sizeof (*(ptr))) { \ + case 1: \ + case 2: \ + case 4: \ + *(ptr) = (var); \ + break; \ + case 8: { \ + typeof(*(ptr)) __pu_val = 0; \ + memcpy(ptr, &__pu_val, sizeof(__pu_val)); \ + } \ + break; \ + default: \ + __pu_err = __put_user_bad (); \ + break; \ + } \ + __pu_err; \ + }) +#define __put_user_bad() (bad_user_access_length (), (-EFAULT)) + +#define put_user(x, ptr) __put_user(x, ptr) +#define get_user(x, ptr) __get_user(x, ptr) + +#define __copy_from_user(to, from, n) (memcpy (to, from, n), 0) +#define __copy_to_user(to, from, n) (memcpy(to, from, n), 0) + +#define copy_from_user(to, from, n) __copy_from_user (to, from, n) +#define copy_to_user(to, from, n) __copy_to_user(to, from, n) + +#define copy_to_user_ret(to,from,n,retval) \ + ({ if (copy_to_user (to,from,n)) return retval; }) + +#define copy_from_user_ret(to,from,n,retval) \ + ({ if (copy_from_user (to,from,n)) return retval; }) + +/* + * Copy a null terminated string from userspace. + */ + +static inline long +strncpy_from_user (char *dst, const char *src, long count) +{ + char *tmp; + strncpy (dst, src, count); + for (tmp = dst; *tmp && count > 0; tmp++, count--) + ; + return tmp - dst; +} + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 on exception, a value greater than N if too long + */ +static inline long strnlen_user (const char *src, long n) +{ + return strlen (src) + 1; +} + +#define strlen_user(str) strnlen_user (str, 32767) + +/* + * Zero Userspace + */ + +static inline unsigned long +clear_user (void *to, unsigned long n) +{ + memset (to, 0, n); + return 0; +} + +#endif /* __V850_UACCESS_H__ */ diff -Nru a/include/asm-v850/ucontext.h b/include/asm-v850/ucontext.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/ucontext.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,14 @@ +#ifndef __V850_UCONTEXT_H__ +#define __V850_UCONTEXT_H__ + +#include + +struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + struct sigcontext uc_mcontext; + sigset_t uc_sigmask; /* mask last for extensibility */ +}; + +#endif /* __V850_UCONTEXT_H__ */ diff -Nru a/include/asm-v850/unaligned.h b/include/asm-v850/unaligned.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/unaligned.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,130 @@ +/* + * include/asm-v850/unaligned.h -- Unaligned memory access + * + * Copyright (C) 2001 NEC Corporation + * Copyright (C) 2001 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * This file is a copy of the arm version, include/asm-arm/unaligned.h + * + * Note that some v850 chips support unaligned access, but it seems too + * annoying to use. + */ + +#ifndef __V850_UNALIGNED_H__ +#define __V850_UNALIGNED_H__ + +#include + +extern int __bug_unaligned_x(void *ptr); + +/* + * What is the most efficient way of loading/storing an unaligned value? + * + * That is the subject of this file. Efficiency here is defined as + * minimum code size with minimum register usage for the common cases. + * It is currently not believed that long longs are common, so we + * trade efficiency for the chars, shorts and longs against the long + * longs. + * + * Current stats with gcc 2.7.2.2 for these functions: + * + * ptrsize get: code regs put: code regs + * 1 1 1 1 2 + * 2 3 2 3 2 + * 4 7 3 7 3 + * 8 20 6 16 6 + * + * gcc 2.95.1 seems to code differently: + * + * ptrsize get: code regs put: code regs + * 1 1 1 1 2 + * 2 3 2 3 2 + * 4 7 4 7 4 + * 8 19 8 15 6 + * + * which may or may not be more efficient (depending upon whether + * you can afford the extra registers). Hopefully the gcc 2.95 + * is inteligent enough to decide if it is better to use the + * extra register, but evidence so far seems to suggest otherwise. + * + * Unfortunately, gcc is not able to optimise the high word + * out of long long >> 32, or the low word from long long << 32 + */ + +#define __get_unaligned_2(__p) \ + (__p[0] | __p[1] << 8) + +#define __get_unaligned_4(__p) \ + (__p[0] | __p[1] << 8 | __p[2] << 16 | __p[3] << 24) + +#define get_unaligned(ptr) \ + ({ \ + __typeof__(*(ptr)) __v; \ + __u8 *__p = (__u8 *)(ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: __v = *(ptr); break; \ + case 2: __v = __get_unaligned_2(__p); break; \ + case 4: __v = __get_unaligned_4(__p); break; \ + case 8: { \ + unsigned int __v1, __v2; \ + __v2 = __get_unaligned_4((__p+4)); \ + __v1 = __get_unaligned_4(__p); \ + __v = ((unsigned long long)__v2 << 32 | __v1); \ + } \ + break; \ + default: __v = __bug_unaligned_x(__p); break; \ + } \ + __v; \ + }) + + +extern inline void __put_unaligned_2(__u32 __v, register __u8 *__p) +{ + *__p++ = __v; + *__p++ = __v >> 8; +} + +extern inline void __put_unaligned_4(__u32 __v, register __u8 *__p) +{ + __put_unaligned_2(__v >> 16, __p + 2); + __put_unaligned_2(__v, __p); +} + +extern inline void __put_unaligned_8(const unsigned long long __v, register __u8 *__p) +{ + /* + * tradeoff: 8 bytes of stack for all unaligned puts (2 + * instructions), or an extra register in the long long + * case - go for the extra register. + */ + __put_unaligned_4(__v >> 32, __p+4); + __put_unaligned_4(__v, __p); +} + +/* + * Try to store an unaligned value as efficiently as possible. + */ +#define put_unaligned(val,ptr) \ + ({ \ + switch (sizeof(*(ptr))) { \ + case 1: \ + *(ptr) = (val); \ + break; \ + case 2: __put_unaligned_2((val),(__u8 *)(ptr)); \ + break; \ + case 4: __put_unaligned_4((val),(__u8 *)(ptr)); \ + break; \ + case 8: __put_unaligned_8((val),(__u8 *)(ptr)); \ + break; \ + default: __bug_unaligned_x(ptr); \ + break; \ + } \ + (void) 0; \ + }) + + +#endif /* __V850_UNALIGNED_H__ */ diff -Nru a/include/asm-v850/unistd.h b/include/asm-v850/unistd.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/unistd.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,411 @@ +/* + * include/asm-v850/unistd.h -- System call numbers and invocation mechanism + * + * Copyright (C) 2001,02 NEC Corporation + * Copyright (C) 2001,02 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + */ + +#ifndef __V850_UNISTD_H__ +#define __V850_UNISTD_H__ + +#include + +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_chown 16 +#define __NR_break 17 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_stty 31 +#define __NR_gtty 32 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_ftime 35 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_prof 44 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_umount2 52 +#define __NR_lock 53 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_setpgid 57 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 +#define __NR_sigsuspend 72 +#define __NR_sigpending 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_ugetrlimit 76 +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_select 82 +#define __NR_symlink 83 +#define __NR_readlink 85 +#define __NR_uselib 86 +#define __NR_swapon 87 +#define __NR_reboot 88 +#define __NR_readdir 89 +#define __NR_mmap 90 +#define __NR_munmap 91 +#define __NR_truncate 92 +#define __NR_ftruncate 93 +#define __NR_fchmod 94 +#define __NR_fchown 95 +#define __NR_getpriority 96 +#define __NR_setpriority 97 +#define __NR_profil 98 +#define __NR_statfs 99 +#define __NR_fstatfs 100 +#define __NR_socketcall 102 +#define __NR_syslog 103 +#define __NR_setitimer 104 +#define __NR_getitimer 105 +#define __NR_stat 106 +#define __NR_lstat 107 +#define __NR_fstat 108 +#define __NR_vhangup 111 +#define __NR_wait4 114 +#define __NR_swapoff 115 +#define __NR_sysinfo 116 +#define __NR_ipc 117 +#define __NR_fsync 118 +#define __NR_sigreturn 119 +#define __NR_clone 120 +#define __NR_setdomainname 121 +#define __NR_uname 122 +#define __NR_cacheflush 123 +#define __NR_adjtimex 124 +#define __NR_mprotect 125 +#define __NR_sigprocmask 126 +#define __NR_create_module 127 +#define __NR_init_module 128 +#define __NR_delete_module 129 +#define __NR_get_kernel_syms 130 +#define __NR_quotactl 131 +#define __NR_getpgid 132 +#define __NR_fchdir 133 +#define __NR_bdflush 134 +#define __NR_sysfs 135 +#define __NR_personality 136 +#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define __NR_setfsuid 138 +#define __NR_setfsgid 139 +#define __NR__llseek 140 +#define __NR_getdents 141 +#define __NR_flock 143 +#define __NR_msync 144 +#define __NR_readv 145 +#define __NR_writev 146 +#define __NR_getsid 147 +#define __NR_fdatasync 148 +#define __NR__sysctl 149 +#define __NR_mlock 150 +#define __NR_munlock 151 +#define __NR_mlockall 152 +#define __NR_munlockall 153 +#define __NR_sched_setparam 154 +#define __NR_sched_getparam 155 +#define __NR_sched_setscheduler 156 +#define __NR_sched_getscheduler 157 +#define __NR_sched_yield 158 +#define __NR_sched_get_priority_max 159 +#define __NR_sched_get_priority_min 160 +#define __NR_sched_rr_get_interval 161 +#define __NR_nanosleep 162 +#define __NR_mremap 163 +#define __NR_setresuid 164 +#define __NR_getresuid 165 +#define __NR_query_module 167 +#define __NR_poll 168 +#define __NR_nfsservctl 169 +#define __NR_setresgid 170 +#define __NR_getresgid 171 +#define __NR_prctl 172 +#define __NR_rt_sigreturn 173 +#define __NR_rt_sigaction 174 +#define __NR_rt_sigprocmask 175 +#define __NR_rt_sigpending 176 +#define __NR_rt_sigtimedwait 177 +#define __NR_rt_sigqueueinfo 178 +#define __NR_rt_sigsuspend 179 +#define __NR_pread 180 +#define __NR_pwrite 181 +#define __NR_lchown 182 +#define __NR_getcwd 183 +#define __NR_capget 184 +#define __NR_capset 185 +#define __NR_sigaltstack 186 +#define __NR_sendfile 187 +#define __NR_getpmsg 188 /* some people actually want streams */ +#define __NR_putpmsg 189 /* some people actually want streams */ +#define __NR_vfork 190 +#define __NR_mmap2 192 +#define __NR_truncate64 193 +#define __NR_ftruncate64 194 +#define __NR_stat64 195 +#define __NR_lstat64 196 +#define __NR_fstat64 197 +#define __NR_fcntl64 198 +#define __NR_getdents64 199 +#define __NR_pivot_root 200 +#define __NR_gettid 201 +#define __NR_tkill 202 +/* #define __NR_mincore 203 */ +/* #define __NR_madvise 204 */ + + +/* Syscall protocol: + Syscall number in r12, args in r6-r9, r13-r14 + Return value in r10 + Trap 0 for `short' syscalls, where all the args can fit in function + call argument registers, and trap 1 when there are additional args in + r13-r14. */ + +#define SYSCALL_NUM "r12" +#define SYSCALL_ARG0 "r6" +#define SYSCALL_ARG1 "r7" +#define SYSCALL_ARG2 "r8" +#define SYSCALL_ARG3 "r9" +#define SYSCALL_ARG4 "r13" +#define SYSCALL_ARG5 "r14" +#define SYSCALL_RET "r10" + +#define SYSCALL_SHORT_TRAP "0" +#define SYSCALL_LONG_TRAP "1" + +/* Registers clobbered by any syscall. This _doesn't_ include the syscall + number (r12) or the `extended arg' registers (r13, r14), even though + they are actually clobbered too (this is because gcc's `asm' statement + doesn't allow a clobber to be used as an input or output). */ +#define SYSCALL_CLOBBERS "r1", "r5", "r11", "r15", "r16", \ + "r17", "r18", "r19" + +/* Registers clobbered by a `short' syscall. This includes all clobbers + except the syscall number (r12). */ +#define SYSCALL_SHORT_CLOBBERS SYSCALL_CLOBBERS, "r13", "r14" + + +#define __syscall_return(type, res) \ + do { \ + /* user-visible error numbers are in the range -1 - -124: \ + see */ \ + if ((unsigned long)(res) >= (unsigned long)(-125)) { \ + errno = -(res); \ + res = -1; \ + } \ + return (type) (res); \ + } while (0) + + +#define _syscall0(type, name) \ +type name (void) \ +{ \ + register unsigned long __syscall __asm__ (SYSCALL_NUM) = __NR_##name; \ + register unsigned long __ret __asm__ (SYSCALL_RET); \ + __asm__ __volatile__ ("trap " SYSCALL_SHORT_TRAP \ + : "=r" (__ret), "=r" (__syscall) \ + : "1" (__syscall) \ + : SYSCALL_SHORT_CLOBBERS); \ + __syscall_return (type, __ret); \ +} + +#define _syscall1(type, name, atype, a) \ +type name (atype a) \ +{ \ + register atype __a __asm__ (SYSCALL_ARG0) = a; \ + register unsigned long __syscall __asm__ (SYSCALL_NUM) = __NR_##name; \ + register unsigned long __ret __asm__ (SYSCALL_RET); \ + __asm__ __volatile__ ("trap " SYSCALL_SHORT_TRAP \ + : "=r" (__ret), "=r" (__syscall) \ + : "1" (__syscall), "r" (__a) \ + : SYSCALL_SHORT_CLOBBERS); \ + __syscall_return (type, __ret); \ +} + +#define _syscall2(type, name, atype, a, btype, b) \ +type name (atype a, btype b) \ +{ \ + register atype __a __asm__ (SYSCALL_ARG0) = a; \ + register btype __b __asm__ (SYSCALL_ARG1) = b; \ + register unsigned long __syscall __asm__ (SYSCALL_NUM) = __NR_##name; \ + register unsigned long __ret __asm__ (SYSCALL_RET); \ + __asm__ __volatile__ ("trap " SYSCALL_SHORT_TRAP \ + : "=r" (__ret), "=r" (__syscall) \ + : "1" (__syscall), "r" (__a), "r" (__b) \ + : SYSCALL_SHORT_CLOBBERS); \ + __syscall_return (type, __ret); \ +} + +#define _syscall3(type, name, atype, a, btype, b, ctype, c) \ +type name (atype a, btype b, ctype c) \ +{ \ + register atype __a __asm__ (SYSCALL_ARG0) = a; \ + register btype __b __asm__ (SYSCALL_ARG1) = b; \ + register ctype __c __asm__ (SYSCALL_ARG2) = c; \ + register unsigned long __syscall __asm__ (SYSCALL_NUM) = __NR_##name; \ + register unsigned long __ret __asm__ (SYSCALL_RET); \ + __asm__ __volatile__ ("trap " SYSCALL_SHORT_TRAP \ + : "=r" (__ret), "=r" (__syscall) \ + : "1" (__syscall), "r" (__a), "r" (__b), "r" (__c) \ + : SYSCALL_SHORT_CLOBBERS); \ + __syscall_return (type, __ret); \ +} + +#define _syscall4(type, name, atype, a, btype, b, ctype, c, dtype, d) \ +type name (atype a, btype b, ctype c, dtype d) \ +{ \ + register atype __a __asm__ (SYSCALL_ARG0) = a; \ + register btype __b __asm__ (SYSCALL_ARG1) = b; \ + register ctype __c __asm__ (SYSCALL_ARG2) = c; \ + register dtype __d __asm__ (SYSCALL_ARG3) = d; \ + register unsigned long __syscall __asm__ (SYSCALL_NUM) = __NR_##name; \ + register unsigned long __ret __asm__ (SYSCALL_RET); \ + __asm__ __volatile__ ("trap " SYSCALL_SHORT_TRAP \ + : "=r" (__ret), "=r" (__syscall) \ + : "1" (__syscall), \ + "r" (__a), "r" (__b), "r" (__c), "r" (__d) \ + : SYSCALL_SHORT_CLOBBERS); \ + __syscall_return (type, __ret); \ +} + +#define _syscall5(type, name, atype, a, btype, b, ctype, c, dtype, d, etype,e)\ +type name (atype a, btype b, ctype c, dtype d, etype e) \ +{ \ + register atype __a __asm__ (SYSCALL_ARG0) = a; \ + register btype __b __asm__ (SYSCALL_ARG1) = b; \ + register ctype __c __asm__ (SYSCALL_ARG2) = c; \ + register dtype __d __asm__ (SYSCALL_ARG3) = d; \ + register etype __e __asm__ (SYSCALL_ARG4) = e; \ + register unsigned long __syscall __asm__ (SYSCALL_NUM) = __NR_##name; \ + register unsigned long __ret __asm__ (SYSCALL_RET); \ + __asm__ __volatile__ ("trap " SYSCALL_LONG_TRAP \ + : "=r" (__ret), "=r" (__syscall), "=r" (__e) \ + : "1" (__syscall), \ + "r" (__a), "r" (__b), "r" (__c), "r" (__d), "2" (__e) \ + : SYSCALL_CLOBBERS); \ + __syscall_return (type, __ret); \ +} + +#define _syscall6(type, name, atype, a, btype, b, ctype, c, dtype, d, etype, e, ftype, f) \ +type name (atype a, btype b, ctype c, dtype d, etype e, ftype f) \ +{ \ + register atype __a __asm__ (SYSCALL_ARG0) = a; \ + register btype __b __asm__ (SYSCALL_ARG1) = b; \ + register ctype __c __asm__ (SYSCALL_ARG2) = c; \ + register dtype __d __asm__ (SYSCALL_ARG3) = d; \ + register etype __e __asm__ (SYSCALL_ARG4) = e; \ + register etype __f __asm__ (SYSCALL_ARG5) = f; \ + register unsigned long __syscall __asm__ (SYSCALL_NUM) = __NR_##name; \ + register unsigned long __ret __asm__ (SYSCALL_RET); \ + __asm__ __volatile__ ("trap " SYSCALL_LONG_TRAP \ + : "=r" (__ret), "=r" (__syscall), \ + "=r" (__e), "=r" (__f) \ + : "1" (__syscall), \ + "r" (__a), "r" (__b), "r" (__c), "r" (__d), \ + "2" (__e), "3" (__f) \ + : SYSCALL_CLOBBERS); \ + __syscall_return (type, __ret); \ +} + + +#ifdef __KERNEL_SYSCALLS__ + +/* + * we need this inline - forking from kernel space will result + * in NO COPY ON WRITE (!!!), until an execve is executed. This + * is no problem, but for the stack. This is handled by not letting + * main() use the stack at all after fork(). Thus, no function + * calls - which means inline code for fork too, as otherwise we + * would use the stack upon exit from 'fork()'. + * + * Actually only pause and fork are needed inline, so that there + * won't be any messing with the stack from main(), but we define + * some others too. + */ +#define __NR__exit __NR_exit +extern inline _syscall0(pid_t,setsid) +extern inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) +extern inline _syscall3(int,read,int,fd,char *,buf,off_t,count) +extern inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) +extern inline _syscall1(int,dup,int,fd) +extern inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) +extern inline _syscall3(int,open,const char *,file,int,flag,int,mode) +extern inline _syscall1(int,close,int,fd) +extern inline _syscall1(int,_exit,int,exitcode) +extern inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) + +extern inline pid_t wait(int * wait_stat) +{ + return waitpid (-1, wait_stat, 0); +} + +#endif + +/* + * "Conditional" syscalls + */ +#define cond_syscall(name) \ + asm (".weak\t" C_SYMBOL_STRING(name) ";" \ + ".set\t" C_SYMBOL_STRING(name) "," C_SYMBOL_STRING(sys_ni_syscall)); +#if 0 +/* This doesn't work if there's a function prototype for NAME visible, + because the argument types probably won't match. */ +#define cond_syscall(name) \ + void name (void) __attribute__ ((weak, alias ("sys_ni_syscall"))); +#endif + +#endif /* __V850_UNISTD_H__ */ diff -Nru a/include/asm-v850/user.h b/include/asm-v850/user.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-v850/user.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,56 @@ +#ifndef __V850_USER_H__ +#define __V850_USER_H__ + +/* Adapted from . */ + +#ifdef __KERNEL__ + +#include +#include + +/* + * Core file format: The core file is written in such a way that gdb + * can understand it and provide useful information to the user (under + * linux we use the `trad-core' bfd, NOT the osf-core). The file contents + * are as follows: + * + * upage: 1 page consisting of a user struct that tells gdb + * what is present in the file. Directly after this is a + * copy of the task_struct, which is currently not used by gdb, + * but it may come in handy at some point. All of the registers + * are stored as part of the upage. The upage should always be + * only one page long. + * data: The data segment follows next. We use current->end_text to + * current->brk to pick up all of the user variables, plus any memory + * that may have been sbrk'ed. No attempt is made to determine if a + * page is demand-zero or if a page is totally unused, we just cover + * the entire range. All of the addresses are rounded in such a way + * that an integral number of pages is written. + * stack: We need the stack information in order to get a meaningful + * backtrace. We need to write the data from usp to + * current->start_stack, so we round each of these in order to be able + * to write an integer number of pages. + */ +struct user { + struct pt_regs regs; /* entire machine state */ + size_t u_tsize; /* text size (pages) */ + size_t u_dsize; /* data size (pages) */ + size_t u_ssize; /* stack size (pages) */ + unsigned long start_code; /* text starting address */ + unsigned long start_data; /* data starting address */ + unsigned long start_stack; /* stack starting address */ + long int signal; /* signal causing core dump */ + struct regs * u_ar0; /* help gdb find registers */ + unsigned long magic; /* identifies a core file */ + char u_comm[32]; /* user command name */ +}; + +#define NBPG PAGE_SIZE +#define UPAGES 1 +#define HOST_TEXT_START_ADDR (u.start_code) +#define HOST_DATA_START_ADDR (u.start_data) +#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) + +#endif /* __KERNEL__ */ + +#endif /* __V850_USER_H__ */ diff -Nru a/include/asm-x86_64/mman.h b/include/asm-x86_64/mman.h --- a/include/asm-x86_64/mman.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-x86_64/mman.h Mon Nov 4 14:31:01 2002 @@ -19,6 +19,8 @@ #define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ #define MAP_LOCKED 0x2000 /* pages are locked */ #define MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ +#define MAP_NONBLOCK 0x10000 /* do not block on IO */ #define MS_ASYNC 1 /* sync memory asynchronously */ #define MS_INVALIDATE 2 /* invalidate the caches */ diff -Nru a/include/asm-x86_64/poll.h b/include/asm-x86_64/poll.h --- a/include/asm-x86_64/poll.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-x86_64/poll.h Mon Nov 4 14:31:01 2002 @@ -15,6 +15,7 @@ #define POLLWRNORM 0x0100 #define POLLWRBAND 0x0200 #define POLLMSG 0x0400 +#define POLLREMOVE 0x1000 struct pollfd { int fd; diff -Nru a/include/asm-x86_64/ptrace.h b/include/asm-x86_64/ptrace.h --- a/include/asm-x86_64/ptrace.h Mon Nov 4 14:31:01 2002 +++ b/include/asm-x86_64/ptrace.h Mon Nov 4 14:31:01 2002 @@ -32,10 +32,7 @@ /* top of stack page */ #define FRAME_SIZE 168 -#define PTRACE_SETOPTIONS 21 - -/* options set using PTRACE_SETOPTIONS */ -#define PTRACE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_OLDSETOPTIONS 21 /* Dummy values for ptrace */ #define FS 1000 diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h --- a/include/linux/blkdev.h Mon Nov 4 14:31:01 2002 +++ b/include/linux/blkdev.h Mon Nov 4 14:31:01 2002 @@ -11,6 +11,22 @@ #include +/* + * Disk stats ... + */ + +#define DK_MAX_MAJOR 16 +#define DK_MAX_DISK 16 + +struct disk_stat { + unsigned int drive[DK_MAX_MAJOR][DK_MAX_DISK]; + unsigned int drive_rio[DK_MAX_MAJOR][DK_MAX_DISK]; + unsigned int drive_wio[DK_MAX_MAJOR][DK_MAX_DISK]; + unsigned int drive_rblk[DK_MAX_MAJOR][DK_MAX_DISK]; + unsigned int drive_wblk[DK_MAX_MAJOR][DK_MAX_DISK]; +}; +extern struct disk_stat dkstat; + struct request_queue; typedef struct request_queue request_queue_t; struct elevator_s; @@ -31,7 +47,6 @@ * blkdev_dequeue_request! */ unsigned long flags; /* see REQ_ bits below */ - kdev_t rq_dev; sector_t sector; unsigned long nr_sectors; unsigned int current_nr_sectors; @@ -77,6 +92,7 @@ /* * when request is used as a packet command carrier */ + unsigned int cmd_len; unsigned char cmd[16]; unsigned int data_len; diff -Nru a/include/linux/cpu.h b/include/linux/cpu.h --- a/include/linux/cpu.h Mon Nov 4 14:31:01 2002 +++ b/include/linux/cpu.h Mon Nov 4 14:31:01 2002 @@ -1,5 +1,5 @@ /* - * cpu.h - generic cpu defition + * include/linux/cpu.h - generic cpu definition * * This is mainly for topological representation. We define the * basic 'struct cpu' here, which can be embedded in per-arch @@ -15,14 +15,18 @@ * See the following for how to do this: * - drivers/base/intf.c * - Documentation/driver-model/interface.txt - * */ +#ifndef _LINUX_CPU_H_ +#define _LINUX_CPU_H_ #include - -extern struct device_class cpu_devclass; +#include struct cpu { + int node_id; /* The node which contains the CPU */ struct sys_device sysdev; }; +extern int register_cpu(struct cpu *, int, struct node *); + +#endif /* _LINUX_CPU_H_ */ diff -Nru a/include/linux/cpufreq.h b/include/linux/cpufreq.h --- a/include/linux/cpufreq.h Mon Nov 4 14:31:02 2002 +++ b/include/linux/cpufreq.h Mon Nov 4 14:31:02 2002 @@ -5,7 +5,7 @@ * (C) 2002 Dominik Brodowski * * - * $Id: cpufreq.h,v 1.26 2002/09/21 09:05:29 db Exp $ + * $Id: cpufreq.h,v 1.27 2002/10/08 14:54:23 db Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -148,11 +148,9 @@ int cpufreq_set_policy(struct cpufreq_policy *policy); int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu); -#ifdef CONFIG_CPU_FREQ_26_API #ifdef CONFIG_PM int cpufreq_restore(void); #endif -#endif #ifdef CONFIG_CPU_FREQ_24_API @@ -160,9 +158,6 @@ * CPUFREQ 2.4. INTERFACE * *********************************************************************/ int cpufreq_setmax(unsigned int cpu); -#ifdef CONFIG_PM -int cpufreq_restore(void); -#endif int cpufreq_set(unsigned int kHz, unsigned int cpu); unsigned int cpufreq_get(unsigned int cpu); diff -Nru a/include/linux/dcache.h b/include/linux/dcache.h --- a/include/linux/dcache.h Mon Nov 4 14:31:03 2002 +++ b/include/linux/dcache.h Mon Nov 4 14:31:03 2002 @@ -7,6 +7,7 @@ #include #include #include +#include #include /* for BUG() */ /* @@ -64,7 +65,7 @@ return end_name_hash(hash); } -#define DNAME_INLINE_LEN 16 +#define DNAME_INLINE_LEN_MIN 16 struct dcookie_struct; @@ -85,10 +86,12 @@ struct super_block * d_sb; /* The root of the dentry tree */ unsigned long d_vfs_flags; void * d_fsdata; /* fs-specific data */ - unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */ struct dcookie_struct * d_cookie; /* cookie, if any */ -}; + unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */ +} ____cacheline_aligned; +#define DNAME_INLINE_LEN (sizeof(struct dentry)-offsetof(struct dentry,d_iname)) + struct dentry_operations { int (*d_revalidate)(struct dentry *, int); int (*d_hash) (struct dentry *, struct qstr *); diff -Nru a/include/linux/dcookies.h b/include/linux/dcookies.h --- a/include/linux/dcookies.h Mon Nov 4 14:31:01 2002 +++ b/include/linux/dcookies.h Mon Nov 4 14:31:01 2002 @@ -44,7 +44,7 @@ * Returns 0 on success, with *cookie filled in */ int get_dcookie(struct dentry * dentry, struct vfsmount * vfsmnt, - u32 * cookie); + unsigned long * cookie); #else @@ -59,7 +59,7 @@ } static inline int get_dcookie(struct dentry * dentry, - struct vfsmount * vfsmnt, u32 * cookie) + struct vfsmount * vfsmnt, unsigned long * cookie) { return -ENOSYS; } diff -Nru a/include/linux/device.h b/include/linux/device.h --- a/include/linux/device.h Mon Nov 4 14:31:02 2002 +++ b/include/linux/device.h Mon Nov 4 14:31:02 2002 @@ -28,7 +28,7 @@ #include #include #include -#include +#include #define DEVICE_NAME_SIZE 80 #define DEVICE_ID_SIZE 32 @@ -65,14 +65,13 @@ atomic_t refcount; u32 present; + struct subsystem subsys; + struct subsystem drvsubsys; + struct subsystem devsubsys; struct list_head node; struct list_head devices; struct list_head drivers; - struct driver_dir_entry dir; - struct driver_dir_entry device_dir; - struct driver_dir_entry driver_dir; - int (*match)(struct device * dev, struct device_driver * drv); struct device * (*add) (struct device * parent, char * bus_id); int (*hotplug) (struct device *dev, char **envp, @@ -119,12 +118,11 @@ atomic_t refcount; u32 present; + struct kobject kobj; struct list_head bus_list; struct list_head class_list; struct list_head devices; - struct driver_dir_entry dir; - int (*probe) (struct device * dev); int (*remove) (struct device * dev); void (*shutdown) (struct device * dev); @@ -177,14 +175,13 @@ u32 devnum; + struct subsystem subsys; + struct subsystem devsubsys; + struct subsystem drvsubsys; struct list_head node; struct list_head drivers; struct list_head intf_list; - struct driver_dir_entry dir; - struct driver_dir_entry driver_dir; - struct driver_dir_entry device_dir; - int (*add_device)(struct device *); void (*remove_device)(struct device *); int (*hotplug)(struct device *dev, char **envp, @@ -232,9 +229,9 @@ char * name; struct device_class * devclass; + struct kobject kobj; struct list_head node; struct list_head devices; - struct driver_dir_entry dir; u32 devnum; @@ -275,6 +272,7 @@ struct list_head intf_list; struct device * parent; + struct kobject kobj; char name[DEVICE_NAME_SIZE]; /* descriptive ascii string */ char bus_id[BUS_ID_SIZE]; /* position on parent bus */ @@ -285,8 +283,6 @@ * persists for the right amount of time */ struct bus_type * bus; /* type of bus device is on */ - struct driver_dir_entry dir; - struct device_driver *driver; /* which driver has allocated this device */ void *driver_data; /* data private to the driver */ @@ -437,6 +433,11 @@ extern int device_suspend(u32 state, u32 level); extern void device_resume(u32 level); extern void device_shutdown(void); + + +/* drivrs/base/firmware.c */ +extern int firmware_register(struct subsystem *); +extern void firmware_uregister(struct subsystem *); /* debugging and troubleshooting/diagnostic helpers. */ #ifdef DEBUG diff -Nru a/include/linux/driverfs_fs.h b/include/linux/driverfs_fs.h --- a/include/linux/driverfs_fs.h Mon Nov 4 14:31:02 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,68 +0,0 @@ -/* - * driverfs_fs.h - definitions for the device driver filesystem - * - * Copyright (c) 2001 Patrick Mochel - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This is a simple, ram-based filesystem, which allows kernel - * callbacks for read/write of files. - * - * Please see Documentation/filesystems/driverfs.txt for more information. - */ - -#ifndef _DRIVER_FS_H_ -#define _DRIVER_FS_H_ - -struct driver_dir_entry; -struct attribute; - -struct driverfs_ops { - int (*open)(struct driver_dir_entry *); - int (*close)(struct driver_dir_entry *); - ssize_t (*show)(struct driver_dir_entry *, struct attribute *,char *, size_t, loff_t); - ssize_t (*store)(struct driver_dir_entry *,struct attribute *,const char *, size_t, loff_t); -}; - -struct driver_dir_entry { - char * name; - struct dentry * dentry; - mode_t mode; - struct driverfs_ops * ops; -}; - -struct attribute { - char * name; - mode_t mode; -}; - -extern int -driverfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *); - -extern void -driverfs_remove_dir(struct driver_dir_entry * entry); - -extern int -driverfs_create_file(struct attribute * attr, - struct driver_dir_entry * parent); - -extern int -driverfs_create_symlink(struct driver_dir_entry * parent, - char * name, char * target); - -extern void -driverfs_remove_file(struct driver_dir_entry *, const char * name); - -#endif /* _DDFS_H_ */ diff -Nru a/include/linux/elf.h b/include/linux/elf.h --- a/include/linux/elf.h Mon Nov 4 14:31:01 2002 +++ b/include/linux/elf.h Mon Nov 4 14:31:01 2002 @@ -81,6 +81,9 @@ #define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_V850 87 /* NEC v850 */ + + /* * This is an interim value that we will use until the committee comes * up with a final number. diff -Nru a/include/linux/eventpoll.h b/include/linux/eventpoll.h --- a/include/linux/eventpoll.h Mon Nov 4 14:31:01 2002 +++ b/include/linux/eventpoll.h Mon Nov 4 14:31:01 2002 @@ -1,6 +1,6 @@ /* * include/linux/eventpoll.h ( Efficent event polling implementation ) - * Copyright (C) 2001,...,2002 Davide Libenzi + * Copyright (C) 2001,...,2002 Davide Libenzi * * 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 @@ -14,37 +14,25 @@ #ifndef _LINUX_EVENTPOLL_H #define _LINUX_EVENTPOLL_H +/* Forward declarations to avoid compiler errors */ +struct file; +struct pollfd; -#define EVENTPOLL_MINOR 124 -#define POLLFD_X_PAGE (PAGE_SIZE / sizeof(struct pollfd)) -#define MAX_FDS_IN_EVENTPOLL (1024 * 128) -#define MAX_EVENTPOLL_PAGES (MAX_FDS_IN_EVENTPOLL / POLLFD_X_PAGE) -#define EVENT_PAGE_INDEX(n) ((n) / POLLFD_X_PAGE) -#define EVENT_PAGE_REM(n) ((n) % POLLFD_X_PAGE) -#define EVENT_PAGE_OFFSET(n) (((n) % POLLFD_X_PAGE) * sizeof(struct pollfd)) -#define EP_FDS_PAGES(n) (((n) + POLLFD_X_PAGE - 1) / POLLFD_X_PAGE) -#define EP_MAP_SIZE(n) (EP_FDS_PAGES(n) * PAGE_SIZE * 2) - - -struct evpoll { - int ep_timeout; - unsigned long ep_resoff; -}; - -#define EP_ALLOC _IOR('P', 1, int) -#define EP_POLL _IOWR('P', 2, struct evpoll) -#define EP_FREE _IO('P', 3) -#define EP_ISPOLLED _IOWR('P', 4, struct pollfd) +/* Valid opcodes to issue to sys_epoll_ctl() */ #define EP_CTL_ADD 1 #define EP_CTL_DEL 2 #define EP_CTL_MOD 3 -asmlinkage int sys_epoll_create(int maxfds); +/* Kernel space functions implementing the user space "epoll" API */ +asmlinkage int sys_epoll_create(int size); asmlinkage int sys_epoll_ctl(int epfd, int op, int fd, unsigned int events); -asmlinkage int sys_epoll_wait(int epfd, struct pollfd const **events, int timeout); +asmlinkage int sys_epoll_wait(int epfd, struct pollfd *events, int maxevents, + int timeout); +/* Used in fs/file_table.c:__fput() to unlink files from the eventpoll interface */ +void ep_notify_file_close(struct file *file); #endif diff -Nru a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h --- a/include/linux/ext2_fs.h Mon Nov 4 14:31:01 2002 +++ b/include/linux/ext2_fs.h Mon Nov 4 14:31:01 2002 @@ -58,8 +58,6 @@ */ #define EXT2_BAD_INO 1 /* Bad blocks inode */ #define EXT2_ROOT_INO 2 /* Root inode */ -#define EXT2_ACL_IDX_INO 3 /* ACL inode */ -#define EXT2_ACL_DATA_INO 4 /* ACL inode */ #define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */ #define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */ @@ -99,7 +97,6 @@ #else # define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size) #endif -#define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry)) #define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) #ifdef __KERNEL__ # define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) @@ -134,28 +131,6 @@ #endif /* - * ACL structures - */ -struct ext2_acl_header /* Header of Access Control Lists */ -{ - __u32 aclh_size; - __u32 aclh_file_count; - __u32 aclh_acle_count; - __u32 aclh_first_acle; -}; - -struct ext2_acl_entry /* Access Control List Entry */ -{ - __u32 acle_size; - __u16 acle_perms; /* Access permissions */ - __u16 acle_type; /* Type of entry */ - __u16 acle_tag; /* User or group identity */ - __u16 acle_pad1; - __u32 acle_next; /* Pointer on next entry for the */ - /* same inode or on next free entry */ -}; - -/* * Structure of a blocks group descriptor */ struct ext2_group_desc @@ -216,10 +191,11 @@ #define EXT2_JOURNAL_DATA_FL 0x00004000 /* Reserved for ext3 */ #define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */ #define EXT2_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ +#define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ #define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ -#define EXT2_FL_USER_VISIBLE 0x00011FFF /* User visible flags */ -#define EXT2_FL_USER_MODIFIABLE 0x000100FF /* User modifiable flags */ +#define EXT2_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ +#define EXT2_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ /* * ioctl commands @@ -325,6 +301,7 @@ * Mount flags */ #define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */ +#define EXT2_MOUNT_OLDALLOC 0x0002 /* Don't use the new Orlov allocator */ #define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */ #define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */ #define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */ @@ -332,6 +309,8 @@ #define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */ #define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */ #define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */ +#define EXT2_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */ +#define EXT2_MOUNT_POSIX_ACL 0x8000 /* POSIX Access Control Lists */ #define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt #define set_opt(o, opt) o |= EXT2_MOUNT_##opt @@ -410,7 +389,20 @@ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ __u16 s_padding1; - __u32 s_reserved[204]; /* Padding to the end of the block */ + /* + * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set. + */ + __u8 s_journal_uuid[16]; /* uuid of journal superblock */ + __u32 s_journal_inum; /* inode number of journal file */ + __u32 s_journal_dev; /* device number of journal file */ + __u32 s_last_orphan; /* start of list of inodes to delete */ + __u32 s_hash_seed[4]; /* HTREE hash seed */ + __u8 s_def_hash_version; /* Default hash version to use */ + __u8 s_reserved_char_pad; + __u16 s_reserved_word_pad; + __u32 s_default_mount_opts; + __u32 s_first_meta_bg; /* First metablock block group */ + __u32 s_reserved[190]; /* Padding to the end of the block */ }; /* @@ -473,10 +465,12 @@ #define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 #define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 +#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 #define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff -#define EXT2_FEATURE_COMPAT_SUPP 0 -#define EXT2_FEATURE_INCOMPAT_SUPP EXT2_FEATURE_INCOMPAT_FILETYPE +#define EXT2_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR +#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ + EXT2_FEATURE_INCOMPAT_META_BG) #define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ EXT2_FEATURE_RO_COMPAT_BTREE_DIR) @@ -488,6 +482,20 @@ */ #define EXT2_DEF_RESUID 0 #define EXT2_DEF_RESGID 0 + +/* + * Default mount options + */ +#define EXT2_DEFM_DEBUG 0x0001 +#define EXT2_DEFM_BSDGROUPS 0x0002 +#define EXT2_DEFM_XATTR_USER 0x0004 +#define EXT2_DEFM_ACL 0x0008 +#define EXT2_DEFM_UID16 0x0010 + /* Not used by ext2, but reserved for use by ext3 */ +#define EXT3_DEFM_JMODE 0x0060 +#define EXT3_DEFM_JMODE_DATA 0x0020 +#define EXT3_DEFM_JMODE_ORDERED 0x0040 +#define EXT3_DEFM_JMODE_WBACK 0x0060 /* * Structure of a directory entry diff -Nru a/include/linux/ext2_fs_sb.h b/include/linux/ext2_fs_sb.h --- a/include/linux/ext2_fs_sb.h Mon Nov 4 14:31:02 2002 +++ b/include/linux/ext2_fs_sb.h Mon Nov 4 14:31:02 2002 @@ -43,6 +43,8 @@ int s_inode_size; int s_first_ino; u32 s_next_generation; + unsigned long s_dir_count; + u8 *s_debts; }; #endif /* _LINUX_EXT2_FS_SB */ diff -Nru a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h --- a/include/linux/ext3_fs.h Mon Nov 4 14:31:02 2002 +++ b/include/linux/ext3_fs.h Mon Nov 4 14:31:02 2002 @@ -64,8 +64,6 @@ */ #define EXT3_BAD_INO 1 /* Bad blocks inode */ #define EXT3_ROOT_INO 2 /* Root inode */ -#define EXT3_ACL_IDX_INO 3 /* ACL inode */ -#define EXT3_ACL_DATA_INO 4 /* ACL inode */ #define EXT3_BOOT_LOADER_INO 5 /* Boot loader inode */ #define EXT3_UNDEL_DIR_INO 6 /* Undelete directory inode */ #define EXT3_RESIZE_INO 7 /* Reserved group descriptors inode */ @@ -95,7 +93,6 @@ #else # define EXT3_BLOCK_SIZE(s) (EXT3_MIN_BLOCK_SIZE << (s)->s_log_block_size) #endif -#define EXT3_ACLE_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / sizeof (struct ext3_acl_entry)) #define EXT3_ADDR_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / sizeof (__u32)) #ifdef __KERNEL__ # define EXT3_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) @@ -130,28 +127,6 @@ #endif /* - * ACL structures - */ -struct ext3_acl_header /* Header of Access Control Lists */ -{ - __u32 aclh_size; - __u32 aclh_file_count; - __u32 aclh_acle_count; - __u32 aclh_first_acle; -}; - -struct ext3_acl_entry /* Access Control List Entry */ -{ - __u32 acle_size; - __u16 acle_perms; /* Access permissions */ - __u16 acle_type; /* Type of entry */ - __u16 acle_tag; /* User or group identity */ - __u16 acle_pad1; - __u32 acle_next; /* Pointer on next entry for the */ - /* same inode or on next free entry */ -}; - -/* * Structure of a blocks group descriptor */ struct ext3_group_desc @@ -211,10 +186,11 @@ #define EXT3_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */ #define EXT3_NOTAIL_FL 0x00008000 /* file tail should not be merged */ #define EXT3_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ +#define EXT3_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ #define EXT3_RESERVED_FL 0x80000000 /* reserved for ext3 lib */ -#define EXT3_FL_USER_VISIBLE 0x00015FFF /* User visible flags */ -#define EXT3_FL_USER_MODIFIABLE 0x000100FF /* User modifiable flags */ +#define EXT3_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ +#define EXT3_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ /* * Inode dynamic state flags @@ -333,6 +309,7 @@ * Mount flags */ #define EXT3_MOUNT_CHECK 0x0001 /* Do mount-time checks */ +#define EXT3_MOUNT_OLDALLOC 0x0002 /* Don't use the new Orlov allocator */ #define EXT3_MOUNT_GRPID 0x0004 /* Create files with directory's group */ #define EXT3_MOUNT_DEBUG 0x0008 /* Some debugging messages */ #define EXT3_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */ @@ -347,6 +324,8 @@ #define EXT3_MOUNT_WRITEBACK_DATA 0x0C00 /* No data ordering */ #define EXT3_MOUNT_UPDATE_JOURNAL 0x1000 /* Update the journal format */ #define EXT3_MOUNT_NO_UID32 0x2000 /* Disable 32-bit UIDs */ +#define EXT3_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */ +#define EXT3_MOUNT_POSIX_ACL 0x8000 /* POSIX Access Control Lists */ /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */ #ifndef _LINUX_EXT2_FS_H @@ -357,6 +336,7 @@ #else #define EXT2_MOUNT_NOLOAD EXT3_MOUNT_NOLOAD #define EXT2_MOUNT_ABORT EXT3_MOUNT_ABORT +#define EXT2_MOUNT_DATA_FLAGS EXT3_MOUNT_DATA_FLAGS #endif #define ext3_set_bit ext2_set_bit @@ -449,7 +429,9 @@ __u8 s_def_hash_version; /* Default hash version to use */ __u8 s_reserved_char_pad; __u16 s_reserved_word_pad; - __u32 s_reserved[192]; /* Padding to the end of the block */ + __u32 s_default_mount_opts; + __u32 s_first_meta_bg; /* First metablock block group */ + __u32 s_reserved[190]; /* Padding to the end of the block */ }; #ifdef __KERNEL__ @@ -528,8 +510,11 @@ #define EXT3_FEATURE_INCOMPAT_FILETYPE 0x0002 #define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ +#define EXT3_FEATURE_INCOMPAT_META_BG 0x0010 -#define EXT3_FEATURE_COMPAT_SUPP 0 +#define EXT3_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR +#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ + EXT2_FEATURE_INCOMPAT_META_BG) #define EXT3_FEATURE_INCOMPAT_SUPP (EXT3_FEATURE_INCOMPAT_FILETYPE| \ EXT3_FEATURE_INCOMPAT_RECOVER) #define EXT3_FEATURE_RO_COMPAT_SUPP (EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \ @@ -543,6 +528,19 @@ #define EXT3_DEF_RESGID 0 /* + * Default mount options + */ +#define EXT3_DEFM_DEBUG 0x0001 +#define EXT3_DEFM_BSDGROUPS 0x0002 +#define EXT3_DEFM_XATTR_USER 0x0004 +#define EXT3_DEFM_ACL 0x0008 +#define EXT3_DEFM_UID16 0x0010 +#define EXT3_DEFM_JMODE 0x0060 +#define EXT3_DEFM_JMODE_DATA 0x0020 +#define EXT3_DEFM_JMODE_ORDERED 0x0040 +#define EXT3_DEFM_JMODE_WBACK 0x0060 + +/* * Structure of a directory entry */ #define EXT3_NAME_LEN 255 @@ -708,11 +706,13 @@ extern void ext3_free_inode (handle_t *, struct inode *); extern struct inode * ext3_orphan_get (struct super_block *, ino_t); extern unsigned long ext3_count_free_inodes (struct super_block *); +extern unsigned long ext3_count_dirs (struct super_block *); extern void ext3_check_inodes_bitmap (struct super_block *); extern unsigned long ext3_count_free (struct buffer_head *, unsigned); /* inode.c */ +extern int ext3_forget(handle_t *, int, struct inode *, struct buffer_head *, int); extern struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *); extern struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *); @@ -781,8 +781,10 @@ /* namei.c */ extern struct inode_operations ext3_dir_inode_operations; +extern struct inode_operations ext3_special_inode_operations; /* symlink.c */ +extern struct inode_operations ext3_symlink_inode_operations; extern struct inode_operations ext3_fast_symlink_inode_operations; diff -Nru a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h --- a/include/linux/ext3_fs_i.h Mon Nov 4 14:31:00 2002 +++ b/include/linux/ext3_fs_i.h Mon Nov 4 14:31:00 2002 @@ -41,6 +41,10 @@ __u32 i_prealloc_count; #endif __u32 i_dir_start_lookup; +#ifdef CONFIG_EXT3_FS_POSIX_ACL + struct posix_acl *i_acl; + struct posix_acl *i_default_acl; +#endif struct list_head i_orphan; /* unlinked but open inodes */ diff -Nru a/include/linux/ext3_fs_sb.h b/include/linux/ext3_fs_sb.h --- a/include/linux/ext3_fs_sb.h Mon Nov 4 14:31:02 2002 +++ b/include/linux/ext3_fs_sb.h Mon Nov 4 14:31:02 2002 @@ -50,6 +50,8 @@ u32 s_next_generation; u32 s_hash_seed[4]; int s_def_hash_version; + unsigned long s_dir_count; + u8 *s_debts; /* Journaling */ struct inode * s_journal_inode; diff -Nru a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h --- a/include/linux/ext3_jbd.h Mon Nov 4 14:31:00 2002 +++ b/include/linux/ext3_jbd.h Mon Nov 4 14:31:00 2002 @@ -30,13 +30,19 @@ #define EXT3_SINGLEDATA_TRANS_BLOCKS 8 +/* Extended attributes may touch two data buffers, two bitmap buffers, + * and two group and summaries. */ + +#define EXT3_XATTR_TRANS_BLOCKS 8 + /* Define the minimum size for a transaction which modifies data. This * needs to take into account the fact that we may end up modifying two * quota files too (one for the group, one for the user quota). The * superblock only gets updated once, of course, so don't bother * counting that again for the quota updates. */ -#define EXT3_DATA_TRANS_BLOCKS (3 * EXT3_SINGLEDATA_TRANS_BLOCKS - 2) +#define EXT3_DATA_TRANS_BLOCKS (3 * EXT3_SINGLEDATA_TRANS_BLOCKS + \ + EXT3_XATTR_TRANS_BLOCKS - 2) extern int ext3_writepage_trans_blocks(struct inode *inode); diff -Nru a/include/linux/fcblist.h b/include/linux/fcblist.h --- a/include/linux/fcblist.h Mon Nov 4 14:31:02 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,71 +0,0 @@ -/* - * include/linux/fcblist.h ( File event callbacks handling ) - * Copyright (C) 2001,...,2002 Davide Libenzi - * - * 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. - * - * Davide Libenzi - * - */ - -#ifndef __LINUX_FCBLIST_H -#define __LINUX_FCBLIST_H - -#include -#include -#include -#include -#include - - - -/* file callback notification events */ -#define ION_IN 1 -#define ION_OUT 2 -#define ION_HUP 3 -#define ION_ERR 4 - -#define FCB_LOCAL_SIZE 4 - - -struct fcb_struct { - struct list_head llink; - void (*cbproc)(struct file *, void *, unsigned long *, long *); - void *data; - unsigned long local[FCB_LOCAL_SIZE]; -}; - - -extern long ion_band_table[]; -extern long poll_band_table[]; - - -void file_notify_event(struct file *filep, long *event); - -int file_notify_addcb(struct file *filep, - void (*cbproc)(struct file *, void *, unsigned long *, long *), - void *data); - -int file_notify_delcb(struct file *filep, - void (*cbproc)(struct file *, void *, unsigned long *, long *)); - -void file_notify_cleanup(struct file *filep); - - -static inline void file_notify_init(struct file *filep) -{ - rwlock_init(&filep->f_cblock); - INIT_LIST_HEAD(&filep->f_cblist); -} - -static inline void file_send_notify(struct file *filep, long ioevt, long plevt) -{ - long event[] = { ioevt, plevt, -1 }; - - file_notify_event(filep, event); -} - -#endif diff -Nru a/include/linux/flat.h b/include/linux/flat.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/flat.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,83 @@ + +/* Copyright (C) 1998 Kenneth Albanowski + * The Silver Hammer Group, Ltd. + * Copyright (C) 2002 David McCullough + */ + +#ifndef _LINUX_FLAT_H +#define _LINUX_FLAT_H + +#define FLAT_VERSION 0x00000004L + +/* + * To make everything easier to port and manage cross platform + * development, all fields are in network byte order. + */ + +struct flat_hdr { + char magic[4]; + unsigned long rev; /* version (as above) */ + unsigned long entry; /* Offset of first executable instruction + with text segment from beginning of file */ + unsigned long data_start; /* Offset of data segment from beginning of + file */ + unsigned long data_end; /* Offset of end of data segment + from beginning of file */ + unsigned long bss_end; /* Offset of end of bss segment from beginning + of file */ + + /* (It is assumed that data_end through bss_end forms the bss segment.) */ + + unsigned long stack_size; /* Size of stack, in bytes */ + unsigned long reloc_start; /* Offset of relocation records from + beginning of file */ + unsigned long reloc_count; /* Number of relocation records */ + unsigned long flags; + unsigned long build_date; /* When the program/library was built */ + unsigned long filler[5]; /* Reservered, set to zero */ +}; + +#define FLAT_FLAG_RAM 0x0001 /* load program entirely into RAM */ +#define FLAT_FLAG_GOTPIC 0x0002 /* program is PIC with GOT */ +#define FLAT_FLAG_GZIP 0x0004 /* all but the header is compressed */ +#define FLAT_FLAG_GZDATA 0x0008 /* only data/relocs are compressed (for XIP) */ + + +/* + * While it would be nice to keep this header clean, users of older + * tools still need this support in the kernel. So this section is + * purely for compatibility with old tool chains. + * + * DO NOT make changes or enhancements to the old format please, just work + * with the format above, except to fix bugs with old format support. + */ + +#include + +#define OLD_FLAT_VERSION 0x00000002L +#define OLD_FLAT_RELOC_TYPE_TEXT 0 +#define OLD_FLAT_RELOC_TYPE_DATA 1 +#define OLD_FLAT_RELOC_TYPE_BSS 2 + +typedef union { + unsigned long value; + struct { +# if defined(mc68000) && !defined(CONFIG_COLDFIRE) + signed long offset : 30; + unsigned long type : 2; +# define OLD_FLAT_FLAG_RAM 0x1 /* load program entirely into RAM */ +# elif defined(__BIG_ENDIAN_BITFIELD) + unsigned long type : 2; + signed long offset : 30; +# define OLD_FLAT_FLAG_RAM 0x1 /* load program entirely into RAM */ +# elif defined(__LITTLE_ENDIAN_BITFIELD) + signed long offset : 30; + unsigned long type : 2; +# define OLD_FLAT_FLAG_RAM 0x1 /* load program entirely into RAM */ +# else +# error "Unknown bitfield order for flat files." +# endif + } reloc; +} flat_v2_reloc_t; + +#endif /* _LINUX_FLAT_H */ diff -Nru a/include/linux/fs.h b/include/linux/fs.h --- a/include/linux/fs.h Mon Nov 4 14:31:01 2002 +++ b/include/linux/fs.h Mon Nov 4 14:31:01 2002 @@ -110,6 +110,7 @@ #define MS_MOVE 8192 #define MS_REC 16384 #define MS_VERBOSE 32768 +#define MS_POSIXACL (1<<16) /* VFS does not apply the umask */ #define MS_ACTIVE (1<<30) #define MS_NOUSER (1<<31) @@ -164,6 +165,7 @@ #define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE) #define IS_NOATIME(inode) (__IS_FLG(inode, MS_NOATIME) || ((inode)->i_flags & S_NOATIME)) #define IS_NODIRATIME(inode) __IS_FLG(inode, MS_NODIRATIME) +#define IS_POSIXACL(inode) __IS_FLG(inode, MS_POSIXACL) #define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD) @@ -504,10 +506,6 @@ /* needed for tty driver, and maybe others */ void *private_data; - - /* file callback list */ - rwlock_t f_cblock; - struct list_head f_cblist; }; extern spinlock_t files_lock; #define file_list_lock() spin_lock(&files_lock); @@ -1147,6 +1145,7 @@ extern int filemap_fdatawait(struct address_space *); extern void sync_supers(void); extern sector_t bmap(struct inode *, sector_t); +extern int setattr_mask(unsigned int); extern int notify_change(struct dentry *, struct iattr *); extern int permission(struct inode *, int); extern int vfs_permission(struct inode *, int); @@ -1225,6 +1224,7 @@ extern void __iget(struct inode * inode); extern void clear_inode(struct inode *); +extern void destroy_inode(struct inode *); extern struct inode *new_inode(struct super_block *); extern void remove_suid(struct dentry *); diff -Nru a/include/linux/genhd.h b/include/linux/genhd.h --- a/include/linux/genhd.h Mon Nov 4 14:31:01 2002 +++ b/include/linux/genhd.h Mon Nov 4 14:31:01 2002 @@ -62,7 +62,7 @@ sector_t start_sect; sector_t nr_sects; devfs_handle_t de; /* primary (master) devfs entry */ - struct device *hd_driverfs_dev; /* support driverfs hiearchy */ + struct kobject kobj; unsigned reads, read_sectors, writes, write_sectors; int policy; }; @@ -93,7 +93,7 @@ devfs_handle_t de; /* more of the same */ devfs_handle_t disk_de; /* piled higher and deeper */ struct device *driverfs_dev; - struct device disk_dev; + struct kobject kobj; struct timer_rand_state *random; int policy; @@ -129,8 +129,6 @@ { disk->capacity = size; } - -extern struct device_class disk_devclass; #endif /* __KERNEL__ */ diff -Nru a/include/linux/hugetlb.h b/include/linux/hugetlb.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/hugetlb.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,53 @@ +#ifndef _LINUX_HUGETLB_H +#define _LINUX_HUGETLB_H + +#ifdef CONFIG_HUGETLB_PAGE +static inline int is_vm_hugetlb_page(struct vm_area_struct *vma) +{ + return vma->vm_flags & VM_HUGETLB; +} + +int copy_hugetlb_page_range(struct mm_struct *, struct mm_struct *, struct vm_area_struct *); +int follow_hugetlb_page(struct mm_struct *, struct vm_area_struct *, struct page **, struct vm_area_struct **, unsigned long *, int *, int); +void zap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned long); +void unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned long); +int hugetlb_prefault(struct address_space *, struct vm_area_struct *); +void huge_page_release(struct page *); +#else /* !CONFIG_HUGETLB_PAGE */ +static inline int is_vm_hugetlb_page(struct vm_area_struct *vma) +{ + return 0; +} + +#define follow_hugetlb_page(m,v,p,vs,a,b,i) ({ BUG(); 0; }) +#define copy_hugetlb_page_range(src, dst, vma) ({ BUG(); 0; }) +#define hugetlb_prefault(mapping, vma) ({ BUG(); 0; }) +#define zap_hugepage_range(vma, start, len) BUG() +#define unmap_hugepage_range(vma, start, end) BUG() +#define huge_page_release(page) BUG() + +#endif /* !CONFIG_HUGETLB_PAGE */ + +#ifdef CONFIG_HUGETLBFS +extern struct file_operations hugetlbfs_file_operations; +extern struct vm_operations_struct hugetlb_vm_ops; +struct file *hugetlb_zero_setup(size_t); + +static inline int is_file_hugepages(struct file *file) +{ + return file->f_op == &hugetlbfs_file_operations; +} + +static inline void set_file_hugepages(struct file *file) +{ + file->f_op = &hugetlbfs_file_operations; +} +#else /* !CONFIG_HUGETLBFS */ + +#define is_file_hugepages(file) 0 +#define set_file_hugepages(file) BUG() +#define hugetlb_zero_setup(size) ERR_PTR(-ENOSYS) + +#endif /* !CONFIG_HUGETLBFS */ + +#endif /* _LINUX_HUGETLB_H */ diff -Nru a/include/linux/ipc.h b/include/linux/ipc.h --- a/include/linux/ipc.h Mon Nov 4 14:31:00 2002 +++ b/include/linux/ipc.h Mon Nov 4 14:31:00 2002 @@ -56,6 +56,8 @@ /* used by in-kernel data structures */ struct kern_ipc_perm { + spinlock_t lock; + int deleted; key_t key; uid_t uid; gid_t gid; diff -Nru a/include/linux/isapnp.h b/include/linux/isapnp.h --- a/include/linux/isapnp.h Mon Nov 4 14:31:01 2002 +++ b/include/linux/isapnp.h Mon Nov 4 14:31:01 2002 @@ -196,7 +196,7 @@ int isapnp_proc_done(void); #else static inline isapnp_proc_init(void) { return 0; } -static inline isapnp_proc_done(void) { return 0; ) +static inline isapnp_proc_done(void) { return 0; } #endif /* misc */ diff -Nru a/include/linux/kdev_t.h b/include/linux/kdev_t.h --- a/include/linux/kdev_t.h Mon Nov 4 14:31:02 2002 +++ b/include/linux/kdev_t.h Mon Nov 4 14:31:02 2002 @@ -36,7 +36,7 @@ Admissible operations on an object of type kdev_t: - passing it along - comparing it for equality with another such object -- storing it in inode->i_rdev, req->rq_dev, de->dc_dev, tty->device +- storing it in inode->i_rdev or tty->device - using its bit pattern as argument in a hash function - finding its major and minor - complaining about it diff -Nru a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h --- a/include/linux/kernel_stat.h Mon Nov 4 14:31:01 2002 +++ b/include/linux/kernel_stat.h Mon Nov 4 14:31:01 2002 @@ -5,6 +5,7 @@ #include #include #include +#include /* * 'kernel_stat.h' contains the definitions needed for doing @@ -12,26 +13,25 @@ * used by rstatd/perfmeter */ -#define DK_MAX_MAJOR 16 -#define DK_MAX_DISK 16 +struct cpu_usage_stat { + unsigned int user; + unsigned int nice; + unsigned int system; + unsigned int idle; + unsigned int iowait; +}; struct kernel_stat { - unsigned int per_cpu_user[NR_CPUS], - per_cpu_nice[NR_CPUS], - per_cpu_system[NR_CPUS], - per_cpu_idle[NR_CPUS], - per_cpu_iowait[NR_CPUS]; - unsigned int dk_drive[DK_MAX_MAJOR][DK_MAX_DISK]; - unsigned int dk_drive_rio[DK_MAX_MAJOR][DK_MAX_DISK]; - unsigned int dk_drive_wio[DK_MAX_MAJOR][DK_MAX_DISK]; - unsigned int dk_drive_rblk[DK_MAX_MAJOR][DK_MAX_DISK]; - unsigned int dk_drive_wblk[DK_MAX_MAJOR][DK_MAX_DISK]; + struct cpu_usage_stat cpustat; #if !defined(CONFIG_ARCH_S390) - unsigned int irqs[NR_CPUS][NR_IRQS]; + unsigned int irqs[NR_IRQS]; #endif }; -extern struct kernel_stat kstat; +DECLARE_PER_CPU(struct kernel_stat, kstat); + +#define kstat_cpu(cpu) per_cpu(kstat, cpu) +#define kstat_this_cpu kstat_cpu(smp_processor_id()) extern unsigned long nr_context_switches(void); @@ -50,8 +50,9 @@ { int i, sum=0; - for (i = 0 ; i < NR_CPUS ; i++) - sum += kstat.irqs[i][irq]; + for (i = 0 ; i < NR_CPUS ; i++) + if (cpu_possible(i)) + sum += kstat_cpu(i).irqs[irq]; return sum; } diff -Nru a/include/linux/kobject.h b/include/linux/kobject.h --- a/include/linux/kobject.h Mon Nov 4 14:31:00 2002 +++ b/include/linux/kobject.h Mon Nov 4 14:31:00 2002 @@ -12,8 +12,10 @@ #include #include +#define KOBJ_NAME_LEN 16 + struct kobject { - char name[16]; + char name[KOBJ_NAME_LEN]; atomic_t refcount; struct list_head entry; struct kobject * parent; diff -Nru a/include/linux/mbcache.h b/include/linux/mbcache.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/mbcache.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,72 @@ +/* + File: linux/mbcache.h + + (C) 2001 by Andreas Gruenbacher, +*/ + +/* Hardwire the number of additional indexes */ +#define MB_CACHE_INDEXES_COUNT 1 + +struct mb_cache_entry; + +struct mb_cache_op { + void (*free)(struct mb_cache_entry *); +}; + +struct mb_cache { + struct list_head c_cache_list; + const char *c_name; + struct mb_cache_op c_op; + atomic_t c_entry_count; + int c_bucket_bits; +#ifndef MB_CACHE_INDEXES_COUNT + int c_indexes_count; +#endif + kmem_cache_t *c_entry_cache; + struct list_head *c_block_hash; + struct list_head *c_indexes_hash[0]; +}; + +struct mb_cache_entry_index { + struct list_head o_list; + unsigned int o_key; +}; + +struct mb_cache_entry { + struct list_head e_lru_list; + struct mb_cache *e_cache; + atomic_t e_used; + struct block_device *e_bdev; + sector_t e_block; + struct list_head e_block_list; + struct mb_cache_entry_index e_indexes[0]; +}; + +/* Functions on caches */ + +struct mb_cache * mb_cache_create(const char *, struct mb_cache_op *, size_t, + int, int); +void mb_cache_shrink(struct mb_cache *, struct block_device *); +void mb_cache_destroy(struct mb_cache *); + +/* Functions on cache entries */ + +struct mb_cache_entry *mb_cache_entry_alloc(struct mb_cache *); +int mb_cache_entry_insert(struct mb_cache_entry *, struct block_device *, + sector_t, unsigned int[]); +void mb_cache_entry_rehash(struct mb_cache_entry *, unsigned int[]); +void mb_cache_entry_release(struct mb_cache_entry *); +void mb_cache_entry_takeout(struct mb_cache_entry *); +void mb_cache_entry_free(struct mb_cache_entry *); +struct mb_cache_entry *mb_cache_entry_dup(struct mb_cache_entry *); +struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *, + struct block_device *, + sector_t); +#if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) +struct mb_cache_entry *mb_cache_entry_find_first(struct mb_cache *cache, int, + struct block_device *, + unsigned int); +struct mb_cache_entry *mb_cache_entry_find_next(struct mb_cache_entry *, int, + struct block_device *, + unsigned int); +#endif diff -Nru a/include/linux/memblk.h b/include/linux/memblk.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/memblk.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,32 @@ +/* + * include/linux/memblk.h - generic memblk definition + * + * This is mainly for topological representation. We define the + * basic 'struct memblk' here, which can be embedded in per-arch + * definitions of memory blocks. + * + * Basic handling of the devices is done in drivers/base/memblk.c + * and system devices are handled in drivers/base/sys.c. + * + * MemBlks are exported via driverfs in the class/memblk/devices/ + * directory. + * + * Per-memblk interfaces can be implemented using a struct device_interface. + * See the following for how to do this: + * - drivers/base/intf.c + * - Documentation/driver-model/interface.txt + */ +#ifndef _LINUX_MEMBLK_H_ +#define _LINUX_MEMBLK_H_ + +#include +#include + +struct memblk { + int node_id; /* The node which contains the MemBlk */ + struct sys_device sysdev; +}; + +extern int register_memblk(struct memblk *, int, struct node *); + +#endif /* _LINUX_MEMBLK_H_ */ diff -Nru a/include/linux/miscdevice.h b/include/linux/miscdevice.h --- a/include/linux/miscdevice.h Mon Nov 4 14:31:02 2002 +++ b/include/linux/miscdevice.h Mon Nov 4 14:31:02 2002 @@ -7,12 +7,12 @@ #define PSMOUSE_MINOR 1 #define MS_BUSMOUSE_MINOR 2 #define ATIXL_BUSMOUSE_MINOR 3 -#define AMIGAMOUSE_MINOR 4 +/*#define AMIGAMOUSE_MINOR 4 FIXME OBSOLETE */ #define ATARIMOUSE_MINOR 5 #define SUN_MOUSE_MINOR 6 #define APOLLO_MOUSE_MINOR 7 #define PC110PAD_MINOR 9 -#define ADB_MOUSE_MINOR 10 +/*#define ADB_MOUSE_MINOR 10 FIXME OBSOLETE */ #define WATCHDOG_MINOR 130 /* Watchdog timer */ #define TEMP_MINOR 131 /* Temperature Sensor */ #define RTC_MINOR 135 diff -Nru a/include/linux/mm.h b/include/linux/mm.h --- a/include/linux/mm.h Mon Nov 4 14:31:00 2002 +++ b/include/linux/mm.h Mon Nov 4 14:31:00 2002 @@ -130,6 +130,7 @@ void (*open)(struct vm_area_struct * area); void (*close)(struct vm_area_struct * area); struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int unused); + int (*populate)(struct vm_area_struct * area, unsigned long address, unsigned long len, unsigned long prot, unsigned long pgoff, int nonblock); }; /* forward declaration; pte_chain is meant to be internal to rmap.c */ @@ -365,9 +366,12 @@ extern pmd_t *FASTCALL(__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address)); extern pte_t *FASTCALL(pte_alloc_kernel(struct mm_struct *mm, pmd_t *pmd, unsigned long address)); extern pte_t *FASTCALL(pte_alloc_map(struct mm_struct *mm, pmd_t *pmd, unsigned long address)); +extern int install_page(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, struct page *page, unsigned long prot); extern int handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma, unsigned long address, int write_access); extern int make_pages_present(unsigned long addr, unsigned long end); extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); +extern int sys_remap_file_pages(unsigned long start, unsigned long size, unsigned long prot, unsigned long pgoff, unsigned long nonblock); + extern struct page * follow_page(struct mm_struct *mm, unsigned long address, int write); int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, @@ -376,20 +380,6 @@ int __set_page_dirty_buffers(struct page *page); int __set_page_dirty_nobuffers(struct page *page); -#ifdef CONFIG_HUGETLB_PAGE -#define is_vm_hugetlb_page(vma) (vma->vm_flags & VM_HUGETLB) -extern int copy_hugetlb_page_range(struct mm_struct *, struct mm_struct *, struct vm_area_struct *); -extern int follow_hugetlb_page(struct mm_struct *, struct vm_area_struct *, struct page **, struct vm_area_struct **, unsigned long *, int *, int); -extern int free_hugepages(struct vm_area_struct *); - -#else -#define is_vm_hugetlb_page(vma) (0) -#define follow_hugetlb_page(mm, vma, pages, vmas, start, len, i) (0) -#define copy_hugetlb_page_range(dst, src, vma) (0) -#define free_hugepages(mpnt) do { } while(0) -#endif - - /* * Prototype to add a shrinker callback for ageable caches. * @@ -449,11 +439,11 @@ extern void mem_init(void); extern void show_mem(void); extern void si_meminfo(struct sysinfo * val); +#ifdef CONFIG_NUMA +extern void si_meminfo_node(struct sysinfo *val, int nid); +#endif extern void swapin_readahead(swp_entry_t); -extern int can_share_swap_page(struct page *); -extern int remove_exclusive_swap_page(struct page *); - /* mmap.c */ extern void insert_vm_struct(struct mm_struct *, struct vm_area_struct *); extern void build_mmap_rb(struct mm_struct *); @@ -533,6 +523,7 @@ struct vm_area_struct **pprev); extern int split_vma(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long addr, int new_below); +extern void unmap_vma(struct mm_struct *mm, struct vm_area_struct *area); /* Look up the first VMA which intersects the interval start_addr..end_addr-1, NULL if none. Assume start_addr < end_addr. */ diff -Nru a/include/linux/mmzone.h b/include/linux/mmzone.h --- a/include/linux/mmzone.h Mon Nov 4 14:31:00 2002 +++ b/include/linux/mmzone.h Mon Nov 4 14:31:00 2002 @@ -279,6 +279,61 @@ #endif /* !CONFIG_DISCONTIGMEM */ + +extern DECLARE_BITMAP(node_online_map, MAX_NUMNODES); +extern DECLARE_BITMAP(memblk_online_map, MAX_NR_MEMBLKS); + +#if defined(CONFIG_DISCONTIGMEM) || defined(CONFIG_NUMA) + +#define node_online(node) test_bit(node, node_online_map) +#define node_set_online(node) set_bit(node, node_online_map) +#define node_set_offline(node) clear_bit(node, node_online_map) +static inline unsigned int num_online_nodes(void) +{ + int i, num = 0; + + for(i = 0; i < MAX_NUMNODES; i++){ + if (node_online(i)) + num++; + } + return num; +} + +#define memblk_online(memblk) test_bit(memblk, memblk_online_map) +#define memblk_set_online(memblk) set_bit(memblk, memblk_online_map) +#define memblk_set_offline(memblk) clear_bit(memblk, memblk_online_map) +static inline unsigned int num_online_memblks(void) +{ + int i, num = 0; + + for(i = 0; i < MAX_NR_MEMBLKS; i++){ + if (memblk_online(i)) + num++; + } + return num; +} + +#else /* !CONFIG_DISCONTIGMEM && !CONFIG_NUMA */ + +#define node_online(node) \ + ({ BUG_ON((node) != 0); test_bit(node, node_online_map); }) +#define node_set_online(node) \ + ({ BUG_ON((node) != 0); set_bit(node, node_online_map); }) +#define node_set_offline(node) \ + ({ BUG_ON((node) != 0); clear_bit(node, node_online_map); }) +#define num_online_nodes() 1 + +#define memblk_online(memblk) \ + ({ BUG_ON((memblk) != 0); test_bit(memblk, memblk_online_map); }) +#define memblk_set_online(memblk) \ + ({ BUG_ON((memblk) != 0); set_bit(memblk, memblk_online_map); }) +#define memblk_set_offline(memblk) \ + ({ BUG_ON((memblk) != 0); clear_bit(memblk, memblk_online_map); }) +#define num_online_memblks() 1 + +#endif /* CONFIG_DISCONTIGMEM || CONFIG_NUMA */ + + #define MAP_ALIGN(x) ((((x) % sizeof(struct page)) == 0) ? (x) : ((x) + \ sizeof(struct page) - ((x) % sizeof(struct page)))) diff -Nru a/include/linux/mtd/compatmac.h b/include/linux/mtd/compatmac.h --- a/include/linux/mtd/compatmac.h Mon Nov 4 14:31:02 2002 +++ b/include/linux/mtd/compatmac.h Mon Nov 4 14:31:02 2002 @@ -193,6 +193,7 @@ #define spin_lock_bh(lock) do {start_bh_atomic();spin_lock(lock);} while(0) #define spin_unlock_bh(lock) do {spin_unlock(lock);end_bh_atomic();} while(0) #else +#include #include #include #endif diff -Nru a/include/linux/node.h b/include/linux/node.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/node.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,34 @@ +/* + * include/linux/node.h - generic node definition + * + * This is mainly for topological representation. We define the + * basic 'struct node' here, which can be embedded in per-arch + * definitions of processors. + * + * Basic handling of the devices is done in drivers/base/node.c + * and system devices are handled in drivers/base/sys.c. + * + * Nodes are exported via driverfs in the class/node/devices/ + * directory. + * + * Per-node interfaces can be implemented using a struct device_interface. + * See the following for how to do this: + * - drivers/base/intf.c + * - Documentation/driver-model/interface.txt + */ +#ifndef _LINUX_NODE_H_ +#define _LINUX_NODE_H_ + +#include + +struct node { + unsigned long cpumap; /* Bitmap of CPUs on the Node */ + struct sys_root sysroot; +}; + +extern int register_node(struct node *, int, struct node *); + +#define to_node(_root) container_of(_root, struct node, sysroot) +#define to_root(_dev) container_of(_dev, struct sys_root, dev) + +#endif /* _LINUX_NODE_H_ */ diff -Nru a/include/linux/page-flags.h b/include/linux/page-flags.h --- a/include/linux/page-flags.h Mon Nov 4 14:31:02 2002 +++ b/include/linux/page-flags.h Mon Nov 4 14:31:02 2002 @@ -114,9 +114,10 @@ #define mod_page_state(member, delta) \ do { \ - int cpu = get_cpu(); \ - per_cpu(page_states, cpu).member += (delta); \ - put_cpu(); \ + unsigned long flags; \ + local_irq_save(flags); \ + __get_cpu_var(page_states).member += (delta); \ + local_irq_restore(flags); \ } while (0) #define inc_page_state(member) mod_page_state(member, 1UL) @@ -236,8 +237,12 @@ * The PageSwapCache predicate doesn't use a PG_flag at this time, * but it may again do so one day. */ +#ifdef CONFIG_SWAP extern struct address_space swapper_space; #define PageSwapCache(page) ((page)->mapping == &swapper_space) +#else +#define PageSwapCache(page) 0 +#endif struct page; /* forward declaration */ diff -Nru a/include/linux/pagevec.h b/include/linux/pagevec.h --- a/include/linux/pagevec.h Mon Nov 4 14:31:03 2002 +++ b/include/linux/pagevec.h Mon Nov 4 14:31:03 2002 @@ -20,7 +20,7 @@ void __pagevec_release_nonlru(struct pagevec *pvec); void __pagevec_free(struct pagevec *pvec); void __pagevec_lru_add(struct pagevec *pvec); -void lru_add_drain(void); +void __pagevec_lru_add_active(struct pagevec *pvec); void pagevec_deactivate_inactive(struct pagevec *pvec); void pagevec_strip(struct pagevec *pvec); unsigned int pagevec_lookup(struct pagevec *pvec, struct address_space *mapping, diff -Nru a/include/linux/pci.h b/include/linux/pci.h --- a/include/linux/pci.h Mon Nov 4 14:31:01 2002 +++ b/include/linux/pci.h Mon Nov 4 14:31:01 2002 @@ -643,6 +643,10 @@ void *pci_pool_alloc (struct pci_pool *pool, int flags, dma_addr_t *handle); void pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t addr); +#if defined(CONFIG_ISA) || defined(CONFIG_EISA) +extern struct pci_dev *isa_bridge; +#endif + #endif /* CONFIG_PCI */ /* Include architecture-dependent settings and functions */ @@ -702,6 +706,8 @@ #define pci_for_each_dev(dev) \ for(dev = NULL; 0; ) + +#define isa_bridge ((struct pci_dev *)NULL) #else diff -Nru a/include/linux/personality.h b/include/linux/personality.h --- a/include/linux/personality.h Mon Nov 4 14:31:02 2002 +++ b/include/linux/personality.h Mon Nov 4 14:31:02 2002 @@ -63,6 +63,7 @@ PER_SOLARIS = 0x000d | STICKY_TIMEOUTS, PER_UW7 = 0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, PER_OSF4 = 0x000f, /* OSF/1 v4 */ + PER_HPUX = 0x0010, PER_MASK = 0x00ff, }; diff -Nru a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h --- a/include/linux/pipe_fs_i.h Mon Nov 4 14:31:02 2002 +++ b/include/linux/pipe_fs_i.h Mon Nov 4 14:31:02 2002 @@ -12,8 +12,6 @@ unsigned int waiting_writers; unsigned int r_counter; unsigned int w_counter; - struct file *rdfile; - struct file *wrfile; struct fasync_struct *fasync_readers; struct fasync_struct *fasync_writers; }; @@ -32,8 +30,6 @@ #define PIPE_WAITING_WRITERS(inode) ((inode).i_pipe->waiting_writers) #define PIPE_RCOUNTER(inode) ((inode).i_pipe->r_counter) #define PIPE_WCOUNTER(inode) ((inode).i_pipe->w_counter) -#define PIPE_READFILE(inode) ((inode).i_pipe->rdfile) -#define PIPE_WRITEFILE(inode) ((inode).i_pipe->wrfile) #define PIPE_FASYNC_READERS(inode) (&((inode).i_pipe->fasync_readers)) #define PIPE_FASYNC_WRITERS(inode) (&((inode).i_pipe->fasync_writers)) diff -Nru a/include/linux/poll.h b/include/linux/poll.h --- a/include/linux/poll.h Mon Nov 4 14:31:01 2002 +++ b/include/linux/poll.h Mon Nov 4 14:31:01 2002 @@ -13,6 +13,9 @@ struct poll_table_page; typedef struct poll_table_struct { + int queue; + void *priv; + void (*qproc)(void *, wait_queue_head_t *); int error; struct poll_table_page * table; } poll_table; @@ -27,9 +30,24 @@ static inline void poll_initwait(poll_table* pt) { + pt->queue = 1; + pt->qproc = NULL; + pt->priv = NULL; pt->error = 0; pt->table = NULL; } + +static inline void poll_initwait_ex(poll_table* pt, int queue, + void (*qproc)(void *, wait_queue_head_t *), + void *priv) +{ + pt->queue = queue; + pt->qproc = qproc; + pt->priv = priv; + pt->error = 0; + pt->table = NULL; +} + extern void poll_freewait(poll_table* pt); diff -Nru a/include/linux/posix_acl.h b/include/linux/posix_acl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/posix_acl.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,87 @@ +/* + File: linux/posix_acl.h + + (C) 2002 Andreas Gruenbacher, +*/ + + +#ifndef __LINUX_POSIX_ACL_H +#define __LINUX_POSIX_ACL_H + +#include + +#define ACL_UNDEFINED_ID (-1) + +/* a_type field in acl_user_posix_entry_t */ +#define ACL_TYPE_ACCESS (0x8000) +#define ACL_TYPE_DEFAULT (0x4000) + +/* e_tag entry in struct posix_acl_entry */ +#define ACL_USER_OBJ (0x01) +#define ACL_USER (0x02) +#define ACL_GROUP_OBJ (0x04) +#define ACL_GROUP (0x08) +#define ACL_MASK (0x10) +#define ACL_OTHER (0x20) + +/* permissions in the e_perm field */ +#define ACL_READ (0x04) +#define ACL_WRITE (0x02) +#define ACL_EXECUTE (0x01) +//#define ACL_ADD (0x08) +//#define ACL_DELETE (0x10) + +struct posix_acl_entry { + short e_tag; + unsigned short e_perm; + unsigned int e_id; +}; + +struct posix_acl { + atomic_t a_refcount; + unsigned int a_count; + struct posix_acl_entry a_entries[0]; +}; + +#define FOREACH_ACL_ENTRY(pa, acl, pe) \ + for(pa=(acl)->a_entries, pe=pa+(acl)->a_count; paa_refcount); + return acl; +} + +/* + * Free an ACL handle. + */ +static inline void +posix_acl_release(struct posix_acl *acl) +{ + if (acl && atomic_dec_and_test(&acl->a_refcount)) + kfree(acl); +} + + +/* posix_acl.c */ + +extern struct posix_acl *posix_acl_alloc(int, int); +extern struct posix_acl *posix_acl_clone(const struct posix_acl *, int); +extern int posix_acl_valid(const struct posix_acl *); +extern int posix_acl_permission(struct inode *, const struct posix_acl *, int); +extern struct posix_acl *posix_acl_from_mode(mode_t, int); +extern int posix_acl_equiv_mode(const struct posix_acl *, mode_t *); +extern int posix_acl_create_masq(struct posix_acl *, mode_t *); +extern int posix_acl_chmod_masq(struct posix_acl *, mode_t); +extern int posix_acl_masq_nfs_mode(struct posix_acl *, mode_t *); + +extern struct posix_acl *get_posix_acl(struct inode *, int); +extern int set_posix_acl(struct inode *, int, struct posix_acl *); + +#endif /* __LINUX_POSIX_ACL_H */ diff -Nru a/include/linux/posix_acl_xattr.h b/include/linux/posix_acl_xattr.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/posix_acl_xattr.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,55 @@ +/* + File: linux/posix_acl_xattr.h + + Extended attribute system call representation of Access Control Lists. + + Copyright (C) 2000 by Andreas Gruenbacher + Copyright (C) 2002 SGI - Silicon Graphics, Inc + */ +#ifndef _POSIX_ACL_XATTR_H +#define _POSIX_ACL_XATTR_H + +#include + +/* Extended attribute names */ +#define POSIX_ACL_XATTR_ACCESS "system.posix_acl_access" +#define POSIX_ACL_XATTR_DEFAULT "system.posix_acl_default" + +/* Supported ACL a_version fields */ +#define POSIX_ACL_XATTR_VERSION 0x0002 + + +/* An undefined entry e_id value */ +#define ACL_UNDEFINED_ID (-1) + +typedef struct { + __u16 e_tag; + __u16 e_perm; + __u32 e_id; +} posix_acl_xattr_entry; + +typedef struct { + __u32 a_version; + posix_acl_xattr_entry a_entries[0]; +} posix_acl_xattr_header; + + +static inline size_t +posix_acl_xattr_size(int count) +{ + return (sizeof(posix_acl_xattr_header) + + (count * sizeof(posix_acl_xattr_entry))); +} + +static inline int +posix_acl_xattr_count(size_t size) +{ + if (size < sizeof(posix_acl_xattr_header)) + return -1; + size -= sizeof(posix_acl_xattr_header); + if (size % sizeof(posix_acl_xattr_entry)) + return -1; + return size / sizeof(posix_acl_xattr_entry); +} + +#endif /* _POSIX_ACL_XATTR_H */ diff -Nru a/include/linux/ptrace.h b/include/linux/ptrace.h --- a/include/linux/ptrace.h Mon Nov 4 14:31:00 2002 +++ b/include/linux/ptrace.h Mon Nov 4 14:31:00 2002 @@ -23,6 +23,23 @@ #define PTRACE_SYSCALL 24 +/* 0x4200-0x4300 are reserved for architecture-independent additions. */ +#define PTRACE_SETOPTIONS 0x4200 +#define PTRACE_GETEVENTMSG 0x4201 + +/* options set using PTRACE_SETOPTIONS */ +#define PTRACE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_O_TRACEFORK 0x00000002 +#define PTRACE_O_TRACEVFORK 0x00000004 +#define PTRACE_O_TRACECLONE 0x00000008 +#define PTRACE_O_TRACEEXEC 0x00000010 + +/* Wait extended result codes for the above trace options. */ +#define PTRACE_EVENT_FORK 1 +#define PTRACE_EVENT_VFORK 2 +#define PTRACE_EVENT_CLONE 3 +#define PTRACE_EVENT_EXEC 4 + #include #include @@ -32,6 +49,8 @@ extern int ptrace_detach(struct task_struct *, unsigned int); extern void ptrace_disable(struct task_struct *); extern int ptrace_check_attach(struct task_struct *task, int kill); +extern int ptrace_request(struct task_struct *child, long request, long addr, long data); +extern void ptrace_notify(int exit_code); extern void __ptrace_link(struct task_struct *child, struct task_struct *new_parent); extern void __ptrace_unlink(struct task_struct *child); diff -Nru a/include/linux/sched.h b/include/linux/sched.h --- a/include/linux/sched.h Mon Nov 4 14:31:00 2002 +++ b/include/linux/sched.h Mon Nov 4 14:31:00 2002 @@ -51,6 +51,7 @@ #define CLONE_SETTID 0x00100000 /* write the TID back to userspace */ #define CLONE_CLEARTID 0x00200000 /* clear the userspace TID */ #define CLONE_DETACHED 0x00400000 /* parent wants no child-exit signal */ +#define CLONE_UNTRACED 0x00800000 /* set if the tracing process can't force CLONE_PTRACE on this clone */ /* * List of flags we want to share for kernel threads, @@ -173,6 +174,7 @@ struct vm_area_struct * mmap; /* list of VMAs */ struct rb_root mm_rb; struct vm_area_struct * mmap_cache; /* last find_vma result */ + unsigned long free_area_cache; /* first hole */ pgd_t * pgd; atomic_t mm_users; /* How many users with user space? */ atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */ @@ -388,6 +390,8 @@ void *journal_info; struct dentry *proc_dentry; struct backing_dev_info *backing_dev_info; + + unsigned long ptrace_message; }; extern void __put_task_struct(struct task_struct *tsk); @@ -426,6 +430,10 @@ #define PT_DTRACE 0x00000002 /* delayed trace (used on m68k, i386) */ #define PT_TRACESYSGOOD 0x00000004 #define PT_PTRACE_CAP 0x00000008 /* ptracer can follow suid-exec */ +#define PT_TRACE_FORK 0x00000010 +#define PT_TRACE_VFORK 0x00000020 +#define PT_TRACE_CLONE 0x00000040 +#define PT_TRACE_EXEC 0x00000080 /* * Limit the stack by to some sane default: root can always diff -Nru a/include/linux/sem.h b/include/linux/sem.h --- a/include/linux/sem.h Mon Nov 4 14:31:01 2002 +++ b/include/linux/sem.h Mon Nov 4 14:31:01 2002 @@ -2,6 +2,7 @@ #define _LINUX_SEM_H #include +#include /* semop flags */ #define SEM_UNDO 0x1000 /* undo the operation on exit */ diff -Nru a/include/linux/serial_core.h b/include/linux/serial_core.h --- a/include/linux/serial_core.h Mon Nov 4 14:31:00 2002 +++ b/include/linux/serial_core.h Mon Nov 4 14:31:00 2002 @@ -154,6 +154,7 @@ unsigned int flags; #define UPF_HUP_NOTIFY (1 << 0) +#define UPF_FOURPORT (1 << 1) #define UPF_SAK (1 << 2) #define UPF_SPD_MASK (0x1030) #define UPF_SPD_HI (0x0010) @@ -167,6 +168,9 @@ #define UPF_LOW_LATENCY (1 << 13) #define UPF_BUGGY_UART (1 << 14) #define UPF_AUTOPROBE (1 << 15) +#define UPF_BOOT_ONLYMCA (1 << 22) +#define UPF_CONS_FLOW (1 << 23) +#define UPF_SHARE_IRQ (1 << 24) #define UPF_BOOT_AUTOCONF (1 << 28) #define UPF_RESOURCES (1 << 30) #define UPF_IOREMAP (1 << 31) @@ -247,8 +251,6 @@ /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 -#define EVT_WRITE_WAKEUP 0 - struct module; struct tty_driver; @@ -269,7 +271,7 @@ struct tty_driver *tty_driver; }; -void uart_event(struct uart_port *port, int event); +void uart_write_wakeup(struct uart_port *port); struct uart_port *uart_get_console(struct uart_port *ports, int nr, struct console *c); void uart_parse_options(char *options, int *baud, int *parity, int *bits, @@ -380,7 +382,7 @@ if (status) { tty->hw_stopped = 0; port->ops->start_tx(port, 0); - uart_event(port, EVT_WRITE_WAKEUP); + uart_write_wakeup(port); } } else { if (!status) { diff -Nru a/include/linux/shm.h b/include/linux/shm.h --- a/include/linux/shm.h Mon Nov 4 14:31:02 2002 +++ b/include/linux/shm.h Mon Nov 4 14:31:02 2002 @@ -88,6 +88,7 @@ /* shm_mode upper byte flags */ #define SHM_DEST 01000 /* segment will be destroyed on last detach */ #define SHM_LOCKED 02000 /* segment will not be swapped */ +#define SHM_HUGETLB 04000 /* segment will use huge TLB pages */ asmlinkage long sys_shmget (key_t key, size_t size, int flag); asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, unsigned long *addr); diff -Nru a/include/linux/som.h b/include/linux/som.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/som.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,154 @@ +#ifndef _LINUX_SOM_H +#define _LINUX_SOM_H + +/* File format definition for SOM executables / shared libraries */ + +/* we need struct timespec */ +#include + +#define SOM_PAGESIZE 4096 + +/* this is the SOM header */ +struct som_hdr { + short system_id; /* magic number - system */ + short a_magic; /* magic number - file type */ + unsigned int version_id; /* versiod ID: YYMMDDHH */ + struct timespec file_time; /* system clock */ + unsigned int entry_space; /* space for entry point */ + unsigned int entry_subspace; /* subspace for entry point */ + unsigned int entry_offset; /* offset of entry point */ + unsigned int aux_header_location; /* auxiliary header location */ + unsigned int aux_header_size; /* auxiliary header size */ + unsigned int som_length; /* length of entire SOM */ + unsigned int presumed_dp; /* compiler's DP value */ + unsigned int space_location; /* space dictionary location */ + unsigned int space_total; /* number of space entries */ + unsigned int subspace_location; /* subspace entries location */ + unsigned int subspace_total; /* number of subspace entries */ + unsigned int loader_fixup_location; /* MPE/iX loader fixup */ + unsigned int loader_fixup_total; /* number of fixup records */ + unsigned int space_strings_location; /* (sub)space names */ + unsigned int space_strings_size; /* size of strings area */ + unsigned int init_array_location; /* reserved */ + unsigned int init_array_total; /* reserved */ + unsigned int compiler_location; /* module dictionary */ + unsigned int compiler_total; /* number of modules */ + unsigned int symbol_location; /* symbol dictionary */ + unsigned int symbol_total; /* number of symbols */ + unsigned int fixup_request_location; /* fixup requests */ + unsigned int fixup_request_total; /* number of fixup requests */ + unsigned int symbol_strings_location;/* module & symbol names area */ + unsigned int symbol_strings_size; /* size of strings area */ + unsigned int unloadable_sp_location; /* unloadable spaces location */ + unsigned int unloadable_sp_size; /* size of data */ + unsigned int checksum; +}; + +/* values for system_id */ + +#define SOM_SID_PARISC_1_0 0x020b +#define SOM_SID_PARISC_1_1 0x0210 +#define SOM_SID_PARISC_2_0 0x0214 + +/* values for a_magic */ + +#define SOM_LIB_EXEC 0x0104 +#define SOM_RELOCATABLE 0x0106 +#define SOM_EXEC_NONSHARE 0x0107 +#define SOM_EXEC_SHARE 0x0108 +#define SOM_EXEC_DEMAND 0x010B +#define SOM_LIB_DYN 0x010D +#define SOM_LIB_SHARE 0x010E +#define SOM_LIB_RELOC 0x0619 + +/* values for version_id. Decimal not hex, yes. Grr. */ + +#define SOM_ID_OLD 85082112 +#define SOM_ID_NEW 87102412 + +struct aux_id { + unsigned int mandatory :1; /* the linker must understand this */ + unsigned int copy :1; /* Must be copied by the linker */ + unsigned int append :1; /* Must be merged by the linker */ + unsigned int ignore :1; /* Discard section if unknown */ + unsigned int reserved :12; + unsigned int type :16; /* Header type */ + unsigned int length; /* length of _following_ data */ +}; + +/* The Exec Auxiliary Header. Called The HP-UX Header within HP apparently. */ +struct som_exec_auxhdr { + struct aux_id som_auxhdr; + int exec_tsize; /* Text size in bytes */ + int exec_tmem; /* Address to load text at */ + int exec_tfile; /* Location of text in file */ + int exec_dsize; /* Data size in bytes */ + int exec_dmem; /* Address to load data at */ + int exec_dfile; /* Location of data in file */ + int exec_bsize; /* Uninitialised data (bss) */ + int exec_entry; /* Address to start executing */ + int exec_flags; /* loader flags */ + int exec_bfill; /* initialisation value for bss */ +}; + +/* Oh, the things people do to avoid casts. Shame it'll break with gcc's + * new aliasing rules really. + */ +union name_pt { + char * n_name; + unsigned int n_strx; +}; + +/* The Space Dictionary */ +struct space_dictionary_record { + union name_pt name; /* index to subspace name */ + unsigned int is_loadable :1; /* loadable */ + unsigned int is_defined :1; /* defined within file */ + unsigned int is_private :1; /* not sharable */ + unsigned int has_intermediate_code :1; /* contains intermediate code */ + unsigned int is_tspecific :1; /* thread specific */ + unsigned int reserved :11; /* for future expansion */ + unsigned int sort_key :8; /* for linker */ + unsigned int reserved2 :8; /* for future expansion */ + + int space_number; /* index */ + int subspace_index; /* index into subspace dict */ + unsigned int subspace_quantity; /* number of subspaces */ + int loader_fix_index; /* for loader */ + unsigned int loader_fix_quantity; /* for loader */ + int init_pointer_index; /* data pointer array index */ + unsigned int init_pointer_quantity; /* number of data pointers */ +}; + +/* The Subspace Dictionary */ +struct subspace_dictionary_record { + int space_index; + unsigned int access_control_bits :7; + unsigned int memory_resident :1; + unsigned int dup_common :1; + unsigned int is_common :1; + unsigned int quadrant :2; + unsigned int initially_frozen :1; + unsigned int is_first :1; + unsigned int code_only :1; + unsigned int sort_key :8; + unsigned int replicate_init :1; + unsigned int continuation :1; + unsigned int is_tspecific :1; + unsigned int is_comdat :1; + unsigned int reserved :4; + + int file_loc_init_value; + unsigned int initialization_length; + unsigned int subspace_start; + unsigned int subspace_length; + + unsigned int reserved2 :5; + unsigned int alignment :27; + + union name_pt name; + int fixup_request_index; + unsigned int fixup_request_quantity; +}; + +#endif /* _LINUX_SOM_H */ diff -Nru a/include/linux/swap.h b/include/linux/swap.h --- a/include/linux/swap.h Mon Nov 4 14:31:00 2002 +++ b/include/linux/swap.h Mon Nov 4 14:31:00 2002 @@ -1,11 +1,13 @@ #ifndef _LINUX_SWAP_H #define _LINUX_SWAP_H +#include #include #include #include #include #include +#include #include #define SWAP_FLAG_PREFER 0x8000 /* set if swap priority specified */ @@ -36,13 +38,11 @@ * bootbits... */ union swap_header { - struct - { + struct { char reserved[PAGE_SIZE - 10]; char magic[10]; /* SWAP-SPACE or SWAPSPACE2 */ } magic; - struct - { + struct { char bootbits[1024]; /* Space for disklabel etc. */ unsigned int version; unsigned int last_page; @@ -62,6 +62,10 @@ #ifdef __KERNEL__ +struct sysinfo; +struct address_space; +struct zone; + /* * A swap extent maps a range of a swapfile's PAGE_SIZE pages onto a range of * disk blocks. A list of swap extents maps the entire swapfile. (Where the @@ -84,8 +88,6 @@ #define MAX_SWAP_BADPAGES \ ((__swapoffset(magic.magic) - __swapoffset(info.badpages)) / sizeof(int)) -#include - enum { SWP_USED = (1 << 0), /* is slot in swap_info[] used? */ SWP_WRITEOK = (1 << 1), /* ok to write to this swap? */ @@ -122,24 +124,40 @@ int next; /* next entry on swap list */ }; -struct inode; -extern int nr_swap_pages; +struct swap_list_t { + int head; /* head of priority-ordered swapfile list */ + int next; /* swapfile to be used next */ +}; /* Swap 50% full? Release swapcache more aggressively.. */ #define vm_swap_full() (nr_swap_pages*2 < total_swap_pages) +/* linux/mm/page_alloc.c */ extern unsigned long totalram_pages; extern unsigned long totalhigh_pages; +extern int nr_swap_pages; /* XXX: shouldn't this be ulong? --hch */ extern unsigned int nr_free_pages(void); +extern unsigned int nr_free_pages_pgdat(pg_data_t *pgdat); extern unsigned int nr_free_buffer_pages(void); extern unsigned int nr_free_pagecache_pages(void); -/* Incomplete types for prototype declarations: */ -struct task_struct; -struct vm_area_struct; -struct sysinfo; -struct address_space; -struct zone; +/* linux/mm/filemap.c */ +extern void FASTCALL(mark_page_accessed(struct page *)); + +/* linux/mm/swap.c */ +extern void FASTCALL(lru_cache_add(struct page *)); +extern void FASTCALL(lru_cache_add_active(struct page *)); +extern void FASTCALL(activate_page(struct page *)); +extern void lru_add_drain(void); +extern void swap_setup(void); + +/* linux/mm/vmscan.c */ +extern int try_to_free_pages(struct zone *, unsigned int, unsigned int); +extern int shrink_all_memory(int); +extern int vm_swappiness; + +/* linux/mm/oom_kill.c */ +extern void out_of_memory(void); /* linux/mm/rmap.c */ extern int FASTCALL(page_referenced(struct page *)); @@ -154,42 +172,31 @@ #define SWAP_FAIL 2 #define SWAP_ERROR 3 -/* linux/mm/swap.c */ -extern void FASTCALL(lru_cache_add(struct page *)); - -extern void FASTCALL(activate_page(struct page *)); - -extern void swap_setup(void); - -/* linux/mm/vmscan.c */ -extern int try_to_free_pages(struct zone *, unsigned int, unsigned int); -int shrink_all_memory(int nr_pages); -extern int vm_swappiness; +/* linux/mm/shmem.c */ +extern int shmem_unuse(swp_entry_t entry, struct page *page); +#ifdef CONFIG_SWAP /* linux/mm/page_io.c */ -int swap_readpage(struct file *file, struct page *page); -int swap_writepage(struct page *page); -int rw_swap_page_sync(int rw, swp_entry_t entry, struct page *page); - -/* linux/mm/page_alloc.c */ +extern int swap_readpage(struct file *, struct page *); +extern int swap_writepage(struct page *); +extern int rw_swap_page_sync(int, swp_entry_t, struct page *); /* linux/mm/swap_state.c */ +extern struct address_space swapper_space; +#define total_swapcache_pages swapper_space.nrpages extern void show_swap_cache_info(void); extern int add_to_swap_cache(struct page *, swp_entry_t); extern int add_to_swap(struct page *); -extern void __delete_from_swap_cache(struct page *page); -extern void delete_from_swap_cache(struct page *page); -extern int move_to_swap_cache(struct page *page, swp_entry_t entry); -extern int move_from_swap_cache(struct page *page, unsigned long index, - struct address_space *mapping); -extern void free_page_and_swap_cache(struct page *page); -extern void free_pages_and_swap_cache(struct page **pages, int nr); +extern void __delete_from_swap_cache(struct page *); +extern void delete_from_swap_cache(struct page *); +extern int move_to_swap_cache(struct page *, swp_entry_t); +extern int move_from_swap_cache(struct page *, unsigned long, + struct address_space *); +extern void free_page_and_swap_cache(struct page *); +extern void free_pages_and_swap_cache(struct page **, int); extern struct page * lookup_swap_cache(swp_entry_t); extern struct page * read_swap_cache_async(swp_entry_t); -/* linux/mm/oom_kill.c */ -extern void out_of_memory(void); - /* linux/mm/swapfile.c */ extern int total_swap_pages; extern unsigned int nr_swapfiles; @@ -200,19 +207,12 @@ extern int valid_swaphandles(swp_entry_t, unsigned long *); extern void swap_free(swp_entry_t); extern void free_swap_and_cache(swp_entry_t); -sector_t map_swap_page(struct swap_info_struct *p, pgoff_t offset); -struct swap_info_struct *get_swap_info_struct(unsigned type); +extern sector_t map_swap_page(struct swap_info_struct *, pgoff_t); +extern struct swap_info_struct *get_swap_info_struct(unsigned); +extern int can_share_swap_page(struct page *); +extern int remove_exclusive_swap_page(struct page *); -struct swap_list_t { - int head; /* head of priority-ordered swapfile list */ - int next; /* swapfile to be used next */ -}; extern struct swap_list_t swap_list; -asmlinkage long sys_swapoff(const char *); -asmlinkage long sys_swapon(const char *, int); - -extern void FASTCALL(mark_page_accessed(struct page *)); - extern spinlock_t swaplock; #define swap_list_lock() spin_lock(&swaplock) @@ -220,8 +220,39 @@ #define swap_device_lock(p) spin_lock(&p->sdev_lock) #define swap_device_unlock(p) spin_unlock(&p->sdev_lock) -extern int shmem_unuse(swp_entry_t entry, struct page *page); +#else /* CONFIG_SWAP */ -#endif /* __KERNEL__*/ +#define total_swap_pages 0 +#define total_swapcache_pages 0UL + +#define si_swapinfo(val) \ + do { (val)->freeswap = (val)->totalswap = 0; } while (0) +#define free_page_and_swap_cache(page) \ + page_cache_release(page) +#define free_pages_and_swap_cache(pages, nr) \ + release_pages((pages), (nr), 0); + +#define show_swap_cache_info() /*NOTHING*/ +#define free_swap_and_cache(swp) /*NOTHING*/ +#define swap_duplicate(swp) /*NOTHING*/ +#define swap_free(swp) /*NOTHING*/ +#define read_swap_cache_async(swp) NULL +#define lookup_swap_cache(swp) NULL +#define valid_swaphandles(swp, off) 0 +#define can_share_swap_page(p) 0 +#define remove_exclusive_swap_page(p) 0 +#define move_to_swap_cache(p, swp) 1 +#define move_from_swap_cache(p, i, m) 1 +#define __delete_from_swap_cache(p) /*NOTHING*/ +#define delete_from_swap_cache(p) /*NOTHING*/ + +static inline swp_entry_t get_swap_page(void) +{ + swp_entry_t entry; + entry.val = 0; + return entry; +} +#endif /* CONFIG_SWAP */ +#endif /* __KERNEL__*/ #endif /* _LINUX_SWAP_H */ diff -Nru a/include/linux/sysfs.h b/include/linux/sysfs.h --- a/include/linux/sysfs.h Mon Nov 4 14:31:01 2002 +++ b/include/linux/sysfs.h Mon Nov 4 14:31:01 2002 @@ -9,18 +9,16 @@ #ifndef _SYSFS_H_ #define _SYSFS_H_ -struct driver_dir_entry; -struct attribute; struct kobject; -struct sysfs_ops { - ssize_t (*show)(struct kobject *, struct attribute *,char *, size_t, loff_t); - ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t, loff_t); -}; - struct attribute { char * name; mode_t mode; +}; + +struct sysfs_ops { + ssize_t (*show)(struct kobject *, struct attribute *,char *, size_t, loff_t); + ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t, loff_t); }; extern int diff -Nru a/include/linux/videodev.h b/include/linux/videodev.h --- a/include/linux/videodev.h Mon Nov 4 14:31:03 2002 +++ b/include/linux/videodev.h Mon Nov 4 14:31:03 2002 @@ -4,10 +4,10 @@ #include #include -#if 0 +#if 1 /* * v4l2 is still work-in-progress, integration planed for 2.5.x - * v4l2 project homepage: http://www.thedirks.org/v4l2/ + * documentation: http://bytesex.org/v4l/ * patches available from: http://bytesex.org/patches/ */ # define HAVE_V4L2 1 @@ -32,10 +32,7 @@ int minor; /* new interface -- we will use file_operations directly - * like soundcore does. - * kernel_ioctl() will be called by video_generic_ioctl. - * video_generic_ioctl() does the userspace copying of the - * ioctl arguments */ + * like soundcore does. */ struct file_operations *fops; void *priv; /* Used to be 'private' but that upsets C++ */ @@ -397,7 +394,7 @@ #define VID_HARDWARE_PWC 31 /* Philips webcams */ #define VID_HARDWARE_MEYE 32 /* Sony Vaio MotionEye cameras */ #define VID_HARDWARE_CPIA2 33 -#define VID_HARDWARE_VICAM 34 +#define VID_HARDWARE_VICAM 34 #endif /* __LINUX_VIDEODEV_H */ diff -Nru a/include/linux/videodev2.h b/include/linux/videodev2.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/videodev2.h Mon Nov 4 14:31:04 2002 @@ -0,0 +1,859 @@ +#ifndef __LINUX_VIDEODEV2_H +#define __LINUX_VIDEODEV2_H +/* + * Video for Linux Two + * + * Header file for v4l or V4L2 drivers and applications, for + * Linux kernels 2.2.x or 2.4.x. + * + * See http://bytesex.org/v4l/ for API specs and other + * v4l2 documentation. + * + * Author: Bill Dirks + * Justin Schoeman + * et al. + */ +#include /* need struct timeval */ + +/* + * M I S C E L L A N E O U S + */ + +/* Four-character-code (FOURCC) */ +#define v4l2_fourcc(a,b,c,d)\ + (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24)) + +/* + * E N U M S + */ +enum v4l2_field { + V4L2_FIELD_ANY = 0, /* driver can choose from none, + top, bottom, interlaced + depending on whatever it thinks + is approximate ... */ + V4L2_FIELD_NONE = 1, /* this device has no fields ... */ + V4L2_FIELD_TOP = 2, /* top field only */ + V4L2_FIELD_BOTTOM = 3, /* bottom field only */ + V4L2_FIELD_INTERLACED = 4, /* both fields interlaced */ + V4L2_FIELD_SEQ_TB = 5, /* both fields sequential into one + buffer, top-bottom order */ + V4L2_FIELD_SEQ_BT = 6, /* same as above + bottom-top order */ + V4L2_FIELD_ALTERNATE = 7, /* both fields alternating into + separate buffers */ +}; +#define V4L2_FIELD_HAS_TOP(field) \ + ((field) == V4L2_FIELD_TOP ||\ + (field) == V4L2_FIELD_INTERLACED ||\ + (field) == V4L2_FIELD_SEQ_TB ||\ + (field) == V4L2_FIELD_SEQ_BT) +#define V4L2_FIELD_HAS_BOTTOM(field) \ + ((field) == V4L2_FIELD_BOTTOM ||\ + (field) == V4L2_FIELD_INTERLACED ||\ + (field) == V4L2_FIELD_SEQ_TB ||\ + (field) == V4L2_FIELD_SEQ_BT) +#define V4L2_FIELD_HAS_BOTH(field) \ + ((field) == V4L2_FIELD_INTERLACED ||\ + (field) == V4L2_FIELD_SEQ_TB ||\ + (field) == V4L2_FIELD_SEQ_BT) + +enum v4l2_buf_type { + V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, + V4L2_BUF_TYPE_VIDEO_OUTPUT = 2, + V4L2_BUF_TYPE_VIDEO_OVERLAY = 3, + V4L2_BUF_TYPE_VBI_CAPTURE = 4, + V4L2_BUF_TYPE_VBI_OUTPUT = 5, + V4L2_BUF_TYPE_PRIVATE = 0x80, +}; + +enum v4l2_ctrl_type { + V4L2_CTRL_TYPE_INTEGER = 1, + V4L2_CTRL_TYPE_BOOLEAN = 2, + V4L2_CTRL_TYPE_MENU = 3, + V4L2_CTRL_TYPE_BUTTON = 4, +}; + +enum v4l2_tuner_type { + V4L2_TUNER_RADIO = 1, + V4L2_TUNER_ANALOG_TV = 2, +}; + +enum v4l2_memory { + V4L2_MEMORY_MMAP = 1, + V4L2_MEMORY_USERPTR = 2, + V4L2_MEMORY_OVERLAY = 3, +}; + +/* see also http://vektor.theorem.ca/graphics/ycbcr/ */ +enum v4l2_colorspace { + /* ITU-R 601 -- broadcast NTSC/PAL */ + V4L2_COLORSPACE_SMPTE170M = 1, + + /* 1125-Line (US) HDTV */ + V4L2_COLORSPACE_SMPTE240M = 2, + + /* HD and modern captures. */ + V4L2_COLORSPACE_REC709 = 3, + + /* broken BT878 extents (601, luma range 16-253 instead of 16-235) */ + V4L2_COLORSPACE_BT878 = 4, + + /* These should be useful. Assume 601 extents. */ + V4L2_COLORSPACE_470_SYSTEM_M = 5, + V4L2_COLORSPACE_470_SYSTEM_BG = 6, + + /* I know there will be cameras that send this. So, this is + * unspecified chromaticities and full 0-255 on each of the + * Y'CbCr components + */ + V4L2_COLORSPACE_JPEG = 7, + + /* For RGB colourspaces, this is probably a good start. */ + V4L2_COLORSPACE_SRGB = 8, +}; + +struct v4l2_rect { + __s32 left; + __s32 top; + __s32 width; + __s32 height; +}; + +struct v4l2_fract { + __u32 numerator; + __u32 denominator; +}; + +/* + * D R I V E R C A P A B I L I T I E S + */ +struct v4l2_capability +{ + __u8 driver[16]; /* i.e. "bttv" */ + __u8 card[32]; /* i.e. "Hauppauge WinTV" */ + __u8 bus_info[32]; /* "PCI:" + pci_dev->slot_name */ + __u32 version; /* should use KERNEL_VERSION() */ + __u32 capabilities; /* Device capabilities */ + __u32 reserved[4]; +}; + +/* Values for 'capabilities' field */ +#define V4L2_CAP_VIDEO_CAPTURE 0x00000001 /* Is a video capture device */ +#define V4L2_CAP_VIDEO_OUTPUT 0x00000002 /* Is a video output device */ +#define V4L2_CAP_VIDEO_OVERLAY 0x00000004 /* Can do video overlay */ +#define V4L2_CAP_VBI_CAPTURE 0x00000010 /* Is a VBI capture device */ +#define V4L2_CAP_VBI_OUTPUT 0x00000020 /* Is a VBI output device */ +#define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */ + +#define V4L2_CAP_TUNER 0x00010000 /* Has a tuner */ +#define V4L2_CAP_AUDIO 0x00020000 /* has audio support */ + +#define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */ +#define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */ +#define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */ + +/* + * V I D E O I M A G E F O R M A T + */ + +struct v4l2_pix_format +{ + __u32 width; + __u32 height; + __u32 pixelformat; + enum v4l2_field field; + __u32 bytesperline; /* for padding, zero if unused */ + __u32 sizeimage; + enum v4l2_colorspace colorspace; + __u32 priv; /* private data, depends on pixelformat */ +}; + +/* Pixel format FOURCC depth Description */ +#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R','G','B','1') /* 8 RGB-3-3-2 */ +#define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R','G','B','O') /* 16 RGB-5-5-5 */ +#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R','G','B','P') /* 16 RGB-5-6-5 */ +#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R','G','B','Q') /* 16 RGB-5-5-5 BE */ +#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R','G','B','R') /* 16 RGB-5-6-5 BE */ +#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B','G','R','3') /* 24 BGR-8-8-8 */ +#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R','G','B','3') /* 24 RGB-8-8-8 */ +#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B','G','R','4') /* 32 BGR-8-8-8-8 */ +#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R','G','B','4') /* 32 RGB-8-8-8-8 */ +#define V4L2_PIX_FMT_GREY v4l2_fourcc('G','R','E','Y') /* 8 Greyscale */ +#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y','V','U','9') /* 9 YVU 4:1:0 */ +#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y','V','1','2') /* 12 YVU 4:2:0 */ +#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y','U','Y','V') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U','Y','V','Y') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4','2','2','P') /* 16 YVU422 planar */ +#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4','1','1','P') /* 16 YVU411 planar */ +#define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y','4','1','P') /* 12 YUV 4:1:1 */ + +/* two planes -- one Y, one Cr + Cb interleaved */ +#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N','V','1','2') /* 12 Y/CbCr 4:2:0 */ +#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N','V','2','1') /* 12 Y/CrCb 4:2:0 */ + +/* The following formats are not defined in the V4L2 specification */ +#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y','U','V','9') /* 9 YUV 4:1:0 */ +#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y','U','1','2') /* 12 YUV 4:2:0 */ +#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') /* 8 8-bit color */ + +/* compressed formats */ +#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M','J','P','G') /* Motion-JPEG */ +#define V4L2_PIX_FMT_JPEG v4l2_fourcc('J','P','E','G') /* JFIF JPEG */ +#define V4L2_PIX_FMT_DV v4l2_fourcc('d','v','s','d') /* 1394 */ +#define V4L2_PIX_FMT_MPEG v4l2_fourcc('M','P','E','G') /* MPEG */ + +/* Vendor-specific formats */ +#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') /* Winnov hw compres */ + +/* + * F O R M A T E N U M E R A T I O N + */ +struct v4l2_fmtdesc +{ + __u32 index; /* Format number */ + enum v4l2_buf_type type; /* buffer type */ + __u32 flags; + __u8 description[32]; /* Description string */ + __u32 pixelformat; /* Format fourcc */ + __u32 reserved[4]; +}; + +#define V4L2_FMT_FLAG_COMPRESSED 0x0001 + + +/* + * T I M E C O D E + */ +struct v4l2_timecode +{ + __u32 type; + __u32 flags; + __u8 frames; + __u8 seconds; + __u8 minutes; + __u8 hours; + __u8 userbits[4]; +}; + +/* Type */ +#define V4L2_TC_TYPE_24FPS 1 +#define V4L2_TC_TYPE_25FPS 2 +#define V4L2_TC_TYPE_30FPS 3 +#define V4L2_TC_TYPE_50FPS 4 +#define V4L2_TC_TYPE_60FPS 5 + +/* Flags */ +#define V4L2_TC_FLAG_DROPFRAME 0x0001 /* "drop-frame" mode */ +#define V4L2_TC_FLAG_COLORFRAME 0x0002 +#define V4L2_TC_USERBITS_field 0x000C +#define V4L2_TC_USERBITS_USERDEFINED 0x0000 +#define V4L2_TC_USERBITS_8BITCHARS 0x0008 +/* The above is based on SMPTE timecodes */ + + +/* + * C O M P R E S S I O N P A R A M E T E R S + */ +#if 0 +/* ### generic compression settings don't work, there is too much + * ### codec-specific stuff. Maybe reuse that for MPEG codec settings + * ### later ... */ +struct v4l2_compression +{ + __u32 quality; + __u32 keyframerate; + __u32 pframerate; + __u32 reserved[5]; +}; +#endif + +struct v4l2_jpegcompression +{ + int quality; + + int APPn; /* Number of APP segment to be written, + * must be 0..15 */ + int APP_len; /* Length of data in JPEG APPn segment */ + char APP_data[60]; /* Data in the JPEG APPn segment. */ + + int COM_len; /* Length of data in JPEG COM segment */ + char COM_data[60]; /* Data in JPEG COM segment */ + + __u32 jpeg_markers; /* Which markers should go into the JPEG + * output. Unless you exactly know what + * you do, leave them untouched. + * Inluding less markers will make the + * resulting code smaller, but there will + * be fewer aplications which can read it. + * The presence of the APP and COM marker + * is influenced by APP_len and COM_len + * ONLY, not by this property! */ + +#define V4L2_JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ +#define V4L2_JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ +#define V4L2_JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ +#define V4L2_JPEG_MARKER_COM (1<<6) /* Comment segment */ +#define V4L2_JPEG_MARKER_APP (1<<7) /* App segment, driver will + * allways use APP0 */ +}; + + +/* + * M E M O R Y - M A P P I N G B U F F E R S + */ +struct v4l2_requestbuffers +{ + __u32 count; + enum v4l2_buf_type type; + enum v4l2_memory memory; + __u32 reserved[2]; +}; + +struct v4l2_buffer +{ + __u32 index; + enum v4l2_buf_type type; + __u32 bytesused; + __u32 flags; + enum v4l2_field field; + struct timeval timestamp; + struct v4l2_timecode timecode; + __u32 sequence; + + /* memory location */ + enum v4l2_memory memory; + union { + __u32 offset; + unsigned long userptr; + } m; + __u32 length; + + __u32 reserved[2]; +}; + +/* Flags for 'flags' field */ +#define V4L2_BUF_FLAG_MAPPED 0x0001 /* Buffer is mapped (flag) */ +#define V4L2_BUF_FLAG_QUEUED 0x0002 /* Buffer is queued for processing */ +#define V4L2_BUF_FLAG_DONE 0x0004 /* Buffer is ready */ +#define V4L2_BUF_FLAG_KEYFRAME 0x0008 /* Image is a keyframe (I-frame) */ +#define V4L2_BUF_FLAG_PFRAME 0x0010 /* Image is a P-frame */ +#define V4L2_BUF_FLAG_BFRAME 0x0020 /* Image is a B-frame */ +#define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */ + +/* + * O V E R L A Y P R E V I E W + */ +struct v4l2_framebuffer +{ + __u32 capability; + __u32 flags; +/* FIXME: in theory we should pass something like PCI device + memory + * region + offset instead of some physical address */ + void* base; + struct v4l2_pix_format fmt; +}; +/* Flags for the 'capability' field. Read only */ +#define V4L2_FBUF_CAP_EXTERNOVERLAY 0x0001 +#define V4L2_FBUF_CAP_CHROMAKEY 0x0002 +#define V4L2_FBUF_CAP_LIST_CLIPPING 0x0004 +#define V4L2_FBUF_CAP_BITMAP_CLIPPING 0x0008 +/* Flags for the 'flags' field. */ +#define V4L2_FBUF_FLAG_PRIMARY 0x0001 +#define V4L2_FBUF_FLAG_OVERLAY 0x0002 +#define V4L2_FBUF_FLAG_CHROMAKEY 0x0004 + +struct v4l2_clip +{ + struct v4l2_rect c; + struct v4l2_clip *next; +}; + +struct v4l2_window +{ + struct v4l2_rect w; + enum v4l2_field field; + __u32 chromakey; + struct v4l2_clip *clips; + __u32 clipcount; + void *bitmap; +}; + + +/* + * C A P T U R E P A R A M E T E R S + */ +struct v4l2_captureparm +{ + __u32 capability; /* Supported modes */ + __u32 capturemode; /* Current mode */ + struct v4l2_fract timeperframe; /* Time per frame in .1us units */ + __u32 extendedmode; /* Driver-specific extensions */ + __u32 readbuffers; /* # of buffers for read */ + __u32 reserved[4]; +}; +/* Flags for 'capability' and 'capturemode' fields */ +#define V4L2_MODE_HIGHQUALITY 0x0001 /* High quality imaging mode */ +#define V4L2_CAP_TIMEPERFRAME 0x1000 /* timeperframe field is supported */ + +struct v4l2_outputparm +{ + __u32 capability; /* Supported modes */ + __u32 outputmode; /* Current mode */ + struct v4l2_fract timeperframe; /* Time per frame in seconds */ + __u32 extendedmode; /* Driver-specific extensions */ + __u32 writebuffers; /* # of buffers for write */ + __u32 reserved[4]; +}; + +/* + * I N P U T I M A G E C R O P P I N G + */ + +struct v4l2_cropcap { + enum v4l2_buf_type type; + struct v4l2_rect bounds; + struct v4l2_rect defrect; + struct v4l2_fract pixelaspect; +}; + +struct v4l2_crop { + enum v4l2_buf_type type; + struct v4l2_rect c; +}; + +/* + * A N A L O G V I D E O S T A N D A R D + */ + +typedef __u64 v4l2_std_id; + +/* one bit for each */ +#define V4L2_STD_PAL_B ((v4l2_std_id)0x00000001) +#define V4L2_STD_PAL_B1 ((v4l2_std_id)0x00000002) +#define V4L2_STD_PAL_G ((v4l2_std_id)0x00000004) +#define V4L2_STD_PAL_H ((v4l2_std_id)0x00000008) +#define V4L2_STD_PAL_I ((v4l2_std_id)0x00000010) +#define V4L2_STD_PAL_D ((v4l2_std_id)0x00000020) +#define V4L2_STD_PAL_D1 ((v4l2_std_id)0x00000040) +#define V4L2_STD_PAL_K ((v4l2_std_id)0x00000080) + +#define V4L2_STD_PAL_M ((v4l2_std_id)0x00000100) +#define V4L2_STD_PAL_N ((v4l2_std_id)0x00000200) +#define V4L2_STD_PAL_Nc ((v4l2_std_id)0x00000400) +#define V4L2_STD_PAL_60 ((v4l2_std_id)0x00000800) + +#define V4L2_STD_NTSC_M ((v4l2_std_id)0x00001000) +#define V4L2_STD_NTSC_M_JP ((v4l2_std_id)0x00002000) + +#define V4L2_STD_SECAM_B ((v4l2_std_id)0x00010000) +#define V4L2_STD_SECAM_D ((v4l2_std_id)0x00020000) +#define V4L2_STD_SECAM_G ((v4l2_std_id)0x00040000) +#define V4L2_STD_SECAM_H ((v4l2_std_id)0x00080000) +#define V4L2_STD_SECAM_K ((v4l2_std_id)0x00100000) +#define V4L2_STD_SECAM_K1 ((v4l2_std_id)0x00200000) +#define V4L2_STD_SECAM_L ((v4l2_std_id)0x00400000) + +/* ATSC/HDTV */ +#define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000) +#define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000) + +/* some common needed stuff */ +#define V4L2_STD_PAL_BG (V4L2_STD_PAL_B |\ + V4L2_STD_PAL_B1 |\ + V4L2_STD_PAL_G) +#define V4L2_STD_PAL_DK (V4L2_STD_PAL_D |\ + V4L2_STD_PAL_D1 |\ + V4L2_STD_PAL_K) +#define V4L2_STD_PAL (V4L2_STD_PAL_BG |\ + V4L2_STD_PAL_DK |\ + V4L2_STD_PAL_H |\ + V4L2_STD_PAL_I) +#define V4L2_STD_NTSC (V4L2_STD_NTSC_M |\ + V4L2_STD_NTSC_M_JP) +#define V4L2_STD_SECAM (V4L2_STD_SECAM_B |\ + V4L2_STD_SECAM_D |\ + V4L2_STD_SECAM_G |\ + V4L2_STD_SECAM_H |\ + V4L2_STD_SECAM_K |\ + V4L2_STD_SECAM_K1 |\ + V4L2_STD_SECAM_L) + +#define V4L2_STD_525_60 (V4L2_STD_PAL_M |\ + V4L2_STD_PAL_60 |\ + V4L2_STD_NTSC) +#define V4L2_STD_625_50 (V4L2_STD_PAL |\ + V4L2_STD_PAL_N |\ + V4L2_STD_PAL_Nc |\ + V4L2_STD_SECAM) + +#define V4L2_STD_UNKNOWN 0 +#define V4L2_STD_ALL (V4L2_STD_525_60 |\ + V4L2_STD_625_50) + +struct v4l2_standard +{ + __u32 index; + v4l2_std_id id; + __u8 name[24]; + struct v4l2_fract frameperiod; /* Frames, not fields */ + __u32 framelines; + __u32 reserved[4]; +}; + + +/* + * V I D E O I N P U T S + */ +struct v4l2_input +{ + __u32 index; /* Which input */ + __u8 name[32]; /* Label */ + __u32 type; /* Type of input */ + __u32 audioset; /* Associated audios (bitfield) */ + __u32 tuner; /* Associated tuner */ + v4l2_std_id std; + __u32 status; + __u32 reserved[4]; +}; +/* Values for the 'type' field */ +#define V4L2_INPUT_TYPE_TUNER 1 +#define V4L2_INPUT_TYPE_CAMERA 2 + +/* field 'status' - general */ +#define V4L2_IN_ST_NO_POWER 0x00000001 /* Attached device is off */ +#define V4L2_IN_ST_NO_SIGNAL 0x00000002 +#define V4L2_IN_ST_NO_COLOR 0x00000004 + +/* field 'status' - analog */ +#define V4L2_IN_ST_NO_H_LOCK 0x00000100 /* No horizontal sync lock */ +#define V4L2_IN_ST_COLOR_KILL 0x00000200 /* Color killer is active */ + +/* field 'status' - digital */ +#define V4L2_IN_ST_NO_SYNC 0x00010000 /* No synchronization lock */ +#define V4L2_IN_ST_NO_EQU 0x00020000 /* No equalizer lock */ +#define V4L2_IN_ST_NO_CARRIER 0x00040000 /* Carrier recovery failed */ + +/* field 'status' - VCR and set-top box */ +#define V4L2_IN_ST_MACROVISION 0x01000000 /* Macrovision detected */ +#define V4L2_IN_ST_NO_ACCESS 0x02000000 /* Conditional access denied */ +#define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */ + +/* + * V I D E O O U T P U T S + */ +struct v4l2_output +{ + __u32 index; /* Which output */ + __u8 name[32]; /* Label */ + __u32 type; /* Type of output */ + __u32 audioset; /* Associated audios (bitfield) */ + __u32 modulator; /* Associated modulator */ + v4l2_std_id std; + __u32 reserved[4]; +}; +/* Values for the 'type' field */ +#define V4L2_OUTPUT_TYPE_MODULATOR 1 +#define V4L2_OUTPUT_TYPE_ANALOG 2 +#define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 + +/* + * C O N T R O L S + */ +struct v4l2_control +{ + __u32 id; + __s32 value; +}; + +/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */ +struct v4l2_queryctrl +{ + __u32 id; + enum v4l2_ctrl_type type; + __u8 name[32]; /* Whatever */ + __s32 minimum; /* Note signedness */ + __s32 maximum; + __s32 step; + __s32 default_value; + __u32 flags; + __u32 reserved[2]; +}; + +/* Used in the VIDIOC_QUERYMENU ioctl for querying menu items */ +struct v4l2_querymenu +{ + __u32 id; + __u32 index; + __u8 name[32]; /* Whatever */ + __u32 reserved; +}; + +/* Control flags */ +#define V4L2_CTRL_FLAG_DISABLED 0x0001 +#define V4L2_CTRL_FLAG_GRABBED 0x0002 + +/* Control IDs defined by V4L2 */ +#define V4L2_CID_BASE 0x00980900 +/* IDs reserved for driver specific controls */ +#define V4L2_CID_PRIVATE_BASE 0x08000000 + +#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0) +#define V4L2_CID_CONTRAST (V4L2_CID_BASE+1) +#define V4L2_CID_SATURATION (V4L2_CID_BASE+2) +#define V4L2_CID_HUE (V4L2_CID_BASE+3) +#define V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5) +#define V4L2_CID_AUDIO_BALANCE (V4L2_CID_BASE+6) +#define V4L2_CID_AUDIO_BASS (V4L2_CID_BASE+7) +#define V4L2_CID_AUDIO_TREBLE (V4L2_CID_BASE+8) +#define V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9) +#define V4L2_CID_AUDIO_LOUDNESS (V4L2_CID_BASE+10) +#define V4L2_CID_BLACK_LEVEL (V4L2_CID_BASE+11) +#define V4L2_CID_AUTO_WHITE_BALANCE (V4L2_CID_BASE+12) +#define V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13) +#define V4L2_CID_RED_BALANCE (V4L2_CID_BASE+14) +#define V4L2_CID_BLUE_BALANCE (V4L2_CID_BASE+15) +#define V4L2_CID_GAMMA (V4L2_CID_BASE+16) +#define V4L2_CID_WHITENESS (V4L2_CID_GAMMA) /* ? Not sure */ +#define V4L2_CID_EXPOSURE (V4L2_CID_BASE+17) +#define V4L2_CID_AUTOGAIN (V4L2_CID_BASE+18) +#define V4L2_CID_GAIN (V4L2_CID_BASE+19) +#define V4L2_CID_HFLIP (V4L2_CID_BASE+20) +#define V4L2_CID_VFLIP (V4L2_CID_BASE+21) +#define V4L2_CID_HCENTER (V4L2_CID_BASE+22) +#define V4L2_CID_VCENTER (V4L2_CID_BASE+23) +#define V4L2_CID_LASTP1 (V4L2_CID_BASE+24) /* last CID + 1 */ + +/* + * T U N I N G + */ +struct v4l2_tuner +{ + __u32 index; + __u8 name[32]; + enum v4l2_tuner_type type; + __u32 capability; + __u32 rangelow; + __u32 rangehigh; + __u32 rxsubchans; + __u32 audmode; + __s32 signal; + __s32 afc; + __u32 reserved[4]; +}; + +struct v4l2_modulator +{ + __u32 index; + __u8 name[32]; + __u32 capability; + __u32 rangelow; + __u32 rangehigh; + __u32 txsubchans; + __u32 reserved[4]; +}; + +/* Flags for the 'capability' field */ +#define V4L2_TUNER_CAP_LOW 0x0001 +#define V4L2_TUNER_CAP_NORM 0x0002 +#define V4L2_TUNER_CAP_STEREO 0x0010 +#define V4L2_TUNER_CAP_LANG2 0x0020 +#define V4L2_TUNER_CAP_SAP 0x0020 +#define V4L2_TUNER_CAP_LANG1 0x0040 + +/* Flags for the 'rxsubchans' field */ +#define V4L2_TUNER_SUB_MONO 0x0001 +#define V4L2_TUNER_SUB_STEREO 0x0002 +#define V4L2_TUNER_SUB_LANG2 0x0004 +#define V4L2_TUNER_SUB_SAP 0x0004 +#define V4L2_TUNER_SUB_LANG1 0x0008 + +/* Values for the 'audmode' field */ +#define V4L2_TUNER_MODE_MONO 0x0000 +#define V4L2_TUNER_MODE_STEREO 0x0001 +#define V4L2_TUNER_MODE_LANG2 0x0002 +#define V4L2_TUNER_MODE_SAP 0x0002 +#define V4L2_TUNER_MODE_LANG1 0x0003 + +struct v4l2_frequency +{ + __u32 tuner; + enum v4l2_tuner_type type; + __u32 frequency; + __u32 reserved[8]; +}; + +/* + * A U D I O + */ +struct v4l2_audio +{ + __u32 index; + __u8 name[32]; + __u32 capability; + __u32 mode; + __u32 reserved[2]; +}; +/* Flags for the 'capability' field */ +#define V4L2_AUDCAP_STEREO 0x00001 +#define V4L2_AUDCAP_AVL 0x00002 + +/* Flags for the 'mode' field */ +#define V4L2_AUDMODE_AVL 0x00001 + +struct v4l2_audioout +{ + __u32 index; + __u8 name[32]; + __u32 capability; + __u32 mode; + __u32 reserved[2]; +}; + +/* + * D A T A S E R V I C E S ( V B I ) + * + * Data services API by Michael Schimek + */ + +struct v4l2_vbi_format +{ + __u32 sampling_rate; /* in 1 Hz */ + __u32 offset; + __u32 samples_per_line; + __u32 sample_format; /* V4L2_PIX_FMT_* */ + __s32 start[2]; + __u32 count[2]; + __u32 flags; /* V4L2_VBI_* */ + __u32 reserved[2]; /* must be zero */ +}; + +/* VBI flags */ +#define V4L2_VBI_UNSYNC (1<< 0) +#define V4L2_VBI_INTERLACED (1<< 1) + + +/* + * A G G R E G A T E S T R U C T U R E S + */ + +/* Stream data format + */ +struct v4l2_format +{ + enum v4l2_buf_type type; + union + { + struct v4l2_pix_format pix; // V4L2_BUF_TYPE_VIDEO_CAPTURE + struct v4l2_window win; // V4L2_BUF_TYPE_VIDEO_OVERLAY + struct v4l2_vbi_format vbi; // V4L2_BUF_TYPE_VBI_CAPTURE + __u8 raw_data[200]; // user-defined + } fmt; +}; + + +/* Stream type-dependent parameters + */ +struct v4l2_streamparm +{ + enum v4l2_buf_type type; + union + { + struct v4l2_captureparm capture; + struct v4l2_outputparm output; + __u8 raw_data[200]; /* user-defined */ + } parm; +}; + + + +/* + * I O C T L C O D E S F O R V I D E O D E V I C E S + * + */ +#define VIDIOC_QUERYCAP _IOR ('V', 0, struct v4l2_capability) +#define VIDIOC_RESERVED _IO ('V', 1) +#define VIDIOC_ENUM_FMT _IOWR ('V', 2, struct v4l2_fmtdesc) +#define VIDIOC_G_FMT _IOWR ('V', 4, struct v4l2_format) +#define VIDIOC_S_FMT _IOWR ('V', 5, struct v4l2_format) +#if 0 +#define VIDIOC_G_COMP _IOR ('V', 6, struct v4l2_compression) +#define VIDIOC_S_COMP _IOW ('V', 7, struct v4l2_compression) +#endif +#define VIDIOC_REQBUFS _IOWR ('V', 8, struct v4l2_requestbuffers) +#define VIDIOC_QUERYBUF _IOWR ('V', 9, struct v4l2_buffer) +#define VIDIOC_G_FBUF _IOR ('V', 10, struct v4l2_framebuffer) +#define VIDIOC_S_FBUF _IOW ('V', 11, struct v4l2_framebuffer) +#define VIDIOC_OVERLAY _IOWR ('V', 14, int) +#define VIDIOC_QBUF _IOWR ('V', 15, struct v4l2_buffer) +#define VIDIOC_DQBUF _IOWR ('V', 17, struct v4l2_buffer) +#define VIDIOC_STREAMON _IOW ('V', 18, int) +#define VIDIOC_STREAMOFF _IOW ('V', 19, int) +#define VIDIOC_G_PARM _IOWR ('V', 21, struct v4l2_streamparm) +#define VIDIOC_S_PARM _IOW ('V', 22, struct v4l2_streamparm) +#define VIDIOC_G_STD _IOR ('V', 23, v4l2_std_id) +#define VIDIOC_S_STD _IOW ('V', 24, v4l2_std_id) +#define VIDIOC_ENUMSTD _IOWR ('V', 25, struct v4l2_standard) +#define VIDIOC_ENUMINPUT _IOWR ('V', 26, struct v4l2_input) +#define VIDIOC_G_CTRL _IOWR ('V', 27, struct v4l2_control) +#define VIDIOC_S_CTRL _IOW ('V', 28, struct v4l2_control) +#define VIDIOC_G_TUNER _IOWR ('V', 29, struct v4l2_tuner) +#define VIDIOC_S_TUNER _IOW ('V', 30, struct v4l2_tuner) +#define VIDIOC_G_AUDIO _IOWR ('V', 33, struct v4l2_audio) +#define VIDIOC_S_AUDIO _IOW ('V', 34, struct v4l2_audio) +#define VIDIOC_QUERYCTRL _IOWR ('V', 36, struct v4l2_queryctrl) +#define VIDIOC_QUERYMENU _IOWR ('V', 37, struct v4l2_querymenu) +#define VIDIOC_G_INPUT _IOR ('V', 38, int) +#define VIDIOC_S_INPUT _IOWR ('V', 39, int) +#define VIDIOC_G_OUTPUT _IOR ('V', 46, int) +#define VIDIOC_S_OUTPUT _IOWR ('V', 47, int) +#define VIDIOC_ENUMOUTPUT _IOWR ('V', 48, struct v4l2_output) +#define VIDIOC_G_AUDOUT _IOWR ('V', 49, struct v4l2_audioout) +#define VIDIOC_S_AUDOUT _IOW ('V', 50, struct v4l2_audioout) +#define VIDIOC_G_MODULATOR _IOWR ('V', 54, struct v4l2_modulator) +#define VIDIOC_S_MODULATOR _IOW ('V', 55, struct v4l2_modulator) +#define VIDIOC_G_FREQUENCY _IOWR ('V', 56, struct v4l2_frequency) +#define VIDIOC_S_FREQUENCY _IOW ('V', 57, struct v4l2_frequency) +#define VIDIOC_CROPCAP _IOR ('V', 58, struct v4l2_cropcap) +#define VIDIOC_G_CROP _IOWR ('V', 59, struct v4l2_crop) +#define VIDIOC_S_CROP _IOW ('V', 60, struct v4l2_crop) +#define VIDIOC_G_JPEGCOMP _IOR ('V', 61, struct v4l2_jpegcompression) +#define VIDIOC_S_JPEGCOMP _IOW ('V', 62, struct v4l2_jpegcompression) +#define VIDIOC_QUERYSTD _IOR ('V', 63, v4l2_std_id) +#define VIDIOC_TRY_FMT _IOWR ('V', 63, struct v4l2_format) + +#define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */ + + +#ifdef __KERNEL__ +/* + * + * V 4 L 2 D R I V E R H E L P E R A P I + * + * Some commonly needed functions for drivers (v4l2-common.o module) + */ +#include + +/* Video standard functions */ +extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs); +extern int v4l2_video_std_construct(struct v4l2_standard *vs, + int id, char *name); + +/* Compatibility layer interface */ +typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg); +int v4l_compat_translate_ioctl(struct inode *inode, struct file *file, + int cmd, void *arg, v4l2_kioctl driver_ioctl); + +/* names for fancy debug output */ +extern char *v4l2_field_names[]; +extern char *v4l2_type_names[]; +extern char *v4l2_ioctl_names[]; + +#endif /* __KERNEL__ */ +#endif /* __LINUX_VIDEODEV2_H */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff -Nru a/include/linux/xattr_acl.h b/include/linux/xattr_acl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/xattr_acl.h Mon Nov 4 14:31:03 2002 @@ -0,0 +1,50 @@ +/* + File: linux/xattr_acl.h + + (extended attribute representation of access control lists) + + (C) 2000 Andreas Gruenbacher, +*/ + +#ifndef _LINUX_XATTR_ACL_H +#define _LINUX_XATTR_ACL_H + +#include + +#define XATTR_NAME_ACL_ACCESS "system.posix_acl_access" +#define XATTR_NAME_ACL_DEFAULT "system.posix_acl_default" + +#define XATTR_ACL_VERSION 0x0002 + +typedef struct { + __u16 e_tag; + __u16 e_perm; + __u32 e_id; +} xattr_acl_entry; + +typedef struct { + __u32 a_version; + xattr_acl_entry a_entries[0]; +} xattr_acl_header; + +static inline size_t xattr_acl_size(int count) +{ + return sizeof(xattr_acl_header) + count * sizeof(xattr_acl_entry); +} + +static inline int xattr_acl_count(size_t size) +{ + if (size < sizeof(xattr_acl_header)) + return -1; + size -= sizeof(xattr_acl_header); + if (size % sizeof(xattr_acl_entry)) + return -1; + return size / sizeof(xattr_acl_entry); +} + +struct posix_acl * posix_acl_from_xattr(const void *value, size_t size); +int posix_acl_to_xattr(const struct posix_acl *acl, void *buffer, size_t size); + + + +#endif /* _LINUX_XATTR_ACL_H */ diff -Nru a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h --- a/include/net/bluetooth/bluetooth.h Mon Nov 4 14:31:01 2002 +++ b/include/net/bluetooth/bluetooth.h Mon Nov 4 14:31:01 2002 @@ -53,7 +53,7 @@ #define SOL_SCO 17 #define SOL_RFCOMM 18 -#define BT_INFO(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg) +#define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg) #define BT_DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n" , __FUNCTION__ , ## arg) #define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __FUNCTION__ , ## arg) @@ -62,6 +62,8 @@ #else #define BT_DMP(D...) #endif + +extern struct proc_dir_entry *proc_bt; /* Connection and socket states */ enum { diff -Nru a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h --- a/include/net/bluetooth/hci_core.h Mon Nov 4 14:31:02 2002 +++ b/include/net/bluetooth/hci_core.h Mon Nov 4 14:31:02 2002 @@ -29,6 +29,7 @@ #ifndef __HCI_CORE_H #define __HCI_CORE_H +#include #include /* HCI upper protocols */ @@ -37,6 +38,8 @@ #define HCI_INIT_TIMEOUT (HZ * 10) +extern struct proc_dir_entry *proc_bt_hci; + /* HCI Core structures */ struct inquiry_entry { @@ -111,6 +114,10 @@ atomic_t promisc; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *proc; +#endif + int (*open)(struct hci_dev *hdev); int (*close)(struct hci_dev *hdev); int (*flush)(struct hci_dev *hdev); @@ -148,8 +155,8 @@ }; extern struct hci_proto *hci_proto[]; -extern struct list_head hdev_list; -extern rwlock_t hdev_list_lock; +extern struct list_head hci_dev_list; +extern rwlock_t hci_dev_list_lock; /* ----- Inquiry cache ----- */ #define INQUIRY_CACHE_AGE_MAX (HZ*30) // 30 seconds @@ -344,6 +351,9 @@ hci_sched_rx(hdev); return 0; } + +int hci_dev_proc_init(struct hci_dev *hdev); +void hci_dev_proc_cleanup(struct hci_dev *hdev); /* ----- LMP capabilities ----- */ #define lmp_rswitch_capable(dev) (dev->features[0] & LMP_RSWITCH) diff -Nru a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h --- a/include/net/bluetooth/rfcomm.h Mon Nov 4 14:31:01 2002 +++ b/include/net/bluetooth/rfcomm.h Mon Nov 4 14:31:01 2002 @@ -345,4 +345,6 @@ int rfcomm_init_ttys(void); void rfcomm_cleanup_ttys(void); +extern struct proc_dir_entry *proc_bt_rfcomm; + #endif /* __RFCOMM_H */ diff -Nru a/include/net/sock.h b/include/net/sock.h --- a/include/net/sock.h Mon Nov 4 14:31:02 2002 +++ b/include/net/sock.h Mon Nov 4 14:31:02 2002 @@ -52,9 +52,6 @@ #include #include #include -#include -#include -#include /* * This structure really needs to be cleaned up. @@ -769,13 +766,8 @@ static inline void sk_wake_async(struct sock *sk, int how, int band) { - if (sk->socket) { - if (sk->socket->file) - file_send_notify(sk->socket->file, ion_band_table[band - POLL_IN], - poll_band_table[band - POLL_IN]); - if (sk->socket->fasync_list) - sock_wake_async(sk->socket, how, band); - } + if (sk->socket && sk->socket->fasync_list) + sock_wake_async(sk->socket, how, band); } #define SOCK_MIN_SNDBUF 2048 diff -Nru a/include/rxrpc/call.h b/include/rxrpc/call.h --- a/include/rxrpc/call.h Mon Nov 4 14:31:01 2002 +++ b/include/rxrpc/call.h Mon Nov 4 14:31:01 2002 @@ -153,7 +153,7 @@ (CALL)->app_scr_alloc += (SIZE); \ if ((SIZE)>RXRPC_CALL_SCRATCH_SIZE || \ (size_t)((CALL)->app_scr_alloc - (u8*)(CALL)) > RXRPC_CALL_SCRATCH_SIZE) { \ - printk("rxrpc_call_alloc_scratch(%p,%u)\n",(CALL),(SIZE)); \ + printk("rxrpc_call_alloc_scratch(%p,%Zu)\n",(CALL),(size_t)(SIZE)); \ BUG(); \ } \ ptr; \ @@ -167,7 +167,7 @@ (CALL)->app_scr_alloc += size; \ if (size>RXRPC_CALL_SCRATCH_SIZE || \ (size_t)((CALL)->app_scr_alloc - (u8*)(CALL)) > RXRPC_CALL_SCRATCH_SIZE) { \ - printk("rxrpc_call_alloc_scratch(%p,%u)\n",(CALL),size); \ + printk("rxrpc_call_alloc_scratch(%p,%Zu)\n",(CALL),size); \ BUG(); \ } \ ptr; \ diff -Nru a/include/rxrpc/peer.h b/include/rxrpc/peer.h --- a/include/rxrpc/peer.h Mon Nov 4 14:31:02 2002 +++ b/include/rxrpc/peer.h Mon Nov 4 14:31:02 2002 @@ -57,8 +57,8 @@ /* calculated RTT cache */ #define RXRPC_RTT_CACHE_SIZE 32 suseconds_t rtt; /* current RTT estimate (in uS) */ - unsigned short rtt_point; /* next entry at which to insert */ - unsigned short rtt_usage; /* amount of cache actually used */ + unsigned rtt_point; /* next entry at which to insert */ + unsigned rtt_usage; /* amount of cache actually used */ suseconds_t rtt_cache[RXRPC_RTT_CACHE_SIZE]; /* calculated RTT cache */ }; diff -Nru a/include/scsi/scsi.h b/include/scsi/scsi.h --- a/include/scsi/scsi.h Mon Nov 4 14:31:03 2002 +++ b/include/scsi/scsi.h Mon Nov 4 14:31:03 2002 @@ -15,6 +15,13 @@ */ /* + * SCSI command lengths + */ + +extern const unsigned char scsi_command_size[8]; +#define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7] + +/* * SCSI opcodes */ diff -Nru a/init/Makefile b/init/Makefile --- a/init/Makefile Mon Nov 4 14:31:01 2002 +++ b/init/Makefile Mon Nov 4 14:31:01 2002 @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -obj-y := main.o version.o do_mounts.o +obj-y := main.o version.o do_mounts.o initramfs.o # files to be removed upon make clean clean-files := ../include/linux/compile.h diff -Nru a/init/do_mounts.c b/init/do_mounts.c --- a/init/do_mounts.c Mon Nov 4 14:31:01 2002 +++ b/init/do_mounts.c Mon Nov 4 14:31:01 2002 @@ -101,7 +101,7 @@ /* read device number from .../dev */ - sprintf(path, "/sys/bus/block/devices/%s/dev", name); + sprintf(path, "/sys/block/%s/dev", name); fd = open(path, 0, 0); if (fd < 0) goto fail; @@ -119,7 +119,7 @@ return res; /* otherwise read range from .../range */ - sprintf(path, "/sys/bus/block/devices/%s/range", name); + sprintf(path, "/sys/block/%s/range", name); fd = open(path, 0, 0); if (fd < 0) goto fail; @@ -166,7 +166,7 @@ int part; sys_mkdir("/sys", 0700); - if (sys_mount("driverfs", "/sys", "driverfs", 0, NULL) < 0) + if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) < 0) goto out; if (strncmp(name, "/dev/", 5) != 0) { @@ -748,9 +748,7 @@ mount_initrd = 0; real_root_dev = ROOT_DEV; #endif - sys_mkdir("/dev", 0700); - sys_mkdir("/root", 0700); - sys_mknod("/dev/console", S_IFCHR|0600, MKDEV(TTYAUX_MAJOR, 1)); + #ifdef CONFIG_DEVFS_FS sys_mount("devfs", "/dev", "devfs", 0, NULL); do_devfs = 1; diff -Nru a/init/initramfs.c b/init/initramfs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/init/initramfs.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,462 @@ +#define __KERNEL_SYSCALLS__ +#include +#include +#include +#include +#include +#include +#include + +static void __init error(char *x) +{ + panic("populate_root: %s\n", x); +} + +static void __init *malloc(int size) +{ + return kmalloc(size, GFP_KERNEL); +} + +static void __init free(void *where) +{ + kfree(where); +} + +asmlinkage long sys_mkdir(char *name, int mode); +asmlinkage long sys_mknod(char *name, int mode, dev_t dev); +asmlinkage long sys_symlink(char *old, char *new); +asmlinkage long sys_link(char *old, char *new); +asmlinkage long sys_write(int fd, const char *buf, size_t size); +asmlinkage long sys_chown(char *name, uid_t uid, gid_t gid); +asmlinkage long sys_lchown(char *name, uid_t uid, gid_t gid); +asmlinkage long sys_fchown(int fd, uid_t uid, gid_t gid); +asmlinkage long sys_chmod(char *name, mode_t mode); +asmlinkage long sys_fchmod(int fd, mode_t mode); + +/* link hash */ + +static struct hash { + int ino, minor, major; + struct hash *next; + char *name; +} *head[32]; + +static inline int hash(int major, int minor, int ino) +{ + unsigned long tmp = ino + minor + (major << 3); + tmp += tmp >> 5; + return tmp & 31; +} + +static char __init *find_link(int major, int minor, int ino, char *name) +{ + struct hash **p, *q; + for (p = head + hash(major, minor, ino); *p; p = &(*p)->next) { + if ((*p)->ino != ino) + continue; + if ((*p)->minor != minor) + continue; + if ((*p)->major != major) + continue; + return (*p)->name; + } + q = (struct hash *)malloc(sizeof(struct hash)); + if (!q) + error("can't allocate link hash entry"); + q->ino = ino; + q->minor = minor; + q->major = major; + q->name = name; + q->next = NULL; + *p = q; + return NULL; +} + +static void __init free_hash(void) +{ + struct hash **p, *q; + for (p = head; p < head + 32; p++) { + while (*p) { + q = *p; + *p = q->next; + free(q); + } + } +} + +/* cpio header parsing */ + +static __initdata unsigned long ino, major, minor, nlink; +static __initdata mode_t mode; +static __initdata unsigned long body_len, name_len; +static __initdata uid_t uid; +static __initdata gid_t gid; +static __initdata dev_t rdev; + +static void __init parse_header(char *s) +{ + unsigned long parsed[12]; + char buf[9]; + int i; + + buf[8] = '\0'; + for (i = 0, s += 6; i < 12; i++, s += 8) { + memcpy(buf, s, 8); + parsed[i] = simple_strtoul(buf, NULL, 16); + } + ino = parsed[0]; + mode = parsed[1]; + uid = parsed[2]; + gid = parsed[3]; + nlink = parsed[4]; + body_len = parsed[6]; + major = parsed[7]; + minor = parsed[8]; + rdev = MKDEV(parsed[9], parsed[10]); + name_len = parsed[11]; +} + +/* FSM */ + +enum state { + Start, + Collect, + GotHeader, + SkipIt, + GotName, + CopyFile, + GotSymlink, + Reset +} state, next_state; + +char *victim; +unsigned count; +loff_t this_header, next_header; + +static inline void eat(unsigned n) +{ + victim += n; + this_header += n; + count -= n; +} + +#define N_ALIGN(len) ((((len) + 1) & ~3) + 2) + +static __initdata char *collected; +static __initdata int remains; +static __initdata char *collect; + +static void __init read_into(char *buf, unsigned size, enum state next) +{ + if (count >= size) { + collected = victim; + eat(size); + state = next; + } else { + collect = collected = buf; + remains = size; + next_state = next; + state = Collect; + } +} + +static __initdata char *header_buf, *symlink_buf, *name_buf; + +static int __init do_start(void) +{ + read_into(header_buf, 110, GotHeader); + return 0; +} + +static int __init do_collect(void) +{ + unsigned n = remains; + if (count < n) + n = count; + memcpy(collect, victim, n); + eat(n); + collect += n; + if (remains -= n) + return 1; + state = next_state; + return 0; +} + +static int __init do_header(void) +{ + parse_header(collected); + next_header = this_header + N_ALIGN(name_len) + body_len; + next_header = (next_header + 3) & ~3; + if (name_len <= 0 || name_len > PATH_MAX) + state = SkipIt; + else if (S_ISLNK(mode)) { + if (body_len > PATH_MAX) + state = SkipIt; + else { + collect = collected = symlink_buf; + remains = N_ALIGN(name_len) + body_len; + next_state = GotSymlink; + state = Collect; + } + } else if (body_len && !S_ISREG(mode)) + state = SkipIt; + else + read_into(name_buf, N_ALIGN(name_len), GotName); + return 0; +} + +static int __init do_skip(void) +{ + if (this_header + count <= next_header) { + eat(count); + return 1; + } else { + eat(next_header - this_header); + state = next_state; + return 0; + } +} + +static int __init do_reset(void) +{ + while(count && *victim == '\0') + eat(1); + if (count && (this_header & 3)) + error("broken padding"); + return 1; +} + +static int __init maybe_link(void) +{ + if (nlink >= 2) { + char *old = find_link(major, minor, ino, collected); + if (old) + return (sys_link(old, collected) < 0) ? -1 : 1; + } + return 0; +} + +static __initdata int wfd; + +static int __init do_name(void) +{ + state = SkipIt; + next_state = Start; + if (strcmp(collected, "TRAILER!!!") == 0) { + free_hash(); + next_state = Reset; + return 0; + } + printk(KERN_INFO "-> %s\n", collected); + if (S_ISREG(mode)) { + if (maybe_link() >= 0) { + wfd = sys_open(collected, O_WRONLY|O_CREAT, mode); + if (wfd >= 0) { + sys_fchown(wfd, uid, gid); + sys_fchmod(wfd, mode); + state = CopyFile; + } + } + } else if (S_ISDIR(mode)) { + sys_mkdir(collected, mode); + sys_chown(collected, uid, gid); + } else if (S_ISBLK(mode) || S_ISCHR(mode) || + S_ISFIFO(mode) || S_ISSOCK(mode)) { + if (maybe_link() == 0) { + sys_mknod(collected, mode, rdev); + sys_chown(collected, uid, gid); + } + } else + panic("populate_root: bogus mode: %o\n", mode); + return 0; +} + +static int __init do_copy(void) +{ + if (count >= body_len) { + sys_write(wfd, victim, body_len); + sys_close(wfd); + eat(body_len); + state = SkipIt; + return 0; + } else { + sys_write(wfd, victim, count); + body_len -= count; + eat(count); + return 1; + } +} + +static int __init do_symlink(void) +{ + collected[N_ALIGN(name_len) + body_len] = '\0'; + sys_symlink(collected + N_ALIGN(name_len), collected); + sys_lchown(collected, uid, gid); + state = SkipIt; + next_state = Start; + return 0; +} + +static __initdata int (*actions[])(void) = { + [Start] do_start, + [Collect] do_collect, + [GotHeader] do_header, + [SkipIt] do_skip, + [GotName] do_name, + [CopyFile] do_copy, + [GotSymlink] do_symlink, + [Reset] do_reset, +}; + +static int __init write_buffer(char *buf, unsigned len) +{ + count = len; + victim = buf; + + while (!actions[state]()) + ; + return len - count; +} + +static void __init flush_buffer(char *buf, unsigned len) +{ + int written; + while ((written = write_buffer(buf, len)) < len) { + char c = buf[written]; + if (c == '0') { + buf += written; + len -= written; + state = Start; + continue; + } else + error("junk in compressed archive"); + } +} + +/* + * gzip declarations + */ + +#define OF(args) args + +#ifndef memzero +#define memzero(s, n) memset ((s), 0, (n)) +#endif + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define WSIZE 0x8000 /* window size--must be a power of two, and */ + /* at least 32K for zip's deflate method */ + +static uch *inbuf; +static uch *window; + +static unsigned insize; /* valid bytes in inbuf */ +static unsigned inptr; /* index of next byte to be processed in inbuf */ +static unsigned outcnt; /* bytes in output buffer */ +static long bytes_out; + +#define get_byte() (inptr < insize ? inbuf[inptr++] : -1) + +/* Diagnostic functions (stubbed out) */ +#define Assert(cond,msg) +#define Trace(x) +#define Tracev(x) +#define Tracevv(x) +#define Tracec(c,x) +#define Tracecv(c,x) + +#define STATIC static + +static void flush_window(void); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +#include "../lib/inflate.c" + +static void __init gzip_mark(void **ptr) +{ +} + +static void __init gzip_release(void **ptr) +{ +} + +/* =========================================================================== + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ +static void __init flush_window(void) +{ + ulg c = crc; /* temporary variable */ + unsigned n; + uch *in, ch; + + flush_buffer(window, outcnt); + in = window; + for (n = 0; n < outcnt; n++) { + ch = *in++; + c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + outcnt = 0; +} + +static void __init unpack_to_rootfs(char *buf, unsigned len) +{ + int written; + header_buf = malloc(110); + symlink_buf = malloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1); + name_buf = malloc(N_ALIGN(PATH_MAX)); + window = malloc(WSIZE); + if (!window || !header_buf || !symlink_buf || !name_buf) + error("can't allocate buffers"); + state = Start; + this_header = 0; + while (len) { + loff_t saved_offset = this_header; + if (*buf == '0' && !(this_header & 3)) { + state = Start; + written = write_buffer(buf, len); + buf += written; + len -= written; + continue; + } else if (!*buf) { + buf++; + len--; + this_header++; + continue; + } + this_header = 0; + insize = len; + inbuf = buf; + inptr = 0; + outcnt = 0; /* bytes in output buffer */ + bytes_out = 0; + crc = (ulg)0xffffffffL; /* shift register contents */ + makecrc(); + if (gunzip()) + error("ungzip failed"); + if (state != Reset) + error("junk in gzipped archive"); + this_header = saved_offset + inptr; + buf += inptr; + len -= inptr; + } + free(window); + free(name_buf); + free(symlink_buf); + free(header_buf); +} + +extern char __initramfs_start, __initramfs_end; + +void __init populate_rootfs(void) +{ + unpack_to_rootfs(&__initramfs_start, + &__initramfs_end - &__initramfs_start); +} diff -Nru a/init/main.c b/init/main.c --- a/init/main.c Mon Nov 4 14:31:01 2002 +++ b/init/main.c Mon Nov 4 14:31:01 2002 @@ -72,6 +72,7 @@ extern void pte_chain_init(void); extern void radix_tree_init(void); extern void free_initmem(void); +extern void populate_rootfs(void); #ifdef CONFIG_TC extern void tc_init(void); @@ -101,7 +102,7 @@ char *execute_command; /* Setup configured maximum number of CPUs to activate */ -static unsigned int max_cpus = UINT_MAX; +static unsigned int max_cpus = NR_CPUS; /* * Setup routine for controlling SMP activation @@ -433,6 +434,7 @@ vfs_caches_init(num_physpages); radix_tree_init(); signals_init(); + populate_rootfs(); #ifdef CONFIG_PROC_FS proc_root_init(); #endif diff -Nru a/ipc/msg.c b/ipc/msg.c --- a/ipc/msg.c Mon Nov 4 14:31:00 2002 +++ b/ipc/msg.c Mon Nov 4 14:31:00 2002 @@ -65,7 +65,7 @@ static struct ipc_ids msg_ids; #define msg_lock(id) ((struct msg_queue*)ipc_lock(&msg_ids,id)) -#define msg_unlock(id) ipc_unlock(&msg_ids,id) +#define msg_unlock(msq) ipc_unlock(&(msq)->q_perm) #define msg_rmid(id) ((struct msg_queue*)ipc_rmid(&msg_ids,id)) #define msg_checkid(msq, msgid) \ ipc_checkid(&msg_ids,&msq->q_perm,msgid) @@ -93,7 +93,7 @@ int retval; struct msg_queue *msq; - msq = (struct msg_queue *) kmalloc (sizeof (*msq), GFP_KERNEL); + msq = ipc_rcu_alloc(sizeof(*msq)); if (!msq) return -ENOMEM; @@ -103,14 +103,14 @@ msq->q_perm.security = NULL; retval = security_ops->msg_queue_alloc_security(msq); if (retval) { - kfree(msq); + ipc_rcu_free(msq, sizeof(*msq)); return retval; } id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni); if(id == -1) { security_ops->msg_queue_free_security(msq); - kfree(msq); + ipc_rcu_free(msq, sizeof(*msq)); return -ENOSPC; } @@ -122,7 +122,7 @@ INIT_LIST_HEAD(&msq->q_messages); INIT_LIST_HEAD(&msq->q_receivers); INIT_LIST_HEAD(&msq->q_senders); - msg_unlock(id); + msg_unlock(msq); return msg_buildid(id,msq->q_perm.seq); } @@ -271,7 +271,7 @@ expunge_all(msq,-EIDRM); ss_wakeup(&msq->q_senders,1); - msg_unlock(id); + msg_unlock(msq); tmp = msq->q_messages.next; while(tmp != &msq->q_messages) { @@ -282,7 +282,7 @@ } atomic_sub(msq->q_cbytes, &msg_bytes); security_ops->msg_queue_free_security(msq); - kfree(msq); + ipc_rcu_free(msq, sizeof(struct msg_queue)); } asmlinkage long sys_msgget (key_t key, int msgflg) @@ -308,7 +308,7 @@ ret = -EACCES; else ret = msg_buildid(id, msq->q_perm.seq); - msg_unlock(id); + msg_unlock(msq); } up(&msg_ids.sem); return ret; @@ -488,7 +488,7 @@ tbuf.msg_qbytes = msq->q_qbytes; tbuf.msg_lspid = msq->q_lspid; tbuf.msg_lrpid = msq->q_lrpid; - msg_unlock(msqid); + msg_unlock(msq); if (copy_msqid_to_user(buf, &tbuf, version)) return -EFAULT; return success_return; @@ -541,7 +541,7 @@ * due to a larger queue size. */ ss_wakeup(&msq->q_senders,0); - msg_unlock(msqid); + msg_unlock(msq); break; } case IPC_RMID: @@ -553,10 +553,10 @@ up(&msg_ids.sem); return err; out_unlock_up: - msg_unlock(msqid); + msg_unlock(msq); goto out_up; out_unlock: - msg_unlock(msqid); + msg_unlock(msq); return err; } @@ -651,7 +651,7 @@ goto out_unlock_free; } ss_add(msq, &s); - msg_unlock(msqid); + msg_unlock(msq); schedule(); current->state= TASK_RUNNING; @@ -684,7 +684,7 @@ msg = NULL; out_unlock_free: - msg_unlock(msqid); + msg_unlock(msq); out_free: if(msg!=NULL) free_msg(msg); @@ -766,7 +766,7 @@ atomic_sub(msg->m_ts,&msg_bytes); atomic_dec(&msg_hdrs); ss_wakeup(&msq->q_senders,0); - msg_unlock(msqid); + msg_unlock(msq); out_success: msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz; if (put_user (msg->m_type, &msgp->mtype) || @@ -777,7 +777,6 @@ return msgsz; } else { - struct msg_queue *t; /* no message waiting. Prepare for pipelined * receive. */ @@ -795,7 +794,7 @@ msr_d.r_maxsize = msgsz; msr_d.r_msg = ERR_PTR(-EAGAIN); current->state = TASK_INTERRUPTIBLE; - msg_unlock(msqid); + msg_unlock(msq); schedule(); current->state = TASK_RUNNING; @@ -804,21 +803,19 @@ if(!IS_ERR(msg)) goto out_success; - t = msg_lock(msqid); - if(t==NULL) - msqid=-1; + msq = msg_lock(msqid); msg = (struct msg_msg*)msr_d.r_msg; if(!IS_ERR(msg)) { /* our message arived while we waited for * the spinlock. Process it. */ - if(msqid!=-1) - msg_unlock(msqid); + if(msq) + msg_unlock(msq); goto out_success; } err = PTR_ERR(msg); if(err == -EAGAIN) { - if(msqid==-1) + if(!msq) BUG(); list_del(&msr_d.r_list); if (signal_pending(current)) @@ -828,8 +825,8 @@ } } out_unlock: - if(msqid!=-1) - msg_unlock(msqid); + if(msq) + msg_unlock(msq); return err; } @@ -862,7 +859,7 @@ msq->q_stime, msq->q_rtime, msq->q_ctime); - msg_unlock(i); + msg_unlock(msq); pos += len; if(pos < offset) { diff -Nru a/ipc/sem.c b/ipc/sem.c --- a/ipc/sem.c Mon Nov 4 14:31:01 2002 +++ b/ipc/sem.c Mon Nov 4 14:31:01 2002 @@ -69,7 +69,7 @@ #define sem_lock(id) ((struct sem_array*)ipc_lock(&sem_ids,id)) -#define sem_unlock(id) ipc_unlock(&sem_ids,id) +#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm) #define sem_rmid(id) ((struct sem_array*)ipc_rmid(&sem_ids,id)) #define sem_checkid(sma, semid) \ ipc_checkid(&sem_ids,&sma->sem_perm,semid) @@ -126,7 +126,7 @@ return -ENOSPC; size = sizeof (*sma) + nsems * sizeof (struct sem); - sma = (struct sem_array *) ipc_alloc(size); + sma = ipc_rcu_alloc(size); if (!sma) { return -ENOMEM; } @@ -138,14 +138,14 @@ sma->sem_perm.security = NULL; retval = security_ops->sem_alloc_security(sma); if (retval) { - ipc_free(sma, size); + ipc_rcu_free(sma, size); return retval; } id = ipc_addid(&sem_ids, &sma->sem_perm, sc_semmni); if(id == -1) { security_ops->sem_free_security(sma); - ipc_free(sma, size); + ipc_rcu_free(sma, size); return -ENOSPC; } used_sems += nsems; @@ -156,7 +156,7 @@ /* sma->undo = NULL; */ sma->sem_nsems = nsems; sma->sem_ctime = CURRENT_TIME; - sem_unlock(id); + sem_unlock(sma); return sem_buildid(id, sma->sem_perm.seq); } @@ -189,7 +189,7 @@ err = -EACCES; else err = sem_buildid(id, sma->sem_perm.seq); - sem_unlock(id); + sem_unlock(sma); } up(&sem_ids.sem); @@ -205,12 +205,12 @@ if(smanew==NULL) return -EIDRM; if(smanew != sma || sem_checkid(sma,semid) || sma->sem_nsems != nsems) { - sem_unlock(semid); + sem_unlock(smanew); return -EIDRM; } if (ipcperms(&sma->sem_perm, flg)) { - sem_unlock(semid); + sem_unlock(smanew); return -EACCES; } return 0; @@ -423,12 +423,12 @@ q->prev = NULL; wake_up_process(q->sleeper); /* doesn't sleep */ } - sem_unlock(id); + sem_unlock(sma); used_sems -= sma->sem_nsems; size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem); security_ops->sem_free_security(sma); - ipc_free(sma, size); + ipc_rcu_free(sma, size); } static unsigned long copy_semid_to_user(void *buf, struct semid64_ds *in, int version) @@ -456,6 +456,7 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semun arg) { int err = -EINVAL; + struct sem_array *sma; switch(cmd) { case IPC_INFO: @@ -489,7 +490,6 @@ } case SEM_STAT: { - struct sem_array *sma; struct semid64_ds tbuf; int id; @@ -511,7 +511,7 @@ tbuf.sem_otime = sma->sem_otime; tbuf.sem_ctime = sma->sem_ctime; tbuf.sem_nsems = sma->sem_nsems; - sem_unlock(semid); + sem_unlock(sma); if (copy_semid_to_user (arg.buf, &tbuf, version)) return -EFAULT; return id; @@ -521,7 +521,7 @@ } return err; out_unlock: - sem_unlock(semid); + sem_unlock(sma); return err; } @@ -555,7 +555,7 @@ int i; if(nsems > SEMMSL_FAST) { - sem_unlock(semid); + sem_unlock(sma); sem_io = ipc_alloc(sizeof(ushort)*nsems); if(sem_io == NULL) return -ENOMEM; @@ -566,7 +566,7 @@ for (i = 0; i < sma->sem_nsems; i++) sem_io[i] = sma->sem_base[i].semval; - sem_unlock(semid); + sem_unlock(sma); err = 0; if(copy_to_user(array, sem_io, nsems*sizeof(ushort))) err = -EFAULT; @@ -577,7 +577,7 @@ int i; struct sem_undo *un; - sem_unlock(semid); + sem_unlock(sma); if(nsems > SEMMSL_FAST) { sem_io = ipc_alloc(sizeof(ushort)*nsems); @@ -619,7 +619,7 @@ tbuf.sem_otime = sma->sem_otime; tbuf.sem_ctime = sma->sem_ctime; tbuf.sem_nsems = sma->sem_nsems; - sem_unlock(semid); + sem_unlock(sma); if (copy_semid_to_user (arg.buf, &tbuf, version)) return -EFAULT; return 0; @@ -665,7 +665,7 @@ } } out_unlock: - sem_unlock(semid); + sem_unlock(sma); out_free: if(sem_io != fast_sem_io) ipc_free(sem_io, sizeof(ushort)*nsems); @@ -750,18 +750,18 @@ ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | (setbuf.mode & S_IRWXUGO); sma->sem_ctime = CURRENT_TIME; - sem_unlock(semid); + sem_unlock(sma); err = 0; break; default: - sem_unlock(semid); + sem_unlock(sma); err = -EINVAL; break; } return err; out_unlock: - sem_unlock(semid); + sem_unlock(sma); return err; } @@ -914,7 +914,7 @@ saved_add_count = 0; if (current->sysvsem.undo_list != NULL) saved_add_count = current->sysvsem.undo_list->add_count; - sem_unlock(semid); + sem_unlock(sma); unlock_semundo(); error = get_undo_list(&undo_list); @@ -1052,18 +1052,17 @@ current->sysvsem.sleep_list = &queue; for (;;) { - struct sem_array* tmp; queue.status = -EINTR; queue.sleeper = current; current->state = TASK_INTERRUPTIBLE; - sem_unlock(semid); + sem_unlock(sma); unlock_semundo(); schedule(); lock_semundo(); - tmp = sem_lock(semid); - if(tmp==NULL) { + sma = sem_lock(semid); + if(sma==NULL) { if(queue.prev != NULL) BUG(); current->sysvsem.sleep_list = NULL; @@ -1098,7 +1097,7 @@ if (alter) update_queue (sma); out_unlock_semundo_free: - sem_unlock(semid); + sem_unlock(sma); out_semundo_free: unlock_semundo(); out_free: @@ -1185,7 +1184,7 @@ remove_from_queue(q->sma,q); } if(sma!=NULL) - sem_unlock(semid); + sem_unlock(sma); } undo_list = current->sysvsem.undo_list; @@ -1233,7 +1232,7 @@ /* maybe some queued-up processes were waiting for this */ update_queue(sma); next_entry: - sem_unlock(semid); + sem_unlock(sma); } __exit_semundo(current); @@ -1265,7 +1264,7 @@ sma->sem_perm.cgid, sma->sem_otime, sma->sem_ctime); - sem_unlock(i); + sem_unlock(sma); pos += len; if(pos < offset) { diff -Nru a/ipc/shm.c b/ipc/shm.c --- a/ipc/shm.c Mon Nov 4 14:31:02 2002 +++ b/ipc/shm.c Mon Nov 4 14:31:02 2002 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -37,9 +38,7 @@ static struct ipc_ids shm_ids; #define shm_lock(id) ((struct shmid_kernel*)ipc_lock(&shm_ids,id)) -#define shm_unlock(id) ipc_unlock(&shm_ids,id) -#define shm_lockall() ipc_lockall(&shm_ids) -#define shm_unlockall() ipc_unlockall(&shm_ids) +#define shm_unlock(shp) ipc_unlock(&(shp)->shm_perm) #define shm_get(id) ((struct shmid_kernel*)ipc_get(&shm_ids,id)) #define shm_buildid(id, seq) \ ipc_buildid(&shm_ids, id, seq) @@ -92,7 +91,7 @@ shp->shm_atim = CURRENT_TIME; shp->shm_lprid = current->pid; shp->shm_nattch++; - shm_unlock(id); + shm_unlock(shp); } /* This is called by fork, once for every shm attach. */ @@ -113,11 +112,12 @@ { shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT; shm_rmid (shp->id); - shm_unlock(shp->id); - shmem_lock(shp->shm_file, 0); + shm_unlock(shp); + if (!is_file_hugepages(shp->shm_file)) + shmem_lock(shp->shm_file, 0); fput (shp->shm_file); security_ops->shm_free_security(shp); - kfree (shp); + ipc_rcu_free(shp, sizeof(struct shmid_kernel)); } /* @@ -143,7 +143,7 @@ shp->shm_flags & SHM_DEST) shm_destroy (shp); else - shm_unlock(id); + shm_unlock(shp); up (&shm_ids.sem); } @@ -180,7 +180,7 @@ if (shm_tot + numpages >= shm_ctlall) return -ENOSPC; - shp = (struct shmid_kernel *) kmalloc (sizeof (*shp), GFP_USER); + shp = ipc_rcu_alloc(sizeof(*shp)); if (!shp) return -ENOMEM; @@ -190,12 +190,16 @@ shp->shm_perm.security = NULL; error = security_ops->shm_alloc_security(shp); if (error) { - kfree(shp); + ipc_rcu_free(shp, sizeof(*shp)); return error; } - sprintf (name, "SYSV%08x", key); - file = shmem_file_setup(name, size, VM_ACCOUNT); + if (shmflg & SHM_HUGETLB) + file = hugetlb_zero_setup(size); + else { + sprintf (name, "SYSV%08x", key); + file = shmem_file_setup(name, size, VM_ACCOUNT); + } error = PTR_ERR(file); if (IS_ERR(file)) goto no_file; @@ -214,16 +218,19 @@ shp->id = shm_buildid(id,shp->shm_perm.seq); shp->shm_file = file; file->f_dentry->d_inode->i_ino = shp->id; - file->f_op = &shm_file_operations; + if (shmflg & SHM_HUGETLB) + set_file_hugepages(file); + else + file->f_op = &shm_file_operations; shm_tot += numpages; - shm_unlock (id); + shm_unlock(shp); return shp->id; no_id: fput(file); no_file: security_ops->shm_free_security(shp); - kfree(shp); + ipc_rcu_free(shp, sizeof(*shp)); return error; } @@ -252,9 +259,10 @@ err = -EACCES; else err = shm_buildid(id, shp->shm_perm.seq); - shm_unlock(id); + shm_unlock(shp); } up(&shm_ids.sem); + return err; } @@ -379,8 +387,10 @@ struct shmid_kernel *shp; int err, version; - if (cmd < 0 || shmid < 0) - return -EINVAL; + if (cmd < 0 || shmid < 0) { + err = -EINVAL; + goto out; + } version = ipc_parse_version(&cmd); @@ -401,7 +411,7 @@ err= shm_ids.max_id; if(err<0) err = 0; - return err; + goto out; } case SHM_INFO: { @@ -409,19 +419,20 @@ memset(&shm_info,0,sizeof(shm_info)); down(&shm_ids.sem); - shm_lockall(); shm_info.used_ids = shm_ids.in_use; shm_get_stat (&shm_info.shm_rss, &shm_info.shm_swp); shm_info.shm_tot = shm_tot; shm_info.swap_attempts = 0; shm_info.swap_successes = 0; err = shm_ids.max_id; - shm_unlockall(); up(&shm_ids.sem); - if(copy_to_user (buf, &shm_info, sizeof(shm_info))) - return -EFAULT; + if(copy_to_user (buf, &shm_info, sizeof(shm_info))) { + err = -EFAULT; + goto out; + } - return err < 0 ? 0 : err; + err = err < 0 ? 0 : err; + goto out; } case SHM_STAT: case IPC_STAT: @@ -430,9 +441,10 @@ int result; memset(&tbuf, 0, sizeof(tbuf)); shp = shm_lock(shmid); - if(shp==NULL) - return -EINVAL; - if(cmd==SHM_STAT) { + if(shp==NULL) { + err = -EINVAL; + goto out; + } else if(cmd==SHM_STAT) { err = -EINVAL; if (shmid > shm_ids.max_id) goto out_unlock; @@ -454,10 +466,12 @@ tbuf.shm_cpid = shp->shm_cprid; tbuf.shm_lpid = shp->shm_lprid; tbuf.shm_nattch = shp->shm_nattch; - shm_unlock(shmid); + shm_unlock(shp); if(copy_shmid_to_user (buf, &tbuf, version)) - return -EFAULT; - return result; + err = -EFAULT; + else + err = result; + goto out; } case SHM_LOCK: case SHM_UNLOCK: @@ -465,24 +479,30 @@ /* Allow superuser to lock segment in memory */ /* Should the pages be faulted in here or leave it to user? */ /* need to determine interaction with current->swappable */ - if (!capable(CAP_IPC_LOCK)) - return -EPERM; + if (!capable(CAP_IPC_LOCK)) { + err = -EPERM; + goto out; + } shp = shm_lock(shmid); - if(shp==NULL) - return -EINVAL; + if(shp==NULL) { + err = -EINVAL; + goto out; + } err = shm_checkid(shp,shmid); if(err) goto out_unlock; if(cmd==SHM_LOCK) { - shmem_lock(shp->shm_file, 1); + if (!is_file_hugepages(shp->shm_file)) + shmem_lock(shp->shm_file, 1); shp->shm_flags |= SHM_LOCKED; } else { - shmem_lock(shp->shm_file, 0); + if (!is_file_hugepages(shp->shm_file)) + shmem_lock(shp->shm_file, 0); shp->shm_flags &= ~SHM_LOCKED; } - shm_unlock(shmid); - return err; + shm_unlock(shp); + goto out; } case IPC_RMID: { @@ -514,17 +534,19 @@ shp->shm_flags |= SHM_DEST; /* Do not find it any more */ shp->shm_perm.key = IPC_PRIVATE; - shm_unlock(shmid); + shm_unlock(shp); } else shm_destroy (shp); up(&shm_ids.sem); - return err; + goto out; } case IPC_SET: { - if(copy_shmid_from_user (&setbuf, buf, version)) - return -EFAULT; + if(copy_shmid_from_user (&setbuf, buf, version)) { + err = -EFAULT; + goto out; + } down(&shm_ids.sem); shp = shm_lock(shmid); err=-EINVAL; @@ -549,17 +571,19 @@ } default: - return -EINVAL; + err = -EINVAL; + goto out; } err = 0; out_unlock_up: - shm_unlock(shmid); + shm_unlock(shp); out_up: up(&shm_ids.sem); - return err; + goto out; out_unlock: - shm_unlock(shmid); + shm_unlock(shp); +out: return err; } @@ -579,10 +603,10 @@ int acc_mode; void *user_addr; - if (shmid < 0) - return -EINVAL; - - if ((addr = (ulong)shmaddr)) { + if (shmid < 0) { + err = -EINVAL; + goto out; + } else if ((addr = (ulong)shmaddr)) { if (addr & (SHMLBA-1)) { if (shmflg & SHM_RND) addr &= ~(SHMLBA-1); /* round down */ @@ -612,21 +636,24 @@ * additional creator id... */ shp = shm_lock(shmid); - if(shp == NULL) - return -EINVAL; + if(shp == NULL) { + err = -EINVAL; + goto out; + } err = shm_checkid(shp,shmid); if (err) { - shm_unlock(shmid); - return err; + shm_unlock(shp); + goto out; } if (ipcperms(&shp->shm_perm, acc_mode)) { - shm_unlock(shmid); - return -EACCES; + shm_unlock(shp); + err = -EACCES; + goto out; } file = shp->shm_file; size = file->f_dentry->d_inode->i_size; shp->shm_nattch++; - shm_unlock(shmid); + shm_unlock(shp); down_write(¤t->mm->mmap_sem); if (addr && !(shmflg & SHM_REMAP)) { @@ -655,15 +682,15 @@ shp->shm_flags & SHM_DEST) shm_destroy (shp); else - shm_unlock(shmid); + shm_unlock(shp); up (&shm_ids.sem); *raddr = (unsigned long) user_addr; err = 0; if (IS_ERR(user_addr)) err = PTR_ERR(user_addr); +out: return err; - } /* @@ -673,18 +700,24 @@ asmlinkage long sys_shmdt (char *shmaddr) { struct mm_struct *mm = current->mm; - struct vm_area_struct *shmd, *shmdnext; + struct vm_area_struct *vma; + unsigned long address = (unsigned long)shmaddr; int retval = -EINVAL; down_write(&mm->mmap_sem); - for (shmd = mm->mmap; shmd; shmd = shmdnext) { - shmdnext = shmd->vm_next; - if (shmd->vm_ops == &shm_vm_ops - && shmd->vm_start - (shmd->vm_pgoff << PAGE_SHIFT) == (ulong) shmaddr) { - do_munmap(mm, shmd->vm_start, shmd->vm_end - shmd->vm_start); - retval = 0; - } - } + vma = find_vma(mm, address); + if (!vma) + goto out; + if (vma->vm_start != address) + goto out; + + /* ->vm_pgoff is always 0, see do_mmap() in sys_shmat() */ + retval = 0; + if (vma->vm_ops == &shm_vm_ops || (vma->vm_flags & VM_HUGETLB)) + do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start); + else + retval = -EINVAL; +out: up_write(&mm->mmap_sem); return retval; } @@ -727,7 +760,7 @@ shp->shm_atim, shp->shm_dtim, shp->shm_ctim); - shm_unlock(i); + shm_unlock(shp); pos += len; if(pos < offset) { diff -Nru a/ipc/util.c b/ipc/util.c --- a/ipc/util.c Mon Nov 4 14:31:01 2002 +++ b/ipc/util.c Mon Nov 4 14:31:01 2002 @@ -8,6 +8,8 @@ * Chris Evans, * Nov 1999 - ipc helper functions, unified SMP locking * Manfred Spraul + * Oct 2002 - One lock per IPC id. RCU ipc_free for lock-free grow_ary(). + * Mingming Cao */ #include @@ -20,6 +22,8 @@ #include #include #include +#include +#include #if defined(CONFIG_SYSVIPC) @@ -69,13 +73,12 @@ ids->seq_max = seq_limit; } - ids->entries = ipc_alloc(sizeof(struct ipc_id)*size); + ids->entries = ipc_rcu_alloc(sizeof(struct ipc_id)*size); if(ids->entries == NULL) { printk(KERN_ERR "ipc_init_ids() failed, ipc service disabled.\n"); ids->size = 0; } - ids->ary = SPIN_LOCK_UNLOCKED; for(i=0;isize;i++) ids->entries[i].p = NULL; } @@ -84,7 +87,8 @@ * ipc_findkey - find a key in an ipc identifier set * @ids: Identifier set * @key: The key to find - * + * + * Requires ipc_ids.sem locked. * Returns the identifier if found or -1 if not. */ @@ -92,8 +96,9 @@ { int id; struct kern_ipc_perm* p; + int max_id = ids->max_id; - for (id = 0; id <= ids->max_id; id++) { + for (id = 0; id <= max_id; id++) { p = ids->entries[id].p; if(p==NULL) continue; @@ -103,6 +108,9 @@ return -1; } +/* + * Requires ipc_ids.sem locked + */ static int grow_ary(struct ipc_ids* ids, int newsize) { struct ipc_id* new; @@ -114,21 +122,21 @@ if(newsize <= ids->size) return newsize; - new = ipc_alloc(sizeof(struct ipc_id)*newsize); + new = ipc_rcu_alloc(sizeof(struct ipc_id)*newsize); if(new == NULL) return ids->size; memcpy(new, ids->entries, sizeof(struct ipc_id)*ids->size); for(i=ids->size;iary); - old = ids->entries; - ids->entries = new; i = ids->size; + + ids->entries = new; + wmb(); ids->size = newsize; - spin_unlock(&ids->ary); - ipc_free(old, sizeof(struct ipc_id)*i); + + ipc_rcu_free(old, sizeof(struct ipc_id)*i); return ids->size; } @@ -166,7 +174,10 @@ if(ids->seq > ids->seq_max) ids->seq = 0; - spin_lock(&ids->ary); + new->lock = SPIN_LOCK_UNLOCKED; + new->deleted = 0; + rcu_read_lock(); + spin_lock(&new->lock); ids->entries[id].p = new; return id; } @@ -180,6 +191,8 @@ * fed an invalid identifier. The entry is removed and internal * variables recomputed. The object associated with the identifier * is returned. + * ipc_ids.sem and the spinlock for this ID is hold before this function + * is called, and remain locked on the exit. */ struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id) @@ -188,6 +201,7 @@ int lid = id % SEQ_MULTIPLIER; if(lid >= ids->size) BUG(); + p = ids->entries[lid].p; ids->entries[lid].p = NULL; if(p==NULL) @@ -202,6 +216,7 @@ } while (ids->entries[lid].p == NULL); ids->max_id = lid; } + p->deleted = 1; return p; } @@ -224,14 +239,14 @@ } /** - * ipc_free - free ipc space + * ipc_free - free ipc space * @ptr: pointer returned by ipc_alloc * @size: size of block * * Free a block created with ipc_alloc. The caller must know the size * used in the allocation call. */ - + void ipc_free(void* ptr, int size) { if(size > PAGE_SIZE) @@ -240,6 +255,85 @@ kfree(ptr); } +struct ipc_rcu_kmalloc +{ + struct rcu_head rcu; + /* "void *" makes sure alignment of following data is sane. */ + void *data[0]; +}; + +struct ipc_rcu_vmalloc +{ + struct rcu_head rcu; + struct work_struct work; + /* "void *" makes sure alignment of following data is sane. */ + void *data[0]; +}; + +static inline int rcu_use_vmalloc(int size) +{ + /* Too big for a single page? */ + if (sizeof(struct ipc_rcu_kmalloc) + size > PAGE_SIZE) + return 1; + return 0; +} + +/** + * ipc_rcu_alloc - allocate ipc and rcu space + * @size: size desired + * + * Allocate memory for the rcu header structure + the object. + * Returns the pointer to the object. + * NULL is returned if the allocation fails. + */ + +void* ipc_rcu_alloc(int size) +{ + void* out; + /* + * We prepend the allocation with the rcu struct, and + * workqueue if necessary (for vmalloc). + */ + if (rcu_use_vmalloc(size)) { + out = vmalloc(sizeof(struct ipc_rcu_vmalloc) + size); + if (out) out += sizeof(struct ipc_rcu_vmalloc); + } else { + out = kmalloc(sizeof(struct ipc_rcu_kmalloc)+size, GFP_KERNEL); + if (out) out += sizeof(struct ipc_rcu_kmalloc); + } + + return out; +} + +/** + * ipc_schedule_free - free ipc + rcu space + * + * Since RCU callback function is called in bh, + * we need to defer the vfree to schedule_work + */ +static void ipc_schedule_free(void* arg) +{ + struct ipc_rcu_vmalloc *free = arg; + + INIT_WORK(&free->work, vfree, free); + schedule_work(&free->work); +} + +void ipc_rcu_free(void* ptr, int size) +{ + if (rcu_use_vmalloc(size)) { + struct ipc_rcu_vmalloc *free; + free = ptr - sizeof(*free); + call_rcu(&free->rcu, ipc_schedule_free, free); + } else { + struct ipc_rcu_kmalloc *free; + free = ptr - sizeof(*free); + /* kfree takes a "const void *" so gcc warns. So we cast. */ + call_rcu(&free->rcu, (void (*)(void *))kfree, free); + } + +} + /** * ipcperms - check IPC permissions * @ipcp: IPC permission set @@ -311,6 +405,77 @@ out->cgid = NEW_TO_OLD_GID(in->cgid); out->mode = in->mode; out->seq = in->seq; +} + +/* + * ipc_get() requires ipc_ids.sem down, otherwise we need a rmb() here + * to sync with grow_ary(); + * + * So far only shm_get_stat() uses ipc_get() via shm_get(). So ipc_get() + * is called with shm_ids.sem locked. Thus a rmb() is not needed here, + * as grow_ary() also requires shm_ids.sem down(for shm). + * + * But if ipc_get() is used in the future without ipc_ids.sem down, + * we need to add a rmb() before accessing the entries array + */ +struct kern_ipc_perm* ipc_get(struct ipc_ids* ids, int id) +{ + struct kern_ipc_perm* out; + int lid = id % SEQ_MULTIPLIER; + if(lid >= ids->size) + return NULL; + rmb(); + out = ids->entries[lid].p; + return out; +} + +struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id) +{ + struct kern_ipc_perm* out; + int lid = id % SEQ_MULTIPLIER; + + rcu_read_lock(); + if(lid >= ids->size) { + rcu_read_unlock(); + return NULL; + } + + /* we need a barrier here to sync with grow_ary() */ + rmb(); + out = ids->entries[lid].p; + if(out == NULL) { + rcu_read_unlock(); + return NULL; + } + spin_lock(&out->lock); + + /* ipc_rmid() may have already freed the ID while ipc_lock + * was spinning: here verify that the structure is still valid + */ + if (out->deleted) { + spin_unlock(&out->lock); + rcu_read_unlock(); + return NULL; + } + return out; +} + +void ipc_unlock(struct kern_ipc_perm* perm) +{ + spin_unlock(&perm->lock); + rcu_read_unlock(); +} + +int ipc_buildid(struct ipc_ids* ids, int id, int seq) +{ + return SEQ_MULTIPLIER*seq + id; +} + +int ipc_checkid(struct ipc_ids* ids, struct kern_ipc_perm* ipcp, int uid) +{ + if(uid/SEQ_MULTIPLIER != ipcp->seq) + return 1; + return 0; } #ifndef __ia64__ diff -Nru a/ipc/util.h b/ipc/util.h --- a/ipc/util.h Mon Nov 4 14:31:02 2002 +++ b/ipc/util.h Mon Nov 4 14:31:02 2002 @@ -4,7 +4,6 @@ * * ipc helper functions (c) 1999 Manfred Spraul */ - #define USHRT_MAX 0xffff #define SEQ_MULTIPLIER (IPCMNI) @@ -19,7 +18,6 @@ unsigned short seq; unsigned short seq_max; struct semaphore sem; - spinlock_t ary; struct ipc_id* entries; }; @@ -27,7 +25,6 @@ struct kern_ipc_perm* p; }; - void __init ipc_init_ids(struct ipc_ids* ids, int size); /* must be called with ids->sem acquired.*/ @@ -44,57 +41,17 @@ */ void* ipc_alloc(int size); void ipc_free(void* ptr, int size); +/* for allocation that need to be freed by RCU + * both function can sleep + */ +void* ipc_rcu_alloc(int size); +void ipc_rcu_free(void* arg, int size); -extern inline void ipc_lockall(struct ipc_ids* ids) -{ - spin_lock(&ids->ary); -} - -extern inline struct kern_ipc_perm* ipc_get(struct ipc_ids* ids, int id) -{ - struct kern_ipc_perm* out; - int lid = id % SEQ_MULTIPLIER; - if(lid >= ids->size) - return NULL; - - out = ids->entries[lid].p; - return out; -} - -extern inline void ipc_unlockall(struct ipc_ids* ids) -{ - spin_unlock(&ids->ary); -} -extern inline struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id) -{ - struct kern_ipc_perm* out; - int lid = id % SEQ_MULTIPLIER; - if(lid >= ids->size) - return NULL; - - spin_lock(&ids->ary); - out = ids->entries[lid].p; - if(out==NULL) - spin_unlock(&ids->ary); - return out; -} - -extern inline void ipc_unlock(struct ipc_ids* ids, int id) -{ - spin_unlock(&ids->ary); -} - -extern inline int ipc_buildid(struct ipc_ids* ids, int id, int seq) -{ - return SEQ_MULTIPLIER*seq + id; -} - -extern inline int ipc_checkid(struct ipc_ids* ids, struct kern_ipc_perm* ipcp, int uid) -{ - if(uid/SEQ_MULTIPLIER != ipcp->seq) - return 1; - return 0; -} +struct kern_ipc_perm* ipc_get(struct ipc_ids* ids, int id); +struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id); +void ipc_unlock(struct kern_ipc_perm* perm); +int ipc_buildid(struct ipc_ids* ids, int id, int seq); +int ipc_checkid(struct ipc_ids* ids, struct kern_ipc_perm* ipcp, int uid); void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out); diff -Nru a/kernel/cpufreq.c b/kernel/cpufreq.c --- a/kernel/cpufreq.c Mon Nov 4 14:31:01 2002 +++ b/kernel/cpufreq.c Mon Nov 4 14:31:01 2002 @@ -4,7 +4,7 @@ * Copyright (C) 2001 Russell King * (C) 2002 Dominik Brodowski * - * $Id: cpufreq.c,v 1.43 2002/09/21 09:05:29 db Exp $ + * $Id: cpufreq.c,v 1.45 2002/10/08 14:54:23 db Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -21,13 +21,10 @@ #include #include #include +#include #include -#ifdef CONFIG_CPU_FREQ_26_API -#include -#endif - #ifdef CONFIG_CPU_FREQ_24_API #include #endif @@ -200,7 +197,6 @@ __setup("cpufreq=", cpufreq_setup); -#ifdef CONFIG_CPU_FREQ_26_API #ifdef CONFIG_PROC_FS /** @@ -335,7 +331,6 @@ return; } #endif /* CONFIG_PROC_FS */ -#endif /* CONFIG_CPU_FREQ_26_API */ @@ -344,10 +339,6 @@ *********************************************************************/ #ifdef CONFIG_CPU_FREQ_24_API -/* NOTE #1: when you use this API, you may not use any other calls, - * except cpufreq_[un]register_notifier, of course. - */ - /** * cpufreq_set - set the CPU frequency * @freq: target frequency in kHz @@ -879,7 +870,7 @@ cpufreq_driver->policy[policy->cpu].max = policy->max; cpufreq_driver->policy[policy->cpu].policy = policy->policy; } - + #ifdef CONFIG_CPU_FREQ_24_API if (policy->cpu == CPUFREQ_ALL_CPUS) { for (i=0;icpu == CPUFREQ_ALL_CPUS) { + int i; + for (i=0;inew; + } else + cpu_cur_freq[freqs->cpu] = freqs->new; +#endif break; } up(&cpufreq_notifier_sem); @@ -992,9 +991,7 @@ ret = cpufreq_set_policy(&default_policy); -#ifdef CONFIG_CPU_FREQ_26_API cpufreq_proc_init(); -#endif #ifdef CONFIG_CPU_FREQ_24_API down(&cpufreq_driver_sem); @@ -1042,9 +1039,7 @@ up(&cpufreq_driver_sem); -#ifdef CONFIG_CPU_FREQ_26_API cpufreq_proc_exit(); -#endif #ifdef CONFIG_CPU_FREQ_24_API cpufreq_sysctl_exit(); @@ -1086,13 +1081,7 @@ policy.cpu = i; up(&cpufreq_driver_sem); -#ifdef CONFIG_CPU_FREQ_26_API cpufreq_set_policy(&policy); -#endif - -#ifdef CONFIG_CPU_FREQ_24_API - cpufreq_set(cpu_cur_freq[i], i); -#endif } return 0; diff -Nru a/kernel/fork.c b/kernel/fork.c --- a/kernel/fork.c Mon Nov 4 14:31:00 2002 +++ b/kernel/fork.c Mon Nov 4 14:31:00 2002 @@ -215,6 +215,7 @@ mm->locked_vm = 0; mm->mmap = NULL; mm->mmap_cache = NULL; + mm->free_area_cache = TASK_UNMAPPED_BASE; mm->map_count = 0; mm->rss = 0; mm->cpu_vm_mask = 0; @@ -308,6 +309,8 @@ mm->page_table_lock = SPIN_LOCK_UNLOCKED; mm->ioctx_list_lock = RW_LOCK_UNLOCKED; mm->default_kioctx = (struct kioctx)INIT_KIOCTX(mm->default_kioctx, *mm); + mm->free_area_cache = TASK_UNMAPPED_BASE; + mm->pgd = pgd_alloc(mm); if (mm->pgd) return mm; @@ -943,6 +946,22 @@ goto fork_out; } +static inline int fork_traceflag (unsigned clone_flags) +{ + if (clone_flags & (CLONE_UNTRACED | CLONE_IDLETASK)) + return 0; + else if (clone_flags & CLONE_VFORK) { + if (current->ptrace & PT_TRACE_VFORK) + return PTRACE_EVENT_VFORK; + } else if ((clone_flags & CSIGNAL) != SIGCHLD) { + if (current->ptrace & PT_TRACE_CLONE) + return PTRACE_EVENT_CLONE; + } else if (current->ptrace & PT_TRACE_FORK) + return PTRACE_EVENT_FORK; + + return 0; +} + /* * Ok, this is the main fork-routine. * @@ -956,6 +975,13 @@ int *user_tid) { struct task_struct *p; + int trace = 0; + + if (unlikely(current->ptrace)) { + trace = fork_traceflag (clone_flags); + if (trace) + clone_flags |= CLONE_PTRACE; + } p = copy_process(clone_flags, stack_start, regs, stack_size, user_tid); if (!IS_ERR(p)) { @@ -971,6 +997,12 @@ wake_up_forked_process(p); /* do this last */ ++total_forks; + + if (unlikely (trace)) { + current->ptrace_message = (unsigned long) p->pid; + ptrace_notify ((trace << 8) | SIGTRAP); + } + if (clone_flags & CLONE_VFORK) wait_for_completion(&vfork); else diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c --- a/kernel/ksyms.c Mon Nov 4 14:31:00 2002 +++ b/kernel/ksyms.c Mon Nov 4 14:31:00 2002 @@ -493,7 +493,6 @@ EXPORT_SYMBOL(loops_per_jiffy); #endif -EXPORT_SYMBOL(kstat); /* misc */ EXPORT_SYMBOL(panic); diff -Nru a/kernel/module.c b/kernel/module.c --- a/kernel/module.c Mon Nov 4 14:31:02 2002 +++ b/kernel/module.c Mon Nov 4 14:31:02 2002 @@ -425,11 +425,11 @@ printk(KERN_ERR "init_module: mod->deps out of bounds.\n"); goto err2; } - if (mod->init && !mod_bound(mod->init, 0, mod)) { + if (mod->init && !mod_bound((unsigned long)mod->init, 0, mod)) { printk(KERN_ERR "init_module: mod->init out of bounds.\n"); goto err2; } - if (mod->cleanup && !mod_bound(mod->cleanup, 0, mod)) { + if (mod->cleanup && !mod_bound((unsigned long)mod->cleanup, 0, mod)) { printk(KERN_ERR "init_module: mod->cleanup out of bounds.\n"); goto err2; } @@ -449,7 +449,7 @@ goto err2; } if (mod_member_present(mod, can_unload) - && mod->can_unload && !mod_bound(mod->can_unload, 0, mod)) { + && mod->can_unload && !mod_bound((unsigned long)mod->can_unload, 0, mod)) { printk(KERN_ERR "init_module: mod->can_unload out of bounds.\n"); goto err2; } diff -Nru a/kernel/ptrace.c b/kernel/ptrace.c --- a/kernel/ptrace.c Mon Nov 4 14:31:03 2002 +++ b/kernel/ptrace.c Mon Nov 4 14:31:03 2002 @@ -248,3 +248,72 @@ } return copied; } + +static int ptrace_setoptions(struct task_struct *child, long data) +{ + if (data & PTRACE_O_TRACESYSGOOD) + child->ptrace |= PT_TRACESYSGOOD; + else + child->ptrace &= ~PT_TRACESYSGOOD; + + if (data & PTRACE_O_TRACEFORK) + child->ptrace |= PT_TRACE_FORK; + else + child->ptrace &= ~PT_TRACE_FORK; + + if (data & PTRACE_O_TRACEVFORK) + child->ptrace |= PT_TRACE_VFORK; + else + child->ptrace &= ~PT_TRACE_VFORK; + + if (data & PTRACE_O_TRACECLONE) + child->ptrace |= PT_TRACE_CLONE; + else + child->ptrace &= ~PT_TRACE_CLONE; + + if (data & PTRACE_O_TRACEEXEC) + child->ptrace |= PT_TRACE_EXEC; + else + child->ptrace &= ~PT_TRACE_EXEC; + + if ((data & (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK + | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE + | PTRACE_O_TRACEEXEC)) + != data) + return -EINVAL; + + return 0; +} + +int ptrace_request(struct task_struct *child, long request, + long addr, long data) +{ + int ret = -EIO; + + switch (request) { +#ifdef PTRACE_OLDSETOPTIONS + case PTRACE_OLDSETOPTIONS: +#endif + case PTRACE_SETOPTIONS: + ret = ptrace_setoptions(child, data); + break; + case PTRACE_GETEVENTMSG: + ret = put_user(child->ptrace_message, (unsigned long *) data); + break; + default: + break; + } + + return ret; +} + +void ptrace_notify(int exit_code) +{ + BUG_ON (!(current->ptrace & PT_PTRACED)); + + /* Let the debugger run. */ + current->exit_code = exit_code; + set_current_state(TASK_STOPPED); + notify_parent(current, SIGCHLD); + schedule(); +} diff -Nru a/kernel/sched.c b/kernel/sched.c --- a/kernel/sched.c Mon Nov 4 14:31:02 2002 +++ b/kernel/sched.c Mon Nov 4 14:31:02 2002 @@ -839,6 +839,8 @@ #endif +DEFINE_PER_CPU(struct kernel_stat, kstat); + /* * We place interactive tasks back into the active array, if possible. * @@ -872,21 +874,21 @@ if (p == rq->idle) { /* note: this timer irq context must be accounted for as well */ if (irq_count() - HARDIRQ_OFFSET >= SOFTIRQ_OFFSET) - kstat.per_cpu_system[cpu] += sys_ticks; + kstat_cpu(cpu).cpustat.system += sys_ticks; else if (atomic_read(&nr_iowait_tasks) > 0) - kstat.per_cpu_iowait[cpu] += sys_ticks; + kstat_cpu(cpu).cpustat.iowait += sys_ticks; else - kstat.per_cpu_idle[cpu] += sys_ticks; + kstat_cpu(cpu).cpustat.idle += sys_ticks; #if CONFIG_SMP idle_tick(rq); #endif return; } if (TASK_NICE(p) > 0) - kstat.per_cpu_nice[cpu] += user_ticks; + kstat_cpu(cpu).cpustat.nice += user_ticks; else - kstat.per_cpu_user[cpu] += user_ticks; - kstat.per_cpu_system[cpu] += sys_ticks; + kstat_cpu(cpu).cpustat.user += user_ticks; + kstat_cpu(cpu).cpustat.system += sys_ticks; /* Task might have expired already, but not scheduled off yet */ if (p->array != rq->active) { @@ -2112,11 +2114,44 @@ spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; #endif +static void kstat_init_cpu(int cpu) +{ + /* Add any initialisation to kstat here */ + /* Useful when cpu offlining logic is added.. */ +} + +static int __devinit kstat_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + int cpu = (unsigned long)hcpu; + switch(action) { + case CPU_UP_PREPARE: + kstat_init_cpu(cpu); + break; + default: + break; + } + return NOTIFY_OK; +} + +static struct notifier_block __devinitdata kstat_nb = { + .notifier_call = kstat_cpu_notify, + .next = NULL, +}; + +__init static void init_kstat(void) { + kstat_cpu_notify(&kstat_nb, (unsigned long)CPU_UP_PREPARE, + (void *)(long)smp_processor_id()); + register_cpu_notifier(&kstat_nb); +} + void __init sched_init(void) { runqueue_t *rq; int i, j, k; + /* Init the kstat counters */ + init_kstat(); for (i = 0; i < NR_CPUS; i++) { prio_array_t *array; diff -Nru a/kernel/sys.c b/kernel/sys.c --- a/kernel/sys.c Mon Nov 4 14:31:00 2002 +++ b/kernel/sys.c Mon Nov 4 14:31:00 2002 @@ -204,6 +204,8 @@ cond_syscall(sys_quotactl) cond_syscall(sys_acct) cond_syscall(sys_lookup_dcookie) +cond_syscall(sys_swapon) +cond_syscall(sys_swapoff) static int set_one_prio(struct task_struct *p, int niceval, int error) { diff -Nru a/kernel/timer.c b/kernel/timer.c --- a/kernel/timer.c Mon Nov 4 14:31:01 2002 +++ b/kernel/timer.c Mon Nov 4 14:31:01 2002 @@ -409,7 +409,6 @@ /* Don't completely fail for HZ > 500. */ int tickadj = 500/HZ ? : 1; /* microsecs */ -struct kernel_stat kstat; /* * phase-lock loop variables diff -Nru a/lib/kobject.c b/lib/kobject.c --- a/lib/kobject.c Mon Nov 4 14:31:02 2002 +++ b/lib/kobject.c Mon Nov 4 14:31:02 2002 @@ -2,9 +2,10 @@ * kobject.c - library routines for handling generic kernel objects */ -#define DEBUG 1 +#define DEBUG 0 #include +#include #include #include @@ -76,11 +77,13 @@ } up_write(&s->rwsem); } - error = sysfs_create_dir(kobj); - if (!error) { - error = kobject_populate_dir(kobj); - if (error) - sysfs_remove_dir(kobj); + if (strlen(kobj->name)) { + error = sysfs_create_dir(kobj); + if (!error) { + error = kobject_populate_dir(kobj); + if (error) + sysfs_remove_dir(kobj); + } } return error; } diff -Nru a/lib/rwsem-spinlock.c b/lib/rwsem-spinlock.c --- a/lib/rwsem-spinlock.c Mon Nov 4 14:31:01 2002 +++ b/lib/rwsem-spinlock.c Mon Nov 4 14:31:01 2002 @@ -290,7 +290,7 @@ */ void __downgrade_write(struct rw_semaphore *sem) { - rwsemtrace(sem,"Entering __rwsem_downgrade"); + rwsemtrace(sem,"Entering __downgrade_write"); spin_lock(&sem->wait_lock); @@ -300,7 +300,7 @@ spin_unlock(&sem->wait_lock); - rwsemtrace(sem,"Leaving __rwsem_downgrade"); + rwsemtrace(sem,"Leaving __downgrade_write"); } EXPORT_SYMBOL(init_rwsem); diff -Nru a/mm/Makefile b/mm/Makefile --- a/mm/Makefile Mon Nov 4 14:31:02 2002 +++ b/mm/Makefile Mon Nov 4 14:31:02 2002 @@ -4,11 +4,12 @@ export-objs := shmem.o filemap.o mempool.o page_alloc.o page-writeback.o -obj-y := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \ - vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \ - page_alloc.o swap_state.o swapfile.o oom_kill.o \ - shmem.o highmem.o mempool.o msync.o mincore.o readahead.o \ - pdflush.o page-writeback.o rmap.o madvise.o vcache.o \ - truncate.o +obj-y := memory.o mmap.o filemap.o fremap.o mprotect.o mlock.o mremap.o \ + vmalloc.o slab.o bootmem.o swap.o vmscan.o page_alloc.o \ + oom_kill.o shmem.o highmem.o mempool.o msync.o mincore.o \ + readahead.o pdflush.o page-writeback.o rmap.o madvise.o \ + vcache.o truncate.o + +obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o include $(TOPDIR)/Rules.make diff -Nru a/mm/filemap.c b/mm/filemap.c --- a/mm/filemap.c Mon Nov 4 14:31:01 2002 +++ b/mm/filemap.c Mon Nov 4 14:31:01 2002 @@ -9,6 +9,7 @@ * most "normal" filesystems (but you don't /have/ to use this: * the NFS filesystem used to do this differently, for example) */ +#include #include #include #include @@ -248,37 +249,6 @@ } /* - * This adds the requested page to the page cache if it isn't already there, - * and schedules an I/O to read in its contents from disk. - */ -static int FASTCALL(page_cache_read(struct file * file, unsigned long offset)); -static int page_cache_read(struct file * file, unsigned long offset) -{ - struct address_space *mapping = file->f_dentry->d_inode->i_mapping; - struct page *page; - int error; - - page = page_cache_alloc_cold(mapping); - if (!page) - return -ENOMEM; - - error = add_to_page_cache_lru(page, mapping, offset); - if (!error) { - error = mapping->a_ops->readpage(file, page); - page_cache_release(page); - return error; - } - - /* - * We arrive here in the unlikely event that someone - * raced with us and added our page to the cache first - * or we are out of memory for radix-tree nodes. - */ - page_cache_release(page); - return error == -EEXIST ? 0 : error; -} - -/* * In order to wait for pages to become available there must be * waitqueues associated with pages. By using a hash table of * waitqueues where the bucket discipline is to maintain all @@ -288,7 +258,7 @@ * at a cost of "thundering herd" phenomena during rare hash * collisions. */ -static inline wait_queue_head_t *page_waitqueue(struct page *page) +static wait_queue_head_t *page_waitqueue(struct page *page) { const struct zone *zone = page_zone(page); @@ -550,24 +520,6 @@ } /* - * Mark a page as having seen activity. - * - * inactive,unreferenced -> inactive,referenced - * inactive,referenced -> active,unreferenced - * active,unreferenced -> active,referenced - */ -void mark_page_accessed(struct page *page) -{ - if (!PageActive(page) && PageReferenced(page)) { - activate_page(page); - ClearPageReferenced(page); - return; - } else if (!PageReferenced(page)) { - SetPageReferenced(page); - } -} - -/* * This is a generic file read routine, and uses the * inode->i_op->readpage() function for the actual low-level * stuff. @@ -758,7 +710,7 @@ return ret; } -static inline void fault_in_pages_readable(const char *uaddr, int size) +static void fault_in_pages_readable(const char *uaddr, int size) { volatile char c; int ret; @@ -996,6 +948,38 @@ return ret; } +#ifdef CONFIG_MMU +/* + * This adds the requested page to the page cache if it isn't already there, + * and schedules an I/O to read in its contents from disk. + */ +static int FASTCALL(page_cache_read(struct file * file, unsigned long offset)); +static int page_cache_read(struct file * file, unsigned long offset) +{ + struct address_space *mapping = file->f_dentry->d_inode->i_mapping; + struct page *page; + int error; + + page = page_cache_alloc_cold(mapping); + if (!page) + return -ENOMEM; + + error = add_to_page_cache_lru(page, mapping, offset); + if (!error) { + error = mapping->a_ops->readpage(file, page); + page_cache_release(page); + return error; + } + + /* + * We arrive here in the unlikely event that someone + * raced with us and added our page to the cache first + * or we are out of memory for radix-tree nodes. + */ + page_cache_release(page); + return error == -EEXIST ? 0 : error; +} + /* * filemap_nopage() is invoked via the vma operations vector for a * mapped memory region to read in file data during a page fault. @@ -1004,7 +988,6 @@ * it in the page cache, and handles the special cases reasonably without * having a lot of duplicated code. */ - struct page * filemap_nopage(struct vm_area_struct * area, unsigned long address, int unused) { int error; @@ -1166,8 +1149,159 @@ return NULL; } +static struct page * filemap_getpage(struct file *file, unsigned long pgoff, + int nonblock) +{ + struct address_space *mapping = file->f_dentry->d_inode->i_mapping; + struct page *page; + int error; + + /* + * Do we have something in the page cache already? + */ +retry_find: + page = find_get_page(mapping, pgoff); + if (!page) { + if (nonblock) + return NULL; + goto no_cached_page; + } + + /* + * Ok, found a page in the page cache, now we need to check + * that it's up-to-date. + */ + if (!PageUptodate(page)) + goto page_not_uptodate; + +success: + /* + * Found the page and have a reference on it, need to check sharing + * and possibly copy it over to another page.. + */ + mark_page_accessed(page); + flush_page_to_ram(page); + + return page; + +no_cached_page: + error = page_cache_read(file, pgoff); + + /* + * The page we want has now been added to the page cache. + * In the unlikely event that someone removed it in the + * meantime, we'll just come back here and read it again. + */ + if (error >= 0) + goto retry_find; + + /* + * An error return from page_cache_read can result if the + * system is low on memory, or a problem occurs while trying + * to schedule I/O. + */ + return NULL; + +page_not_uptodate: + lock_page(page); + + /* Did it get unhashed while we waited for it? */ + if (!page->mapping) { + unlock_page(page); + goto err; + } + + /* Did somebody else get it up-to-date? */ + if (PageUptodate(page)) { + unlock_page(page); + goto success; + } + + if (!mapping->a_ops->readpage(file, page)) { + wait_on_page_locked(page); + if (PageUptodate(page)) + goto success; + } + + /* + * Umm, take care of errors if the page isn't up-to-date. + * Try to re-read it _once_. We do this synchronously, + * because there really aren't any performance issues here + * and we need to check for errors. + */ + lock_page(page); + + /* Somebody truncated the page on us? */ + if (!page->mapping) { + unlock_page(page); + goto err; + } + /* Somebody else successfully read it in? */ + if (PageUptodate(page)) { + unlock_page(page); + goto success; + } + + ClearPageError(page); + if (!mapping->a_ops->readpage(file, page)) { + wait_on_page_locked(page); + if (PageUptodate(page)) + goto success; + } + + /* + * Things didn't work out. Return zero to tell the + * mm layer so, possibly freeing the page cache page first. + */ +err: + page_cache_release(page); + + return NULL; +} + +static int filemap_populate(struct vm_area_struct *vma, + unsigned long addr, + unsigned long len, + unsigned long prot, + unsigned long pgoff, + int nonblock) +{ + struct file *file = vma->vm_file; + struct address_space *mapping = file->f_dentry->d_inode->i_mapping; + struct inode *inode = mapping->host; + unsigned long size; + struct mm_struct *mm = vma->vm_mm; + struct page *page; + int err; + +repeat: + size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + if (pgoff + (len >> PAGE_CACHE_SHIFT) > size) + return -EINVAL; + + page = filemap_getpage(file, pgoff, nonblock); + if (!page && !nonblock) + return -ENOMEM; + if (page) { + err = install_page(mm, vma, addr, page, prot); + if (err) { + page_cache_release(page); + return err; + } + } + + len -= PAGE_SIZE; + addr += PAGE_SIZE; + pgoff++; + if (len) + goto repeat; + + return 0; +} + static struct vm_operations_struct generic_file_vm_ops = { .nopage = filemap_nopage, + .populate = filemap_populate, }; /* This is used for a general mmap of a disk file */ @@ -1187,6 +1321,12 @@ vma->vm_ops = &generic_file_vm_ops; return 0; } +#else +int generic_file_mmap(struct file * file, struct vm_area_struct * vma) +{ + return -ENOSYS; +} +#endif /* CONFIG_MMU */ static inline struct page *__read_cache_page(struct address_space *mapping, unsigned long index, @@ -1296,7 +1436,7 @@ return page; } -inline void remove_suid(struct dentry *dentry) +void remove_suid(struct dentry *dentry) { struct iattr newattrs; struct inode *inode = dentry->d_inode; @@ -1332,7 +1472,7 @@ return left; } -static inline int +static int __filemap_copy_from_user_iovec(char *vaddr, const struct iovec *iov, size_t base, size_t bytes) { diff -Nru a/mm/fremap.c b/mm/fremap.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/mm/fremap.c Mon Nov 4 14:31:03 2002 @@ -0,0 +1,146 @@ +/* + * linux/mm/mpopulate.c + * + * Explicit pagetable population and nonlinear (random) mappings support. + * + * started by Ingo Molnar, Copyright (C) 2002 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static inline void zap_pte(struct mm_struct *mm, pte_t *ptep) +{ + pte_t pte = *ptep; + + if (pte_none(pte)) + return; + if (pte_present(pte)) { + unsigned long pfn = pte_pfn(pte); + + pte = ptep_get_and_clear(ptep); + if (pfn_valid(pfn)) { + struct page *page = pfn_to_page(pfn); + if (!PageReserved(page)) { + if (pte_dirty(pte)) + set_page_dirty(page); + page_remove_rmap(page, ptep); + page_cache_release(page); + mm->rss--; + } + } + } else { + free_swap_and_cache(pte_to_swp_entry(pte)); + pte_clear(ptep); + } +} + +/* + * Install a page to a given virtual memory address, release any + * previously existing mapping. + */ +int install_page(struct mm_struct *mm, struct vm_area_struct *vma, + unsigned long addr, struct page *page, unsigned long prot) +{ + int err = -ENOMEM; + pte_t *pte, entry; + pgd_t *pgd; + pmd_t *pmd; + + pgd = pgd_offset(mm, addr); + spin_lock(&mm->page_table_lock); + + pmd = pmd_alloc(mm, pgd, addr); + if (!pmd) + goto err_unlock; + + pte = pte_alloc_map(mm, pmd, addr); + if (!pte) + goto err_unlock; + + zap_pte(mm, pte); + + mm->rss++; + flush_page_to_ram(page); + flush_icache_page(vma, page); + entry = mk_pte(page, protection_map[prot]); + if (prot & PROT_WRITE) + entry = pte_mkwrite(pte_mkdirty(entry)); + set_pte(pte, entry); + page_add_rmap(page, pte); + pte_unmap(pte); + flush_tlb_page(vma, addr); + + spin_unlock(&mm->page_table_lock); + + return 0; + +err_unlock: + spin_unlock(&mm->page_table_lock); + return err; +} + +/*** + * sys_remap_file_pages - remap arbitrary pages of a shared backing store + * file within an existing vma. + * @start: start of the remapped virtual memory range + * @size: size of the remapped virtual memory range + * @prot: new protection bits of the range + * @pgoff: to be mapped page of the backing store file + * @flags: 0 or MAP_NONBLOCKED - the later will cause no IO. + * + * this syscall works purely via pagetables, so it's the most efficient + * way to map the same (large) file into a given virtual window. Unlike + * mremap()/mmap() it does not create any new vmas. + * + * The new mappings do not live across swapout, so either use MAP_LOCKED + * or use PROT_NONE in the original linear mapping and add a special + * SIGBUS pagefault handler to reinstall zapped mappings. + */ +int sys_remap_file_pages(unsigned long start, unsigned long size, + unsigned long prot, unsigned long pgoff, unsigned long flags) +{ + struct mm_struct *mm = current->mm; + unsigned long end = start + size; + struct vm_area_struct *vma; + int err = -EINVAL; + + /* + * Sanitize the syscall parameters: + */ + start = PAGE_ALIGN(start); + size = PAGE_ALIGN(size); + prot &= 0xf; + + down_read(&mm->mmap_sem); + + vma = find_vma(mm, start); + /* + * Make sure the vma is shared, that it supports prefaulting, + * and that the remapped range is valid and fully within + * the single existing vma: + */ + if (vma && (vma->vm_flags & VM_SHARED) && + vma->vm_ops && vma->vm_ops->populate && + end > start && start >= vma->vm_start && + end <= vma->vm_end) { + /* + * Change the default protection to PROT_NONE: + */ + if (pgprot_val(vma->vm_page_prot) != pgprot_val(__S000)) + vma->vm_page_prot = __S000; + err = vma->vm_ops->populate(vma, start, size, prot, + pgoff, flags & MAP_NONBLOCK); + } + + up_read(&mm->mmap_sem); + + return err; +} + diff -Nru a/mm/highmem.c b/mm/highmem.c --- a/mm/highmem.c Mon Nov 4 14:31:02 2002 +++ b/mm/highmem.c Mon Nov 4 14:31:02 2002 @@ -229,7 +229,7 @@ /* * highmem version, map in to vec */ -static inline void bounce_copy_vec(struct bio_vec *to, unsigned char *vfrom) +static void bounce_copy_vec(struct bio_vec *to, unsigned char *vfrom) { unsigned long flags; unsigned char *vto; @@ -272,7 +272,7 @@ * queue gfp mask set, *to may or may not be a highmem page. kmap it * always, it will do the Right Thing */ -static inline void copy_to_high_bio_irq(struct bio *to, struct bio *from) +static void copy_to_high_bio_irq(struct bio *to, struct bio *from) { unsigned char *vfrom; struct bio_vec *tovec, *fromvec; @@ -338,7 +338,7 @@ return 0; } -static inline void __bounce_end_io_read(struct bio *bio, mempool_t *pool) +static void __bounce_end_io_read(struct bio *bio, mempool_t *pool) { struct bio *bio_orig = bio->bi_private; diff -Nru a/mm/memory.c b/mm/memory.c --- a/mm/memory.c Mon Nov 4 14:31:01 2002 +++ b/mm/memory.c Mon Nov 4 14:31:01 2002 @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -397,6 +398,11 @@ { pgd_t * dir; + if (is_vm_hugetlb_page(vma)) { + unmap_hugepage_range(vma, address, end); + return; + } + BUG_ON(address >= end); dir = pgd_offset(vma->vm_mm, address); @@ -436,6 +442,11 @@ mmu_gather_t *tlb; unsigned long end, block; + if (is_vm_hugetlb_page(vma)) { + zap_hugepage_range(vma, address, size); + return; + } + spin_lock(&mm->page_table_lock); /* @@ -573,6 +584,7 @@ i = -EFAULT; goto out; } + flush_dcache_page(pages[i]); if (!PageReserved(pages[i])) page_cache_get(pages[i]); } @@ -588,7 +600,7 @@ return i; } -static inline void zeromap_pte_range(pte_t * pte, unsigned long address, +static void zeromap_pte_range(pte_t * pte, unsigned long address, unsigned long size, pgprot_t prot) { unsigned long end; @@ -830,7 +842,7 @@ page_remove_rmap(old_page, page_table); break_cow(vma, new_page, address, page_table); page_add_rmap(new_page, page_table); - lru_cache_add(new_page); + lru_cache_add_active(new_page); /* Free the old page.. */ new_page = old_page; @@ -955,12 +967,13 @@ num = valid_swaphandles(entry, &offset); for (i = 0; i < num; offset++, i++) { /* Ok, do the async read-ahead now */ - new_page = read_swap_cache_async(swp_entry(swp_type(entry), offset)); + new_page = read_swap_cache_async(swp_entry(swp_type(entry), + offset)); if (!new_page) break; page_cache_release(new_page); } - return; + lru_add_drain(); /* Push any new pages onto the LRU now */ } /* @@ -995,7 +1008,7 @@ ret = VM_FAULT_MINOR; pte_unmap(page_table); spin_unlock(&mm->page_table_lock); - return ret; + goto out; } /* Had to read the page from swap area: Major fault */ @@ -1017,7 +1030,8 @@ spin_unlock(&mm->page_table_lock); unlock_page(page); page_cache_release(page); - return VM_FAULT_MINOR; + ret = VM_FAULT_MINOR; + goto out; } /* The page isn't present yet, go ahead with the fault. */ @@ -1041,6 +1055,7 @@ update_mmu_cache(vma, address, pte); pte_unmap(page_table); spin_unlock(&mm->page_table_lock); +out: return ret; } @@ -1080,7 +1095,7 @@ mm->rss++; flush_page_to_ram(page); entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); - lru_cache_add(page); + lru_cache_add_active(page); mark_page_accessed(page); } @@ -1139,7 +1154,7 @@ } copy_user_highpage(page, new_page, address); page_cache_release(new_page); - lru_cache_add(page); + lru_cache_add_active(page); new_page = page; } diff -Nru a/mm/mmap.c b/mm/mmap.c --- a/mm/mmap.c Mon Nov 4 14:31:02 2002 +++ b/mm/mmap.c Mon Nov 4 14:31:02 2002 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -95,7 +96,7 @@ * this compensates for the swap-space over-allocation * (ie "nr_swap_pages" being too small). */ - free += swapper_space.nrpages; + free += total_swapcache_pages; /* * The code below doesn't account for free space in the @@ -132,7 +133,7 @@ } /* Remove one vm structure from the inode's i_mapping address space. */ -static inline void remove_shared_vm_struct(struct vm_area_struct *vma) +static void remove_shared_vm_struct(struct vm_area_struct *vma) { struct file *file = vma->vm_file; @@ -301,7 +302,7 @@ } } -static inline void __vma_link_rb(struct mm_struct * mm, struct vm_area_struct * vma, +static void __vma_link_rb(struct mm_struct * mm, struct vm_area_struct * vma, struct rb_node ** rb_link, struct rb_node * rb_parent) { rb_link_node(&vma->vm_rb, rb_parent, rb_link); @@ -335,8 +336,9 @@ __vma_link_file(vma); } -static inline void vma_link(struct mm_struct * mm, struct vm_area_struct * vma, struct vm_area_struct * prev, - struct rb_node ** rb_link, struct rb_node * rb_parent) +static void vma_link(struct mm_struct *mm, struct vm_area_struct *vma, + struct vm_area_struct *prev, struct rb_node **rb_link, + struct rb_node *rb_parent) { struct address_space *mapping = NULL; @@ -606,6 +608,12 @@ mm->locked_vm += len >> PAGE_SHIFT; make_pages_present(addr, addr + len); } + if (flags & MAP_POPULATE) { + up_write(&mm->mmap_sem); + sys_remap_file_pages(addr, len, prot, + pgoff, flags & MAP_NONBLOCK); + down_write(&mm->mmap_sem); + } return addr; unmap_and_free_vma: @@ -638,24 +646,33 @@ #ifndef HAVE_ARCH_UNMAPPED_AREA static inline unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { + struct mm_struct *mm = current->mm; struct vm_area_struct *vma; + int found_hole = 0; if (len > TASK_SIZE) return -ENOMEM; if (addr) { addr = PAGE_ALIGN(addr); - vma = find_vma(current->mm, addr); + vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && (!vma || addr + len <= vma->vm_start)) return addr; } - addr = PAGE_ALIGN(TASK_UNMAPPED_BASE); + addr = mm->free_area_cache; - for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) { + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { /* At this point: (!vma || addr < vma->vm_end). */ if (TASK_SIZE - len < addr) return -ENOMEM; + /* + * Record the first available hole. + */ + if (!found_hole && (!vma || addr < vma->vm_start)) { + mm->free_area_cache = addr; + found_hole = 1; + } if (!vma || addr + len <= vma->vm_start) return addr; addr = vma->vm_end; @@ -939,13 +956,19 @@ * By the time this function is called, the area struct has been * removed from the process mapping list. */ -static void unmap_vma(struct mm_struct *mm, struct vm_area_struct *area) +void unmap_vma(struct mm_struct *mm, struct vm_area_struct *area) { size_t len = area->vm_end - area->vm_start; area->vm_mm->total_vm -= len >> PAGE_SHIFT; if (area->vm_flags & VM_LOCKED) area->vm_mm->locked_vm -= len >> PAGE_SHIFT; + /* + * Is this a new hole at the lowest possible address? + */ + if (area->vm_start >= TASK_UNMAPPED_BASE && + area->vm_start < area->vm_mm->free_area_cache) + area->vm_mm->free_area_cache = area->vm_start; remove_shared_vm_struct(area); @@ -1024,14 +1047,10 @@ touched = NULL; do { struct vm_area_struct *next = mpnt->vm_next; - if (!(is_vm_hugetlb_page(mpnt))) { - mpnt->vm_next = touched; - touched = mpnt; - rb_erase(&mpnt->vm_rb, &mm->mm_rb); - mm->map_count--; - } - else - free_hugepages(mpnt); + mpnt->vm_next = touched; + touched = mpnt; + rb_erase(&mpnt->vm_rb, &mm->mm_rb); + mm->map_count--; mpnt = next; } while (mpnt && mpnt->vm_start < end); *npp = mpnt; @@ -1264,8 +1283,6 @@ profile_exit_mmap(mm); - release_segments(mm); - spin_lock(&mm->page_table_lock); tlb = tlb_gather_mmu(mm, 1); @@ -1284,10 +1301,7 @@ vm_unacct_memory((end - start) >> PAGE_SHIFT); mm->map_count--; - if (!(is_vm_hugetlb_page(mpnt))) - unmap_page_range(tlb, mpnt, start, end); - else - mpnt->vm_ops->close(mpnt); + unmap_page_range(tlb, mpnt, start, end); mpnt = mpnt->vm_next; } diff -Nru a/mm/mprotect.c b/mm/mprotect.c --- a/mm/mprotect.c Mon Nov 4 14:31:01 2002 +++ b/mm/mprotect.c Mon Nov 4 14:31:01 2002 @@ -9,6 +9,7 @@ */ #include +#include #include #include #include diff -Nru a/mm/mremap.c b/mm/mremap.c --- a/mm/mremap.c Mon Nov 4 14:31:02 2002 +++ b/mm/mremap.c Mon Nov 4 14:31:02 2002 @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -20,7 +21,7 @@ #include #include -static inline pte_t *get_one_pte_map_nested(struct mm_struct *mm, unsigned long addr) +static pte_t *get_one_pte_map_nested(struct mm_struct *mm, unsigned long addr) { pgd_t * pgd; pmd_t * pmd; @@ -80,7 +81,7 @@ return pte; } -static inline int copy_one_pte(struct mm_struct *mm, pte_t * src, pte_t * dst) +static int copy_one_pte(struct mm_struct *mm, pte_t * src, pte_t * dst) { int error = 0; pte_t pte; @@ -169,7 +170,7 @@ return -1; } -static inline unsigned long move_vma(struct vm_area_struct * vma, +static unsigned long move_vma(struct vm_area_struct * vma, unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long new_addr) { diff -Nru a/mm/msync.c b/mm/msync.c --- a/mm/msync.c Mon Nov 4 14:31:01 2002 +++ b/mm/msync.c Mon Nov 4 14:31:01 2002 @@ -39,7 +39,7 @@ return 0; } -static inline int filemap_sync_pte_range(pmd_t * pmd, +static int filemap_sync_pte_range(pmd_t * pmd, unsigned long address, unsigned long end, struct vm_area_struct *vma, unsigned int flags) { diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c --- a/mm/page_alloc.c Mon Nov 4 14:31:00 2002 +++ b/mm/page_alloc.c Mon Nov 4 14:31:00 2002 @@ -29,6 +29,10 @@ #include #include +#include + +DECLARE_BITMAP(node_online_map, MAX_NUMNODES); +DECLARE_BITMAP(memblk_online_map, MAX_NR_MEMBLKS); struct pglist_data *pgdat_list; unsigned long totalram_pages; unsigned long totalhigh_pages; @@ -51,7 +55,7 @@ /* * Temporary debugging check for pages not lying within a given zone. */ -static inline int bad_range(struct zone *zone, struct page *page) +static int bad_range(struct zone *zone, struct page *page) { if (page_to_pfn(page) >= zone->zone_start_pfn + zone->spanned_pages) return 1; @@ -209,14 +213,29 @@ return page; } +static inline void set_page_refs(struct page *page, int order) +{ +#ifdef CONFIG_MMU + set_page_count(page, 1); +#else + int i; + + /* + * We need to reference all the pages for this order, otherwise if + * anyone accesses one of the pages with (get/put) it will be freed. + */ + for (i = 0; i < (1 << order); i++) + set_page_count(page+i, 1); +#endif /* CONFIG_MMU */ +} + /* * This page is about to be returned from the page allocator */ -static void prep_new_page(struct page *page) +static void prep_new_page(struct page *page, int order) { - if ( page->mapping || - page_mapped(page) || - (page->flags & ( + if (page->mapping || page_mapped(page) || + (page->flags & ( 1 << PG_private | 1 << PG_locked | 1 << PG_lru | @@ -228,7 +247,7 @@ page->flags &= ~(1 << PG_uptodate | 1 << PG_error | 1 << PG_referenced | 1 << PG_arch_1 | 1 << PG_checked); - set_page_count(page, 1); + set_page_refs(page, order); } /* @@ -295,7 +314,7 @@ list_for_each(curr, &temp) { page = list_entry(curr, struct page, list); BUG_ON(bad_range(zone, page)); - prep_new_page(page); + prep_new_page(page, order); } list_splice(&temp, list->prev); return allocated; @@ -386,7 +405,7 @@ if (page != NULL) { BUG_ON(bad_range(zone, page)); - prep_new_page(page); + prep_new_page(page, order); } return page; } @@ -461,7 +480,7 @@ /* here we're in the low on memory slow path */ rebalance: - if (current->flags & (PF_MEMALLOC | PF_MEMDIE)) { + if ((current->flags & (PF_MEMALLOC | PF_MEMDIE)) && !in_interrupt()) { /* go through the zonelist yet again, ignoring mins */ for (i = 0; zones[i] != NULL; i++) { struct zone *z = zones[i]; @@ -470,13 +489,6 @@ if (page) return page; } -nopage: - if (!(current->flags & PF_NOWARN)) { - printk("%s: page allocation failure." - " order:%d, mode:0x%x\n", - current->comm, order, gfp_mask); - } - return NULL; } /* Atomic allocations - we can't balance anything */ @@ -502,13 +514,21 @@ } } - /* Don't let big-order allocations loop */ - if (order > 3) - goto nopage; + /* + * Don't let big-order allocations loop. Yield for kswapd, try again. + */ + if (order <= 3) { + yield(); + goto rebalance; + } - /* Yield for kswapd, and try again */ - yield(); - goto rebalance; +nopage: + if (!(current->flags & PF_NOWARN)) { + printk("%s: page allocation failure." + " order:%d, mode:0x%x\n", + current->comm, order, gfp_mask); + } + return NULL; } /* @@ -594,6 +614,18 @@ return pages; } +#ifdef CONFIG_NUMA +unsigned int nr_free_pages_pgdat(pg_data_t *pgdat) +{ + unsigned int i, sum = 0; + + for (i = 0; i < MAX_NR_ZONES; i++) + sum += pgdat->node_zones[i].free_pages; + + return sum; +} +#endif + static unsigned int nr_free_zone_pages(int offset) { pg_data_t *pgdat; @@ -721,6 +753,19 @@ val->mem_unit = PAGE_SIZE; } +#ifdef CONFIG_NUMA +void si_meminfo_node(struct sysinfo *val, int nid) +{ + pg_data_t *pgdat = NODE_DATA(nid); + + val->totalram = pgdat->node_size; + val->freeram = nr_free_pages_pgdat(pgdat); + val->totalhigh = pgdat->node_zones[ZONE_HIGHMEM].spanned_pages; + val->freehigh = pgdat->node_zones[ZONE_HIGHMEM].free_pages; + val->mem_unit = PAGE_SIZE; +} +#endif + #define K(x) ((x) << (PAGE_SHIFT-10)) /* @@ -1138,6 +1183,7 @@ pgdat->node_mem_map = node_mem_map; free_area_init_core(pgdat, zones_size, zholes_size); + memblk_set_online(__node_to_memblk(nid)); calculate_zone_bitmap(pgdat, zones_size); } diff -Nru a/mm/shmem.c b/mm/shmem.c --- a/mm/shmem.c Mon Nov 4 14:31:01 2002 +++ b/mm/shmem.c Mon Nov 4 14:31:01 2002 @@ -53,6 +53,7 @@ /* Flag allocation requirements to shmem_getpage and shmem_swp_alloc */ enum sgp_type { + SGP_QUICK, /* don't try more than file page cache lookup */ SGP_READ, /* don't exceed i_size, don't allocate page */ SGP_CACHE, /* don't exceed i_size, may allocate page */ SGP_WRITE, /* may exceed i_size, may allocate page */ @@ -757,6 +758,8 @@ if (filepage && PageUptodate(filepage)) goto done; error = 0; + if (sgp == SGP_QUICK) + goto failed; spin_lock(&info->lock); shmem_recalc_inode(inode); @@ -949,6 +952,42 @@ return page; } +static int shmem_populate(struct vm_area_struct *vma, + unsigned long addr, unsigned long len, + unsigned long prot, unsigned long pgoff, int nonblock) +{ + struct inode *inode = vma->vm_file->f_dentry->d_inode; + struct mm_struct *mm = vma->vm_mm; + enum sgp_type sgp = nonblock? SGP_QUICK: SGP_CACHE; + unsigned long size; + + size = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (pgoff >= size || pgoff + (len >> PAGE_SHIFT) > size) + return -EINVAL; + + while ((long) len > 0) { + struct page *page = NULL; + int err; + /* + * Will need changing if PAGE_CACHE_SIZE != PAGE_SIZE + */ + err = shmem_getpage(inode, pgoff, &page, sgp); + if (err) + return err; + if (page) { + err = install_page(mm, vma, addr, page, prot); + if (err) { + page_cache_release(page); + return err; + } + } + len -= PAGE_SIZE; + addr += PAGE_SIZE; + pgoff++; + } + return 0; +} + void shmem_lock(struct file *file, int lock) { struct inode *inode = file->f_dentry->d_inode; @@ -1821,6 +1860,7 @@ static struct vm_operations_struct shmem_vm_ops = { .nopage = shmem_nopage, + .populate = shmem_populate, }; static struct super_block *shmem_get_sb(struct file_system_type *fs_type, diff -Nru a/mm/slab.c b/mm/slab.c --- a/mm/slab.c Mon Nov 4 14:31:02 2002 +++ b/mm/slab.c Mon Nov 4 14:31:02 2002 @@ -2058,6 +2058,7 @@ next_irqon: local_irq_enable(); next: + ; } check_irq_on(); up(&cache_chain_sem); diff -Nru a/mm/swap.c b/mm/swap.c --- a/mm/swap.c Mon Nov 4 14:31:01 2002 +++ b/mm/swap.c Mon Nov 4 14:31:01 2002 @@ -22,6 +22,7 @@ #include #include #include +#include /* How many pages do we try to swap or page in/out together? */ int page_cluster; @@ -43,15 +44,33 @@ spin_unlock_irq(&zone->lru_lock); } +/* + * Mark a page as having seen activity. + * + * inactive,unreferenced -> inactive,referenced + * inactive,referenced -> active,unreferenced + * active,unreferenced -> active,referenced + */ +void mark_page_accessed(struct page *page) +{ + if (!PageActive(page) && PageReferenced(page) && PageLRU(page)) { + activate_page(page); + ClearPageReferenced(page); + } else if (!PageReferenced(page)) { + SetPageReferenced(page); + } +} + /** * lru_cache_add: add a page to the page lists * @page: the page to add */ -static struct pagevec lru_add_pvecs[NR_CPUS]; +static DEFINE_PER_CPU(struct pagevec, lru_add_pvecs) = { 0, }; +static DEFINE_PER_CPU(struct pagevec, lru_add_active_pvecs) = { 0, }; void lru_cache_add(struct page *page) { - struct pagevec *pvec = &lru_add_pvecs[get_cpu()]; + struct pagevec *pvec = &per_cpu(lru_add_pvecs, get_cpu()); page_cache_get(page); if (!pagevec_add(pvec, page)) @@ -59,12 +78,26 @@ put_cpu(); } +void lru_cache_add_active(struct page *page) +{ + struct pagevec *pvec = &per_cpu(lru_add_active_pvecs, get_cpu()); + + page_cache_get(page); + if (!pagevec_add(pvec, page)) + __pagevec_lru_add_active(pvec); + put_cpu(); +} + void lru_add_drain(void) { - struct pagevec *pvec = &lru_add_pvecs[get_cpu()]; + int cpu = get_cpu(); + struct pagevec *pvec = &per_cpu(lru_add_pvecs, cpu); if (pagevec_count(pvec)) __pagevec_lru_add(pvec); + pvec = &per_cpu(lru_add_active_pvecs, cpu); + if (pagevec_count(pvec)) + __pagevec_lru_add_active(pvec); put_cpu(); } @@ -198,8 +231,6 @@ /* * Add the passed pages to the LRU, then drop the caller's refcount * on them. Reinitialises the caller's pagevec. - * - * Mapped pages go onto the active list. */ void __pagevec_lru_add(struct pagevec *pvec) { @@ -218,13 +249,33 @@ } if (TestSetPageLRU(page)) BUG(); - if (page_mapped(page)) { - if (TestSetPageActive(page)) - BUG(); - add_page_to_active_list(zone, page); - } else { - add_page_to_inactive_list(zone, page); + add_page_to_inactive_list(zone, page); + } + if (zone) + spin_unlock_irq(&zone->lru_lock); + pagevec_release(pvec); +} + +void __pagevec_lru_add_active(struct pagevec *pvec) +{ + int i; + struct zone *zone = NULL; + + for (i = 0; i < pagevec_count(pvec); i++) { + struct page *page = pvec->pages[i]; + struct zone *pagezone = page_zone(page); + + if (pagezone != zone) { + if (zone) + spin_unlock_irq(&zone->lru_lock); + zone = pagezone; + spin_lock_irq(&zone->lru_lock); } + if (TestSetPageLRU(page)) + BUG(); + if (TestSetPageActive(page)) + BUG(); + add_page_to_active_list(zone, page); } if (zone) spin_unlock_irq(&zone->lru_lock); diff -Nru a/mm/swap_state.c b/mm/swap_state.c --- a/mm/swap_state.c Mon Nov 4 14:31:01 2002 +++ b/mm/swap_state.c Mon Nov 4 14:31:01 2002 @@ -376,7 +376,7 @@ /* * Initiate read into locked page and return. */ - lru_cache_add(new_page); + lru_cache_add_active(new_page); swap_readpage(NULL, new_page); return new_page; } diff -Nru a/mm/swapfile.c b/mm/swapfile.c --- a/mm/swapfile.c Mon Nov 4 14:31:01 2002 +++ b/mm/swapfile.c Mon Nov 4 14:31:01 2002 @@ -16,7 +16,9 @@ #include #include #include +#include #include +#include #include #include @@ -389,7 +391,7 @@ } /* mmlist_lock and vma->vm_mm->page_table_lock are held */ -static inline void unuse_pmd(struct vm_area_struct * vma, pmd_t *dir, +static void unuse_pmd(struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long size, unsigned long offset, swp_entry_t entry, struct page* page) { @@ -418,7 +420,7 @@ } /* mmlist_lock and vma->vm_mm->page_table_lock are held */ -static inline void unuse_pgd(struct vm_area_struct * vma, pgd_t *dir, +static void unuse_pgd(struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long size, swp_entry_t entry, struct page* page) { @@ -1121,12 +1123,35 @@ return 0; } -struct seq_operations swaps_op = { +static struct seq_operations swaps_op = { .start = swap_start, .next = swap_next, .stop = swap_stop, .show = swap_show }; + +static int swaps_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &swaps_op); +} + +static struct file_operations proc_swaps_operations = { + .open = swaps_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int __init procswaps_init(void) +{ + struct proc_dir_entry *entry; + + entry = create_proc_entry("swaps", 0, NULL); + if (entry) + entry->proc_fops = &proc_swaps_operations; + return 0; +} +__initcall(procswaps_init); #endif /* CONFIG_PROC_FS */ /* diff -Nru a/mm/vmalloc.c b/mm/vmalloc.c --- a/mm/vmalloc.c Mon Nov 4 14:31:02 2002 +++ b/mm/vmalloc.c Mon Nov 4 14:31:02 2002 @@ -23,7 +23,7 @@ rwlock_t vmlist_lock = RW_LOCK_UNLOCKED; struct vm_struct *vmlist; -static inline void unmap_area_pte(pmd_t *pmd, unsigned long address, +static void unmap_area_pte(pmd_t *pmd, unsigned long address, unsigned long size) { unsigned long end; @@ -56,7 +56,7 @@ } while (address < end); } -static inline void unmap_area_pmd(pgd_t *dir, unsigned long address, +static void unmap_area_pmd(pgd_t *dir, unsigned long address, unsigned long size) { unsigned long end; @@ -83,7 +83,7 @@ } while (address < end); } -static inline int map_area_pte(pte_t *pte, unsigned long address, +static int map_area_pte(pte_t *pte, unsigned long address, unsigned long size, pgprot_t prot, struct page ***pages) { @@ -110,7 +110,7 @@ return 0; } -static inline int map_area_pmd(pmd_t *pmd, unsigned long address, +static int map_area_pmd(pmd_t *pmd, unsigned long address, unsigned long size, pgprot_t prot, struct page ***pages) { diff -Nru a/mm/vmscan.c b/mm/vmscan.c --- a/mm/vmscan.c Mon Nov 4 14:31:00 2002 +++ b/mm/vmscan.c Mon Nov 4 14:31:00 2002 @@ -166,7 +166,7 @@ } /* Must be called with page's pte_chain_lock held. */ -static inline int page_mapping_inuse(struct page * page) +static inline int page_mapping_inuse(struct page *page) { struct address_space *mapping = page->mapping; @@ -178,8 +178,14 @@ if (!mapping) return 0; + /* Be more reluctant to reclaim swapcache than pagecache */ + if (PageSwapCache(page)) + return 1; + /* File is mmap'd by somebody. */ - if (!list_empty(&mapping->i_mmap) || !list_empty(&mapping->i_mmap_shared)) + if (!list_empty(&mapping->i_mmap)) + return 1; + if (!list_empty(&mapping->i_mmap_shared)) return 1; return 0; @@ -193,7 +199,7 @@ /* * shrink_list returns the number of reclaimed pages */ -static /* inline */ int +static int shrink_list(struct list_head *page_list, unsigned int gfp_mask, int *max_scan, int *nr_mapped) { @@ -243,6 +249,7 @@ mapping = page->mapping; +#ifdef CONFIG_SWAP /* * Anonymous process memory without backing store. Try to * allocate it some swap space here. @@ -275,6 +282,7 @@ } } pte_chain_unlock(page); +#endif /* CONFIG_SWAP */ /* * FIXME: this is CPU-inefficient for shared mappings. @@ -370,16 +378,21 @@ goto keep_locked; } +#ifdef CONFIG_SWAP if (PageSwapCache(page)) { swp_entry_t swap = { .val = page->index }; __delete_from_swap_cache(page); write_unlock(&mapping->page_lock); swap_free(swap); - } else { - __remove_from_page_cache(page); - write_unlock(&mapping->page_lock); + __put_page(page); /* The pagecache ref */ + goto free_it; } - __put_page(page); /* The pagecache ref */ +#endif /* CONFIG_SWAP */ + + __remove_from_page_cache(page); + write_unlock(&mapping->page_lock); + __put_page(page); + free_it: unlock_page(page); ret++; @@ -417,7 +430,7 @@ * For pagecache intensive workloads, the first loop here is the hottest spot * in the kernel (apart from the copy_*_user functions). */ -static /* inline */ int +static int shrink_cache(const int nr_pages, struct zone *zone, unsigned int gfp_mask, int max_scan, int *nr_mapped) { @@ -521,7 +534,7 @@ * The downside is that we have to touch page->count against each page. * But we had to alter page->flags anyway. */ -static /* inline */ void +static void refill_inactive_zone(struct zone *zone, const int nr_pages_in, struct page_state *ps, int priority) { @@ -667,7 +680,7 @@ * pages. This is a basic per-zone page freer. Used by both kswapd and * direct reclaim. */ -static /* inline */ int +static int shrink_zone(struct zone *zone, int max_scan, unsigned int gfp_mask, const int nr_pages, int *nr_mapped, struct page_state *ps, int priority) { diff -Nru a/net/bluetooth/Makefile b/net/bluetooth/Makefile --- a/net/bluetooth/Makefile Mon Nov 4 14:31:01 2002 +++ b/net/bluetooth/Makefile Mon Nov 4 14:31:01 2002 @@ -10,6 +10,6 @@ obj-$(CONFIG_BT_RFCOMM) += rfcomm/ obj-$(CONFIG_BT_BNEP) += bnep/ -bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o lib.o syms.o +bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_proc.o lib.o syms.o include $(TOPDIR)/Rules.make diff -Nru a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c --- a/net/bluetooth/af_bluetooth.c Mon Nov 4 14:31:01 2002 +++ b/net/bluetooth/af_bluetooth.c Mon Nov 4 14:31:01 2002 @@ -56,6 +56,10 @@ #define BT_DBG( A... ) #endif +#ifdef CONFIG_PROC_FS +struct proc_dir_entry *proc_bt; +#endif + /* Bluetooth sockets */ #define BT_MAX_PROTO 5 static struct net_proto_family *bt_proto[BT_MAX_PROTO]; @@ -323,14 +327,14 @@ extern int hci_sock_init(void); extern int hci_sock_cleanup(void); +extern int hci_proc_init(void); +extern int hci_proc_cleanup(void); static int __init bt_init(void) { - BT_INFO("Bluetooth Core ver %s Copyright (C) 2000,2001 Qualcomm Inc", - VERSION); - BT_INFO("Written 2000,2001 by Maxim Krasnyansky "); + BT_INFO("Core ver %s", VERSION); - proc_mkdir("bluetooth", NULL); + proc_bt = proc_mkdir("bluetooth", NULL); /* Init socket cache */ bt_sock_cache = kmem_cache_create("bt_sock", @@ -338,12 +342,15 @@ SLAB_HWCACHE_ALIGN, 0, 0); if (!bt_sock_cache) { - BT_ERR("Bluetooth socket cache creation failed"); + BT_ERR("Socket cache creation failed"); return -ENOMEM; } sock_register(&bt_sock_family_ops); + BT_INFO("HCI device and connection manager initialized"); + + hci_proc_init(); hci_sock_init(); return 0; } @@ -351,6 +358,7 @@ static void __exit bt_cleanup(void) { hci_sock_cleanup(); + hci_proc_cleanup(); sock_unregister(PF_BLUETOOTH); kmem_cache_destroy(bt_sock_cache); diff -Nru a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c --- a/net/bluetooth/bnep/core.c Mon Nov 4 14:31:02 2002 +++ b/net/bluetooth/bnep/core.c Mon Nov 4 14:31:02 2002 @@ -561,6 +561,8 @@ else strcpy(dev->name, "bnep%d"); + memset(dev->broadcast, 0xff, ETH_ALEN); + /* This is rx header therefor addresses are swaped. * ie eh.h_dest is our local address. */ memcpy(s->eh.h_dest, &src, ETH_ALEN); @@ -701,17 +703,22 @@ } static int __init bnep_init_module(void) -{ - BT_INFO("BNEP: BNEP2 ver %s\n" - "BNEP: Copyright (C) 2002 Inventel\n" - "BNEP: Written 2001,2002 by\n" - "BNEP: \tClement Moreau " - "David Libault \n" - "BNEP: Copyright (C) 2002 Maxim Krasnyanskiy ", - VERSION); +{ + char flt[50] = ""; - bnep_sock_init(); +#ifdef CONFIG_BT_BNEP_PROTO_FILTER + strcat(flt, "protocol "); +#endif +#ifdef CONFIG_BT_BNEP_MC_FILTER + strcat(flt, "multicast"); +#endif + + BT_INFO("BNEP (Ethernet Emulation) ver %s", VERSION); + if (flt[0]) + BT_INFO("BNEP filters: %s", flt); + + bnep_sock_init(); return 0; } @@ -723,6 +730,6 @@ module_init(bnep_init_module); module_exit(bnep_cleanup_module); -MODULE_DESCRIPTION("BNEP ver " VERSION); -MODULE_AUTHOR("David Libault Maxim Krasnyanskiy "); +MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION); +MODULE_AUTHOR("David Libault , Maxim Krasnyanskiy "); MODULE_LICENSE("GPL"); diff -Nru a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c --- a/net/bluetooth/hci_conn.c Mon Nov 4 14:31:03 2002 +++ b/net/bluetooth/hci_conn.c Mon Nov 4 14:31:03 2002 @@ -215,9 +215,9 @@ BT_DBG("%s -> %s", batostr(src), batostr(dst)); - read_lock_bh(&hdev_list_lock); + read_lock_bh(&hci_dev_list_lock); - list_for_each(p, &hdev_list) { + list_for_each(p, &hci_dev_list) { struct hci_dev *d; d = list_entry(p, struct hci_dev, list); @@ -243,7 +243,7 @@ if (hdev) hci_dev_hold(hdev); - read_unlock_bh(&hdev_list_lock); + read_unlock_bh(&hci_dev_list_lock); return hdev; } diff -Nru a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c --- a/net/bluetooth/hci_core.c Mon Nov 4 14:31:01 2002 +++ b/net/bluetooth/hci_core.c Mon Nov 4 14:31:01 2002 @@ -66,8 +66,8 @@ rwlock_t hci_task_lock = RW_LOCK_UNLOCKED; /* HCI device list */ -LIST_HEAD(hdev_list); -rwlock_t hdev_list_lock = RW_LOCK_UNLOCKED; +LIST_HEAD(hci_dev_list); +rwlock_t hci_dev_list_lock = RW_LOCK_UNLOCKED; /* HCI protocols */ #define HCI_MAX_PROTO 2 @@ -298,8 +298,8 @@ if (index < 0) return NULL; - read_lock(&hdev_list_lock); - list_for_each(p, &hdev_list) { + read_lock(&hci_dev_list_lock); + list_for_each(p, &hci_dev_list) { hdev = list_entry(p, struct hci_dev, list); if (hdev->id == index) { hci_dev_hold(hdev); @@ -308,7 +308,7 @@ } hdev = NULL; done: - read_unlock(&hdev_list_lock); + read_unlock(&hci_dev_list_lock); return hdev; } @@ -727,8 +727,8 @@ return -ENOMEM; dr = dl->dev_req; - read_lock_bh(&hdev_list_lock); - list_for_each(p, &hdev_list) { + read_lock_bh(&hci_dev_list_lock); + list_for_each(p, &hci_dev_list) { struct hci_dev *hdev; hdev = list_entry(p, struct hci_dev, list); (dr + n)->dev_id = hdev->id; @@ -736,7 +736,7 @@ if (++n >= dev_num) break; } - read_unlock_bh(&hdev_list_lock); + read_unlock_bh(&hci_dev_list_lock); dl->dev_num = n; size = n * sizeof(struct hci_dev_req) + sizeof(__u16); @@ -787,7 +787,7 @@ /* Register HCI device */ int hci_register_dev(struct hci_dev *hdev) { - struct list_head *head = &hdev_list, *p; + struct list_head *head = &hci_dev_list, *p; int id = 0; BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type); @@ -795,10 +795,10 @@ if (!hdev->open || !hdev->close || !hdev->destruct) return -EINVAL; - write_lock_bh(&hdev_list_lock); + write_lock_bh(&hci_dev_list_lock); /* Find first available device id */ - list_for_each(p, &hdev_list) { + list_for_each(p, &hci_dev_list) { if (list_entry(p, struct hci_dev, list)->id != id) break; head = p; id++; @@ -836,7 +836,9 @@ MOD_INC_USE_COUNT; - write_unlock_bh(&hdev_list_lock); + write_unlock_bh(&hci_dev_list_lock); + + hci_dev_proc_init(hdev); hci_notify(hdev, HCI_DEV_REG); hci_run_hotplug(hdev->name, "register"); @@ -849,9 +851,11 @@ { BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type); - write_lock_bh(&hdev_list_lock); + hci_dev_proc_cleanup(hdev); + + write_lock_bh(&hci_dev_list_lock); list_del(&hdev->list); - write_unlock_bh(&hdev_list_lock); + write_unlock_bh(&hci_dev_list_lock); hci_dev_do_close(hdev); diff -Nru a/net/bluetooth/hci_proc.c b/net/bluetooth/hci_proc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/bluetooth/hci_proc.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,187 @@ +/* + BlueZ - Bluetooth protocol stack for Linux + Copyright (C) 2000-2001 Qualcomm Incorporated + + Written 2000,2001 by Maxim Krasnyansky + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * Bluetooth HCI Proc FS support. + * + * $Id: hci_proc.c,v 1.0 2002/04/17 17:37:16 maxk Exp $ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifndef CONFIG_BT_HCI_CORE_DEBUG +#undef BT_DBG +#define BT_DBG( A... ) +#endif + +#ifdef CONFIG_PROC_FS +struct proc_dir_entry *proc_bt_hci; + +static int hci_seq_open(struct file *file, struct seq_operations *op, void *priv) +{ + struct seq_file *seq; + + if (seq_open(file, op)) + return -ENOMEM; + + seq = file->private_data; + seq->private = priv; + return 0; +} + +static void *inq_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct hci_dev *hdev = seq->private; + struct inquiry_entry *inq; + loff_t l = *pos; + + hci_dev_lock_bh(hdev); + + for (inq = hdev->inq_cache.list; inq; inq = inq->next) + if (!l--) + return inq; + return NULL; +} + +static void *inq_seq_next(struct seq_file *seq, void *e, loff_t *pos) +{ + struct inquiry_entry *inq = e; + return inq->next; +} + +static void inq_seq_stop(struct seq_file *seq, void *e) +{ + struct hci_dev *hdev = seq->private; + hci_dev_unlock_bh(hdev); +} + +static int inq_seq_show(struct seq_file *seq, void *e) +{ + struct inquiry_entry *inq = e; + struct inquiry_info *info = &inq->info; + + seq_printf(seq, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %u\n", batostr(&info->bdaddr), + info->pscan_rep_mode, info->pscan_period_mode, info->pscan_mode, + info->dev_class[0], info->dev_class[1], info->dev_class[2], + info->clock_offset, inq->timestamp); + return 0; +} + +static struct seq_operations inq_seq_ops = { + .start = inq_seq_start, + .next = inq_seq_next, + .stop = inq_seq_stop, + .show = inq_seq_show +}; + +static int inq_seq_open(struct inode *inode, struct file *file) +{ + return hci_seq_open(file, &inq_seq_ops, PDE(inode)->data); +} + +static struct file_operations inq_seq_fops = { + .open = inq_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +int hci_dev_proc_init(struct hci_dev *hdev) +{ + struct proc_dir_entry *e; + char id[10]; + + sprintf(id, "%d", hdev->id); + + hdev->proc = proc_mkdir(id, proc_bt_hci); + if (!hdev->proc) + return -ENOMEM; + + e = create_proc_entry("inquiry_cache", S_IRUGO, hdev->proc); + if (e) { + e->proc_fops = &inq_seq_fops; + e->data = (void *) hdev; + } + + return 0; +} + +void hci_dev_proc_cleanup(struct hci_dev *hdev) +{ + char id[10]; + sprintf(id, "%d", hdev->id); + + remove_proc_entry("inquiry_cache", hdev->proc); + + remove_proc_entry(id, proc_bt_hci); +} + +int __init hci_proc_init(void) +{ + proc_bt_hci = proc_mkdir("hci", proc_bt); + return 0; +} + +void __init hci_proc_cleanup(void) +{ + remove_proc_entry("hci", proc_bt); +} + +#else /* CONFIG_PROC_FS */ + +int hci_dev_proc_init(struct hci_dev *hdev) +{ + return 0; +} + +void hci_dev_proc_cleanup(struct hci_dev *hdev) +{ + return; +} + +int __init hci_proc_init(void) +{ + return 0; +} + +void __init hci_proc_cleanup(void) +{ + return; +} + +#endif /* CONFIG_PROC_FS */ diff -Nru a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c --- a/net/bluetooth/hci_sock.c Mon Nov 4 14:31:02 2002 +++ b/net/bluetooth/hci_sock.c Mon Nov 4 14:31:02 2002 @@ -628,18 +628,21 @@ int hci_sock_init(void) { if (bt_sock_register(BTPROTO_HCI, &hci_sock_family_ops)) { - BT_ERR("Can't register HCI socket"); + BT_ERR("HCI socket registration failed"); return -EPROTO; } hci_register_notifier(&hci_sock_nblock); + + BT_INFO("HCI socket layer initialized"); + return 0; } int hci_sock_cleanup(void) { if (bt_sock_unregister(BTPROTO_HCI)) - BT_ERR("Can't unregister HCI socket"); + BT_ERR("HCI socket unregistration failed"); hci_unregister_notifier(&hci_sock_nblock); return 0; diff -Nru a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c --- a/net/bluetooth/l2cap.c Mon Nov 4 14:31:02 2002 +++ b/net/bluetooth/l2cap.c Mon Nov 4 14:31:02 2002 @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -1993,52 +1994,90 @@ } /* ---- Proc fs support ---- */ -static int l2cap_sock_dump(char *buf, struct bt_sock_list *list) +#ifdef CONFIG_PROC_FS +static void *l2cap_seq_start(struct seq_file *seq, loff_t *pos) { - struct l2cap_pinfo *pi; struct sock *sk; - char *ptr = buf; + loff_t l = *pos; - read_lock_bh(&list->lock); + read_lock_bh(&l2cap_sk_list.lock); - for (sk = list->head; sk; sk = sk->next) { - pi = l2cap_pi(sk); - ptr += sprintf(ptr, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n", - batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->state, pi->psm, pi->scid, pi->dcid, pi->imtu, pi->omtu, - pi->link_mode); - } + for (sk = l2cap_sk_list.head; sk; sk = sk->next) + if (!l--) + return sk; + return NULL; +} - read_unlock_bh(&list->lock); +static void *l2cap_seq_next(struct seq_file *seq, void *e, loff_t *pos) +{ + struct sock *sk = e; + (*pos)++; + return sk->next; +} - ptr += sprintf(ptr, "\n"); - return ptr - buf; +static void l2cap_seq_stop(struct seq_file *seq, void *e) +{ + read_unlock_bh(&l2cap_sk_list.lock); } -static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) +static int l2cap_seq_show(struct seq_file *seq, void *e) { - char *ptr = buf; - int len; + struct sock *sk = e; + struct l2cap_pinfo *pi = l2cap_pi(sk); - BT_DBG("count %d, offset %ld", count, offset); + seq_printf(seq, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n", + batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), + sk->state, pi->psm, pi->scid, pi->dcid, pi->imtu, pi->omtu, + pi->link_mode); + return 0; +} - ptr += l2cap_sock_dump(ptr, &l2cap_sk_list); - len = ptr - buf; +static struct seq_operations l2cap_seq_ops = { + .start = l2cap_seq_start, + .next = l2cap_seq_next, + .stop = l2cap_seq_stop, + .show = l2cap_seq_show +}; - if (len <= count + offset) - *eof = 1; +static int l2cap_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &l2cap_seq_ops); +} - *start = buf + offset; - len -= offset; +static struct file_operations l2cap_seq_fops = { + .open = l2cap_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; - if (len > count) - len = count; - if (len < 0) - len = 0; +static int __init l2cap_proc_init(void) +{ + struct proc_dir_entry *p = create_proc_entry("l2cap", S_IRUGO, proc_bt); + if (!p) + return -ENOMEM; + p->proc_fops = &l2cap_seq_fops; + return 0; +} - return len; +static void __init l2cap_proc_cleanup(void) +{ + remove_proc_entry("l2cap", proc_bt); } +#else /* CONFIG_PROC_FS */ + +static int __init l2cap_proc_init(void) +{ + return 0; +} + +static void __init l2cap_proc_cleanup(void) +{ + return 0; +} +#endif /* CONFIG_PROC_FS */ + static struct proto_ops l2cap_sock_ops = { .family = PF_BLUETOOTH, .release = l2cap_sock_release, @@ -2079,32 +2118,34 @@ int err; if ((err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops))) { - BT_ERR("Can't register L2CAP socket"); + BT_ERR("L2CAP socket registration failed"); return err; } if ((err = hci_register_proto(&l2cap_hci_proto))) { - BT_ERR("Can't register L2CAP protocol"); + BT_ERR("L2CAP protocol registration failed"); return err; } - create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL); - BT_INFO("Bluetooth L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION); - BT_INFO("Written 2000,2001 by Maxim Krasnyansky "); + l2cap_proc_init(); + + BT_INFO("L2CAP ver %s", VERSION); + BT_INFO("L2CAP socket layer initialized"); + return 0; } void l2cap_cleanup(void) { - remove_proc_entry("bluetooth/l2cap", NULL); + l2cap_proc_cleanup(); /* Unregister socket and protocol */ if (bt_sock_unregister(BTPROTO_L2CAP)) - BT_ERR("Can't unregister L2CAP socket"); + BT_ERR("L2CAP socket unregistration failed"); if (hci_unregister_proto(&l2cap_hci_proto)) - BT_ERR("Can't unregister L2CAP protocol"); + BT_ERR("L2CAP protocol unregistration failed"); } module_init(l2cap_init); diff -Nru a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c --- a/net/bluetooth/rfcomm/core.c Mon Nov 4 14:31:00 2002 +++ b/net/bluetooth/rfcomm/core.c Mon Nov 4 14:31:00 2002 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,10 @@ #define BT_DBG(D...) #endif +#ifdef CONFIG_PROC_FS +struct proc_dir_entry *proc_bt_rfcomm; +#endif + struct task_struct *rfcomm_thread; DECLARE_MUTEX(rfcomm_sem); unsigned long rfcomm_event; @@ -1723,77 +1728,128 @@ } /* ---- Proc fs support ---- */ -static int rfcomm_dlc_dump(char *buf) +#ifdef CONFIG_PROC_FS +static void *rfcomm_seq_start(struct seq_file *seq, loff_t *pos) { struct rfcomm_session *s; - struct sock *sk; - struct list_head *p, *pp; - char *ptr = buf; + struct list_head *pp, *p; + loff_t l = *pos; rfcomm_lock(); list_for_each(p, &session_list) { s = list_entry(p, struct rfcomm_session, list); - sk = s->sock->sk; + list_for_each(pp, &s->dlcs) + if (!l--) { + seq->private = s; + return pp; + } + } + return NULL; +} + +static void *rfcomm_seq_next(struct seq_file *seq, void *e, loff_t *pos) +{ + struct rfcomm_session *s = seq->private; + struct list_head *pp, *p = e; + (*pos)++; - list_for_each(pp, &s->dlcs) { - struct rfcomm_dlc *d; - d = list_entry(pp, struct rfcomm_dlc, list); - - ptr += sprintf(ptr, "dlc %s %s %ld %d %d %d %d\n", - batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits); + if (p->next != &s->dlcs) + return p->next; + + for (p = s->list.next; p != &session_list; p = p->next) { + s = list_entry(p, struct rfcomm_session, list); + __list_for_each(pp, &s->dlcs) { + seq->private = s; + return pp; } } - + return NULL; +} + +static void rfcomm_seq_stop(struct seq_file *seq, void *e) +{ rfcomm_unlock(); +} + +static int rfcomm_seq_show(struct seq_file *seq, void *e) +{ + struct rfcomm_session *s = seq->private; + struct sock *sk = s->sock->sk; + struct rfcomm_dlc *d = list_entry(e, struct rfcomm_dlc, list); - return ptr - buf; + seq_printf(seq, "%s %s %ld %d %d %d %d\n", + batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), + d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits); + return 0; +} + +static struct seq_operations rfcomm_seq_ops = { + .start = rfcomm_seq_start, + .next = rfcomm_seq_next, + .stop = rfcomm_seq_stop, + .show = rfcomm_seq_show +}; + +static int rfcomm_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &rfcomm_seq_ops); } -extern int rfcomm_sock_dump(char *buf); +static struct file_operations rfcomm_seq_fops = { + .open = rfcomm_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; -static int rfcomm_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) +static int __init rfcomm_proc_init(void) { - char *ptr = buf; - int len; + struct proc_dir_entry *p; - BT_DBG("count %d, offset %ld", count, offset); + proc_bt_rfcomm = proc_mkdir("rfcomm", proc_bt); - ptr += rfcomm_dlc_dump(ptr); - ptr += rfcomm_sock_dump(ptr); - len = ptr - buf; + p = create_proc_entry("dlc", S_IRUGO, proc_bt_rfcomm); + if (p) + p->proc_fops = &rfcomm_seq_fops; + return 0; +} - if (len <= count + offset) - *eof = 1; +static void __init rfcomm_proc_cleanup(void) +{ + remove_proc_entry("dlc", proc_bt_rfcomm); - *start = buf + offset; - len -= offset; + remove_proc_entry("rfcomm", proc_bt); +} - if (len > count) - len = count; - if (len < 0) - len = 0; +#else /* CONFIG_PROC_FS */ - return len; +static int __init rfcomm_proc_init(void) +{ + return 0; } +static void __init rfcomm_proc_cleanup(void) +{ + return 0; +} +#endif /* CONFIG_PROC_FS */ + /* ---- Initialization ---- */ int __init rfcomm_init(void) { kernel_thread(rfcomm_run, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + BT_INFO("RFCOMM ver %s", VERSION); + + rfcomm_proc_init(); + rfcomm_init_sockets(); #ifdef CONFIG_BT_RFCOMM_TTY rfcomm_init_ttys(); #endif - create_proc_read_entry("bluetooth/rfcomm", 0, 0, rfcomm_read_proc, NULL); - - BT_INFO("Bluetooth RFCOMM ver %s", VERSION); - BT_INFO("Copyright (C) 2002 Maxim Krasnyansky "); - BT_INFO("Copyright (C) 2002 Marcel Holtmann "); return 0; } @@ -1808,14 +1864,13 @@ while (atomic_read(&running)) schedule(); - remove_proc_entry("bluetooth/rfcomm", NULL); - #ifdef CONFIG_BT_RFCOMM_TTY rfcomm_cleanup_ttys(); #endif rfcomm_cleanup_sockets(); - return; + + rfcomm_proc_cleanup(); } module_init(rfcomm_init); diff -Nru a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c --- a/net/bluetooth/rfcomm/sock.c Mon Nov 4 14:31:02 2002 +++ b/net/bluetooth/rfcomm/sock.c Mon Nov 4 14:31:02 2002 @@ -44,6 +44,8 @@ #include #include #include +#include +#include #include #include @@ -772,27 +774,87 @@ } /* ---- Proc fs support ---- */ -int rfcomm_sock_dump(char *buf) +#ifdef CONFIG_PROC_FS +static void *rfcomm_seq_start(struct seq_file *seq, loff_t *pos) { - struct bt_sock_list *list = &rfcomm_sk_list; - struct rfcomm_pinfo *pi; struct sock *sk; - char *ptr = buf; + loff_t l = *pos; - write_lock_bh(&list->lock); + read_lock_bh(&rfcomm_sk_list.lock); - for (sk = list->head; sk; sk = sk->next) { - pi = rfcomm_pi(sk); - ptr += sprintf(ptr, "sk %s %s %d %d\n", - batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->state, rfcomm_pi(sk)->channel); - } + for (sk = rfcomm_sk_list.head; sk; sk = sk->next) + if (!l--) + return sk; + return NULL; +} + +static void *rfcomm_seq_next(struct seq_file *seq, void *e, loff_t *pos) +{ + struct sock *sk = e; + (*pos)++; + return sk->next; +} + +static void rfcomm_seq_stop(struct seq_file *seq, void *e) +{ + read_unlock_bh(&rfcomm_sk_list.lock); +} - write_unlock_bh(&list->lock); +static int rfcomm_seq_show(struct seq_file *seq, void *e) +{ + struct sock *sk = e; + seq_printf(seq, "%s %s %d %d\n", + batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), + sk->state, rfcomm_pi(sk)->channel); + return 0; +} + +static struct seq_operations rfcomm_seq_ops = { + .start = rfcomm_seq_start, + .next = rfcomm_seq_next, + .stop = rfcomm_seq_stop, + .show = rfcomm_seq_show +}; - return ptr - buf; +static int rfcomm_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &rfcomm_seq_ops); } +static struct file_operations rfcomm_seq_fops = { + .open = rfcomm_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int __init rfcomm_sock_proc_init(void) +{ + struct proc_dir_entry *p = create_proc_entry("sock", S_IRUGO, proc_bt_rfcomm); + if (!p) + return -ENOMEM; + p->proc_fops = &rfcomm_seq_fops; + return 0; +} + +static void __init rfcomm_sock_proc_cleanup(void) +{ + remove_proc_entry("sock", proc_bt_rfcomm); +} + +#else /* CONFIG_PROC_FS */ + +static int __init rfcomm_sock_proc_init(void) +{ + return 0; +} + +static void __init rfcomm_sock_proc_cleanup(void) +{ + return 0; +} +#endif /* CONFIG_PROC_FS */ + static struct proto_ops rfcomm_sock_ops = { .family = PF_BLUETOOTH, .release = rfcomm_sock_release, @@ -822,10 +884,13 @@ int err; if ((err = bt_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops))) { - BT_ERR("Can't register RFCOMM socket layer"); + BT_ERR("RFCOMM socket layer registration failed. %d", err); return err; } + rfcomm_sock_proc_init(); + + BT_INFO("RFCOMM socket layer initialized"); return 0; } @@ -833,7 +898,9 @@ { int err; + rfcomm_sock_proc_cleanup(); + /* Unregister socket, protocol and notifier */ if ((err = bt_sock_unregister(BTPROTO_RFCOMM))) - BT_ERR("Can't unregister RFCOMM socket layer %d", err); + BT_ERR("RFCOMM socket layer unregistration failed. %d", err); } diff -Nru a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c --- a/net/bluetooth/rfcomm/tty.c Mon Nov 4 14:31:02 2002 +++ b/net/bluetooth/rfcomm/tty.c Mon Nov 4 14:31:02 2002 @@ -500,10 +500,10 @@ BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig); dev->modem_status = - (v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0 | - (v24_sig & RFCOMM_V24_RTR) ? (TIOCM_RTS | TIOCM_CTS) : 0 | - (v24_sig & RFCOMM_V24_IC) ? TIOCM_RI : 0 | - (v24_sig & RFCOMM_V24_DV) ? TIOCM_CD : 0; + ((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) | + ((v24_sig & RFCOMM_V24_RTR) ? (TIOCM_RTS | TIOCM_CTS) : 0) | + ((v24_sig & RFCOMM_V24_IC) ? TIOCM_RI : 0) | + ((v24_sig & RFCOMM_V24_DV) ? TIOCM_CD : 0); } /* ---- TTY functions ---- */ @@ -572,6 +572,11 @@ if (dlc->state == BT_CONNECTED) break; + if (signal_pending(current)) { + err = -EINTR; + break; + } + schedule(); } set_current_state(TASK_RUNNING); @@ -898,6 +903,8 @@ BT_ERR("Can't register RFCOMM TTY driver"); return -1; } + + BT_INFO("RFCOMM TTY layer initialized"); return 0; } diff -Nru a/net/bluetooth/sco.c b/net/bluetooth/sco.c --- a/net/bluetooth/sco.c Mon Nov 4 14:31:01 2002 +++ b/net/bluetooth/sco.c Mon Nov 4 14:31:01 2002 @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -884,52 +885,86 @@ return 0; } -/* ----- Proc fs support ------ */ -static int sco_sock_dump(char *buf, struct bt_sock_list *list) +/* ---- Proc fs support ---- */ +#ifdef CONFIG_PROC_FS +static void *sco_seq_start(struct seq_file *seq, loff_t *pos) { - struct sco_pinfo *pi; struct sock *sk; - char *ptr = buf; + loff_t l = *pos; - read_lock_bh(&list->lock); + read_lock_bh(&sco_sk_list.lock); - for (sk = list->head; sk; sk = sk->next) { - pi = sco_pi(sk); - ptr += sprintf(ptr, "%s %s %d\n", - batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->state); - } + for (sk = sco_sk_list.head; sk; sk = sk->next) + if (!l--) + return sk; + return NULL; +} - read_unlock_bh(&list->lock); +static void *sco_seq_next(struct seq_file *seq, void *e, loff_t *pos) +{ + struct sock *sk = e; + (*pos)++; + return sk->next; +} - ptr += sprintf(ptr, "\n"); +static void sco_seq_stop(struct seq_file *seq, void *e) +{ + read_unlock_bh(&sco_sk_list.lock); +} - return ptr - buf; +static int sco_seq_show(struct seq_file *seq, void *e) +{ + struct sock *sk = e; + seq_printf(seq, "%s %s %d\n", + batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), sk->state); + return 0; } -static int sco_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) +static struct seq_operations sco_seq_ops = { + .start = sco_seq_start, + .next = sco_seq_next, + .stop = sco_seq_stop, + .show = sco_seq_show +}; + +static int sco_seq_open(struct inode *inode, struct file *file) { - char *ptr = buf; - int len; + return seq_open(file, &sco_seq_ops); +} - BT_DBG("count %d, offset %ld", count, offset); +static struct file_operations sco_seq_fops = { + .open = sco_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; - ptr += sco_sock_dump(ptr, &sco_sk_list); - len = ptr - buf; +static int __init sco_proc_init(void) +{ + struct proc_dir_entry *p = create_proc_entry("sco", S_IRUGO, proc_bt); + if (!p) + return -ENOMEM; + p->proc_fops = &sco_seq_fops; + return 0; +} - if (len <= count + offset) - *eof = 1; +static void __init sco_proc_cleanup(void) +{ + remove_proc_entry("sco", proc_bt); +} - *start = buf + offset; - len -= offset; +#else /* CONFIG_PROC_FS */ - if (len > count) - len = count; - if (len < 0) - len = 0; +static int __init sco_proc_init(void) +{ + return 0; +} - return len; +static void __init sco_proc_cleanup(void) +{ + return 0; } +#endif /* CONFIG_PROC_FS */ static struct proto_ops sco_sock_ops = { .family = PF_BLUETOOTH, @@ -969,19 +1004,20 @@ int err; if ((err = bt_sock_register(BTPROTO_SCO, &sco_sock_family_ops))) { - BT_ERR("Can't register SCO socket layer"); + BT_ERR("SCO socket registration failed"); return err; } if ((err = hci_register_proto(&sco_hci_proto))) { - BT_ERR("Can't register SCO protocol"); + BT_ERR("SCO protocol registration failed"); return err; } - create_proc_read_entry("bluetooth/sco", 0, 0, sco_read_proc, NULL); + sco_proc_init(); + + BT_INFO("SCO (Voice Link) ver %s", VERSION); + BT_INFO("SCO socket layer initialized"); - BT_INFO("Bluetooth SCO ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION); - BT_INFO("Written 2000,2001 by Maxim Krasnyansky "); return 0; } @@ -989,14 +1025,14 @@ { int err; - remove_proc_entry("bluetooth/sco", NULL); + sco_proc_cleanup(); /* Unregister socket, protocol and notifier */ if ((err = bt_sock_unregister(BTPROTO_SCO))) - BT_ERR("Can't unregister SCO socket layer %d", err); + BT_ERR("SCO socket unregistration failed. %d", err); if ((err = hci_unregister_proto(&sco_hci_proto))) - BT_ERR("Can't unregister SCO protocol %d", err); + BT_ERR("SCO protocol unregistration failed. %d", err); } module_init(sco_init); diff -Nru a/net/bluetooth/syms.c b/net/bluetooth/syms.c --- a/net/bluetooth/syms.c Mon Nov 4 14:31:02 2002 +++ b/net/bluetooth/syms.c Mon Nov 4 14:31:02 2002 @@ -78,3 +78,5 @@ EXPORT_SYMBOL(bt_accept_enqueue); EXPORT_SYMBOL(bt_accept_dequeue); EXPORT_SYMBOL(bt_sock_w4_connect); + +EXPORT_SYMBOL(proc_bt); diff -Nru a/net/ipv4/tcp.c b/net/ipv4/tcp.c --- a/net/ipv4/tcp.c Mon Nov 4 14:31:01 2002 +++ b/net/ipv4/tcp.c Mon Nov 4 14:31:01 2002 @@ -476,8 +476,8 @@ if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible(sk->sleep); - if (!(sk->shutdown & SEND_SHUTDOWN)) - sk_wake_async(sk, 2, POLL_OUT); + if (sock->fasync_list && !(sk->shutdown & SEND_SHUTDOWN)) + sock_wake_async(sock, 2, POLL_OUT); } } diff -Nru a/net/rxrpc/Makefile b/net/rxrpc/Makefile --- a/net/rxrpc/Makefile Mon Nov 4 14:31:02 2002 +++ b/net/rxrpc/Makefile Mon Nov 4 14:31:02 2002 @@ -15,19 +15,13 @@ rxrpc_syms.o \ transport.o -#ifeq ($(CONFIG_PROC_FS),y) -rxrpc-objs += proc.o -#endif -#ifeq ($(CONFIG_SYSCTL),y) +ifeq ($(CONFIG_PROC_FS),y) +rxrpc-objs += proc.o +endif +ifeq ($(CONFIG_SYSCTL),y) rxrpc-objs += sysctl.o -#endif - -obj-m := rxrpc.o - -# superfluous for 2.5, but needed for 2.4.. -ifeq "$(VERSION).$(PATCHLEVEL)" "2.4" -rxrpc.o: $(rxrpc-objs) - $(LD) -r -o $@ $(rxrpc-objs) endif + +obj-$(CONFIG_RXRPC) := rxrpc.o include $(TOPDIR)/Rules.make diff -Nru a/net/rxrpc/call.c b/net/rxrpc/call.c --- a/net/rxrpc/call.c Mon Nov 4 14:31:01 2002 +++ b/net/rxrpc/call.c Mon Nov 4 14:31:01 2002 @@ -26,10 +26,10 @@ LIST_HEAD(rxrpc_calls); DECLARE_RWSEM(rxrpc_calls_sem); -unsigned rxrpc_call_rcv_timeout = 30; -unsigned rxrpc_call_acks_timeout = 30; -unsigned rxrpc_call_dfr_ack_timeout = 5; -unsigned short rxrpc_call_max_resend = 10; +unsigned rxrpc_call_rcv_timeout = HZ/3; +unsigned rxrpc_call_acks_timeout = HZ/3; +unsigned rxrpc_call_dfr_ack_timeout = HZ/20; +unsigned short rxrpc_call_max_resend = HZ/10; const char *rxrpc_call_states[] = { "COMPLETE", @@ -131,6 +131,22 @@ /*****************************************************************************/ /* + * calculate a timeout based on an RTT value + */ +static inline unsigned long __rxrpc_rtt_based_timeout(struct rxrpc_call *call, unsigned long val) +{ + unsigned long expiry = call->conn->peer->rtt / (1000000/HZ); + + expiry += 10; + if (expiryHZ) expiry = HZ; + + _leave(" = %lu jiffies",expiry); + return jiffies + expiry; +} /* end __rxrpc_rtt_based_timeout() */ + +/*****************************************************************************/ +/* * create a new call record */ static inline int __rxrpc_create_call(struct rxrpc_connection *conn, @@ -321,7 +337,10 @@ spin_lock(&conn->lock); - if (!conn->channels[cix]) { + if (!conn->channels[cix] || + conn->channels[cix]->app_call_state == RXRPC_CSTATE_COMPLETE || + conn->channels[cix]->app_call_state == RXRPC_CSTATE_ERROR + ) { conn->channels[cix] = call; rxrpc_get_connection(conn); ret = 0; @@ -329,9 +348,10 @@ spin_unlock(&conn->lock); - if (ret<0) free_page((unsigned long)call); - - _leave(" = %p",call); + if (ret<0) { + free_page((unsigned long)call); + call = NULL; + } if (ret==0) { down_write(&rxrpc_calls_sem); @@ -341,6 +361,7 @@ *_call = call; } + _leave(" = %d [%p]",ret,call); return ret; } /* end rxrpc_incoming_call() */ @@ -367,7 +388,8 @@ return; } - conn->channels[ntohl(call->chan_ix)] = NULL; + if (conn->channels[ntohl(call->chan_ix)]==call) + conn->channels[ntohl(call->chan_ix)] = NULL; spin_unlock(&conn->lock); @@ -1005,7 +1027,7 @@ } /* next in sequence - simply append into the call's ready queue */ - _debug("Call add packet %d to readyq (+%d => %d bytes)", + _debug("Call add packet %d to readyq (+%Zd => %Zd bytes)", msg->seq,msg->dsize,call->app_ready_qty); spin_lock(&call->lock); @@ -1021,7 +1043,7 @@ break; /* next in sequence - just move list-to-list */ - _debug("Call transfer packet %d to readyq (+%d => %d bytes)", + _debug("Call transfer packet %d to readyq (+%Zd => %Zd bytes)", pmsg->seq,pmsg->dsize,call->app_ready_qty); call->app_ready_seq = pmsg->seq; @@ -1156,7 +1178,7 @@ /* otherwise just invoke the data function whenever we can satisfy its desire for more * data */ - _proto("Rx Received Op Data: st=%u qty=%u mk=%u%s", + _proto("Rx Received Op Data: st=%u qty=%Zu mk=%Zu%s", call->app_call_state,call->app_ready_qty,call->app_mark, call->app_last_rcv ? " last-rcvd" : ""); @@ -1394,7 +1416,7 @@ char resend, now_complete; u8 acks[16]; - _enter("%p{apc=%u ads=%u},%p,%u,%u", + _enter("%p{apc=%u ads=%u},%p,%u,%Zu", call,call->acks_pend_cnt,call->acks_dftv_seq,msg,seq,count); /* handle re-ACK'ing of definitively ACK'd packets (may be out-of-order ACKs) */ @@ -1443,7 +1465,7 @@ } _proto("Rx ACK of packets #%u-#%u [%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c] (pend=%u)", - seq,seq+chunk-1, + seq,(unsigned)(seq+chunk-1), _acktype[acks[0x0]], _acktype[acks[0x1]], _acktype[acks[0x2]], @@ -1552,7 +1574,7 @@ size_t qty; int ret; - _enter("%p{as=%d buf=%p qty=%u/%u}", + _enter("%p{as=%d buf=%p qty=%Zu/%Zu}", call,call->app_async_read,call->app_read_buf,call->app_ready_qty,call->app_mark); /* check the state */ @@ -1560,7 +1582,7 @@ case RXRPC_CSTATE_SRVR_RCV_ARGS: case RXRPC_CSTATE_CLNT_RCV_REPLY: if (call->app_last_rcv) { - printk("%s(%p,%p,%d): Inconsistent call state (%s, last pkt)", + printk("%s(%p,%p,%Zd): Inconsistent call state (%s, last pkt)", __FUNCTION__,call,call->app_read_buf,call->app_mark, rxrpc_call_states[call->app_call_state]); BUG(); @@ -1574,7 +1596,7 @@ case RXRPC_CSTATE_SRVR_SND_REPLY: if (!call->app_last_rcv) { - printk("%s(%p,%p,%d): Inconsistent call state (%s, not last pkt)", + printk("%s(%p,%p,%Zd): Inconsistent call state (%s, not last pkt)", __FUNCTION__,call,call->app_read_buf,call->app_mark, rxrpc_call_states[call->app_call_state]); BUG(); @@ -1616,11 +1638,11 @@ /* drag as much data as we need out of this packet */ qty = min(call->app_mark,msg->dsize); - _debug("reading %u from skb=%p off=%lu",qty,msg->pkt,msg->offset); + _debug("reading %Zu from skb=%p off=%lu",qty,msg->pkt,msg->offset); if (call->app_read_buf) if (skb_copy_bits(msg->pkt,msg->offset,call->app_read_buf,qty)<0) - panic("%s: Failed to copy data from packet: (%p,%p,%d)", + panic("%s: Failed to copy data from packet: (%p,%p,%Zd)", __FUNCTION__,call,call->app_read_buf,qty); /* if that packet is now empty, discard it */ @@ -1673,7 +1695,7 @@ } if (call->app_last_rcv) { - _debug("Insufficient data (%u/%u)",call->app_ready_qty,call->app_mark); + _debug("Insufficient data (%Zu/%Zu)",call->app_ready_qty,call->app_mark); call->app_async_read = 0; call->app_mark = RXRPC_APP_MARK_EOF; call->app_read_buf = NULL; @@ -1703,7 +1725,7 @@ { int ret; - _enter("%p{arq=%u},%p,%d,%x",call,call->app_ready_qty,buffer,size,flags); + _enter("%p{arq=%Zu},%p,%Zd,%x",call,call->app_ready_qty,buffer,size,flags); spin_lock(&call->lock); @@ -1799,7 +1821,7 @@ char *buf; int ret; - _enter("%p,%u,%p,%02x,%x,%d,%p",call,sioc,siov,rxhdr_flags,alloc_flags,dup_data,size_sent); + _enter("%p,%Zu,%p,%02x,%x,%d,%p",call,sioc,siov,rxhdr_flags,alloc_flags,dup_data,size_sent); *size_sent = 0; size = 0; @@ -1827,7 +1849,7 @@ size += sptr->iov_len; } - _debug("- size=%u mtu=%u",size,call->conn->mtu_size); + _debug("- size=%Zu mtu=%Zu",size,call->conn->mtu_size); do { /* make sure there's a message under construction */ @@ -1837,7 +1859,7 @@ 0,NULL,alloc_flags,&call->snd_nextmsg); if (ret<0) goto out; - _debug("- allocated new message [ds=%u]",call->snd_nextmsg->dsize); + _debug("- allocated new message [ds=%Zu]",call->snd_nextmsg->dsize); } msg = call->snd_nextmsg; @@ -1857,7 +1879,7 @@ space = call->conn->mtu_size - msg->dsize; chunk = min(space,size); - _debug("- [before] space=%u chunk=%u",space,chunk); + _debug("- [before] space=%Zu chunk=%Zu",space,chunk); while (!siov->iov_len) siov++; @@ -1916,7 +1938,7 @@ } } - _debug("- [loaded] chunk=%u size=%u",chunk,size); + _debug("- [loaded] chunk=%Zu size=%Zu",chunk,size); /* dispatch the message when full, final or requesting ACK */ if (msg->dsize>=call->conn->mtu_size || rxhdr_flags) { @@ -1929,7 +1951,7 @@ ret = 0; out: - _leave(" = %d (%d queued, %d rem)",ret,*size_sent,size); + _leave(" = %d (%Zd queued, %Zd rem)",ret,*size_sent,size); return ret; } /* end rxrpc_call_write_data() */ @@ -1960,7 +1982,7 @@ msg->hdr.flags |= RXRPC_MORE_PACKETS; } - _proto("Sending DATA message { ds=%u dc=%u df=%02lu }", + _proto("Sending DATA message { ds=%Zu dc=%u df=%02lu }", msg->dsize,msg->dcount,msg->dfree); /* queue and adjust call state */ @@ -1993,7 +2015,8 @@ call->acks_pend_cnt++; - mod_timer(&call->acks_timeout,jiffies + rxrpc_call_acks_timeout); + mod_timer(&call->acks_timeout, + __rxrpc_rtt_based_timeout(call,rxrpc_call_acks_timeout)); spin_unlock(&call->lock); @@ -2061,7 +2084,7 @@ spin_unlock(&call->lock); /* send each message again (and ignore any errors we might incur) */ - _proto("Resending DATA message { ds=%u dc=%u df=%02lu }", + _proto("Resending DATA message { ds=%Zu dc=%u df=%02lu }", msg->dsize,msg->dcount,msg->dfree); if (rxrpc_conn_sendmsg(call->conn,msg)==0) @@ -2073,7 +2096,7 @@ } /* reset the timeout */ - mod_timer(&call->acks_timeout,jiffies + rxrpc_call_acks_timeout); + mod_timer(&call->acks_timeout,__rxrpc_rtt_based_timeout(call,rxrpc_call_acks_timeout)); spin_unlock(&call->lock); diff -Nru a/net/rxrpc/connection.c b/net/rxrpc/connection.c --- a/net/rxrpc/connection.c Mon Nov 4 14:31:02 2002 +++ b/net/rxrpc/connection.c Mon Nov 4 14:31:02 2002 @@ -121,7 +121,7 @@ conn->out_epoch = rxrpc_epoch; conn->in_clientflag = 0; conn->out_clientflag = RXRPC_CLIENT_INITIATED; - conn->conn_id = htonl((unsigned) conn & RXRPC_CIDMASK); + conn->conn_id = htonl((unsigned long) conn & RXRPC_CIDMASK); conn->service_id = htons(service_id); /* attach to peer */ @@ -547,7 +547,7 @@ msghdr.msg_controllen = 0; msghdr.msg_flags = MSG_CONFIRM|MSG_DONTWAIT; - _net("Sending message type %d of %d bytes to %08x:%d", + _net("Sending message type %d of %Zd bytes to %08x:%d", msg->hdr.type, msg->dsize, htonl(conn->addr.sin_addr.s_addr), diff -Nru a/net/rxrpc/internal.h b/net/rxrpc/internal.h --- a/net/rxrpc/internal.h Mon Nov 4 14:31:01 2002 +++ b/net/rxrpc/internal.h Mon Nov 4 14:31:01 2002 @@ -29,24 +29,24 @@ /* * debug tracing */ -#define kenter(FMT,...) printk("==> %s("FMT")\n",__FUNCTION__,##__VA_ARGS__) -#define kleave(FMT,...) printk("<== %s()"FMT"\n",__FUNCTION__,##__VA_ARGS__) -#define kdebug(FMT,...) printk(" "FMT"\n",##__VA_ARGS__) -#define kproto(FMT,...) printk("### "FMT"\n",##__VA_ARGS__) -#define knet(FMT,...) printk(" "FMT"\n",##__VA_ARGS__) +#define kenter(FMT, a...) printk("==> %s("FMT")\n",__FUNCTION__ , ##a) +#define kleave(FMT, a...) printk("<== %s()"FMT"\n",__FUNCTION__ , ##a) +#define kdebug(FMT, a...) printk(" "FMT"\n" , ##a) +#define kproto(FMT, a...) printk("### "FMT"\n" , ##a) +#define knet(FMT, a...) printk(" "FMT"\n" , ##a) #if 0 -#define _enter(FMT,...) kenter(FMT,##__VA_ARGS__) -#define _leave(FMT,...) kleave(FMT,##__VA_ARGS__) -#define _debug(FMT,...) kdebug(FMT,##__VA_ARGS__) -#define _proto(FMT,...) kproto(FMT,##__VA_ARGS__) -#define _net(FMT,...) knet(FMT,##__VA_ARGS__) +#define _enter(FMT, a...) kenter(FMT , ##a) +#define _leave(FMT, a...) kleave(FMT , ##a) +#define _debug(FMT, a...) kdebug(FMT , ##a) +#define _proto(FMT, a...) kproto(FMT , ##a) +#define _net(FMT, a...) knet(FMT , ##a) #else -#define _enter(FMT,...) do { if (rxrpc_ktrace) kenter(FMT,##__VA_ARGS__); } while(0) -#define _leave(FMT,...) do { if (rxrpc_ktrace) kleave(FMT,##__VA_ARGS__); } while(0) -#define _debug(FMT,...) do { if (rxrpc_kdebug) kdebug(FMT,##__VA_ARGS__); } while(0) -#define _proto(FMT,...) do { if (rxrpc_kproto) kproto(FMT,##__VA_ARGS__); } while(0) -#define _net(FMT,...) do { if (rxrpc_knet) knet (FMT,##__VA_ARGS__); } while(0) +#define _enter(FMT, a...) do { if (rxrpc_ktrace) kenter(FMT , ##a); } while(0) +#define _leave(FMT, a...) do { if (rxrpc_ktrace) kleave(FMT , ##a); } while(0) +#define _debug(FMT, a...) do { if (rxrpc_kdebug) kdebug(FMT , ##a); } while(0) +#define _proto(FMT, a...) do { if (rxrpc_kproto) kproto(FMT , ##a); } while(0) +#define _net(FMT, a...) do { if (rxrpc_knet) knet (FMT , ##a); } while(0) #endif static inline void rxrpc_discard_my_signals(void) diff -Nru a/net/rxrpc/krxiod.c b/net/rxrpc/krxiod.c --- a/net/rxrpc/krxiod.c Mon Nov 4 14:31:00 2002 +++ b/net/rxrpc/krxiod.c Mon Nov 4 14:31:00 2002 @@ -49,11 +49,7 @@ /* only certain signals are of interest */ spin_lock_irq(¤t->sig->siglock); siginitsetinv(¤t->blocked,0); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,3) recalc_sigpending(); -#else - recalc_sigpending(current); -#endif spin_unlock_irq(¤t->sig->siglock); /* loop around waiting for work to do */ diff -Nru a/net/rxrpc/krxsecd.c b/net/rxrpc/krxsecd.c --- a/net/rxrpc/krxsecd.c Mon Nov 4 14:31:01 2002 +++ b/net/rxrpc/krxsecd.c Mon Nov 4 14:31:01 2002 @@ -61,11 +61,7 @@ /* only certain signals are of interest */ spin_lock_irq(¤t->sig->siglock); siginitsetinv(¤t->blocked,0); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,3) recalc_sigpending(); -#else - recalc_sigpending(current); -#endif spin_unlock_irq(¤t->sig->siglock); /* loop around waiting for work to do */ diff -Nru a/net/rxrpc/krxtimod.c b/net/rxrpc/krxtimod.c --- a/net/rxrpc/krxtimod.c Mon Nov 4 14:31:00 2002 +++ b/net/rxrpc/krxtimod.c Mon Nov 4 14:31:00 2002 @@ -79,11 +79,7 @@ /* only certain signals are of interest */ spin_lock_irq(¤t->sig->siglock); siginitsetinv(¤t->blocked,0); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,3) recalc_sigpending(); -#else - recalc_sigpending(current); -#endif spin_unlock_irq(¤t->sig->siglock); /* loop around looking for things to attend to */ diff -Nru a/net/rxrpc/main.c b/net/rxrpc/main.c --- a/net/rxrpc/main.c Mon Nov 4 14:31:02 2002 +++ b/net/rxrpc/main.c Mon Nov 4 14:31:02 2002 @@ -123,5 +123,5 @@ __RXACCT(printk("Outstanding Peers : %d\n",atomic_read(&rxrpc_peer_count))); __RXACCT(printk("Outstanding Transports : %d\n",atomic_read(&rxrpc_transport_count))); - kleave(); + kleave(""); } /* end rxrpc_cleanup() */ diff -Nru a/net/rxrpc/peer.c b/net/rxrpc/peer.c --- a/net/rxrpc/peer.c Mon Nov 4 14:31:01 2002 +++ b/net/rxrpc/peer.c Mon Nov 4 14:31:01 2002 @@ -370,11 +370,13 @@ if (peer->rtt_usagertt_usage++; /* recalculate RTT */ + rtt = 0; for (loop=peer->rtt_usage-1; loop>=0; loop--) rtt += peer->rtt_cache[loop]; - peer->rtt = do_div(rtt,peer->rtt_usage); + do_div(rtt,peer->rtt_usage); + peer->rtt = rtt; - _leave(" RTT=%lu.%lums",peer->rtt/1000,peer->rtt%1000); + _leave(" RTT=%lu.%lums",(long)(peer->rtt/1000),(long)(peer->rtt%1000)); } /* end rxrpc_peer_calculate_rtt() */ diff -Nru a/net/rxrpc/proc.c b/net/rxrpc/proc.c --- a/net/rxrpc/proc.c Mon Nov 4 14:31:02 2002 +++ b/net/rxrpc/proc.c Mon Nov 4 14:31:02 2002 @@ -22,13 +22,6 @@ #include #include "internal.h" -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) -static inline struct proc_dir_entry *PDE(const struct inode *inode) -{ - return (struct proc_dir_entry *)inode->u.generic_ip; -} -#endif - static struct proc_dir_entry *proc_rxrpc; static int rxrpc_proc_transports_open(struct inode *inode, struct file *file); @@ -379,14 +372,14 @@ if (!list_empty(&peer->timeout.link)) timeout = (signed long)peer->timeout.timo_jif - (signed long)jiffies; - seq_printf(m,"%5hu %08x %5d %5d %8ld %5u %7lu\n", + seq_printf(m,"%5hu %08x %5d %5d %8ld %5Zu %7lu\n", peer->trans->port, ntohl(peer->addr.s_addr), atomic_read(&peer->usage), atomic_read(&peer->conn_count), timeout, peer->if_mtu, - peer->rtt + (long) peer->rtt ); return 0; @@ -484,7 +477,7 @@ if (!list_empty(&conn->timeout.link)) timeout = (signed long)conn->timeout.timo_jif - (signed long)jiffies; - seq_printf(m,"%5hu %08x %5hu %04hx %08x %-3.3s %08x %08x %5u %8ld\n", + seq_printf(m,"%5hu %08x %5hu %04hx %08x %-3.3s %08x %08x %5Zu %8ld\n", conn->trans->port, ntohl(conn->addr.sin_addr.s_addr), ntohs(conn->addr.sin_port), diff -Nru a/net/rxrpc/transport.c b/net/rxrpc/transport.c --- a/net/rxrpc/transport.c Mon Nov 4 14:31:02 2002 +++ b/net/rxrpc/transport.c Mon Nov 4 14:31:02 2002 @@ -691,12 +691,12 @@ msg.msg_controllen = (char*)msg.msg_control - (char*)&emsg; if (msg.msg_controllenpage_base; ppage += base >> PAGE_CACHE_SHIFT; + /* Note: The offset means that the length of the first + * page is really (PAGE_CACHE_SIZE - (base & ~PAGE_CACHE_MASK)). + * In order to avoid an extra test inside the loop, + * we bump pglen here, and just subtract PAGE_CACHE_SIZE... */ + pglen += base & ~PAGE_CACHE_MASK; } for (;;) { flush_dcache_page(*ppage); diff -Nru a/scripts/Makefile.build b/scripts/Makefile.build --- a/scripts/Makefile.build Mon Nov 4 14:31:02 2002 +++ b/scripts/Makefile.build Mon Nov 4 14:31:02 2002 @@ -7,7 +7,7 @@ .PHONY: __build __build: -ifdef include-config +ifdef include_config include .config endif diff -Nru a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile --- a/scripts/kconfig/Makefile Mon Nov 4 14:31:03 2002 +++ b/scripts/kconfig/Makefile Mon Nov 4 14:31:03 2002 @@ -34,6 +34,7 @@ $(obj)/qconf.o: $(obj)/.tmp_qtcheck +ifeq ($(MAKECMDGOALS),$(obj)/qconf) -include $(obj)/.tmp_qtcheck # QT needs some extra effort... @@ -52,6 +53,7 @@ LIB=qt; \ if [ -f $$DIR/lib/libqt-mt.so ]; then LIB=qt-mt; fi; \ echo "QTDIR=$$DIR" > $@; echo "QTLIB=$$LIB" >> $@ +endif $(obj)/zconf.tab.o: $(obj)/lex.zconf.c diff -Nru a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c --- a/sound/oss/i810_audio.c Mon Nov 4 14:31:02 2002 +++ b/sound/oss/i810_audio.c Mon Nov 4 14:31:02 2002 @@ -2669,7 +2669,7 @@ codec->codec_write = i810_ac97_set; if(!i810_ac97_probe_and_powerup(card,codec)) { - printk("i810_audio: timed out waiting for codec %d analog ready", num_ac97); + printk("i810_audio: timed out waiting for codec %d analog ready.\n", num_ac97); kfree(codec); break; /* it didn't work */ } diff -Nru a/sound/oss/trident.c b/sound/oss/trident.c --- a/sound/oss/trident.c Mon Nov 4 14:31:02 2002 +++ b/sound/oss/trident.c Mon Nov 4 14:31:02 2002 @@ -3930,9 +3930,11 @@ wReg = ali_ac97_get(card, 0, AC97_POWER_CONTROL); if((wReg & 0x000f) == 0x000f) return 0; - udelay(500); + udelay(5000); } - return 0; + + printk(KERN_ERR "ALi 5451 did not come out of reset.\n"); + return 1; } /* AC97 codec initialisation. */ diff -Nru a/usr/Makefile b/usr/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/usr/Makefile Mon Nov 4 14:31:04 2002 @@ -0,0 +1,18 @@ + +include arch/$(ARCH)/Makefile + +obj-y := initramfs_data.o + +host-progs := gen_init_cpio + +clean-files := initramfs_data.cpio.gz + +$(obj)/initramfs_data.o: $(obj)/initramfs_data.cpio.gz + $(OBJCOPY) $(ARCHBLOBLFLAGS) \ + --rename-section .data=.init.initramfs \ + $(obj)/initramfs_data.cpio.gz $(obj)/initramfs_data.o + $(STRIP) -s $(obj)/initramfs_data.o + +$(obj)/initramfs_data.cpio.gz: $(obj)/gen_init_cpio + ( cd $(obj) ; ./gen_init_cpio | gzip -9c > initramfs_data.cpio.gz ) + diff -Nru a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/usr/gen_init_cpio.c Mon Nov 4 14:31:04 2002 @@ -0,0 +1,137 @@ +#include +#include +#include +#include +#include +#include +#include + +static unsigned int offset; +static unsigned int ino = 721; + +static void push_rest(const char *name) +{ + unsigned int name_len = strlen(name) + 1; + unsigned int tmp_ofs; + + fputs(name, stdout); + putchar(0); + offset += name_len; + + tmp_ofs = name_len + 110; + while (tmp_ofs & 3) { + putchar(0); + offset++; + tmp_ofs++; + } +} + +static void push_hdr(const char *s) +{ + fputs(s, stdout); + offset += 110; +} + +static void cpio_trailer(void) +{ + char s[256]; + const char *name = "TRAILER!!!"; + + sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX" + "%08X%08X%08X%08X%08X%08X%08X", + "070701", /* magic */ + 0, /* ino */ + 0, /* mode */ + (long) 0, /* uid */ + (long) 0, /* gid */ + 1, /* nlink */ + (long) 0, /* mtime */ + 0, /* filesize */ + 0, /* major */ + 0, /* minor */ + 0, /* rmajor */ + 0, /* rminor */ + strlen(name) + 1, /* namesize */ + 0); /* chksum */ + push_hdr(s); + push_rest(name); + + while (offset % 512) { + putchar(0); + offset++; + } +} + +static void cpio_mkdir(const char *name, unsigned int mode, + uid_t uid, gid_t gid) +{ + char s[256]; + time_t mtime = time(NULL); + + sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" + "%08X%08X%08X%08X%08X%08X%08X", + "070701", /* magic */ + ino++, /* ino */ + S_IFDIR | mode, /* mode */ + (long) uid, /* uid */ + (long) gid, /* gid */ + 2, /* nlink */ + (long) mtime, /* mtime */ + 0, /* filesize */ + 3, /* major */ + 1, /* minor */ + 0, /* rmajor */ + 0, /* rminor */ + strlen(name) + 1, /* namesize */ + 0); /* chksum */ + push_hdr(s); + push_rest(name); +} + +static void cpio_mknod(const char *name, unsigned int mode, + uid_t uid, gid_t gid, int dev_type, + unsigned int maj, unsigned int min) +{ + char s[256]; + time_t mtime = time(NULL); + + if (dev_type == 'b') + mode |= S_IFBLK; + else + mode |= S_IFCHR; + + sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" + "%08X%08X%08X%08X%08X%08X%08X", + "070701", /* magic */ + ino++, /* ino */ + mode, /* mode */ + (long) uid, /* uid */ + (long) gid, /* gid */ + 1, /* nlink */ + (long) mtime, /* mtime */ + 0, /* filesize */ + 3, /* major */ + 1, /* minor */ + maj, /* rmajor */ + min, /* rminor */ + strlen(name) + 1, /* namesize */ + 0); /* chksum */ + push_hdr(s); + push_rest(name); +} + +int main (int argc, char *argv[]) +{ + cpio_mkdir("/dev", 0700, 0, 0); + cpio_mknod("/dev/console", 0600, 0, 0, 'c', 5, 1); + cpio_mkdir("/root", 0700, 0, 0); + cpio_trailer(); + + exit(0); + + /* silence compiler warnings */ + return 0; + (void) argc; + (void) argv; +} +