diff options
329 files changed, 4846 insertions, 12085 deletions
diff --git a/Documentation/Changes b/Documentation/Changes index b02f476c2973..488272074c36 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -181,8 +181,8 @@ Intel IA32 microcode -------------------- A driver has been added to allow updating of Intel IA32 microcode, -accessible as both a devfs regular file and as a normal (misc) -character device. If you are not using devfs you may need to: +accessible as a normal (misc) character device. If you are not using +udev you may need to: mkdir /dev/cpu mknod /dev/cpu/microcode c 10 184 @@ -201,7 +201,9 @@ with programs using shared memory. udev ---- udev is a userspace application for populating /dev dynamically with -only entries for devices actually present. udev replaces devfs. +only entries for devices actually present. udev replaces the basic +functionality of devfs, while allowing persistant device naming for +devices. FUSE ---- @@ -231,18 +233,13 @@ The PPP driver has been restructured to support multilink and to enable it to operate over diverse media layers. If you use PPP, upgrade pppd to at least 2.4.0. -If you are not using devfs, you must have the device file /dev/ppp +If you are not using udev, you must have the device file /dev/ppp which can be made by: mknod /dev/ppp c 108 0 as root. -If you use devfsd and build ppp support as modules, you will need -the following in your /etc/devfsd.conf file: - -LOOKUP PPP MODLOAD - Isdn4k-utils ------------ diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index 3630a0d7695f..1ae4dc0fd856 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -348,11 +348,6 @@ X!Earch/i386/kernel/mca.c </sect1> </chapter> - <chapter id="devfs"> - <title>The Device File System</title> -!Efs/devfs/base.c - </chapter> - <chapter id="sysfs"> <title>The Filesystem for Exporting Kernel Objects</title> !Efs/sysfs/file.c diff --git a/Documentation/README.DAC960 b/Documentation/README.DAC960 index 98ea617a0dd6..0e8f618ab534 100644 --- a/Documentation/README.DAC960 +++ b/Documentation/README.DAC960 @@ -78,9 +78,9 @@ also known as "System Drives", and Drive Groups are also called "Packs". Both terms are in use in the Mylex documentation; I have chosen to standardize on the more generic "Logical Drive" and "Drive Group". -DAC960 RAID disk devices are named in the style of the Device File System -(DEVFS). The device corresponding to Logical Drive D on Controller C is -referred to as /dev/rd/cCdD, and the partitions are called /dev/rd/cCdDp1 +DAC960 RAID disk devices are named in the style of the obsolete Device File +System (DEVFS). The device corresponding to Logical Drive D on Controller C +is referred to as /dev/rd/cCdD, and the partitions are called /dev/rd/cCdDp1 through /dev/rd/cCdDp7. For example, partition 3 of Logical Drive 5 on Controller 2 is referred to as /dev/rd/c2d5p3. Note that unlike with SCSI disks the device names will not change in the event of a disk drive failure. diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index b1c6c7036c1c..1cbbb8e28999 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -6,17 +6,6 @@ be removed from this file. --------------------------- -What: devfs -When: July 2005 -Files: fs/devfs/*, include/linux/devfs_fs*.h and assorted devfs - function calls throughout the kernel tree -Why: It has been unmaintained for a number of years, has unfixable - races, contains a naming policy within the kernel that is - against the LSB, and can be replaced by using udev. -Who: Greg Kroah-Hartman <greg@kroah.com> - ---------------------------- - What: RAW driver (CONFIG_RAW_DRIVER) When: December 2005 Why: declared obsolete since kernel 2.6.3 diff --git a/Documentation/filesystems/devfs/ChangeLog b/Documentation/filesystems/devfs/ChangeLog deleted file mode 100644 index e5aba5246d7c..000000000000 --- a/Documentation/filesystems/devfs/ChangeLog +++ /dev/null @@ -1,1977 +0,0 @@ -/* -*- auto-fill -*- */ -=============================================================================== -Changes for patch v1 - -- creation of devfs - -- modified miscellaneous character devices to support devfs -=============================================================================== -Changes for patch v2 - -- bug fix with manual inode creation -=============================================================================== -Changes for patch v3 - -- bugfixes - -- documentation improvements - -- created a couple of scripts (one to save&restore a devfs and the - other to set up compatibility symlinks) - -- devfs support for SCSI discs. New name format is: sd_hHcCiIlL -=============================================================================== -Changes for patch v4 - -- bugfix for the directory reading code - -- bugfix for compilation with kerneld - -- devfs support for generic hard discs - -- rationalisation of the various watchdog drivers -=============================================================================== -Changes for patch v5 - -- support for mounting directly from entries in the devfs (it doesn't - need to be mounted to do this), including the root filesystem. - Mounting of swap partitions also works. Hence, now if you set - CONFIG_DEVFS_ONLY to 'Y' then you won't be able to access your discs - via ordinary device nodes. Naturally, the default is 'N' so that you - can still use your old device nodes. If you want to mount from devfs - entries, make sure you use: append = "root=/dev/sd_..." in your - lilo.conf. It seems LILO looks for the device number (major&minor) - and writes that into the kernel image :-( - -- support for character memory devices (/dev/null, /dev/zero, /dev/full - and so on). Thanks to C. Scott Ananian <cananian@alumni.princeton.edu> -=============================================================================== -Changes for patch v6 - -- support for subdirectories - -- support for symbolic links (created by devfs_mk_symlink(), no - support yet for creation via symlink(2)) - -- SCSI disc naming now cast in stone, with the format: - /dev/sd/c0b1t2u3 controller=0, bus=1, ID=2, LUN=3, whole disc - /dev/sd/c0b1t2u3p4 controller=0, bus=1, ID=2, LUN=3, 4th partition - -- loop devices now appear in devfs - -- tty devices, console, serial ports, etc. now appear in devfs - Thanks to C. Scott Ananian <cananian@alumni.princeton.edu> - -- bugs with mounting devfs-only devices now fixed -=============================================================================== -Changes for patch v7 - -- SCSI CD-ROMS, tapes and generic devices now appear in devfs -=============================================================================== -Changes for patch v8 - -- bugfix with no-rewind SCSI tapes - -- RAMDISCs now appear in devfs - -- better cleaning up of devfs entries created by various modules - -- interface change to <devfs_register> -=============================================================================== -Changes for patch v9 - -- the v8 patch was corrupted somehow, which would affect the patch for - linux/fs/filesystems.c - I've also fixed the v8 patch file on the WWW - -- MetaDevices (/dev/md*) should now appear in devfs -=============================================================================== -Changes for patch v10 - -- bugfix in meta device support for devfs - -- created this ChangeLog file - -- added devfs support to the floppy driver - -- added support for creating sockets in a devfs -=============================================================================== -Changes for patch v11 - -- added DEVFS_FL_HIDE_UNREG flag - -- incorporated better patch for ttyname() in libc 5.4.43 from H.J. Lu. - -- interface change to <devfs_mk_symlink> - -- support for creating symlinks with symlink(2) - -- parallel port printer (/dev/lp*) now appears in devfs -=============================================================================== -Changes for patch v12 - -- added inode check to <devfs_fill_file> function - -- improved devfs support when mounting from devfs - -- added call to <<release>> operation when removing swap areas on - devfs devices - -- increased NR_SUPER to 128 to support large numbers of devfs mounts - (for chroot(2) gaols) - -- fixed bug in SCSI disc support: was generating incorrect minors if - SCSI ID's did not start at 0 and increase by 1 - -- support symlink traversal when mounting root -=============================================================================== -Changes for patch v13 - -- added devfs support to soundcard driver - Thanks to Eric Dumas <dumas@linux.eu.org> and - C. Scott Ananian <cananian@alumni.princeton.edu> - -- added devfs support to the joystick driver - -- loop driver now has it's own subdirectory "/dev/loop/" - -- created <devfs_get_flags> and <devfs_set_flags> functions - -- fix problem with SCSI disc compatibility names (sd{a,b,c,d,e,f}) - which assumes ID's start at 0 and increase by 1. Also only create - devfs entries for SCSI disc partitions which actually exist - Show new names in partition check - Thanks to Jakub Jelinek <jj@sunsite.ms.mff.cuni.cz> -=============================================================================== -Changes for patch v14 - -- bug fix in floppy driver: would not compile without - CONFIG_DEVFS_FS='Y' - Thanks to Jurgen Botz <jbotz@nova.botz.org> - -- bug fix in loop driver - Thanks to C. Scott Ananian <cananian@alumni.princeton.edu> - -- do not create devfs entries for printers not configured - Thanks to C. Scott Ananian <cananian@alumni.princeton.edu> - -- do not create devfs entries for serial ports not present - Thanks to C. Scott Ananian <cananian@alumni.princeton.edu> - -- ensure <tty_register_devfs> is exported from tty_io.c - Thanks to C. Scott Ananian <cananian@alumni.princeton.edu> - -- allow unregistering of devfs symlink entries - -- fixed bug in SCSI disc naming introduced in last patch version -=============================================================================== -Changes for patch v15 - -- ported to kernel 2.1.81 -=============================================================================== -Changes for patch v16 - -- created <devfs_set_symlink_destination> function - -- moved DEVFS_SUPER_MAGIC into header file - -- added DEVFS_FL_HIDE flag - -- created <devfs_get_maj_min> - -- created <devfs_get_handle_from_inode> - -- fixed bugs in searching by major&minor - -- changed interface to <devfs_unregister>, <devfs_fill_file> and - <devfs_find_handle> - -- fixed inode times when symlink created with symlink(2) - -- change tty driver to do auto-creation of devfs entries - Thanks to C. Scott Ananian <cananian@alumni.princeton.edu> - -- fixed bug in genhd.c: whole disc (non-SCSI) was not registered to - devfs - -- updated libc 5.4.43 patch for ttyname() -=============================================================================== -Changes for patch v17 - -- added CONFIG_DEVFS_TTY_COMPAT - Thanks to C. Scott Ananian <cananian@alumni.princeton.edu> - -- bugfix in devfs support for drivers/char/lp.c - Thanks to C. Scott Ananian <cananian@alumni.princeton.edu> - -- clean up serial driver so that PCMCIA devices unregister correctly - Thanks to C. Scott Ananian <cananian@alumni.princeton.edu> - -- fixed bug in genhd.c: whole disc (non-SCSI) was not registered to - devfs [was missing in patch v16] - -- updated libc 5.4.43 patch for ttyname() [was missing in patch v16] - -- all SCSI devices now registered in /dev/sg - -- support removal of devfs entries via unlink(2) -=============================================================================== -Changes for patch v18 - -- added floppy/?u720 floppy entry - -- fixed kerneld support for entries in devfs subdirectories - -- incorporated latest patch for ttyname() in libc 5.4.43 from H.J. Lu. -=============================================================================== -Changes for patch v19 - -- bug fix when looking up unregistered entries: kerneld was not called - -- fixes for kernel 2.1.86 (now requires 2.1.86) -=============================================================================== -Changes for patch v20 - -- only create available floppy entries - Thanks to Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl> - -- new IDE naming scheme following SCSI format (i.e. /dev/id/c0b0t0u0p1 - instead of /dev/hda1) - Thanks to Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl> - -- new XT disc naming scheme following SCSI format (i.e. /dev/xd/c0t0p1 - instead of /dev/xda1) - Thanks to Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl> - -- new non-standard CD-ROM names (i.e. /dev/sbp/c#t#) - Thanks to Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl> - -- allow symlink traversal when mounting the root filesystem - -- Create entries for MD devices at MD init - Thanks to Christophe Leroy <christophe.leroy5@capway.com> -=============================================================================== -Changes for patch v21 - -- ported to kernel 2.1.91 -=============================================================================== -Changes for patch v22 - -- SCSI host number patch ("scsihosts=" kernel option) - Thanks to Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl> -=============================================================================== -Changes for patch v23 - -- Fixed persistence bug with device numbers for manually created - device files - -- Fixed problem with recreating symlinks with different content - -- Added CONFIG_DEVFS_MOUNT (mount devfs on /dev at boot time) -=============================================================================== -Changes for patch v24 - -- Switched from CONFIG_KERNELD to CONFIG_KMOD: module autoloading - should now work again - -- Hide entries which are manually unlinked - -- Always invalidate devfs dentry cache when registering entries - -- Support removal of devfs directories via rmdir(2) - -- Ensure directories created by <devfs_mk_dir> are visible - -- Default no access for "other" for floppy device -=============================================================================== -Changes for patch v25 - -- Updates to CREDITS file and minor IDE numbering change - Thanks to Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl> - -- Invalidate devfs dentry cache when making directories - -- Invalidate devfs dentry cache when removing entries - -- More informative message if root FS mount fails when devfs - configured - -- Fixed persistence bug with fifos -=============================================================================== -Changes for patch v26 - -- ported to kernel 2.1.97 - -- Changed serial directory from "/dev/serial" to "/dev/tts" and - "/dev/consoles" to "/dev/vc" to be more friendly to new procps -=============================================================================== -Changes for patch v27 - -- Added support for IDE4 and IDE5 - Thanks to Andrzej Krzysztofowicz <ankry@green.mif.pg.gda.pl> - -- Documented "scsihosts=" boot parameter - -- Print process command when debugging kerneld/kmod - -- Added debugging for register/unregister/change operations - -- Added "devfs=" boot options - -- Hide unregistered entries by default -=============================================================================== -Changes for patch v28 - -- No longer lock/unlock superblock in <devfs_put_super> (cope with - recent VFS interface change) - -- Do not automatically change ownership/protection of /dev/tty - -- Drop negative dentries when they are released - -- Manage dcache more efficiently -=============================================================================== -Changes for patch v29 - -- Added DEVFS_FL_AUTO_DEVNUM flag -=============================================================================== -Changes for patch v30 - -- No longer set unnecessary methods - -- Ported to kernel 2.1.99-pre3 -=============================================================================== -Changes for patch v31 - -- Added PID display to <call_kerneld> debugging message - -- Added "diread" and "diwrite" options - -- Ported to kernel 2.1.102 - -- Fixed persistence problem with permissions -=============================================================================== -Changes for patch v32 - -- Fixed devfs support in drivers/block/md.c -=============================================================================== -Changes for patch v33 - -- Support legacy device nodes - -- Fixed bug where recreated inodes were hidden - -- New IDE naming scheme: everything is under /dev/ide -=============================================================================== -Changes for patch v34 - -- Improved debugging in <get_vfs_inode> - -- Prevent duplicate calls to <devfs_mk_dir> in SCSI layer - -- No longer free old dentries in <devfs_mk_dir> - -- Free all dentries for a given entry when deleting inodes -=============================================================================== -Changes for patch v35 - -- Ported to kernel 2.1.105 (sound driver changes) -=============================================================================== -Changes for patch v36 - -- Fixed sound driver port -=============================================================================== -Changes for patch v37 - -- Minor documentation tweaks -=============================================================================== -Changes for patch v38 - -- More documentation tweaks - -- Fix for sound driver port - -- Removed ttyname-patch (grab libc 5.4.44 instead) - -- Ported to kernel 2.1.107-pre2 (loop driver fix) -=============================================================================== -Changes for patch v39 - -- Ported to kernel 2.1.107 (hd.c hunk broke due to spelling "fixes"). Sigh - -- Removed many #ifdef's, replaced with trickery in include/devfs_fs.h -=============================================================================== -Changes for patch v40 - -- Fix for sound driver port - -- Limit auto-device numbering to majors 128 to 239 -=============================================================================== -Changes for patch v41 - -- Fixed inode times persistence problem -=============================================================================== -Changes for patch v42 - -- Ported to kernel 2.1.108 (drivers/scsi/hosts.c hunk broke) -=============================================================================== -Changes for patch v43 - -- Fixed spelling in <devfs_readlink> debug - -- Fixed bug in <devfs_setup> parsing "dilookup" - -- More #ifdef's removed - -- Supported Sparc keyboard (/dev/kbd) - -- Supported DSP56001 digital signal processor (/dev/dsp56k) - -- Supported Apple Desktop Bus (/dev/adb) - -- Supported Coda network file system (/dev/cfs*) -=============================================================================== -Changes for patch v44 - -- Fixed devfs inode leak when manually recreating inodes - -- Fixed permission persistence problem when recreating inodes -=============================================================================== -Changes for patch v45 - -- Ported to kernel 2.1.110 -=============================================================================== -Changes for patch v46 - -- Ported to kernel 2.1.112-pre1 - -- Removed harmless "unused variable" compiler warning - -- Fixed modes for manually recreated device nodes -=============================================================================== -Changes for patch v47 - -- Added NULL devfs inode warning in <devfs_read_inode> - -- Force all inode nlink values to 1 -=============================================================================== -Changes for patch v48 - -- Added "dimknod" option - -- Set inode nlink to 0 when freeing dentries - -- Added support for virtual console capture devices (/dev/vcs*) - Thanks to Dennis Hou <smilax@mindmeld.yi.org> - -- Fixed modes for manually recreated symlinks -=============================================================================== -Changes for patch v49 - -- Ported to kernel 2.1.113 -=============================================================================== -Changes for patch v50 - -- Fixed bugs in recreated directories and symlinks -=============================================================================== -Changes for patch v51 - -- Improved robustness of rc.devfs script - Thanks to Roderich Schupp <rsch@experteam.de> - -- Fixed bugs in recreated device nodes - -- Fixed bug in currently unused <devfs_get_handle_from_inode> - -- Defined new <devfs_handle_t> type - -- Improved debugging when getting entries - -- Fixed bug where directories could be emptied - -- Ported to kernel 2.1.115 -=============================================================================== -Changes for patch v52 - -- Replaced dummy .epoch inode with .devfsd character device - -- Modified rc.devfs to take account of above change - -- Removed spurious driver warning messages when CONFIG_DEVFS_FS=n - -- Implemented devfsd protocol revision 0 -=============================================================================== -Changes for patch v53 - -- Ported to kernel 2.1.116 (kmod change broke hunk) - -- Updated Documentation/Configure.help - -- Test and tty pattern patch for rc.devfs script - Thanks to Roderich Schupp <rsch@experteam.de> - -- Added soothing message to warning in <devfs_d_iput> -=============================================================================== -Changes for patch v54 - -- Ported to kernel 2.1.117 - -- Fixed default permissions in sound driver - -- Added support for frame buffer devices (/dev/fb*) -=============================================================================== -Changes for patch v55 - -- Ported to kernel 2.1.119 - -- Use GCC extensions for structure initialisations - -- Implemented async open notification - -- Incremented devfsd protocol revision to 1 -=============================================================================== -Changes for patch v56 - -- Ported to kernel 2.1.120-pre3 - -- Moved async open notification to end of <devfs_open> -=============================================================================== -Changes for patch v57 - -- Ported to kernel 2.1.121 - -- Prepended "/dev/" to module load request - -- Renamed <call_kerneld> to <call_kmod> - -- Created sample modules.conf file -=============================================================================== -Changes for patch v58 - -- Fixed typo "AYSNC" -> "ASYNC" -=============================================================================== -Changes for patch v59 - -- Added open flag for files -=============================================================================== -Changes for patch v60 - -- Ported to kernel 2.1.123-pre2 -=============================================================================== -Changes for patch v61 - -- Set i_blocks=0 and i_blksize=1024 in <devfs_read_inode> -=============================================================================== -Changes for patch v62 - -- Ported to kernel 2.1.123 -=============================================================================== -Changes for patch v63 - -- Ported to kernel 2.1.124-pre2 -=============================================================================== -Changes for patch v64 - -- Fixed Unix98 pty support - -- Increased buffer size in <get_partition_list> to avoid crash and - burn -=============================================================================== -Changes for patch v65 - -- More Unix98 pty support fixes - -- Added test for empty <<name>> in <devfs_find_handle> - -- Renamed <generate_path> to <devfs_generate_path> and published - -- Created /dev/root symlink - Thanks to Roderich Schupp <rsch@ExperTeam.de> - with further modifications by me -=============================================================================== -Changes for patch v66 - -- Yet more Unix98 pty support fixes (now tested) - -- Created <devfs_get_fops> - -- Support media change checks when CONFIG_DEVFS_ONLY=y - -- Abolished Unix98-style PTY names for old PTY devices -=============================================================================== -Changes for patch v67 - -- Added inline declaration for dummy <devfs_generate_path> - -- Removed spurious "unable to register... in devfs" messages when - CONFIG_DEVFS_FS=n - -- Fixed misc. devices when CONFIG_DEVFS_FS=n - -- Limit auto-device numbering to majors 144 to 239 -=============================================================================== -Changes for patch v68 - -- Hide unopened virtual consoles from directory listings - -- Added support for video capture devices - -- Ported to kernel 2.1.125 -=============================================================================== -Changes for patch v69 - -- Fix for CONFIG_VT=n -=============================================================================== -Changes for patch v70 - -- Added support for non-OSS/Free sound cards -=============================================================================== -Changes for patch v71 - -- Ported to kernel 2.1.126-pre2 -=============================================================================== -Changes for patch v72 - -- #ifdef's for CONFIG_DEVFS_DISABLE_OLD_NAMES removed -=============================================================================== -Changes for patch v73 - -- CONFIG_DEVFS_DISABLE_OLD_NAMES replaced with "nocompat" boot option - -- CONFIG_DEVFS_BOOT_OPTIONS removed: boot options always available -=============================================================================== -Changes for patch v74 - -- Removed CONFIG_DEVFS_MOUNT and "mount" boot option and replaced with - "nomount" boot option - -- Documentation updates - -- Updated sample modules.conf -=============================================================================== -Changes for patch v75 - -- Updated sample modules.conf - -- Remount devfs after initrd finishes - -- Ported to kernel 2.1.127 - -- Added support for ISDN - Thanks to Christophe Leroy <christophe.leroy5@capway.com> -=============================================================================== -Changes for patch v76 - -- Updated an email address in ChangeLog - -- CONFIG_DEVFS_ONLY replaced with "only" boot option -=============================================================================== -Changes for patch v77 - -- Added DEVFS_FL_REMOVABLE flag - -- Check for disc change when listing directories with removable media - devices - -- Use DEVFS_FL_REMOVABLE in sd.c - -- Ported to kernel 2.1.128 -=============================================================================== -Changes for patch v78 - -- Only call <scan_dir_for_removable> on first call to <devfs_readdir> - -- Ported to kernel 2.1.129-pre5 - -- ISDN support improvements - Thanks to Christophe Leroy <christophe.leroy5@capway.com> -=============================================================================== -Changes for patch v79 - -- Ported to kernel 2.1.130 - -- Renamed miscdevice "apm" to "apm_bios" to be consistent with - devices.txt -=============================================================================== -Changes for patch v80 - -- Ported to kernel 2.1.131 - -- Updated <devfs_rmdir> for VFS change in 2.1.131 -=============================================================================== -Changes for patch v81 - -- Fixed permissions on /dev/ptmx -=============================================================================== -Changes for patch v82 - -- Ported to kernel 2.1.132-pre4 - -- Changed initial permissions on /dev/pts/* - -- Created <devfs_mk_compat> - -- Added "symlinks" boot option - -- Changed devfs_register_blkdev() back to register_blkdev() for IDE - -- Check for partitions on removable media in <devfs_lookup> -=============================================================================== -Changes for patch v83 - -- Fixed support for ramdisc when using string-based root FS name - -- Ported to kernel 2.2.0-pre1 -=============================================================================== -Changes for patch v84 - -- Ported to kernel 2.2.0-pre7 -=============================================================================== -Changes for patch v85 - -- Compile fixes for driver/sound/sound_common.c (non-module) and - drivers/isdn/isdn_common.c - Thanks to Christophe Leroy <christophe.leroy5@capway.com> - -- Added support for registering regular files - -- Created <devfs_set_file_size> - -- Added /dev/cpu/mtrr as an alternative interface to /proc/mtrr - -- Update devfs inodes from entries if not changed through FS -=============================================================================== -Changes for patch v86 - -- Ported to kernel 2.2.0-pre9 -=============================================================================== -Changes for patch v87 - -- Fixed bug when mounting non-devfs devices in a devfs -=============================================================================== -Changes for patch v88 - -- Fixed <devfs_fill_file> to only initialise temporary inodes - -- Trap for NULL fops in <devfs_register> - -- Return -ENODEV in <devfs_fill_file> for non-driver inodes - -- Fixed bug when unswapping non-devfs devices in a devfs -=============================================================================== -Changes for patch v89 - -- Switched to C data types in include/linux/devfs_fs.h - -- Switched from PATH_MAX to DEVFS_PATHLEN - -- Updated Documentation/filesystems/devfs/modules.conf to take account - of reverse scanning (!) by modprobe - -- Ported to kernel 2.2.0 -=============================================================================== -Changes for patch v90 - -- CONFIG_DEVFS_DISABLE_OLD_TTY_NAMES replaced with "nottycompat" boot - option - -- CONFIG_DEVFS_TTY_COMPAT removed: existing "symlinks" boot option now - controls this. This means you must have libc 5.4.44 or later, or a - recent version of libc 6 if you use the "symlinks" option -=============================================================================== -Changes for patch v91 - -- Switch from <devfs_mk_symlink> to <devfs_mk_compat> in - drivers/char/vc_screen.c to fix problems with Midnight Commander -=============================================================================== -Changes for patch v92 - -- Ported to kernel 2.2.2-pre5 -=============================================================================== -Changes for patch v93 - -- Modified <sd_name> in drivers/scsi/sd.c to cope with devices that - don't exist (which happens with new RAID autostart code printk()s) -=============================================================================== -Changes for patch v94 - -- Fixed bug in joystick driver: only first joystick was registered -=============================================================================== -Changes for patch v95 - -- Fixed another bug in joystick driver - -- Fixed <devfsd_read> to not overrun event buffer -=============================================================================== -Changes for patch v96 - -- Ported to kernel 2.2.5-2 - -- Created <devfs_auto_unregister> - -- Fixed bugs: compatibility entries were not unregistered for: - loop driver - floppy driver - RAMDISC driver - IDE tape driver - SCSI CD-ROM driver - SCSI HDD driver -=============================================================================== -Changes for patch v97 - -- Fixed bugs: compatibility entries were not unregistered for: - ALSA sound driver - partitions in generic disc driver - -- Don't return unregistred entries in <devfs_find_handle> - -- Panic in <devfs_unregister> if entry unregistered - -- Don't panic in <devfs_auto_unregister> for duplicates -=============================================================================== -Changes for patch v98 - -- Don't unregister already unregistered entries in <unregister> - -- Register entry in <sd_detect> - -- Unregister entry in <sd_detach> - -- Changed to <devfs_*register_chrdev> in drivers/char/tty_io.c - -- Ported to kernel 2.2.7 -=============================================================================== -Changes for patch v99 - -- Ported to kernel 2.2.8 - -- Fixed bug in drivers/scsi/sd.c when >16 SCSI discs - -- Disable warning messages when unable to read partition table for - removable media -=============================================================================== -Changes for patch v100 - -- Ported to kernel 2.3.1-pre5 - -- Added "oops-on-panic" boot option - -- Improved debugging in <devfs_register> and <devfs_unregister> - -- Register entry in <sr_detect> - -- Unregister entry in <sr_detach> - -- Register entry in <sg_detect> - -- Unregister entry in <sg_detach> - -- Added support for ALSA drivers -=============================================================================== -Changes for patch v101 - -- Ported to kernel 2.3.2 -=============================================================================== -Changes for patch v102 - -- Update serial driver to register PCMCIA entries - Thanks to Roch-Alexandre Nomine-Beguin <roch@samarkand.infini.fr> - -- Updated an email address in ChangeLog - -- Hide virtual console capture entries from directory listings when - corresponding console device is not open -=============================================================================== -Changes for patch v103 - -- Ported to kernel 2.3.3 -=============================================================================== -Changes for patch v104 - -- Added documentation for some functions - -- Added "doc" target to fs/devfs/Makefile - -- Added "v4l" directory for video4linux devices - -- Replaced call to <devfs_unregister> in <sd_detach> with call to - <devfs_register_partitions> - -- Moved registration for sr and sg drivers from detect() to attach() - methods - -- Register entries in <st_attach> and unregister in <st_detach> - -- Work around IDE driver treating CD-ROM as gendisk - -- Use <sed> instead of <tr> in rc.devfs - -- Updated ToDo list - -- Removed "oops-on-panic" boot option: now always Oops -=============================================================================== -Changes for patch v105 - -- Unregister SCSI host from <scsi_host_no_list> in <scsi_unregister> - Thanks to Zoltán Böszörményi <zboszor@mail.externet.hu> - -- Don't save /dev/log in rc.devfs - -- Ported to kernel 2.3.4-pre1 -=============================================================================== -Changes for patch v106 - -- Fixed silly typo in drivers/scsi/st.c - -- Improved debugging in <devfs_register> -=============================================================================== -Changes for patch v107 - -- Added "diunlink" and "nokmod" boot options - -- Removed superfluous warning message in <devfs_d_iput> -=============================================================================== -Changes for patch v108 - -- Remove entries when unloading sound module -=============================================================================== -Changes for patch v109 - -- Ported to kernel 2.3.6-pre2 -=============================================================================== -Changes for patch v110 - -- Took account of change to <d_alloc_root> -=============================================================================== -Changes for patch v111 - -- Created separate event queue for each mounted devfs - -- Removed <devfs_invalidate_dcache> - -- Created new ioctl()s for devfsd - -- Incremented devfsd protocol revision to 3 - -- Fixed bug when re-creating directories: contents were lost - -- Block access to inodes until devfsd updates permissions -=============================================================================== -Changes for patch v112 - -- Modified patch so it applies against 2.3.5 and 2.3.6 - -- Updated an email address in ChangeLog - -- Do not automatically change ownership/protection of /dev/tty<n> - -- Updated sample modules.conf - -- Switched to sending process uid/gid to devfsd - -- Renamed <call_kmod> to <try_modload> - -- Added DEVFSD_NOTIFY_LOOKUP event - -- Added DEVFSD_NOTIFY_CHANGE event - -- Added DEVFSD_NOTIFY_CREATE event - -- Incremented devfsd protocol revision to 4 - -- Moved kernel-specific stuff to include/linux/devfs_fs_kernel.h -=============================================================================== -Changes for patch v113 - -- Ported to kernel 2.3.9 - -- Restricted permissions on some block devices -=============================================================================== -Changes for patch v114 - -- Added support for /dev/netlink - Thanks to Dennis Hou <smilax@mindmeld.yi.org> - -- Return EISDIR rather than EINVAL for read(2) on directories - -- Ported to kernel 2.3.10 -=============================================================================== -Changes for patch v115 - -- Added support for all remaining character devices - Thanks to Dennis Hou <smilax@mindmeld.yi.org> - -- Cleaned up netlink support -=============================================================================== -Changes for patch v116 - -- Added support for /dev/parport%d - Thanks to Tim Waugh <tim@cyberelk.demon.co.uk> - -- Fixed parallel port ATAPI tape driver - -- Fixed Atari SLM laser printer driver -=============================================================================== -Changes for patch v117 - -- Added support for COSA card - Thanks to Dennis Hou <smilax@mindmeld.yi.org> - -- Fixed drivers/char/ppdev.c: missing #include <linux/init.h> - -- Fixed drivers/char/ftape/zftape/zftape-init.c - Thanks to Vladimir Popov <mashgrad@usa.net> -=============================================================================== -Changes for patch v118 - -- Ported to kernel 2.3.15-pre3 - -- Fixed bug in loop driver - -- Unregister /dev/lp%d entries in drivers/char/lp.c - Thanks to Maciej W. Rozycki <macro@ds2.pg.gda.pl> -=============================================================================== -Changes for patch v119 - -- Ported to kernel 2.3.16 -=============================================================================== -Changes for patch v120 - -- Fixed bug in drivers/scsi/scsi.c - -- Added /dev/ppp - Thanks to Dennis Hou <smilax@mindmeld.yi.org> - -- Ported to kernel 2.3.17 -=============================================================================== -Changes for patch v121 - -- Fixed bug in drivers/block/loop.c - -- Ported to kernel 2.3.18 -=============================================================================== -Changes for patch v122 - -- Ported to kernel 2.3.19 -=============================================================================== -Changes for patch v123 - -- Ported to kernel 2.3.20 -=============================================================================== -Changes for patch v124 - -- Ported to kernel 2.3.21 -=============================================================================== -Changes for patch v125 - -- Created <devfs_get_info>, <devfs_set_info>, - <devfs_get_first_child> and <devfs_get_next_sibling> - Added <<dir>> parameter to <devfs_register>, <devfs_mk_compat>, - <devfs_mk_dir> and <devfs_find_handle> - Work sponsored by SGI - -- Fixed apparent bug in COSA driver - -- Re-instated "scsihosts=" boot option -=============================================================================== -Changes for patch v126 - -- Always create /dev/pts if CONFIG_UNIX98_PTYS=y - -- Fixed call to <devfs_mk_dir> in drivers/block/ide-disk.c - Thanks to Dennis Hou <smilax@mindmeld.yi.org> - -- Allow multiple unregistrations - -- Created /dev/scsi hierarchy - Work sponsored by SGI -=============================================================================== -Changes for patch v127 - -Work sponsored by SGI - -- No longer disable devpts if devfs enabled (caveat emptor) - -- Added flags array to struct gendisk and removed code from - drivers/scsi/sd.c - -- Created /dev/discs hierarchy -=============================================================================== -Changes for patch v128 - -Work sponsored by SGI - -- Created /dev/cdroms hierarchy -=============================================================================== -Changes for patch v129 - -Work sponsored by SGI - -- Removed compatibility entries for sound devices - -- Removed compatibility entries for printer devices - -- Removed compatibility entries for video4linux devices - -- Removed compatibility entries for parallel port devices - -- Removed compatibility entries for frame buffer devices -=============================================================================== -Changes for patch v130 - -Work sponsored by SGI - -- Added major and minor number to devfsd protocol - -- Incremented devfsd protocol revision to 5 - -- Removed compatibility entries for SoundBlaster CD-ROMs - -- Removed compatibility entries for netlink devices - -- Removed compatibility entries for SCSI generic devices - -- Removed compatibility entries for SCSI tape devices -=============================================================================== -Changes for patch v131 - -Work sponsored by SGI - -- Support info pointer for all devfs entry types - -- Added <<info>> parameter to <devfs_mk_dir> and <devfs_mk_symlink> - -- Removed /dev/st hierarchy - -- Removed /dev/sg hierarchy - -- Removed compatibility entries for loop devices - -- Removed compatibility entries for IDE tape devices - -- Removed compatibility entries for SCSI CD-ROMs - -- Removed /dev/sr hierarchy -=============================================================================== -Changes for patch v132 - -Work sponsored by SGI - -- Removed compatibility entries for floppy devices - -- Removed compatibility entries for RAMDISCs - -- Removed compatibility entries for meta-devices - -- Removed compatibility entries for SCSI discs - -- Created <devfs_make_root> - -- Removed /dev/sd hierarchy - -- Support "../" when searching devfs namespace - -- Created /dev/ide/host* hierarchy - -- Supported IDE hard discs in /dev/ide/host* hierarchy - -- Removed compatibility entries for IDE discs - -- Removed /dev/ide/hd hierarchy - -- Supported IDE CD-ROMs in /dev/ide/host* hierarchy - -- Removed compatibility entries for IDE CD-ROMs - -- Removed /dev/ide/cd hierarchy -=============================================================================== -Changes for patch v133 - -Work sponsored by SGI - -- Created <devfs_get_unregister_slave> - -- Fixed bug in fs/partitions/check.c when rescanning -=============================================================================== -Changes for patch v134 - -Work sponsored by SGI - -- Removed /dev/sd, /dev/sr, /dev/st and /dev/sg directories - -- Removed /dev/ide/hd directory - -- Exported <devfs_get_parent> - -- Created <devfs_register_tape> and /dev/tapes hierarchy - -- Removed /dev/ide/mt hierarchy - -- Removed /dev/ide/fd hierarchy - -- Ported to kernel 2.3.25 -=============================================================================== -Changes for patch v135 - -Work sponsored by SGI - -- Removed compatibility entries for virtual console capture devices - -- Removed unused <devfs_set_symlink_destination> - -- Removed compatibility entries for serial devices - -- Removed compatibility entries for console devices - -- Do not hide entries from devfsd or children - -- Removed DEVFS_FL_TTY_COMPAT flag - -- Removed "nottycompat" boot option - -- Removed <devfs_mk_compat> -=============================================================================== -Changes for patch v136 - -Work sponsored by SGI - -- Moved BSD pty devices to /dev/pty - -- Added DEVFS_FL_WAIT flag -=============================================================================== -Changes for patch v137 - -Work sponsored by SGI - -- Really fixed bug in fs/partitions/check.c when rescanning - -- Support new "disc" naming scheme in <get_removable_partition> - -- Allow NULL fops in <devfs_register> - -- Removed redundant name functions in SCSI disc and IDE drivers -=============================================================================== -Changes for patch v138 - -Work sponsored by SGI - -- Fixed old bugs in drivers/block/paride/pt.c, drivers/char/tpqic02.c, - drivers/net/wan/cosa.c and drivers/scsi/scsi.c - Thanks to Sergey Kubushin <ksi@ksi-linux.com> - -- Fall back to major table if NULL fops given to <devfs_register> -=============================================================================== -Changes for patch v139 - -Work sponsored by SGI - -- Corrected and moved <get_blkfops> and <get_chrfops> declarations - from arch/alpha/kernel/osf_sys.c to include/linux/fs.h - -- Removed name function from struct gendisk - -- Updated devfs FAQ -=============================================================================== -Changes for patch v140 - -Work sponsored by SGI - -- Ported to kernel 2.3.27 -=============================================================================== -Changes for patch v141 - -Work sponsored by SGI - -- Bug fix in arch/m68k/atari/joystick.c - -- Moved ISDN and capi devices to /dev/isdn -=============================================================================== -Changes for patch v142 - -Work sponsored by SGI - -- Bug fix in drivers/block/ide-probe.c (patch confusion) -=============================================================================== -Changes for patch v143 - -Work sponsored by SGI - -- Bug fix in drivers/block/blkpg.c:partition_name() -=============================================================================== -Changes for patch v144 - -Work sponsored by SGI - -- Ported to kernel 2.3.29 - -- Removed calls to <devfs_register> from cdu31a, cm206, mcd and mcdx - CD-ROM drivers: generic driver handles this now - -- Moved joystick devices to /dev/joysticks -=============================================================================== -Changes for patch v145 - -Work sponsored by SGI - -- Ported to kernel 2.3.30-pre3 - -- Register whole-disc entry even for invalid partition tables - -- Fixed bug in mounting root FS when initrd enabled - -- Fixed device entry leak with IDE CD-ROMs - -- Fixed compile problem with drivers/isdn/isdn_common.c - -- Moved COSA devices to /dev/cosa - -- Support fifos when unregistering - -- Created <devfs_register_series> and used in many drivers - -- Moved Coda devices to /dev/coda - -- Moved parallel port IDE tapes to /dev/pt - -- Moved parallel port IDE generic devices to /dev/pg -=============================================================================== -Changes for patch v146 - -Work sponsored by SGI - -- Removed obsolete DEVFS_FL_COMPAT and DEVFS_FL_TOLERANT flags - -- Fixed compile problem with fs/coda/psdev.c - -- Reinstate change to <devfs_register_blkdev> in - drivers/block/ide-probe.c now that fs/isofs/inode.c is fixed - -- Switched to <devfs_register_blkdev> in drivers/block/floppy.c, - drivers/scsi/sr.c and drivers/block/md.c - -- Moved DAC960 devices to /dev/dac960 -=============================================================================== -Changes for patch v147 - -Work sponsored by SGI - -- Ported to kernel 2.3.32-pre4 -=============================================================================== -Changes for patch v148 - -Work sponsored by SGI - -- Removed kmod support: use devfsd instead - -- Moved miscellaneous character devices to /dev/misc -=============================================================================== -Changes for patch v149 - -Work sponsored by SGI - -- Ensure include/linux/joystick.h is OK for user-space - -- Improved debugging in <get_vfs_inode> - -- Ensure dentries created by devfsd will be cleaned up -=============================================================================== -Changes for patch v150 - -Work sponsored by SGI - -- Ported to kernel 2.3.34 -=============================================================================== -Changes for patch v151 - -Work sponsored by SGI - -- Ported to kernel 2.3.35-pre1 - -- Created <devfs_get_name> -=============================================================================== -Changes for patch v152 - -Work sponsored by SGI - -- Updated sample modules.conf - -- Ported to kernel 2.3.36-pre1 -=============================================================================== -Changes for patch v153 - -Work sponsored by SGI - -- Ported to kernel 2.3.42 - -- Removed <devfs_fill_file> -=============================================================================== -Changes for patch v154 - -Work sponsored by SGI - -- Took account of device number changes for /dev/fb* -=============================================================================== -Changes for patch v155 - -Work sponsored by SGI - -- Ported to kernel 2.3.43-pre8 - -- Moved /dev/tty0 to /dev/vc/0 - -- Moved sequence number formatting from <_tty_make_name> to drivers -=============================================================================== -Changes for patch v156 - -Work sponsored by SGI - -- Fixed breakage in drivers/scsi/sd.c due to recent SCSI changes -=============================================================================== -Changes for patch v157 - -Work sponsored by SGI - -- Ported to kernel 2.3.45 -=============================================================================== -Changes for patch v158 - -Work sponsored by SGI - -- Ported to kernel 2.3.46-pre2 -=============================================================================== -Changes for patch v159 - -Work sponsored by SGI - -- Fixed drivers/block/md.c - Thanks to Mike Galbraith <mikeg@weiden.de> - -- Documentation fixes - -- Moved device registration from <lp_init> to <lp_register> - Thanks to Tim Waugh <twaugh@redhat.com> -=============================================================================== -Changes for patch v160 - -Work sponsored by SGI - -- Fixed drivers/char/joystick/joystick.c - Thanks to Vojtech Pavlik <vojtech@suse.cz> - -- Documentation updates - -- Fixed arch/i386/kernel/mtrr.c if procfs and devfs not enabled - -- Fixed drivers/char/stallion.c -=============================================================================== -Changes for patch v161 - -Work sponsored by SGI - -- Remove /dev/ide when ide-mod is unloaded - -- Fixed bug in drivers/block/ide-probe.c when secondary but no primary - -- Added DEVFS_FL_NO_PERSISTENCE flag - -- Used new DEVFS_FL_NO_PERSISTENCE flag for Unix98 pty slaves - -- Removed unnecessary call to <update_devfs_inode_from_entry> in - <devfs_readdir> - -- Only set auto-ownership for /dev/pty/s* -=============================================================================== -Changes for patch v162 - -Work sponsored by SGI - -- Set inode->i_size to correct size for symlinks - Thanks to Jeremy Fitzhardinge <jeremy@goop.org> - -- Only give lookup() method to directories to comply with new VFS - assumptions - -- Remove unnecessary tests in symlink methods - -- Don't kill existing block ops in <devfs_read_inode> - -- Restore auto-ownership for /dev/pty/m* -=============================================================================== -Changes for patch v163 - -Work sponsored by SGI - -- Don't create missing directories in <devfs_find_handle> - -- Removed Documentation/filesystems/devfs/mk-devlinks - -- Updated Documentation/filesystems/devfs/README -=============================================================================== -Changes for patch v164 - -Work sponsored by SGI - -- Fixed CONFIG_DEVFS breakage in drivers/char/serial.c introduced in - linux-2.3.99-pre6-7 -=============================================================================== -Changes for patch v165 - -Work sponsored by SGI - -- Ported to kernel 2.3.99-pre6 -=============================================================================== -Changes for patch v166 - -Work sponsored by SGI - -- Added CONFIG_DEVFS_MOUNT -=============================================================================== -Changes for patch v167 - -Work sponsored by SGI - -- Updated Documentation/filesystems/devfs/README - -- Updated sample modules.conf -=============================================================================== -Changes for patch v168 - -Work sponsored by SGI - -- Disabled multi-mount capability (use VFS bindings instead) - -- Updated README from master HTML file -=============================================================================== -Changes for patch v169 - -Work sponsored by SGI - -- Removed multi-mount code - -- Removed compatibility macros: VFS has changed too much -=============================================================================== -Changes for patch v170 - -Work sponsored by SGI - -- Updated README from master HTML file - -- Merged devfs inode into devfs entry -=============================================================================== -Changes for patch v171 - -Work sponsored by SGI - -- Updated sample modules.conf - -- Removed dead code in <devfs_register> which used to call - <free_dentries> - -- Ported to kernel 2.4.0-test2-pre3 -=============================================================================== -Changes for patch v172 - -Work sponsored by SGI - -- Changed interface to <devfs_register> - -- Changed interface to <devfs_register_series> -=============================================================================== -Changes for patch v173 - -Work sponsored by SGI - -- Simplified interface to <devfs_mk_symlink> - -- Simplified interface to <devfs_mk_dir> - -- Simplified interface to <devfs_find_handle> -=============================================================================== -Changes for patch v174 - -Work sponsored by SGI - -- Updated README from master HTML file -=============================================================================== -Changes for patch v175 - -Work sponsored by SGI - -- DocBook update for fs/devfs/base.c - Thanks to Tim Waugh <twaugh@redhat.com> - -- Removed stale fs/tunnel.c (was never used or completed) -=============================================================================== -Changes for patch v176 - -Work sponsored by SGI - -- Updated ToDo list - -- Removed sample modules.conf: now distributed with devfsd - -- Updated README from master HTML file - -- Ported to kernel 2.4.0-test3-pre4 (which had devfs-patch-v174) -=============================================================================== -Changes for patch v177 - -- Updated README from master HTML file - -- Documentation cleanups - -- Ensure <devfs_generate_path> terminates string for root entry - Thanks to Tim Jansen <tim@tjansen.de> - -- Exported <devfs_get_name> to modules - -- Make <devfs_mk_symlink> send events to devfsd - -- Cleaned up option processing in <devfs_setup> - -- Fixed bugs in handling symlinks: could leak or cause Oops - -- Cleaned up directory handling by separating fops - Thanks to Alexander Viro <viro@parcelfarce.linux.theplanet.co.uk> -=============================================================================== -Changes for patch v178 - -- Fixed handling of inverted options in <devfs_setup> -=============================================================================== -Changes for patch v179 - -- Adjusted <try_modload> to account for <devfs_generate_path> fix -=============================================================================== -Changes for patch v180 - -- Fixed !CONFIG_DEVFS_FS stub declaration of <devfs_get_info> -=============================================================================== -Changes for patch v181 - -- Answered question posed by Al Viro and removed his comments from <devfs_open> - -- Moved setting of registered flag after other fields are changed - -- Fixed race between <devfsd_close> and <devfsd_notify_one> - -- Global VFS changes added bogus BKL to devfsd_close(): removed - -- Widened locking in <devfs_readlink> and <devfs_follow_link> - -- Replaced <devfsd_read> stack usage with <devfsd_ioctl> kmalloc - -- Simplified locking in <devfsd_ioctl> and fixed memory leak -=============================================================================== -Changes for patch v182 - -- Created <devfs_*alloc_major> and <devfs_*alloc_devnum> - -- Removed broken devnum allocation and use <devfs_alloc_devnum> - -- Fixed old devnum leak by calling new <devfs_dealloc_devnum> - -- Created <devfs_*alloc_unique_number> - -- Fixed number leak for /dev/cdroms/cdrom%d - -- Fixed number leak for /dev/discs/disc%d -=============================================================================== -Changes for patch v183 - -- Fixed bug in <devfs_setup> which could hang boot process -=============================================================================== -Changes for patch v184 - -- Documentation typo fix for fs/devfs/util.c - -- Fixed drivers/char/stallion.c for devfs - -- Added DEVFSD_NOTIFY_DELETE event - -- Updated README from master HTML file - -- Removed #include <asm/segment.h> from fs/devfs/base.c -=============================================================================== -Changes for patch v185 - -- Made <block_semaphore> and <char_semaphore> in fs/devfs/util.c - private - -- Fixed inode table races by removing it and using inode->u.generic_ip - instead - -- Moved <devfs_read_inode> into <get_vfs_inode> - -- Moved <devfs_write_inode> into <devfs_notify_change> -=============================================================================== -Changes for patch v186 - -- Fixed race in <devfs_do_symlink> for uni-processor - -- Updated README from master HTML file -=============================================================================== -Changes for patch v187 - -- Fixed drivers/char/stallion.c for devfs - -- Fixed drivers/char/rocket.c for devfs - -- Fixed bug in <devfs_alloc_unique_number>: limited to 128 numbers -=============================================================================== -Changes for patch v188 - -- Updated major masks in fs/devfs/util.c up to Linus' "no new majors" - proclamation. Block: were 126 now 122 free, char: were 26 now 19 free - -- Updated README from master HTML file - -- Removed remnant of multi-mount support in <devfs_mknod> - -- Removed unused DEVFS_FL_SHOW_UNREG flag -=============================================================================== -Changes for patch v189 - -- Removed nlink field from struct devfs_inode - -- Removed auto-ownership for /dev/pty/* (BSD ptys) and used - DEVFS_FL_CURRENT_OWNER|DEVFS_FL_NO_PERSISTENCE for /dev/pty/s* (just - like Unix98 pty slaves) and made /dev/pty/m* rw-rw-rw- access -=============================================================================== -Changes for patch v190 - -- Updated README from master HTML file - -- Replaced BKL with global rwsem to protect symlink data (quick and - dirty hack) -=============================================================================== -Changes for patch v191 - -- Replaced global rwsem for symlink with per-link refcount -=============================================================================== -Changes for patch v192 - -- Removed unnecessary #ifdef CONFIG_DEVFS_FS from arch/i386/kernel/mtrr.c - -- Ported to kernel 2.4.10-pre11 - -- Set inode->i_mapping->a_ops for block nodes in <get_vfs_inode> -=============================================================================== -Changes for patch v193 - -- Went back to global rwsem for symlinks (refcount scheme no good) -=============================================================================== -Changes for patch v194 - -- Fixed overrun in <devfs_link> by removing function (not needed) - -- Updated README from master HTML file -=============================================================================== -Changes for patch v195 - -- Fixed buffer underrun in <try_modload> - -- Moved down_read() from <search_for_entry_in_dir> to <find_entry> -=============================================================================== -Changes for patch v196 - -- Fixed race in <devfsd_ioctl> when setting event mask - Thanks to Kari Hurtta <hurtta@leija.mh.fmi.fi> - -- Avoid deadlock in <devfs_follow_link> by using temporary buffer -=============================================================================== -Changes for patch v197 - -- First release of new locking code for devfs core (v1.0) - -- Fixed bug in drivers/cdrom/cdrom.c -=============================================================================== -Changes for patch v198 - -- Discard temporary buffer, now use "%s" for dentry names - -- Don't generate path in <try_modload>: use fake entry instead - -- Use "existing" directory in <_devfs_make_parent_for_leaf> - -- Use slab cache rather than fixed buffer for devfsd events -=============================================================================== -Changes for patch v199 - -- Removed obsolete usage of DEVFS_FL_NO_PERSISTENCE - -- Send DEVFSD_NOTIFY_REGISTERED events in <devfs_mk_dir> - -- Fixed locking bug in <devfs_d_revalidate_wait> due to typo - -- Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from devfsd - or children -=============================================================================== -Changes for patch v200 - -- Ported to kernel 2.5.1-pre2 -=============================================================================== -Changes for patch v201 - -- Fixed bug in <devfsd_read>: was dereferencing freed pointer -=============================================================================== -Changes for patch v202 - -- Fixed bug in <devfsd_close>: was dereferencing freed pointer - -- Added process group check for devfsd privileges -=============================================================================== -Changes for patch v203 - -- Use SLAB_ATOMIC in <devfsd_notify_de> from <devfs_d_delete> -=============================================================================== -Changes for patch v204 - -- Removed long obsolete rc.devfs - -- Return old entry in <devfs_mk_dir> for 2.4.x kernels - -- Updated README from master HTML file - -- Increment refcount on module in <check_disc_changed> - -- Created <devfs_get_handle> and exported <devfs_put> - -- Increment refcount on module in <devfs_get_ops> - -- Created <devfs_put_ops> and used where needed to fix races - -- Added clarifying comments in response to preliminary EMC code review - -- Added poisoning to <devfs_put> - -- Improved debugging messages - -- Fixed unregister bugs in drivers/md/lvm-fs.c -=============================================================================== -Changes for patch v205 - -- Corrected (made useful) debugging message in <unregister> - -- Moved <kmem_cache_create> in <mount_devfs_fs> to <init_devfs_fs> - -- Fixed drivers/md/lvm-fs.c to create "lvm" entry - -- Added magic number to guard against scribbling drivers - -- Only return old entry in <devfs_mk_dir> if a directory - -- Defined macros for error and debug messages - -- Updated README from master HTML file -=============================================================================== -Changes for patch v206 - -- Added support for multiple Compaq cpqarray controllers - -- Fixed (rare, old) race in <devfs_lookup> -=============================================================================== -Changes for patch v207 - -- Fixed deadlock bug in <devfs_d_revalidate_wait> - -- Tag VFS deletable in <devfs_mk_symlink> if handle ignored - -- Updated README from master HTML file -=============================================================================== -Changes for patch v208 - -- Added KERN_* to remaining messages - -- Cleaned up declaration of <stat_read> - -- Updated README from master HTML file -=============================================================================== -Changes for patch v209 - -- Updated README from master HTML file - -- Removed silently introduced calls to lock_kernel() and - unlock_kernel() due to recent VFS locking changes. BKL isn't - required in devfs - -- Changed <devfs_rmdir> to allow later additions if not yet empty - -- Added calls to <devfs_register_partitions> in drivers/block/blkpc.c - <add_partition> and <del_partition> - -- Fixed bug in <devfs_alloc_unique_number>: was clearing beyond - bitfield - -- Fixed bitfield data type for <devfs_*alloc_devnum> - -- Made major bitfield type and initialiser 64 bit safe -=============================================================================== -Changes for patch v210 - -- Updated fs/devfs/util.c to fix shift warning on 64 bit machines - Thanks to Anton Blanchard <anton@samba.org> - -- Updated README from master HTML file -=============================================================================== -Changes for patch v211 - -- Do not put miscellaneous character devices in /dev/misc if they - specify their own directory (i.e. contain a '/' character) - -- Copied macro for error messages from fs/devfs/base.c to - fs/devfs/util.c and made use of this macro - -- Removed 2.4.x compatibility code from fs/devfs/base.c -=============================================================================== -Changes for patch v212 - -- Added BKL to <devfs_open> because drivers still need it -=============================================================================== -Changes for patch v213 - -- Protected <scan_dir_for_removable> and <get_removable_partition> - from changing directory contents -=============================================================================== -Changes for patch v214 - -- Switched to ISO C structure field initialisers - -- Switch to set_current_state() and move before add_wait_queue() - -- Updated README from master HTML file - -- Fixed devfs entry leak in <devfs_readdir> when *readdir fails -=============================================================================== -Changes for patch v215 - -- Created <devfs_find_and_unregister> - -- Switched many functions from <devfs_find_handle> to - <devfs_find_and_unregister> - -- Switched many functions from <devfs_find_handle> to <devfs_get_handle> -=============================================================================== -Changes for patch v216 - -- Switched arch/ia64/sn/io/hcl.c from <devfs_find_handle> to - <devfs_get_handle> - -- Removed deprecated <devfs_find_handle> -=============================================================================== -Changes for patch v217 - -- Exported <devfs_find_and_unregister> and <devfs_only> to modules - -- Updated README from master HTML file - -- Fixed module unload race in <devfs_open> -=============================================================================== -Changes for patch v218 - -- Removed DEVFS_FL_AUTO_OWNER flag - -- Switched lingering structure field initialiser to ISO C - -- Added locking when setting/clearing flags - -- Documentation fix in fs/devfs/util.c diff --git a/Documentation/filesystems/devfs/README b/Documentation/filesystems/devfs/README deleted file mode 100644 index aabfba24bc2e..000000000000 --- a/Documentation/filesystems/devfs/README +++ /dev/null @@ -1,1959 +0,0 @@ -Devfs (Device File System) FAQ - - -Linux Devfs (Device File System) FAQ -Richard Gooch -20-AUG-2002 - - -Document languages: - - - - - - - ------------------------------------------------------------------------------ - -NOTE: the master copy of this document is available online at: - -http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.html -and looks much better than the text version distributed with the -kernel sources. A mirror site is available at: - -http://www.ras.ucalgary.ca/~rgooch/linux/docs/devfs.html - -There is also an optional daemon that may be used with devfs. You can -find out more about it at: - -http://www.atnf.csiro.au/~rgooch/linux/ - -A mailing list is available which you may subscribe to. Send -email -to majordomo@oss.sgi.com with the following line in the -body of the message: -subscribe devfs -To unsubscribe, send the message body: -unsubscribe devfs -instead. The list is archived at - -http://oss.sgi.com/projects/devfs/archive/. - ------------------------------------------------------------------------------ - -Contents - - -What is it? - -Why do it? - -Who else does it? - -How it works - -Operational issues (essential reading) - -Instructions for the impatient -Permissions persistence across reboots -Dealing with drivers without devfs support -All the way with Devfs -Other Issues -Kernel Naming Scheme -Devfsd Naming Scheme -Old Compatibility Names -SCSI Host Probing Issues - - - -Device drivers currently ported - -Allocation of Device Numbers - -Questions and Answers - -Making things work -Alternatives to devfs -What I don't like about devfs -How to report bugs -Strange kernel messages -Compilation problems with devfsd - - -Other resources - -Translations of this document - - ------------------------------------------------------------------------------ - - -What is it? - -Devfs is an alternative to "real" character and block special devices -on your root filesystem. Kernel device drivers can register devices by -name rather than major and minor numbers. These devices will appear in -devfs automatically, with whatever default ownership and -protection the driver specified. A daemon (devfsd) can be used to -override these defaults. Devfs has been in the kernel since 2.3.46. - -NOTE that devfs is entirely optional. If you prefer the old -disc-based device nodes, then simply leave CONFIG_DEVFS_FS=n (the -default). In this case, nothing will change. ALSO NOTE that if you do -enable devfs, the defaults are such that full compatibility is -maintained with the old devices names. - -There are two aspects to devfs: one is the underlying device -namespace, which is a namespace just like any mounted filesystem. The -other aspect is the filesystem code which provides a view of the -device namespace. The reason I make a distinction is because devfs -can be mounted many times, with each mount showing the same device -namespace. Changes made are global to all mounted devfs filesystems. -Also, because the devfs namespace exists without any devfs mounts, you -can easily mount the root filesystem by referring to an entry in the -devfs namespace. - - -The cost of devfs is a small increase in kernel code size and memory -usage. About 7 pages of code (some of that in __init sections) and 72 -bytes for each entry in the namespace. A modest system has only a -couple of hundred device entries, so this costs a few more -pages. Compare this with the suggestion to put /dev on a <a -href="#why-faq-ramdisc">ramdisc. - -On a typical machine, the cost is under 0.2 percent. On a modest -system with 64 MBytes of RAM, the cost is under 0.1 percent. The -accusations of "bloatware" levelled at devfs are not justified. - ------------------------------------------------------------------------------ - - -Why do it? - -There are several problems that devfs addresses. Some of these -problems are more serious than others (depending on your point of -view), and some can be solved without devfs. However, the totality of -these problems really calls out for devfs. - -The choice is a patchwork of inefficient user space solutions, which -are complex and likely to be fragile, or to use a simple and efficient -devfs which is robust. - -There have been many counter-proposals to devfs, all seeking to -provide some of the benefits without actually implementing devfs. So -far there has been an absence of code and no proposed alternative has -been able to provide all the features that devfs does. Further, -alternative proposals require far more complexity in user-space (and -still deliver less functionality than devfs). Some people have the -mantra of reducing "kernel bloat", but don't consider the effects on -user-space. - -A good solution limits the total complexity of kernel-space and -user-space. - - -Major&minor allocation - -The existing scheme requires the allocation of major and minor device -numbers for each and every device. This means that a central -co-ordinating authority is required to issue these device numbers -(unless you're developing a "private" device driver), in order to -preserve uniqueness. Devfs shifts the burden to a namespace. This may -not seem like a huge benefit, but actually it is. Since driver authors -will naturally choose a device name which reflects the functionality -of the device, there is far less potential for namespace conflict. -Solving this requires a kernel change. - -/dev management - -Because you currently access devices through device nodes, these must -be created by the system administrator. For standard devices you can -usually find a MAKEDEV programme which creates all these (hundreds!) -of nodes. This means that changes in the kernel must be reflected by -changes in the MAKEDEV programme, or else the system administrator -creates device nodes by hand. - -The basic problem is that there are two separate databases of -major and minor numbers. One is in the kernel and one is in /dev (or -in a MAKEDEV programme, if you want to look at it that way). This is -duplication of information, which is not good practice. -Solving this requires a kernel change. - -/dev growth - -A typical /dev has over 1200 nodes! Most of these devices simply don't -exist because the hardware is not available. A huge /dev increases the -time to access devices (I'm just referring to the dentry lookup times -and the time taken to read inodes off disc: the next subsection shows -some more horrors). - -An example of how big /dev can grow is if we consider SCSI devices: - -host 6 bits (say up to 64 hosts on a really big machine) -channel 4 bits (say up to 16 SCSI buses per host) -id 4 bits -lun 3 bits -partition 6 bits -TOTAL 23 bits - - -This requires 8 Mega (1024*1024) inodes if we want to store all -possible device nodes. Even if we scrap everything but id,partition -and assume a single host adapter with a single SCSI bus and only one -logical unit per SCSI target (id), that's still 10 bits or 1024 -inodes. Each VFS inode takes around 256 bytes (kernel 2.1.78), so -that's 256 kBytes of inode storage on disc (assuming real inodes take -a similar amount of space as VFS inodes). This is actually not so bad, -because disc is cheap these days. Embedded systems would care about -256 kBytes of /dev inodes, but you could argue that embedded systems -would have hand-tuned /dev directories. I've had to do just that on my -embedded systems, but I would rather just leave it to devfs. - -Another issue is the time taken to lookup an inode when first -referenced. Not only does this take time in scanning through a list in -memory, but also the seek times to read the inodes off disc. -This could be solved in user-space using a clever programme which -scanned the kernel logs and deleted /dev entries which are not -available and created them when they were available. This programme -would need to be run every time a new module was loaded, which would -slow things down a lot. - -There is an existing programme called scsidev which will automatically -create device nodes for SCSI devices. It can do this by scanning files -in /proc/scsi. Unfortunately, to extend this idea to other device -nodes would require significant modifications to existing drivers (so -they too would provide information in /proc). This is a non-trivial -change (I should know: devfs has had to do something similar). Once -you go to this much effort, you may as well use devfs itself (which -also provides this information). Furthermore, such a system would -likely be implemented in an ad-hoc fashion, as different drivers will -provide their information in different ways. - -Devfs is much cleaner, because it (naturally) has a uniform mechanism -to provide this information: the device nodes themselves! - - -Node to driver file_operations translation - -There is an important difference between the way disc-based character -and block nodes and devfs entries make the connection between an entry -in /dev and the actual device driver. - -With the current 8 bit major and minor numbers the connection between -disc-based c&b nodes and per-major drivers is done through a -fixed-length table of 128 entries. The various filesystem types set -the inode operations for c&b nodes to {chr,blk}dev_inode_operations, -so when a device is opened a few quick levels of indirection bring us -to the driver file_operations. - -For miscellaneous character devices a second step is required: there -is a scan for the driver entry with the same minor number as the file -that was opened, and the appropriate minor open method is called. This -scanning is done *every time* you open a device node. Potentially, you -may be searching through dozens of misc. entries before you find your -open method. While not an enormous performance overhead, this does -seem pointless. - -Linux *must* move beyond the 8 bit major and minor barrier, -somehow. If we simply increase each to 16 bits, then the indexing -scheme used for major driver lookup becomes untenable, because the -major tables (one each for character and block devices) would need to -be 64 k entries long (512 kBytes on x86, 1 MByte for 64 bit -systems). So we would have to use a scheme like that used for -miscellaneous character devices, which means the search time goes up -linearly with the average number of major device drivers on your -system. Not all "devices" are hardware, some are higher-level drivers -like KGI, so you can get more "devices" without adding hardware -You can improve this by creating an ordered (balanced:-) -binary tree, in which case your search time becomes log(N). -Alternatively, you can use hashing to speed up the search. -But why do that search at all if you don't have to? Once again, it -seems pointless. - -Note that devfs doesn't use the major&minor system. For devfs -entries, the connection is done when you lookup the /dev entry. When -devfs_register() is called, an internal table is appended which has -the entry name and the file_operations. If the dentry cache doesn't -have the /dev entry already, this internal table is scanned to get the -file_operations, and an inode is created. If the dentry cache already -has the entry, there is *no lookup time* (other than the dentry scan -itself, but we can't avoid that anyway, and besides Linux dentries -cream other OS's which don't have them:-). Furthermore, the number of -node entries in a devfs is only the number of available device -entries, not the number of *conceivable* entries. Even if you remove -unnecessary entries in a disc-based /dev, the number of conceivable -entries remains the same: you just limit yourself in order to save -space. - -Devfs provides a fast connection between a VFS node and the device -driver, in a scalable way. - -/dev as a system administration tool - -Right now /dev contains a list of conceivable devices, most of which I -don't have. Devfs only shows those devices available on my -system. This means that listing /dev is a handy way of checking what -devices are available. - -Major&minor size - -Existing major and minor numbers are limited to 8 bits each. This is -now a limiting factor for some drivers, particularly the SCSI disc -driver, which consumes a single major number. Only 16 discs are -supported, and each disc may have only 15 partitions. Maybe this isn't -a problem for you, but some of us are building huge Linux systems with -disc arrays. With devfs an arbitrary pointer can be associated with -each device entry, which can be used to give an effective 32 bit -device identifier (i.e. that's like having a 32 bit minor -number). Since this is private to the kernel, there are no C library -compatibility issues which you would have with increasing major and -minor number sizes. See the section on "Allocation of Device Numbers" -for details on maintaining compatibility with userspace. - -Solving this requires a kernel change. - -Since writing this, the kernel has been modified so that the SCSI disc -driver has more major numbers allocated to it and now supports up to -128 discs. Since these major numbers are non-contiguous (a result of -unplanned expansion), the implementation is a little more cumbersome -than originally. - -Just like the changes to IPv4 to fix impending limitations in the -address space, people find ways around the limitations. In the long -run, however, solutions like IPv6 or devfs can't be put off forever. - -Read-only root filesystem - -Having your device nodes on the root filesystem means that you can't -operate properly with a read-only root filesystem. This is because you -want to change ownerships and protections of tty devices. Existing -practice prevents you using a CD-ROM as your root filesystem for a -*real* system. Sure, you can boot off a CD-ROM, but you can't change -tty ownerships, so it's only good for installing. - -Also, you can't use a shared NFS root filesystem for a cluster of -discless Linux machines (having tty ownerships changed on a common -/dev is not good). Nor can you embed your root filesystem in a -ROM-FS. - -You can get around this by creating a RAMDISC at boot time, making -an ext2 filesystem in it, mounting it somewhere and copying the -contents of /dev into it, then unmounting it and mounting it over -/dev. - -A devfs is a cleaner way of solving this. - -Non-Unix root filesystem - -Non-Unix filesystems (such as NTFS) can't be used for a root -filesystem because they variously don't support character and block -special files or symbolic links. You can't have a separate disc-based -or RAMDISC-based filesystem mounted on /dev because you need device -nodes before you can mount these. Devfs can be mounted without any -device nodes. Devlinks won't work because symlinks aren't supported. -An alternative solution is to use initrd to mount a RAMDISC initial -root filesystem (which is populated with a minimal set of device -nodes), and then construct a new /dev in another RAMDISC, and finally -switch to your non-Unix root filesystem. This requires clever boot -scripts and a fragile and conceptually complex boot procedure. - -Devfs solves this in a robust and conceptually simple way. - -PTY security - -Current pseudo-tty (pty) devices are owned by root and read-writable -by everyone. The user of a pty-pair cannot change -ownership/protections without being suid-root. - -This could be solved with a secure user-space daemon which runs as -root and does the actual creation of pty-pairs. Such a daemon would -require modification to *every* programme that wants to use this new -mechanism. It also slows down creation of pty-pairs. - -An alternative is to create a new open_pty() syscall which does much -the same thing as the user-space daemon. Once again, this requires -modifications to pty-handling programmes. - -The devfs solution allows a device driver to "tag" certain device -files so that when an unopened device is opened, the ownerships are -changed to the current euid and egid of the opening process, and the -protections are changed to the default registered by the driver. When -the device is closed ownership is set back to root and protections are -set back to read-write for everybody. No programme need be changed. -The devpts filesystem provides this auto-ownership feature for Unix98 -ptys. It doesn't support old-style pty devices, nor does it have all -the other features of devfs. - -Intelligent device management - -Devfs implements a simple yet powerful protocol for communication with -a device management daemon (devfsd) which runs in user space. It is -possible to send a message (either synchronously or asynchronously) to -devfsd on any event, such as registration/unregistration of device -entries, opening and closing devices, looking up inodes, scanning -directories and more. This has many possibilities. Some of these are -already implemented. See: - - -http://www.atnf.csiro.au/~rgooch/linux/ - -Device entry registration events can be used by devfsd to change -permissions of newly-created device nodes. This is one mechanism to -control device permissions. - -Device entry registration/unregistration events can be used to run -programmes or scripts. This can be used to provide automatic mounting -of filesystems when a new block device media is inserted into the -drive. - -Asynchronous device open and close events can be used to implement -clever permissions management. For example, the default permissions on -/dev/dsp do not allow everybody to read from the device. This is -sensible, as you don't want some remote user recording what you say at -your console. However, the console user is also prevented from -recording. This behaviour is not desirable. With asynchronous device -open and close events, you can have devfsd run a programme or script -when console devices are opened to change the ownerships for *other* -device nodes (such as /dev/dsp). On closure, you can run a different -script to restore permissions. An advantage of this scheme over -modifying the C library tty handling is that this works even if your -programme crashes (how many times have you seen the utmp database with -lingering entries for non-existent logins?). - -Synchronous device open events can be used to perform intelligent -device access protections. Before the device driver open() method is -called, the daemon must first validate the open attempt, by running an -external programme or script. This is far more flexible than access -control lists, as access can be determined on the basis of other -system conditions instead of just the UID and GID. - -Inode lookup events can be used to authenticate module autoload -requests. Instead of using kmod directly, the event is sent to -devfsd which can implement an arbitrary authentication before loading -the module itself. - -Inode lookup events can also be used to construct arbitrary -namespaces, without having to resort to populating devfs with symlinks -to devices that don't exist. - -Speculative Device Scanning - -Consider an application (like cdparanoia) that wants to find all -CD-ROM devices on the system (SCSI, IDE and other types), whether or -not their respective modules are loaded. The application must -speculatively open certain device nodes (such as /dev/sr0 for the SCSI -CD-ROMs) in order to make sure the module is loaded. This requires -that all Linux distributions follow the standard device naming scheme -(last time I looked RedHat did things differently). Devfs solves the -naming problem. - -The same application also wants to see which devices are actually -available on the system. With the existing system it needs to read the -/dev directory and speculatively open each /dev/sr* device to -determine if the device exists or not. With a large /dev this is an -inefficient operation, especially if there are many /dev/sr* nodes. A -solution like scsidev could reduce the number of /dev/sr* entries (but -of course that also requires all that inefficient directory scanning). - -With devfs, the application can open the /dev/sr directory -(which triggers the module autoloading if required), and proceed to -read /dev/sr. Since only the available devices will have -entries, there are no inefficencies in directory scanning or device -openings. - ------------------------------------------------------------------------------ - -Who else does it? - -FreeBSD has a devfs implementation. Solaris and AIX each have a -pseudo-devfs (something akin to scsidev but for all devices, with some -unspecified kernel support). BeOS, Plan9 and QNX also have it. SGI's -IRIX 6.4 and above also have a device filesystem. - -While we shouldn't just automatically do something because others do -it, we should not ignore the work of others either. FreeBSD has a lot -of competent people working on it, so their opinion should not be -blithely ignored. - ------------------------------------------------------------------------------ - - -How it works - -Registering device entries - -For every entry (device node) in a devfs-based /dev a driver must call -devfs_register(). This adds the name of the device entry, the -file_operations structure pointer and a few other things to an -internal table. Device entries may be added and removed at any -time. When a device entry is registered, it automagically appears in -any mounted devfs'. - -Inode lookup - -When a lookup operation on an entry is performed and if there is no -driver information for that entry devfs will attempt to call -devfsd. If still no driver information can be found then a negative -dentry is yielded and the next stage operation will be called by the -VFS (such as create() or mknod() inode methods). If driver information -can be found, an inode is created (if one does not exist already) and -all is well. - -Manually creating device nodes - -The mknod() method allows you to create an ordinary named pipe in the -devfs, or you can create a character or block special inode if one -does not already exist. You may wish to create a character or block -special inode so that you can set permissions and ownership. Later, if -a device driver registers an entry with the same name, the -permissions, ownership and times are retained. This is how you can set -the protections on a device even before the driver is loaded. Once you -create an inode it appears in the directory listing. - -Unregistering device entries - -A device driver calls devfs_unregister() to unregister an entry. - -Chroot() gaols - -2.2.x kernels - -The semantics of inode creation are different when devfs is mounted -with the "explicit" option. Now, when a device entry is registered, it -will not appear until you use mknod() to create the device. It doesn't -matter if you mknod() before or after the device is registered with -devfs_register(). The purpose of this behaviour is to support -chroot(2) gaols, where you want to mount a minimal devfs inside the -gaol. Only the devices you specifically want to be available (through -your mknod() setup) will be accessible. - -2.4.x kernels - -As of kernel 2.3.99, the VFS has had the ability to rebind parts of -the global filesystem namespace into another part of the namespace. -This now works even at the leaf-node level, which means that -individual files and device nodes may be bound into other parts of the -namespace. This is like making links, but better, because it works -across filesystems (unlike hard links) and works through chroot() -gaols (unlike symbolic links). - -Because of these improvements to the VFS, the multi-mount capability -in devfs is no longer needed. The administrator may create a minimal -device tree inside a chroot(2) gaol by using VFS bindings. As this -provides most of the features of the devfs multi-mount capability, I -removed the multi-mount support code (after issuing an RFC). This -yielded code size reductions and simplifications. - -If you want to construct a minimal chroot() gaol, the following -command should suffice: - -mount --bind /dev/null /gaol/dev/null - - -Repeat for other device nodes you want to expose. Simple! - ------------------------------------------------------------------------------ - - -Operational issues - - -Instructions for the impatient - -Nobody likes reading documentation. People just want to get in there -and play. So this section tells you quickly the steps you need to take -to run with devfs mounted over /dev. Skip these steps and you will end -up with a nearly unbootable system. Subsequent sections describe the -issues in more detail, and discuss non-essential configuration -options. - -Devfsd -OK, if you're reading this, I assume you want to play with -devfs. First you should ensure that /usr/src/linux contains a -recent kernel source tree. Then you need to compile devfsd, the device -management daemon, available at - -http://www.atnf.csiro.au/~rgooch/linux/. -Because the kernel has a naming scheme -which is quite different from the old naming scheme, you need to -install devfsd so that software and configuration files that use the -old naming scheme will not break. - -Compile and install devfsd. You will be provided with a default -configuration file /etc/devfsd.conf which will provide -compatibility symlinks for the old naming scheme. Don't change this -config file unless you know what you're doing. Even if you think you -do know what you're doing, don't change it until you've followed all -the steps below and booted a devfs-enabled system and verified that it -works. - -Now edit your main system boot script so that devfsd is started at the -very beginning (before any filesystem -checks). /etc/rc.d/rc.sysinit is often the main boot script -on systems with SysV-style boot scripts. On systems with BSD-style -boot scripts it is often /etc/rc. Also check -/sbin/rc. - -NOTE that the line you put into the boot -script should be exactly: - -/sbin/devfsd /dev - -DO NOT use some special daemon-launching -programme, otherwise the boot script may not wait for devfsd to finish -initialising. - -System Libraries -There may still be some problems because of broken software making -assumptions about device names. In particular, some software does not -handle devices which are symbolic links. If you are running a libc 5 -based system, install libc 5.4.44 (if you have libc 5.4.46, go back to -libc 5.4.44, which is actually correct). If you are running a glibc -based system, make sure you have glibc 2.1.3 or later. - -/etc/securetty -PAM (Pluggable Authentication Modules) is supposed to be a flexible -mechanism for providing better user authentication and access to -services. Unfortunately, it's also fragile, complex and undocumented -(check out RedHat 6.1, and probably other distributions as well). PAM -has problems with symbolic links. Append the following lines to your -/etc/securetty file: - -vc/1 -vc/2 -vc/3 -vc/4 -vc/5 -vc/6 -vc/7 -vc/8 - -This will not weaken security. If you have a version of util-linux -earlier than 2.10.h, please upgrade to 2.10.h or later. If you -absolutely cannot upgrade, then also append the following lines to -your /etc/securetty file: - -1 -2 -3 -4 -5 -6 -7 -8 - -This may potentially weaken security by allowing root logins over the -network (a password is still required, though). However, since there -are problems with dealing with symlinks, I'm suspicious of the level -of security offered in any case. - -XFree86 -While not essential, it's probably a good idea to upgrade to XFree86 -4.0, as patches went in to make it more devfs-friendly. If you don't, -you'll probably need to apply the following patch to -/etc/security/console.perms so that ordinary users can run -startx. Note that not all distributions have this file (e.g. Debian), -so if it's not present, don't worry about it. - ---- /etc/security/console.perms.orig Sat Apr 17 16:26:47 1999 -+++ /etc/security/console.perms Fri Feb 25 23:53:55 2000 -@@ -14,7 +14,7 @@ - # man 5 console.perms - - # file classes -- these are regular expressions --<console>=tty[0-9][0-9]* :[0-9]\.[0-9] :[0-9] -+<console>=tty[0-9][0-9]* vc/[0-9][0-9]* :[0-9]\.[0-9] :[0-9] - - # device classes -- these are shell-style globs - <floppy>=/dev/fd[0-1]* - -If the patch does not apply, then change the line: - -<console>=tty[0-9][0-9]* :[0-9]\.[0-9] :[0-9] - -with: - -<console>=tty[0-9][0-9]* vc/[0-9][0-9]* :[0-9]\.[0-9] :[0-9] - - -Disable devpts -I've had a report of devpts mounted on /dev/pts not working -correctly. Since devfs will also manage /dev/pts, there is no -need to mount devpts as well. You should either edit your -/etc/fstab so devpts is not mounted, or disable devpts from -your kernel configuration. - -Unsupported drivers -Not all drivers have devfs support. If you depend on one of these -drivers, you will need to create a script or tarfile that you can use -at boot time to create device nodes as appropriate. There is a -section which describes this. Another -section lists the drivers which have -devfs support. - -/dev/mouse - -Many disributions configure /dev/mouse to be the mouse device -for XFree86 and GPM. I actually think this is a bad idea, because it -adds another level of indirection. When looking at a config file, if -you see /dev/mouse you're left wondering which mouse -is being referred to. Hence I recommend putting the actual mouse -device (for example /dev/psaux) into your -/etc/X11/XF86Config file (and similarly for the GPM -configuration file). - -Alternatively, use the same technique used for unsupported drivers -described above. - -The Kernel -Finally, you need to make sure devfs is compiled into your kernel. Set -CONFIG_EXPERIMENTAL=y, CONFIG_DEVFS_FS=y and CONFIG_DEVFS_MOUNT=y by -using favourite configuration tool (i.e. make config or -make xconfig) and then make clean and then recompile your kernel and -modules. At boot, devfs will be mounted onto /dev. - -If you encounter problems booting (for example if you forgot a -configuration step), you can pass devfs=nomount at the kernel -boot command line. This will prevent the kernel from mounting devfs at -boot time onto /dev. - -In general, a kernel built with CONFIG_DEVFS_FS=y but without mounting -devfs onto /dev is completely safe, and requires no -configuration changes. One exception to take note of is when -LABEL= directives are used in /etc/fstab. In this -case you will be unable to boot properly. This is because the -mount(8) programme uses /proc/partitions as part of -the volume label search process, and the device names it finds are not -available, because setting CONFIG_DEVFS_FS=y changes the names in -/proc/partitions, irrespective of whether devfs is mounted. - -Now you've finished all the steps required. You're now ready to boot -your shiny new kernel. Enjoy. - -Changing the configuration - -OK, you've now booted a devfs-enabled system, and everything works. -Now you may feel like changing the configuration (common targets are -/etc/fstab and /etc/devfsd.conf). Since you have a -system that works, if you make any changes and it doesn't work, you -now know that you only have to restore your configuration files to the -default and it will work again. - - -Permissions persistence across reboots - -If you don't use mknod(2) to create a device file, nor use chmod(2) or -chown(2) to change the ownerships/permissions, the inode ctime will -remain at 0 (the epoch, 12 am, 1-JAN-1970, GMT). Anything with a ctime -later than this has had it's ownership/permissions changed. Hence, a -simple script or programme may be used to tar up all changed inodes, -prior to shutdown. Although effective, many consider this approach a -kludge. - -A much better approach is to use devfsd to save and restore -permissions. It may be configured to record changes in permissions and -will save them in a database (in fact a directory tree), and restore -these upon boot. This is an efficient method and results in immediate -saving of current permissions (unlike the tar approach, which saves -permissions at some unspecified future time). - -The default configuration file supplied with devfsd has config entries -which you may uncomment to enable persistence management. - -If you decide to use the tar approach anyway, be aware that tar will -first unlink(2) an inode before creating a new device node. The -unlink(2) has the effect of breaking the connection between a devfs -entry and the device driver. If you use the "devfs=only" boot option, -you lose access to the device driver, requiring you to reload the -module. I consider this a bug in tar (there is no real need to -unlink(2) the inode first). - -Alternatively, you can use devfsd to provide more sophisticated -management of device permissions. You can use devfsd to store -permissions for whole groups of devices with a single configuration -entry, rather than the conventional single entry per device entry. - -Permissions database stored in mounted-over /dev - -If you wish to save and restore your device permissions into the -disc-based /dev while still mounting devfs onto /dev -you may do so. This requires a 2.4.x kernel (in fact, 2.3.99 or -later), which has the VFS binding facility. You need to do the -following to set this up: - - - -make sure the kernel does not mount devfs at boot time - - -make sure you have a correct /dev/console entry in your -root file-system (where your disc-based /dev lives) - -create the /dev-state directory - - -add the following lines near the very beginning of your boot -scripts: - -mount --bind /dev /dev-state -mount -t devfs none /dev -devfsd /dev - - - - -add the following lines to your /etc/devfsd.conf file: - -REGISTER ^pt[sy] IGNORE -CREATE ^pt[sy] IGNORE -CHANGE ^pt[sy] IGNORE -DELETE ^pt[sy] IGNORE -REGISTER .* COPY /dev-state/$devname $devpath -CREATE .* COPY $devpath /dev-state/$devname -CHANGE .* COPY $devpath /dev-state/$devname -DELETE .* CFUNCTION GLOBAL unlink /dev-state/$devname -RESTORE /dev-state - -Note that the sample devfsd.conf file contains these lines, -as well as other sample configurations you may find useful. See the -devfsd distribution - - -reboot. - - - - -Permissions database stored in normal directory - -If you are using an older kernel which doesn't support VFS binding, -then you won't be able to have the permissions database in a -mounted-over /dev. However, you can still use a regular -directory to store the database. The sample /etc/devfsd.conf -file above may still be used. You will need to create the -/dev-state directory prior to installing devfsd. If you have -old permissions in /dev, then just copy (or move) the device -nodes over to the new directory. - -Which method is better? - -The best method is to have the permissions database stored in the -mounted-over /dev. This is because you will not need to copy -device nodes over to /dev-state, and because it allows you to -switch between devfs and non-devfs kernels, without requiring you to -copy permissions between /dev-state (for devfs) and -/dev (for non-devfs). - - -Dealing with drivers without devfs support - -Currently, not all device drivers in the kernel have been modified to -use devfs. Device drivers which do not yet have devfs support will not -automagically appear in devfs. The simplest way to create device nodes -for these drivers is to unpack a tarfile containing the required -device nodes. You can do this in your boot scripts. All your drivers -will now work as before. - -Hopefully for most people devfs will have enough support so that they -can mount devfs directly over /dev without losing most functionality -(i.e. losing access to various devices). As of 22-JAN-1998 (devfs -patch version 10) I am now running this way. All the devices I have -are available in devfs, so I don't lose anything. - -WARNING: if your configuration requires the old-style device names -(i.e. /dev/hda1 or /dev/sda1), you must install devfsd and configure -it to maintain compatibility entries. It is almost certain that you -will require this. Note that the kernel creates a compatibility entry -for the root device, so you don't need initrd. - -Note that you no longer need to mount devpts if you use Unix98 PTYs, -as devfs can manage /dev/pts itself. This saves you some RAM, as you -don't need to compile and install devpts. Note that some versions of -glibc have a bug with Unix98 pty handling on devfs systems. Contact -the glibc maintainers for a fix. Glibc 2.1.3 has the fix. - -Note also that apart from editing /etc/fstab, other things will need -to be changed if you *don't* install devfsd. Some software (like the X -server) hard-wire device names in their source. It really is much -easier to install devfsd so that compatibility entries are created. -You can then slowly migrate your system to using the new device names -(for example, by starting with /etc/fstab), and then limiting the -compatibility entries that devfsd creates. - -IF YOU CONFIGURE TO MOUNT DEVFS AT BOOT, MAKE SURE YOU INSTALL DEVFSD -BEFORE YOU BOOT A DEVFS-ENABLED KERNEL! - -Now that devfs has gone into the 2.3.46 kernel, I'm getting a lot of -reports back. Many of these are because people are trying to run -without devfsd, and hence some things break. Please just run devfsd if -things break. I want to concentrate on real bugs rather than -misconfiguration problems at the moment. If people are willing to fix -bugs/false assumptions in other code (i.e. glibc, X server) and submit -that to the respective maintainers, that would be great. - - -All the way with Devfs - -The devfs kernel patch creates a rationalised device tree. As stated -above, if you want to keep using the old /dev naming scheme, -you just need to configure devfsd appopriately (see the man -page). People who prefer the old names can ignore this section. For -those of us who like the rationalised names and an uncluttered -/dev, read on. - -If you don't run devfsd, or don't enable compatibility entry -management, then you will have to configure your system to use the new -names. For example, you will then need to edit your -/etc/fstab to use the new disc naming scheme. If you want to -be able to boot non-devfs kernels, you will need compatibility -symlinks in the underlying disc-based /dev pointing back to -the old-style names for when you boot a kernel without devfs. - -You can selectively decide which devices you want compatibility -entries for. For example, you may only want compatibility entries for -BSD pseudo-terminal devices (otherwise you'll have to patch you C -library or use Unix98 ptys instead). It's just a matter of putting in -the correct regular expression into /dev/devfsd.conf. - -There are other choices of naming schemes that you may prefer. For -example, I don't use the kernel-supplied -names, because they are too verbose. A common misconception is -that the kernel-supplied names are meant to be used directly in -configuration files. This is not the case. They are designed to -reflect the layout of the devices attached and to provide easy -classification. - -If you like the kernel-supplied names, that's fine. If you don't then -you should be using devfsd to construct a namespace more to your -liking. Devfsd has built-in code to construct a -namespace that is both logical and easy to -manage. In essence, it creates a convenient abbreviation of the -kernel-supplied namespace. - -You are of course free to build your own namespace. Devfsd has all the -infrastructure required to make this easy for you. All you need do is -write a script. You can even write some C code and devfsd can load the -shared object as a callable extension. - - -Other Issues - -The init programme -Another thing to take note of is whether your init programme -creates a Unix socket /dev/telinit. Some versions of init -create /dev/telinit so that the telinit programme can -communicate with the init process. If you have such a system you need -to make sure that devfs is mounted over /dev *before* init -starts. In other words, you can't leave the mounting of devfs to -/etc/rc, since this is executed after init. Other -versions of init require a named pipe /dev/initctl -which must exist *before* init starts. Once again, you need to -mount devfs and then create the named pipe *before* init -starts. - -The default behaviour now is not to mount devfs onto /dev at -boot time for 2.3.x and later kernels. You can correct this with the -"devfs=mount" boot option. This solves any problems with init, -and also prevents the dreaded: - -Cannot open initial console - -message. For 2.2.x kernels where you need to apply the devfs patch, -the default is to mount. - -If you have automatic mounting of devfs onto /dev then you -may need to create /dev/initctl in your boot scripts. The -following lines should suffice: - -mknod /dev/initctl p -kill -SIGUSR1 1 # tell init that /dev/initctl now exists - -Alternatively, if you don't want the kernel to mount devfs onto -/dev then you could use the following procedure is a -guideline for how to get around /dev/initctl problems: - -# cd /sbin -# mv init init.real -# cat > init -#! /bin/sh -mount -n -t devfs none /dev -mknod /dev/initctl p -exec /sbin/init.real $* -[control-D] -# chmod a+x init - -Note that newer versions of init create /dev/initctl -automatically, so you don't have to worry about this. - -Module autoloading -You will need to configure devfsd to enable module -autoloading. The following lines should be placed in your -/etc/devfsd.conf file: - -LOOKUP .* MODLOAD - - -As of devfsd-v1.3.10, a generic /etc/modules.devfs -configuration file is installed, which is used by the MODLOAD -action. This should be sufficient for most configurations. If you -require further configuration, edit your /etc/modules.conf -file. The way module autoloading work with devfs is: - - -a process attempts to lookup a device node (e.g. /dev/fred) - - -if that device node does not exist, the full pathname is passed to -devfsd as a string - - -devfsd will pass the string to the modprobe programme (provided the -configuration line shown above is present), and specifies that -/etc/modules.devfs is the configuration file - - -/etc/modules.devfs includes /etc/modules.conf to -access local configurations - -modprobe will search it's configuration files, looking for an alias -that translates the pathname into a module name - - -the translated pathname is then used to load the module. - - -If you wanted a lookup of /dev/fred to load the -mymod module, you would require the following configuration -line in /etc/modules.conf: - -alias /dev/fred mymod - -The /etc/modules.devfs configuration file provides many such -aliases for standard device names. If you look closely at this file, -you will note that some modules require multiple alias configuration -lines. This is required to support module autoloading for old and new -device names. - -Mounting root off a devfs device -If you wish to mount root off a devfs device when you pass the -"devfs=only" boot option, then you need to pass in the -"root=<device>" option to the kernel when booting. If you use -LILO, then you must have this in lilo.conf: - -append = "root=<device>" - -Surprised? Yep, so was I. It turns out if you have (as most people -do): - -root = <device> - - -then LILO will determine the device number of <device> and will -write that device number into a special place in the kernel image -before starting the kernel, and the kernel will use that device number -to mount the root filesystem. So, using the "append" variety ensures -that LILO passes the root filesystem device as a string, which devfs -can then use. - -Note that this isn't an issue if you don't pass "devfs=only". - -TTY issues -The ttyname(3) function in some versions of the C library makes -false assumptions about device entries which are symbolic links. The -tty(1) programme is one that depends on this function. I've -written a patch to libc 5.4.43 which fixes this. This has been -included in libc 5.4.44 and a similar fix is in glibc 2.1.3. - - -Kernel Naming Scheme - -The kernel provides a default naming scheme. This scheme is designed -to make it easy to search for specific devices or device types, and to -view the available devices. Some device types (such as hard discs), -have a directory of entries, making it easy to see what devices of -that class are available. Often, the entries are symbolic links into a -directory tree that reflects the topology of available devices. The -topological tree is useful for finding how your devices are arranged. - -Below is a list of the naming schemes for the most common drivers. A -list of reserved device names is -available for reference. Please send email to -rgooch@atnf.csiro.au to obtain an allocation. Please be -patient (the maintainer is busy). An alternative name may be allocated -instead of the requested name, at the discretion of the maintainer. - -Disc Devices - -All discs, whether SCSI, IDE or whatever, are placed under the -/dev/discs hierarchy: - - /dev/discs/disc0 first disc - /dev/discs/disc1 second disc - - -Each of these entries is a symbolic link to the directory for that -device. The device directory contains: - - disc for the whole disc - part* for individual partitions - - -CD-ROM Devices - -All CD-ROMs, whether SCSI, IDE or whatever, are placed under the -/dev/cdroms hierarchy: - - /dev/cdroms/cdrom0 first CD-ROM - /dev/cdroms/cdrom1 second CD-ROM - - -Each of these entries is a symbolic link to the real device entry for -that device. - -Tape Devices - -All tapes, whether SCSI, IDE or whatever, are placed under the -/dev/tapes hierarchy: - - /dev/tapes/tape0 first tape - /dev/tapes/tape1 second tape - - -Each of these entries is a symbolic link to the directory for that -device. The device directory contains: - - mt for mode 0 - mtl for mode 1 - mtm for mode 2 - mta for mode 3 - mtn for mode 0, no rewind - mtln for mode 1, no rewind - mtmn for mode 2, no rewind - mtan for mode 3, no rewind - - -SCSI Devices - -To uniquely identify any SCSI device requires the following -information: - - controller (host adapter) - bus (SCSI channel) - target (SCSI ID) - unit (Logical Unit Number) - - -All SCSI devices are placed under /dev/scsi (assuming devfs -is mounted on /dev). Hence, a SCSI device with the following -parameters: c=1,b=2,t=3,u=4 would appear as: - - /dev/scsi/host1/bus2/target3/lun4 device directory - - -Inside this directory, a number of device entries may be created, -depending on which SCSI device-type drivers were installed. - -See the section on the disc naming scheme to see what entries the SCSI -disc driver creates. - -See the section on the tape naming scheme to see what entries the SCSI -tape driver creates. - -The SCSI CD-ROM driver creates: - - cd - - -The SCSI generic driver creates: - - generic - - -IDE Devices - -To uniquely identify any IDE device requires the following -information: - - controller - bus (aka. primary/secondary) - target (aka. master/slave) - unit - - -All IDE devices are placed under /dev/ide, and uses a similar -naming scheme to the SCSI subsystem. - -XT Hard Discs - -All XT discs are placed under /dev/xd. The first XT disc has -the directory /dev/xd/disc0. - -TTY devices - -The tty devices now appear as: - - New name Old-name Device Type - -------- -------- ----------- - /dev/tts/{0,1,...} /dev/ttyS{0,1,...} Serial ports - /dev/cua/{0,1,...} /dev/cua{0,1,...} Call out devices - /dev/vc/0 /dev/tty Current virtual console - /dev/vc/{1,2,...} /dev/tty{1...63} Virtual consoles - /dev/vcc/{0,1,...} /dev/vcs{1...63} Virtual consoles - /dev/pty/m{0,1,...} /dev/ptyp?? PTY masters - /dev/pty/s{0,1,...} /dev/ttyp?? PTY slaves - - -RAMDISCS - -The RAMDISCS are placed in their own directory, and are named thus: - - /dev/rd/{0,1,2,...} - - -Meta Devices - -The meta devices are placed in their own directory, and are named -thus: - - /dev/md/{0,1,2,...} - - -Floppy discs - -Floppy discs are placed in the /dev/floppy directory. - -Loop devices - -Loop devices are placed in the /dev/loop directory. - -Sound devices - -Sound devices are placed in the /dev/sound directory -(audio, sequencer, ...). - - -Devfsd Naming Scheme - -Devfsd provides a naming scheme which is a convenient abbreviation of -the kernel-supplied namespace. In some -cases, the kernel-supplied naming scheme is quite convenient, so -devfsd does not provide another naming scheme. The convenience names -that devfsd creates are in fact the same names as the original devfs -kernel patch created (before Linus mandated the Big Name -Change). These are referred to as "new compatibility entries". - -In order to configure devfsd to create these convenience names, the -following lines should be placed in your /etc/devfsd.conf: - -REGISTER .* MKNEWCOMPAT -UNREGISTER .* RMNEWCOMPAT - -This will cause devfsd to create (and destroy) symbolic links which -point to the kernel-supplied names. - -SCSI Hard Discs - -All SCSI discs are placed under /dev/sd (assuming devfs is -mounted on /dev). Hence, a SCSI disc with the following -parameters: c=1,b=2,t=3,u=4 would appear as: - - /dev/sd/c1b2t3u4 for the whole disc - /dev/sd/c1b2t3u4p5 for the 5th partition - /dev/sd/c1b2t3u4p5s6 for the 6th slice in the 5th partition - - -SCSI Tapes - -All SCSI tapes are placed under /dev/st. A similar naming -scheme is used as for SCSI discs. A SCSI tape with the -parameters:c=1,b=2,t=3,u=4 would appear as: - - /dev/st/c1b2t3u4m0 for mode 0 - /dev/st/c1b2t3u4m1 for mode 1 - /dev/st/c1b2t3u4m2 for mode 2 - /dev/st/c1b2t3u4m3 for mode 3 - /dev/st/c1b2t3u4m0n for mode 0, no rewind - /dev/st/c1b2t3u4m1n for mode 1, no rewind - /dev/st/c1b2t3u4m2n for mode 2, no rewind - /dev/st/c1b2t3u4m3n for mode 3, no rewind - - -SCSI CD-ROMs - -All SCSI CD-ROMs are placed under /dev/sr. A similar naming -scheme is used as for SCSI discs. A SCSI CD-ROM with the -parameters:c=1,b=2,t=3,u=4 would appear as: - - /dev/sr/c1b2t3u4 - - -SCSI Generic Devices - -The generic (aka. raw) interface for all SCSI devices are placed under -/dev/sg. A similar naming scheme is used as for SCSI discs. A -SCSI generic device with the parameters:c=1,b=2,t=3,u=4 would appear -as: - - /dev/sg/c1b2t3u4 - - -IDE Hard Discs - -All IDE discs are placed under /dev/ide/hd, using a similar -convention to SCSI discs. The following mappings exist between the new -and the old names: - - /dev/hda /dev/ide/hd/c0b0t0u0 - /dev/hdb /dev/ide/hd/c0b0t1u0 - /dev/hdc /dev/ide/hd/c0b1t0u0 - /dev/hdd /dev/ide/hd/c0b1t1u0 - - -IDE Tapes - -A similar naming scheme is used as for IDE discs. The entries will -appear in the /dev/ide/mt directory. - -IDE CD-ROM - -A similar naming scheme is used as for IDE discs. The entries will -appear in the /dev/ide/cd directory. - -IDE Floppies - -A similar naming scheme is used as for IDE discs. The entries will -appear in the /dev/ide/fd directory. - -XT Hard Discs - -All XT discs are placed under /dev/xd. The first XT disc -would appear as /dev/xd/c0t0. - - -Old Compatibility Names - -The old compatibility names are the legacy device names, such as -/dev/hda, /dev/sda, /dev/rtc and so on. -Devfsd can be configured to create compatibility symlinks so that you -may continue to use the old names in your configuration files and so -that old applications will continue to function correctly. - -In order to configure devfsd to create these legacy names, the -following lines should be placed in your /etc/devfsd.conf: - -REGISTER .* MKOLDCOMPAT -UNREGISTER .* RMOLDCOMPAT - -This will cause devfsd to create (and destroy) symbolic links which -point to the kernel-supplied names. - - ------------------------------------------------------------------------------ - - -Device drivers currently ported - -- All miscellaneous character devices support devfs (this is done - transparently through misc_register()) - -- SCSI discs and generic hard discs - -- Character memory devices (null, zero, full and so on) - Thanks to C. Scott Ananian <cananian@alumni.princeton.edu> - -- Loop devices (/dev/loop?) - -- TTY devices (console, serial ports, terminals and pseudo-terminals) - Thanks to C. Scott Ananian <cananian@alumni.princeton.edu> - -- SCSI tapes (/dev/scsi and /dev/tapes) - -- SCSI CD-ROMs (/dev/scsi and /dev/cdroms) - -- SCSI generic devices (/dev/scsi) - -- RAMDISCS (/dev/ram?) - -- Meta Devices (/dev/md*) - -- Floppy discs (/dev/floppy) - -- Parallel port printers (/dev/printers) - -- Sound devices (/dev/sound) - Thanks to Eric Dumas <dumas@linux.eu.org> and - C. Scott Ananian <cananian@alumni.princeton.edu> - -- Joysticks (/dev/joysticks) - -- Sparc keyboard (/dev/kbd) - -- DSP56001 digital signal processor (/dev/dsp56k) - -- Apple Desktop Bus (/dev/adb) - -- Coda network file system (/dev/cfs*) - -- Virtual console capture devices (/dev/vcc) - Thanks to Dennis Hou <smilax@mindmeld.yi.org> - -- Frame buffer devices (/dev/fb) - -- Video capture devices (/dev/v4l) - - ------------------------------------------------------------------------------ - - -Allocation of Device Numbers - -Devfs allows you to write a driver which doesn't need to allocate a -device number (major&minor numbers) for the internal operation of the -kernel. However, there are a number of userspace programmes that use -the device number as a unique handle for a device. An example is the -find programme, which uses device numbers to determine whether -an inode is on a different filesystem than another inode. The device -number used is the one for the block device which a filesystem is -using. To preserve compatibility with userspace programmes, block -devices using devfs need to have unique device numbers allocated to -them. Furthermore, POSIX specifies device numbers, so some kind of -device number needs to be presented to userspace. - -The simplest option (especially when porting drivers to devfs) is to -keep using the old major and minor numbers. Devfs will take whatever -values are given for major&minor and pass them onto userspace. - -This device number is a 16 bit number, so this leaves plenty of space -for large numbers of discs and partitions. This scheme can also be -used for character devices, in particular the tty devices, which are -currently limited to 256 pseudo-ttys (this limits the total number of -simultaneous xterms and remote logins). Note that the device number -is limited to the range 36864-61439 (majors 144-239), in order to -avoid any possible conflicts with existing official allocations. - -Please note that using dynamically allocated block device numbers may -break the NFS daemons (both user and kernel mode), which expect dev_t -for a given device to be constant over the lifetime of remote mounts. - -A final note on this scheme: since it doesn't increase the size of -device numbers, there are no compatibility issues with userspace. - ------------------------------------------------------------------------------ - - -Questions and Answers - - -Making things work -Alternatives to devfs -What I don't like about devfs -How to report bugs -Strange kernel messages -Compilation problems with devfsd - - - -Making things work - -Here are some common questions and answers. - - - -Devfsd doesn't start - -Make sure you have compiled and installed devfsd -Make sure devfsd is being started from your boot -scripts -Make sure you have configured your kernel to enable devfs (see -below) -Make sure devfs is mounted (see below) - - -Devfsd is not managing all my permissions - -Make sure you are capturing the appropriate events. For example, -device entries created by the kernel generate REGISTER events, -but those created by devfsd generate CREATE events. - - -Devfsd is not capturing all REGISTER events - -See the previous entry: you may need to capture CREATE events. - - -X will not start - -Make sure you followed the steps -outlined above. - - -Why don't my network devices appear in devfs? - -This is not a bug. Network devices have their own, completely separate -namespace. They are accessed via socket(2) and -setsockopt(2) calls, and thus require no device nodes. I have -raised the possibilty of moving network devices into the device -namespace, but have had no response. - - -How can I test if I have devfs compiled into my kernel? - -All filesystems built-in or currently loaded are listed in -/proc/filesystems. If you see a devfs entry, then -you know that devfs was compiled into your kernel. If you have -correctly configured and rebuilt your kernel, then devfs will be -built-in. If you think you've configured it in, but -/proc/filesystems doesn't show it, you've made a mistake. -Common mistakes include: - -Using a 2.2.x kernel without applying the devfs patch (if you -don't know how to patch your kernel, use 2.4.x instead, don't bother -asking me how to patch) -Forgetting to set CONFIG_EXPERIMENTAL=y -Forgetting to set CONFIG_DEVFS_FS=y -Forgetting to set CONFIG_DEVFS_MOUNT=y (if you want devfs -to be automatically mounted at boot) -Editing your .config manually, instead of using make -config or make xconfig -Forgetting to run make dep; make clean after changing the -configuration and before compiling -Forgetting to compile your kernel and modules -Forgetting to install your kernel -Forgetting to install your modules - -Please check twice that you've done all these steps before sending in -a bug report. - - - -How can I test if devfs is mounted on /dev? - -The device filesystem will always create an entry called -".devfsd", which is used to communicate with the daemon. Even -if the daemon is not running, this entry will exist. Testing for the -existence of this entry is the approved method of determining if devfs -is mounted or not. Note that the type of entry (i.e. regular file, -character device, named pipe, etc.) may change without notice. Only -the existence of the entry should be relied upon. - - -When I start devfsd, I see the error: -Error opening file: ".devfsd" No such file or directory? - -This means that devfs is not mounted. Make sure you have devfs mounted. - - -How do I mount devfs? - -First make sure you have devfs compiled into your kernel (see -above). Then you will either need to: - -set CONFIG_DEVFS_MOUNT=y in your kernel config -pass devfs=mount to your boot loader -mount devfs manually in your boot scripts with: -mount -t none devfs /dev - - - -Mount by volume LABEL=<label> doesn't work with -devfs - -Most probably you are not mounting devfs onto /dev. What -happens is that if your kernel config has CONFIG_DEVFS_FS=y -then the contents of /proc/partitions will have the devfs -names (such as scsi/host0/bus0/target0/lun0/part1). The -contents of /proc/partitions are used by mount(8) when -mounting by volume label. If devfs is not mounted on /dev, -then mount(8) will fail to find devices. The solution is to -make sure that devfs is mounted on /dev. See above for how to -do that. - - -I have extra or incorrect entries in /dev - -You may have stale entries in your dev-state area. Check for a -RESTORE configuration line in your devfsd configuration -(typically /etc/devfsd.conf). If you have this line, check -the contents of the specified directory for stale entries. Remove -any entries which are incorrect, then reboot. - - -I get "Unable to open initial console" messages at boot - -This usually happens when you don't have devfs automounted onto -/dev at boot time, and there is no valid -/dev/console entry on your root file-system. Create a valid -/dev/console device node. - - - - - -Alternatives to devfs - -I've attempted to collate all the anti-devfs proposals and explain -their limitations. Under construction. - - -Why not just pass device create/remove events to a daemon? - -Here the suggestion is to develop an API in the kernel so that devices -can register create and remove events, and a daemon listens for those -events. The daemon would then populate/depopulate /dev (which -resides on disc). - -This has several limitations: - - -it only works for modules loaded and unloaded (or devices inserted -and removed) after the kernel has finished booting. Without a database -of events, there is no way the daemon could fully populate -/dev - - -if you add a database to this scheme, the question is then how to -present that database to user-space. If you make it a list of strings -with embedded event codes which are passed through a pipe to the -daemon, then this is only of use to the daemon. I would argue that the -natural way to present this data is via a filesystem (since many of -the events will be of a hierarchical nature), such as devfs. -Presenting the data as a filesystem makes it easy for the user to see -what is available and also makes it easy to write scripts to scan the -"database" - - -the tight binding between device nodes and drivers is no longer -possible (requiring the otherwise perfectly avoidable -table lookups) - - -you cannot catch inode lookup events on /dev which means -that module autoloading requires device nodes to be created. This is a -problem, particularly for drivers where only a few inodes are created -from a potentially large set - - -this technique can't be used when the root FS is mounted -read-only - - - - -Just implement a better scsidev - -This suggestion involves taking the scsidev programme and -extending it to scan for all devices, not just SCSI devices. The -scsidev programme works by scanning /proc/scsi - -Problems: - - -the kernel does not currently provide a list of all devices -available. Not all drivers register entries in /proc or -generate kernel messages - - -there is no uniform mechanism to register devices other than the -devfs API - - -implementing such an API is then the same as the -proposal above - - - - -Put /dev on a ramdisc - -This suggestion involves creating a ramdisc and populating it with -device nodes and then mounting it over /dev. - -Problems: - - - -this doesn't help when mounting the root filesystem, since you -still need a device node to do that - - -if you want to use this technique for the root device node as -well, you need to use initrd. This complicates the booting sequence -and makes it significantly harder to administer and configure. The -initrd is essentially opaque, robbing the system administrator of easy -configuration - - -insufficient information is available to correctly populate the -ramdisc. So we come back to the -proposal above to "solve" this - - -a ramdisc-based solution would take more kernel memory, since the -backing store would be (at best) normal VFS inodes and dentries, which -take 284 bytes and 112 bytes, respectively, for each entry. Compare -that to 72 bytes for devfs - - - - -Do nothing: there's no problem - -Sometimes people can be heard to claim that the existing scheme is -fine. This is what they're ignoring: - - -device number size (8 bits each for major and minor) is a real -limitation, and must be fixed somehow. Systems with large numbers of -SCSI devices, for example, will continue to consume the remaining -unallocated major numbers. USB will also need to push beyond the 8 bit -minor limitation - - -simply increasing the device number size is insufficient. Apart -from causing a lot of pain, it doesn't solve the management issues -of a /dev with thousands or more device nodes - - -ignoring the problem of a huge /dev will not make it go -away, and dismisses the legitimacy of a large number of people who -want a dynamic /dev - - -the standard response then becomes: "write a device management -daemon", which brings us back to the -proposal above - - - - -What I don't like about devfs - -Here are some common complaints about devfs, and some suggestions and -solutions that may make it more palatable for you. I can't please -everybody, but I do try :-) - -I hate the naming scheme - -First, remember that no naming scheme will please everybody. You hate -the scheme, others love it. Who's to say who's right and who's wrong? -Ultimately, the person who writes the code gets to choose, and what -exists now is a combination of the choices made by the -devfs author and the -kernel maintainer (Linus). - -However, not all is lost. If you want to create your own naming -scheme, it is a simple matter to write a standalone script, hack -devfsd, or write a script called by devfsd. You can create whatever -naming scheme you like. - -Further, if you want to remove all traces of the devfs naming scheme -from /dev, you can mount devfs elsewhere (say -/devfs) and populate /dev with links into -/devfs. This population can be automated using devfsd if you -wish. - -You can even use the VFS binding facility to make the links, rather -than using symbolic links. This way, you don't even have to see the -"destination" of these symbolic links. - -Devfs puts policy into the kernel - -There's already policy in the kernel. Device numbers are in fact -policy (why should the kernel dictate what device numbers I use?). -Face it, some policy has to be in the kernel. The real difference -between device names as policy and device numbers as policy is that -no one will use device numbers directly, because device -numbers are devoid of meaning to humans and are ugly. At least with -the devfs device names, (even though you can add your own naming -scheme) some people will use the devfs-supplied names directly. This -offends some people :-) - -Devfs is bloatware - -This is not even remotely true. As shown above, -both code and data size are quite modest. - - -How to report bugs - -If you have (or think you have) a bug with devfs, please follow the -steps below: - - - -make sure you have enabled debugging output when configuring your -kernel. You will need to set (at least) the following config options: - -CONFIG_DEVFS_DEBUG=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_SLAB=y - - - -please make sure you have the latest devfs patches applied. The -latest kernel version might not have the latest devfs patches applied -yet (Linus is very busy) - - -save a copy of your complete kernel logs (preferably by -using the dmesg programme) for later inclusion in your bug -report. You may need to use the -s switch to increase the -internal buffer size so you can capture all the boot messages. -Don't edit or trim the dmesg output - - - - -try booting with devfs=dall passed to the kernel boot -command line (read the documentation on your bootloader on how to do -this), and save the result to a file. This may be quite verbose, and -it may overflow the messages buffer, but try to get as much of it as -you can - - -send a copy of your devfsd configuration file(s) - -send the bug report to me first. -Don't expect that I will see it if you post it to the linux-kernel -mailing list. Include all the information listed above, plus -anything else that you think might be relevant. Put the string -devfs somewhere in the subject line, so my mail filters mark -it as urgent - - - - -Here is a general guide on how to ask questions in a way that greatly -improves your chances of getting a reply: - -http://www.tuxedo.org/~esr/faqs/smart-questions.html. If you have -a bug to report, you should also read - -http://www.chiark.greenend.org.uk/~sgtatham/bugs.html. - - -Strange kernel messages - -You may see devfs-related messages in your kernel logs. Below are some -messages and what they mean (and what you should do about them, if -anything). - - - -devfs_register(fred): could not append to parent, err: -17 - -You need to check what the error code means, but usually 17 means -EEXIST. This means that a driver attempted to create an entry -fred in a directory, but there already was an entry with that -name. This is often caused by flawed boot scripts which untar a bunch -of inodes into /dev, as a way to restore permissions. This -message is harmless, as the device nodes will still -provide access to the driver (unless you use the devfs=only -boot option, which is only for dedicated souls:-). If you want to get -rid of these annoying messages, upgrade to devfsd-v1.3.20 and use the -recommended RESTORE directive to restore permissions. - - -devfs_mk_dir(bill): using old entry in dir: c1808724 "" - -This is similar to the message above, except that a driver attempted -to create a directory named bill, and the parent directory -has an entry with the same name. In this case, to ensure that drivers -continue to work properly, the old entry is re-used and given to the -driver. In 2.5 kernels, the driver is given a NULL entry, and thus, -under rare circumstances, may not create the require device nodes. -The solution is the same as above. - - - - - -Compilation problems with devfsd - -Usually, you can compile devfsd just by typing in -make in the source directory, followed by a make -install (as root). Sometimes, you may have problems, particularly -on broken configurations. - - - -error messages relating to DEVFSD_NOTIFY_DELETE - -This happened because you have an ancient set of kernel headers -installed in /usr/include/linux or /usr/src/linux. -Install kernel 2.4.10 or later. You may need to pass the -KERNEL_DIR variable to make (if you did not install -the new kernel sources as /usr/src/linux), or you may copy -the devfs_fs.h file in the kernel source tree into -/usr/include/linux. - - - - ------------------------------------------------------------------------------ - - -Other resources - - - -Douglas Gilbert has written a useful document at - -http://www.torque.net/sg/devfs_scsi.html which -explores the SCSI subsystem and how it interacts with devfs - - -Douglas Gilbert has written another useful document at - -http://www.torque.net/scsi/SCSI-2.4-HOWTO/ which -discusses the Linux SCSI subsystem in 2.4. - - -Johannes Erdfelt has started a discussion paper on Linux and -hot-swap devices, describing what the requirements are for a scalable -solution and how and why he's used devfs+devfsd. Note that this is an -early draft only, available in plain text form at: - -http://johannes.erdfelt.com/hotswap.txt. -Johannes has promised a HTML version will follow. - - -I presented an invited -paper -at the - -2nd Annual Storage Management Workshop held in Miamia, Florida, -U.S.A. in October 2000. - - - - ------------------------------------------------------------------------------ - - -Translations of this document - -This document has been translated into other languages. - - - - -The document master (in English) by rgooch@atnf.csiro.au is -available at - -http://www.atnf.csiro.au/~rgooch/linux/docs/devfs.html - - - -A Korean translation by viatoris@nownuri.net is available at - -http://your.destiny.pe.kr/devfs/devfs.html - - - - ------------------------------------------------------------------------------ -Most flags courtesy of ITA's -Flags of All Countries -used with permission. diff --git a/Documentation/filesystems/devfs/ToDo b/Documentation/filesystems/devfs/ToDo deleted file mode 100644 index afd5a8f2c19b..000000000000 --- a/Documentation/filesystems/devfs/ToDo +++ /dev/null @@ -1,40 +0,0 @@ - Device File System (devfs) ToDo List - - Richard Gooch <rgooch@atnf.csiro.au> - - 3-JUL-2000 - -This is a list of things to be done for better devfs support in the -Linux kernel. If you'd like to contribute to the devfs, please have a -look at this list for anything that is unallocated. Also, if there are -items missing (surely), please contact me so I can add them to the -list (preferably with your name attached to them:-). - - -- >256 ptys - Thanks to C. Scott Ananian <cananian@alumni.princeton.edu> - -- Amiga floppy driver (drivers/block/amiflop.c) - -- Atari floppy driver (drivers/block/ataflop.c) - -- SWIM3 (Super Woz Integrated Machine 3) floppy driver (drivers/block/swim3.c) - -- Amiga ZorroII ramdisc driver (drivers/block/z2ram.c) - -- Parallel port ATAPI CD-ROM (drivers/block/paride/pcd.c) - -- Parallel port ATAPI floppy (drivers/block/paride/pf.c) - -- AP1000 block driver (drivers/ap1000/ap.c, drivers/ap1000/ddv.c) - -- Archimedes floppy (drivers/acorn/block/fd1772.c) - -- MFM hard drive (drivers/acorn/block/mfmhd.c) - -- I2O block device (drivers/message/i2o/i2o_block.c) - -- ST-RAM device (arch/m68k/atari/stram.c) - -- Raw devices - diff --git a/Documentation/filesystems/devfs/boot-options b/Documentation/filesystems/devfs/boot-options deleted file mode 100644 index df3d33b03e0a..000000000000 --- a/Documentation/filesystems/devfs/boot-options +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- auto-fill -*- */ - - Device File System (devfs) Boot Options - - Richard Gooch <rgooch@atnf.csiro.au> - - 18-AUG-2001 - - -When CONFIG_DEVFS_DEBUG is enabled, you can pass several boot options -to the kernel to debug devfs. The boot options are prefixed by -"devfs=", and are separated by commas. Spaces are not allowed. The -syntax looks like this: - -devfs=<option1>,<option2>,<option3> - -and so on. For example, if you wanted to turn on debugging for module -load requests and device registration, you would do: - -devfs=dmod,dreg - -You may prefix "no" to any option. This will invert the option. - - -Debugging Options -================= - -These requires CONFIG_DEVFS_DEBUG to be enabled. -Note that all debugging options have 'd' as the first character. By -default all options are off. All debugging output is sent to the -kernel logs. The debugging options do not take effect until the devfs -version message appears (just prior to the root filesystem being -mounted). - -These are the options: - -dmod print module load requests to <request_module> - -dreg print device register requests to <devfs_register> - -dunreg print device unregister requests to <devfs_unregister> - -dchange print device change requests to <devfs_set_flags> - -dilookup print inode lookup requests - -diget print VFS inode allocations - -diunlink print inode unlinks - -dichange print inode changes - -dimknod print calls to mknod(2) - -dall some debugging turned on - - -Other Options -============= - -These control the default behaviour of devfs. The options are: - -mount mount devfs onto /dev at boot time - -only disable non-devfs device nodes for devfs-capable drivers diff --git a/Documentation/initrd.txt b/Documentation/initrd.txt index 7de1c80cd719..b1b6440237a6 100644 --- a/Documentation/initrd.txt +++ b/Documentation/initrd.txt @@ -67,8 +67,7 @@ initrd adds the following new options: as the last process has closed it, all data is freed and /dev/initrd can't be opened anymore. - root=/dev/ram0 (without devfs) - root=/dev/rd/0 (with devfs) + root=/dev/ram0 initrd is mounted as root, and the normal boot procedure is followed, with the RAM disk still mounted as root. @@ -90,8 +89,7 @@ you're building an install floppy), the root file system creation procedure should create the /initrd directory. If initrd will not be mounted in some cases, its content is still -accessible if the following device has been created (note that this -does not work if using devfs): +accessible if the following device has been created: # mknod /dev/initrd b 1 250 # chmod 400 /dev/initrd @@ -119,8 +117,7 @@ We'll describe the loopback device method: (if space is critical, you may want to use the Minix FS instead of Ext2) 3) mount the file system, e.g. # mount -t ext2 -o loop initrd /mnt - 4) create the console device (not necessary if using devfs, but it can't - hurt to do it anyway): + 4) create the console device: # mkdir /mnt/dev # mknod /mnt/dev/console c 5 1 5) copy all the files that are needed to properly use the initrd @@ -152,12 +149,7 @@ have to be given: root=/dev/ram0 init=/linuxrc rw -if not using devfs, or - - root=/dev/rd/0 init=/linuxrc rw - -if using devfs. (rw is only necessary if writing to the initrd file -system.) +(rw is only necessary if writing to the initrd file system.) With LOADLIN, you simply execute @@ -217,9 +209,9 @@ following command: # exec chroot . what-follows <dev/console >dev/console 2>&1 Where what-follows is a program under the new root, e.g. /sbin/init -If the new root file system will be used with devfs and has no valid -/dev directory, devfs must be mounted before invoking chroot in order to -provide /dev/console. +If the new root file system will be used with udev and has no valid +/dev directory, udev must be initialized before invoking chroot in order +to provide /dev/console. Note: implementation details of pivot_root may change with time. In order to ensure compatibility, the following points should be observed: @@ -236,7 +228,7 @@ Now, the initrd can be unmounted and the memory allocated by the RAM disk can be freed: # umount /initrd -# blockdev --flushbufs /dev/ram0 # /dev/rd/0 if using devfs +# blockdev --flushbufs /dev/ram0 It is also possible to use initrd with an NFS-mounted root, see the pivot_root(8) man page for details. diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt index 1543802ef53e..edc04d74ae23 100644 --- a/Documentation/ioctl-number.txt +++ b/Documentation/ioctl-number.txt @@ -119,7 +119,6 @@ Code Seq# Include File Comments 'c' 00-7F linux/comstats.h conflict! 'c' 00-7F linux/coda.h conflict! 'd' 00-FF linux/char/drm/drm/h conflict! -'d' 00-1F linux/devfs_fs.h conflict! 'd' 00-DF linux/video_decoder.h conflict! 'd' F0-FF linux/digi1.h 'e' all linux/digi1.h conflict! diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 25f8d20dac53..86e9282d1c20 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -35,7 +35,6 @@ parameter is applicable: APM Advanced Power Management support is enabled. AX25 Appropriate AX.25 support is enabled. CD Appropriate CD support is enabled. - DEVFS devfs support is enabled. DRM Direct Rendering Management support is enabled. EDD BIOS Enhanced Disk Drive Services (EDD) is enabled EFI EFI Partitioning (GPT) is enabled @@ -440,9 +439,6 @@ running once the system is up. Format: <area>[,<node>] See also Documentation/networking/decnet.txt. - devfs= [DEVFS] - See Documentation/filesystems/devfs/boot-options. - dhash_entries= [KNL] Set number of hash buckets for dentry cache. diff --git a/arch/cris/arch-v10/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c index f3a85b77c17e..dde813e16294 100644 --- a/arch/cris/arch-v10/kernel/debugport.c +++ b/arch/cris/arch-v10/kernel/debugport.c @@ -541,7 +541,7 @@ init_dummy_console(void) dummy_driver.init_termios = tty_std_termios; dummy_driver.init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */ - dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; dummy_driver.open = dummy_open; dummy_driver.close = dummy_close; diff --git a/arch/cris/arch-v32/kernel/debugport.c b/arch/cris/arch-v32/kernel/debugport.c index ffc1ebf2dfee..3dc587e6201a 100644 --- a/arch/cris/arch-v32/kernel/debugport.c +++ b/arch/cris/arch-v32/kernel/debugport.c @@ -353,7 +353,7 @@ init_dummy_console(void) dummy_driver.init_termios = tty_std_termios; dummy_driver.init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */ - dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; dummy_driver.open = dummy_open; dummy_driver.close = dummy_close; diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c index 0a865889b2a9..40b44cc0d14b 100644 --- a/arch/i386/kernel/microcode.c +++ b/arch/i386/kernel/microcode.c @@ -493,7 +493,6 @@ static struct file_operations microcode_fops = { static struct miscdevice microcode_dev = { .minor = MICROCODE_MINOR, .name = "microcode", - .devfs_name = "cpu/microcode", .fops = µcode_fops, }; diff --git a/arch/ppc/4xx_io/serial_sicc.c b/arch/ppc/4xx_io/serial_sicc.c index 98b25fa0049a..1e113d0f59b8 100644 --- a/arch/ppc/4xx_io/serial_sicc.c +++ b/arch/ppc/4xx_io/serial_sicc.c @@ -1758,7 +1758,7 @@ int __init siccuart_init(void) siccnormal_driver->subtype = SERIAL_TYPE_NORMAL; siccnormal_driver->init_termios = tty_std_termios; siccnormal_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - siccnormal_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + siccnormal_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(siccnormal_driver, &sicc_ops); if (tty_register_driver(siccnormal_driver)) diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index 8437ea7430fe..83a4f91bce5a 100644 --- a/arch/sh/kernel/cpu/sh4/sq.c +++ b/arch/sh/kernel/cpu/sh4/sq.c @@ -417,7 +417,6 @@ static struct file_operations sq_fops = { static struct miscdevice sq_dev = { .minor = STORE_QUEUE_MINOR, .name = "sq", - .devfs_name = "cpu/sq", .fops = &sq_fops, }; diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 79d177149fdb..8654b446ac9e 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -26,6 +26,7 @@ */ #include <linux/config.h> +#include <linux/module.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -40,6 +41,7 @@ #include <asm/vaddrs.h> #include <asm/oplib.h> #include <asm/prom.h> +#include <asm/of_device.h> #include <asm/sbus.h> #include <asm/page.h> #include <asm/pgalloc.h> @@ -143,6 +145,21 @@ void __iomem *sbus_ioremap(struct resource *phyres, unsigned long offset, phyres->start + offset, size, name); } +void __iomem *of_ioremap(struct resource *res, unsigned long offset, + unsigned long size, char *name) +{ + return _sparc_alloc_io(res->flags & 0xF, + res->start + offset, + size, name); +} +EXPORT_SYMBOL(of_ioremap); + +void of_iounmap(void __iomem *base, unsigned long size) +{ + iounmap(base); +} +EXPORT_SYMBOL(of_iounmap); + /* */ void sbus_iounmap(volatile void __iomem *addr, unsigned long size) diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c index 80a809478781..bc956c530376 100644 --- a/arch/sparc/kernel/of_device.c +++ b/arch/sparc/kernel/of_device.c @@ -129,6 +129,26 @@ static int of_device_resume(struct device * dev) return error; } +static int node_match(struct device *dev, void *data) +{ + struct of_device *op = to_of_device(dev); + struct device_node *dp = data; + + return (op->node == dp); +} + +struct of_device *of_find_device_by_node(struct device_node *dp) +{ + struct device *dev = bus_find_device(&of_bus_type, NULL, + dp, node_match); + + if (dev) + return to_of_device(dev); + + return NULL; +} +EXPORT_SYMBOL(of_find_device_by_node); + #ifdef CONFIG_PCI struct bus_type ebus_bus_type = { .name = "ebus", @@ -153,10 +173,459 @@ struct bus_type sbus_bus_type = { EXPORT_SYMBOL(sbus_bus_type); #endif +struct bus_type of_bus_type = { + .name = "of", + .match = of_platform_bus_match, + .probe = of_device_probe, + .remove = of_device_remove, + .suspend = of_device_suspend, + .resume = of_device_resume, +}; +EXPORT_SYMBOL(of_bus_type); + +static inline u64 of_read_addr(u32 *cell, int size) +{ + u64 r = 0; + while (size--) + r = (r << 32) | *(cell++); + return r; +} + +static void __init get_cells(struct device_node *dp, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = of_n_addr_cells(dp); + if (sizec) + *sizec = of_n_size_cells(dp); +} + +/* Max address size we deal with */ +#define OF_MAX_ADDR_CELLS 4 + +struct of_bus { + const char *name; + const char *addr_prop_name; + int (*match)(struct device_node *parent); + void (*count_cells)(struct device_node *child, + int *addrc, int *sizec); + u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna); + int (*translate)(u32 *addr, u64 offset, int na); + unsigned int (*get_flags)(u32 *addr); +}; + +/* + * Default translator (generic bus) + */ + +static void of_bus_default_count_cells(struct device_node *dev, + int *addrc, int *sizec) +{ + get_cells(dev, addrc, sizec); +} + +static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna) +{ + u64 cp, s, da; + + cp = of_read_addr(range, na); + s = of_read_addr(range + na + pna, ns); + da = of_read_addr(addr, na); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_default_translate(u32 *addr, u64 offset, int na) +{ + u64 a = of_read_addr(addr, na); + memset(addr, 0, na * 4); + a += offset; + if (na > 1) + addr[na - 2] = a >> 32; + addr[na - 1] = a & 0xffffffffu; + + return 0; +} + +static unsigned int of_bus_default_get_flags(u32 *addr) +{ + return IORESOURCE_MEM; +} + + +/* + * PCI bus specific translator + */ + +static int of_bus_pci_match(struct device_node *np) +{ + return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex"); +} + +static void of_bus_pci_count_cells(struct device_node *np, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 3; + if (sizec) + *sizec = 2; +} + +static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna) +{ + u64 cp, s, da; + + /* Check address type match */ + if ((addr[0] ^ range[0]) & 0x03000000) + return OF_BAD_ADDR; + + /* Read address values, skipping high cell */ + cp = of_read_addr(range + 1, na - 1); + s = of_read_addr(range + na + pna, ns); + da = of_read_addr(addr + 1, na - 1); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_pci_translate(u32 *addr, u64 offset, int na) +{ + return of_bus_default_translate(addr + 1, offset, na - 1); +} + +static unsigned int of_bus_pci_get_flags(u32 *addr) +{ + unsigned int flags = 0; + u32 w = addr[0]; + + switch((w >> 24) & 0x03) { + case 0x01: + flags |= IORESOURCE_IO; + case 0x02: /* 32 bits */ + case 0x03: /* 64 bits */ + flags |= IORESOURCE_MEM; + } + if (w & 0x40000000) + flags |= IORESOURCE_PREFETCH; + return flags; +} + +/* + * SBUS bus specific translator + */ + +static int of_bus_sbus_match(struct device_node *np) +{ + return !strcmp(np->name, "sbus") || + !strcmp(np->name, "sbi"); +} + +static void of_bus_sbus_count_cells(struct device_node *child, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 2; + if (sizec) + *sizec = 1; +} + +static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna) +{ + return of_bus_default_map(addr, range, na, ns, pna); +} + +static int of_bus_sbus_translate(u32 *addr, u64 offset, int na) +{ + return of_bus_default_translate(addr, offset, na); +} + +static unsigned int of_bus_sbus_get_flags(u32 *addr) +{ + return IORESOURCE_MEM; +} + + +/* + * Array of bus specific translators + */ + +static struct of_bus of_busses[] = { + /* PCI */ + { + .name = "pci", + .addr_prop_name = "assigned-addresses", + .match = of_bus_pci_match, + .count_cells = of_bus_pci_count_cells, + .map = of_bus_pci_map, + .translate = of_bus_pci_translate, + .get_flags = of_bus_pci_get_flags, + }, + /* SBUS */ + { + .name = "sbus", + .addr_prop_name = "reg", + .match = of_bus_sbus_match, + .count_cells = of_bus_sbus_count_cells, + .map = of_bus_sbus_map, + .translate = of_bus_sbus_translate, + .get_flags = of_bus_sbus_get_flags, + }, + /* Default */ + { + .name = "default", + .addr_prop_name = "reg", + .match = NULL, + .count_cells = of_bus_default_count_cells, + .map = of_bus_default_map, + .translate = of_bus_default_translate, + .get_flags = of_bus_default_get_flags, + }, +}; + +static struct of_bus *of_match_bus(struct device_node *np) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(of_busses); i ++) + if (!of_busses[i].match || of_busses[i].match(np)) + return &of_busses[i]; + BUG(); + return NULL; +} + +static int __init build_one_resource(struct device_node *parent, + struct of_bus *bus, + struct of_bus *pbus, + u32 *addr, + int na, int ns, int pna) +{ + u32 *ranges; + unsigned int rlen; + int rone; + u64 offset = OF_BAD_ADDR; + + ranges = of_get_property(parent, "ranges", &rlen); + if (ranges == NULL || rlen == 0) { + offset = of_read_addr(addr, na); + memset(addr, 0, pna * 4); + goto finish; + } + + /* Now walk through the ranges */ + rlen /= 4; + rone = na + pna + ns; + for (; rlen >= rone; rlen -= rone, ranges += rone) { + offset = bus->map(addr, ranges, na, ns, pna); + if (offset != OF_BAD_ADDR) + break; + } + if (offset == OF_BAD_ADDR) + return 1; + + memcpy(addr, ranges + na, 4 * pna); + +finish: + /* Translate it into parent bus space */ + return pbus->translate(addr, offset, pna); +} + +static void __init build_device_resources(struct of_device *op, + struct device *parent) +{ + struct of_device *p_op; + struct of_bus *bus; + int na, ns; + int index, num_reg; + void *preg; + + if (!parent) + return; + + p_op = to_of_device(parent); + bus = of_match_bus(p_op->node); + bus->count_cells(op->node, &na, &ns); + + preg = of_get_property(op->node, bus->addr_prop_name, &num_reg); + if (!preg || num_reg == 0) + return; + + /* Convert to num-cells. */ + num_reg /= 4; + + /* Conver to num-entries. */ + num_reg /= na + ns; + + for (index = 0; index < num_reg; index++) { + struct resource *r = &op->resource[index]; + u32 addr[OF_MAX_ADDR_CELLS]; + u32 *reg = (preg + (index * ((na + ns) * 4))); + struct device_node *dp = op->node; + struct device_node *pp = p_op->node; + struct of_bus *pbus; + u64 size, result = OF_BAD_ADDR; + unsigned long flags; + int dna, dns; + int pna, pns; + + size = of_read_addr(reg + na, ns); + flags = bus->get_flags(reg); + + memcpy(addr, reg, na * 4); + + /* If the immediate parent has no ranges property to apply, + * just use a 1<->1 mapping. + */ + if (of_find_property(pp, "ranges", NULL) == NULL) { + result = of_read_addr(addr, na); + goto build_res; + } + + dna = na; + dns = ns; + + while (1) { + dp = pp; + pp = dp->parent; + if (!pp) { + result = of_read_addr(addr, dna); + break; + } + + pbus = of_match_bus(pp); + pbus->count_cells(dp, &pna, &pns); + + if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna)) + break; + + dna = pna; + dns = pns; + bus = pbus; + } + + build_res: + memset(r, 0, sizeof(*r)); + if (result != OF_BAD_ADDR) { + r->start = result & 0xffffffff; + r->end = result + size - 1; + r->flags = flags | ((result >> 32ULL) & 0xffUL); + } else { + r->start = ~0UL; + r->end = ~0UL; + } + r->name = op->node->name; + } +} + +static struct of_device * __init scan_one_device(struct device_node *dp, + struct device *parent) +{ + struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); + struct linux_prom_irqs *intr; + int len, i; + + if (!op) + return NULL; + + op->node = dp; + + op->clock_freq = of_getintprop_default(dp, "clock-frequency", + (25*1000*1000)); + op->portid = of_getintprop_default(dp, "upa-portid", -1); + if (op->portid == -1) + op->portid = of_getintprop_default(dp, "portid", -1); + + intr = of_get_property(dp, "intr", &len); + if (intr) { + op->num_irqs = len / sizeof(struct linux_prom_irqs); + for (i = 0; i < op->num_irqs; i++) + op->irqs[i] = intr[i].pri; + } else { + unsigned int *irq = of_get_property(dp, "interrupts", &len); + + if (irq) { + op->num_irqs = len / sizeof(unsigned int); + for (i = 0; i < op->num_irqs; i++) + op->irqs[i] = irq[i]; + } else { + op->num_irqs = 0; + } + } + if (sparc_cpu_model == sun4d) { + static int pil_to_sbus[] = { + 0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0, + }; + struct device_node *busp = dp->parent; + struct linux_prom_registers *regs; + int board = of_getintprop_default(busp, "board#", 0); + int slot; + + regs = of_get_property(dp, "reg", NULL); + slot = regs->which_io; + + for (i = 0; i < op->num_irqs; i++) { + int this_irq = op->irqs[i]; + int sbusl = pil_to_sbus[this_irq]; + + if (sbusl) + this_irq = (((board + 1) << 5) + + (sbusl << 2) + + slot); + + op->irqs[i] = this_irq; + } + } + + build_device_resources(op, parent); + + op->dev.parent = parent; + op->dev.bus = &of_bus_type; + if (!parent) + strcpy(op->dev.bus_id, "root"); + else + strcpy(op->dev.bus_id, dp->path_component_name); + + if (of_device_register(op)) { + printk("%s: Could not register of device.\n", + dp->full_name); + kfree(op); + op = NULL; + } + + return op; +} + +static void __init scan_tree(struct device_node *dp, struct device *parent) +{ + while (dp) { + struct of_device *op = scan_one_device(dp, parent); + + if (op) + scan_tree(dp->child, &op->dev); + + dp = dp->sibling; + } +} + +static void __init scan_of_devices(void) +{ + struct device_node *root = of_find_node_by_path("/"); + struct of_device *parent; + + parent = scan_one_device(root, NULL); + if (!parent) + return; + + scan_tree(root->child, &parent->dev); +} + static int __init of_bus_driver_init(void) { - int err = 0; + int err; + err = bus_register(&of_bus_type); #ifdef CONFIG_PCI if (!err) err = bus_register(&ebus_bus_type); @@ -165,7 +634,11 @@ static int __init of_bus_driver_init(void) if (!err) err = bus_register(&sbus_bus_type); #endif - return 0; + + if (!err) + scan_of_devices(); + + return err; } postcore_initcall(of_bus_driver_init); diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c index 946ce6d15819..4b06dcb00ebd 100644 --- a/arch/sparc/kernel/prom.c +++ b/arch/sparc/kernel/prom.c @@ -190,6 +190,36 @@ int of_getintprop_default(struct device_node *np, const char *name, int def) } EXPORT_SYMBOL(of_getintprop_default); +int of_n_addr_cells(struct device_node *np) +{ + int* ip; + do { + if (np->parent) + np = np->parent; + ip = of_get_property(np, "#address-cells", NULL); + if (ip != NULL) + return *ip; + } while (np->parent); + /* No #address-cells property for the root node, default to 2 */ + return 2; +} +EXPORT_SYMBOL(of_n_addr_cells); + +int of_n_size_cells(struct device_node *np) +{ + int* ip; + do { + if (np->parent) + np = np->parent; + ip = of_get_property(np, "#size-cells", NULL); + if (ip != NULL) + return *ip; + } while (np->parent); + /* No #size-cells property for the root node, default to 1 */ + return 1; +} +EXPORT_SYMBOL(of_n_size_cells); + int of_set_property(struct device_node *dp, const char *name, void *val, int len) { struct property **prevp; diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index 7dadcdb4ca42..9631e8f4ae60 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -42,6 +42,7 @@ #include <asm/sun4paddr.h> #include <asm/page.h> #include <asm/pcic.h> +#include <asm/of_device.h> extern unsigned long wall_jiffies; @@ -273,83 +274,31 @@ static __inline__ void sun4_clock_probe(void) #endif } -/* Probe for the mostek real time clock chip. */ -static __inline__ void clock_probe(void) +static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match) { - struct linux_prom_registers clk_reg[2]; - char model[128]; - register int node, cpuunit, bootbus; - struct resource r; - - cpuunit = bootbus = 0; - memset(&r, 0, sizeof(r)); - - /* Determine the correct starting PROM node for the probe. */ - node = prom_getchild(prom_root_node); - switch (sparc_cpu_model) { - case sun4c: - break; - case sun4m: - node = prom_getchild(prom_searchsiblings(node, "obio")); - break; - case sun4d: - node = prom_getchild(bootbus = prom_searchsiblings(prom_getchild(cpuunit = prom_searchsiblings(node, "cpu-unit")), "bootbus")); - break; - default: - prom_printf("CLOCK: Unsupported architecture!\n"); - prom_halt(); - } + struct device_node *dp = op->node; + char *model = of_get_property(dp, "model", NULL); - /* Find the PROM node describing the real time clock. */ - sp_clock_typ = MSTK_INVALID; - node = prom_searchsiblings(node,"eeprom"); - if (!node) { - prom_printf("CLOCK: No clock found!\n"); - prom_halt(); - } + if (!model) + return -ENODEV; - /* Get the model name and setup everything up. */ - model[0] = '\0'; - prom_getstring(node, "model", model, sizeof(model)); - if (strcmp(model, "mk48t02") == 0) { + if (!strcmp(model, "mk48t02")) { sp_clock_typ = MSTK48T02; - if (prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) { - prom_printf("clock_probe: FAILED!\n"); - prom_halt(); - } - if (sparc_cpu_model == sun4d) - prom_apply_generic_ranges (bootbus, cpuunit, clk_reg, 1); - else - prom_apply_obio_ranges(clk_reg, 1); + /* Map the clock register io area read-only */ - r.flags = clk_reg[0].which_io; - r.start = clk_reg[0].phys_addr; - mstk48t02_regs = sbus_ioremap(&r, 0, - sizeof(struct mostek48t02), "mk48t02"); + mstk48t02_regs = of_ioremap(&op->resource[0], 0, + sizeof(struct mostek48t02), + "mk48t02"); mstk48t08_regs = NULL; /* To catch weirdness */ - } else if (strcmp(model, "mk48t08") == 0) { + } else if (!strcmp(model, "mk48t08")) { sp_clock_typ = MSTK48T08; - if(prom_getproperty(node, "reg", (char *) clk_reg, - sizeof(clk_reg)) == -1) { - prom_printf("clock_probe: FAILED!\n"); - prom_halt(); - } - if (sparc_cpu_model == sun4d) - prom_apply_generic_ranges (bootbus, cpuunit, clk_reg, 1); - else - prom_apply_obio_ranges(clk_reg, 1); - /* Map the clock register io area read-only */ - /* XXX r/o attribute is somewhere in r.flags */ - r.flags = clk_reg[0].which_io; - r.start = clk_reg[0].phys_addr; - mstk48t08_regs = sbus_ioremap(&r, 0, - sizeof(struct mostek48t08), "mk48t08"); + mstk48t08_regs = of_ioremap(&op->resource[0], 0, + sizeof(struct mostek48t08), + "mk48t08"); mstk48t02_regs = &mstk48t08_regs->regs; - } else { - prom_printf("CLOCK: Unknown model name '%s'\n",model); - prom_halt(); - } + } else + return -ENODEV; /* Report a low battery voltage condition. */ if (has_low_battery()) @@ -358,6 +307,28 @@ static __inline__ void clock_probe(void) /* Kick start the clock if it is completely stopped. */ if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) kick_start_clock(); + + return 0; +} + +static struct of_device_id clock_match[] = { + { + .name = "eeprom", + }, + {}, +}; + +static struct of_platform_driver clock_driver = { + .name = "clock", + .match_table = clock_match, + .probe = clock_probe, +}; + + +/* Probe for the mostek real time clock chip. */ +static void clock_init(void) +{ + of_register_driver(&clock_driver, &of_bus_type); } void __init sbus_time_init(void) @@ -376,7 +347,7 @@ void __init sbus_time_init(void) if (ARCH_SUN4) sun4_clock_probe(); else - clock_probe(); + clock_init(); sparc_init_timers(timer_interrupt); diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c index c2c69c167d18..718350aba1ec 100644 --- a/arch/sparc64/kernel/auxio.c +++ b/arch/sparc64/kernel/auxio.c @@ -11,10 +11,9 @@ #include <linux/init.h> #include <linux/ioport.h> -#include <asm/oplib.h> +#include <asm/prom.h> +#include <asm/of_device.h> #include <asm/io.h> -#include <asm/sbus.h> -#include <asm/ebus.h> #include <asm/auxio.h> void __iomem *auxio_register = NULL; @@ -111,12 +110,6 @@ void auxio_set_lte(int on) } } -static void __devinit auxio_report_dev(struct device_node *dp) -{ - printk(KERN_INFO "AUXIO: Found device at %s\n", - dp->full_name); -} - static struct of_device_id auxio_match[] = { { .name = "auxio", @@ -126,67 +119,48 @@ static struct of_device_id auxio_match[] = { MODULE_DEVICE_TABLE(of, auxio_match); -#ifdef CONFIG_SBUS -static int __devinit auxio_sbus_probe(struct of_device *dev, const struct of_device_id *match) +static int __devinit auxio_probe(struct of_device *dev, const struct of_device_id *match) { - struct sbus_dev *sdev = to_sbus_device(&dev->dev); - - auxio_devtype = AUXIO_TYPE_SBUS; - auxio_register = sbus_ioremap(&sdev->resource[0], 0, - sdev->reg_addrs[0].reg_size, - "auxiliaryIO"); - if (!auxio_register) + struct device_node *dp = dev->node; + unsigned long size; + + if (!strcmp(dp->parent->name, "ebus")) { + auxio_devtype = AUXIO_TYPE_EBUS; + size = sizeof(u32); + } else if (!strcmp(dp->parent->name, "sbus")) { + auxio_devtype = AUXIO_TYPE_SBUS; + size = 1; + } else { + printk("auxio: Unknown parent bus type [%s]\n", + dp->parent->name); return -ENODEV; - - auxio_report_dev(dev->node); - return 0; -} - -static struct of_platform_driver auxio_sbus_driver = { - .name = "auxio", - .match_table = auxio_match, - .probe = auxio_sbus_probe, -}; -#endif - -#ifdef CONFIG_PCI -static int __devinit auxio_ebus_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct linux_ebus_device *edev = to_ebus_device(&dev->dev); - - auxio_devtype = AUXIO_TYPE_EBUS; - auxio_register = ioremap(edev->resource[0].start, sizeof(u32)); + } + auxio_register = of_ioremap(&dev->resource[0], 0, size, "auxio"); if (!auxio_register) return -ENODEV; - auxio_report_dev(dev->node); + printk(KERN_INFO "AUXIO: Found device at %s\n", + dp->full_name); - auxio_set_led(AUXIO_LED_ON); + if (auxio_devtype == AUXIO_TYPE_EBUS) + auxio_set_led(AUXIO_LED_ON); return 0; } -static struct of_platform_driver auxio_ebus_driver = { +static struct of_platform_driver auxio_driver = { .name = "auxio", .match_table = auxio_match, - .probe = auxio_ebus_probe, + .probe = auxio_probe, }; -#endif -static int __init auxio_probe(void) +static int __init auxio_init(void) { -#ifdef CONFIG_SBUS - of_register_driver(&auxio_sbus_driver, &sbus_bus_type); -#endif -#ifdef CONFIG_PCI - of_register_driver(&auxio_ebus_driver, &ebus_bus_type); -#endif - - return 0; + return of_register_driver(&auxio_driver, &of_bus_type); } /* Must be after subsys_initcall() so that busses are probed. Must * be before device_initcall() because things like the floppy driver * need to use the AUXIO register. */ -fs_initcall(auxio_probe); +fs_initcall(auxio_init); diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 98e0a8cbeecd..aac014d15ad3 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -20,6 +20,8 @@ #include <asm/pbm.h> #include <asm/ebus.h> #include <asm/oplib.h> +#include <asm/prom.h> +#include <asm/of_device.h> #include <asm/bpp.h> #include <asm/irq.h> @@ -279,45 +281,12 @@ static inline void *ebus_alloc(size_t size) return mem; } -int __init ebus_intmap_match(struct linux_ebus *ebus, - struct linux_prom_registers *reg, - int *interrupt) -{ - struct linux_prom_ebus_intmap *imap; - struct linux_prom_ebus_intmask *imask; - unsigned int hi, lo, irq; - int i, len, n_imap; - - imap = of_get_property(ebus->prom_node, "interrupt-map", &len); - if (!imap) - return 0; - n_imap = len / sizeof(imap[0]); - - imask = of_get_property(ebus->prom_node, "interrupt-map-mask", NULL); - if (!imask) - return 0; - - hi = reg->which_io & imask->phys_hi; - lo = reg->phys_addr & imask->phys_lo; - irq = *interrupt & imask->interrupt; - for (i = 0; i < n_imap; i++) { - if ((imap[i].phys_hi == hi) && - (imap[i].phys_lo == lo) && - (imap[i].interrupt == irq)) { - *interrupt = imap[i].cinterrupt; - return 0; - } - } - return -1; -} - -void __init fill_ebus_child(struct device_node *dp, - struct linux_prom_registers *preg, - struct linux_ebus_child *dev, - int non_standard_regs) +static void __init fill_ebus_child(struct device_node *dp, + struct linux_ebus_child *dev, + int non_standard_regs) { + struct of_device *op; int *regs; - int *irqs; int i, len; dev->prom_node = dp; @@ -354,12 +323,16 @@ void __init fill_ebus_child(struct device_node *dp, } } - for (i = 0; i < PROMINTR_MAX; i++) - dev->irqs[i] = PCI_IRQ_NONE; - - irqs = of_get_property(dp, "interrupts", &len); - if (!irqs) { + op = of_find_device_by_node(dp); + if (!op) { dev->num_irqs = 0; + } else { + dev->num_irqs = op->num_irqs; + for (i = 0; i < dev->num_irqs; i++) + dev->irqs[i] = op->irqs[i]; + } + + if (!dev->num_irqs) { /* * Oh, well, some PROMs don't export interrupts * property to children of EBus devices... @@ -375,23 +348,6 @@ void __init fill_ebus_child(struct device_node *dp, dev->irqs[0] = dev->parent->irqs[1]; } } - } else { - dev->num_irqs = len / sizeof(irqs[0]); - for (i = 0; i < dev->num_irqs; i++) { - struct pci_pbm_info *pbm = dev->bus->parent; - struct pci_controller_info *p = pbm->parent; - - if (ebus_intmap_match(dev->bus, preg, &irqs[i]) != -1) { - dev->irqs[i] = p->irq_build(pbm, - dev->bus->self, - irqs[i]); - } else { - /* If we get a bogus interrupt property, just - * record the raw value instead of punting. - */ - dev->irqs[i] = irqs[i]; - } - } } } @@ -403,72 +359,32 @@ static int __init child_regs_nonstandard(struct linux_ebus_device *dev) return 0; } -void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev) +static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev) { - struct linux_prom_registers *regs; struct linux_ebus_child *child; - int *irqs; - int i, n, len; + struct of_device *op; + int i, len; dev->prom_node = dp; printk(" [%s", dp->name); - regs = of_get_property(dp, "reg", &len); - if (!regs) { + op = of_find_device_by_node(dp); + if (!op) { dev->num_addrs = 0; - goto probe_interrupts; - } - - if (len % sizeof(struct linux_prom_registers)) { - prom_printf("UGH: proplen for %s was %d, need multiple of %d\n", - dev->prom_node->name, len, - (int)sizeof(struct linux_prom_registers)); - prom_halt(); - } - dev->num_addrs = len / sizeof(struct linux_prom_registers); - - for (i = 0; i < dev->num_addrs; i++) { - /* XXX Learn how to interpret ebus ranges... -DaveM */ - if (regs[i].which_io >= 0x10) - n = (regs[i].which_io - 0x10) >> 2; - else - n = regs[i].which_io; - - dev->resource[i].start = dev->bus->self->resource[n].start; - dev->resource[i].start += (unsigned long)regs[i].phys_addr; - dev->resource[i].end = - (dev->resource[i].start + (unsigned long)regs[i].reg_size - 1UL); - dev->resource[i].flags = IORESOURCE_MEM; - dev->resource[i].name = dev->prom_node->name; - request_resource(&dev->bus->self->resource[n], - &dev->resource[i]); - } - -probe_interrupts: - for (i = 0; i < PROMINTR_MAX; i++) - dev->irqs[i] = PCI_IRQ_NONE; - - irqs = of_get_property(dp, "interrupts", &len); - if (!irqs) { dev->num_irqs = 0; } else { - dev->num_irqs = len / sizeof(irqs[0]); - for (i = 0; i < dev->num_irqs; i++) { - struct pci_pbm_info *pbm = dev->bus->parent; - struct pci_controller_info *p = pbm->parent; - - if (ebus_intmap_match(dev->bus, ®s[0], &irqs[i]) != -1) { - dev->irqs[i] = p->irq_build(pbm, - dev->bus->self, - irqs[i]); - } else { - /* If we get a bogus interrupt property, just - * record the raw value instead of punting. - */ - dev->irqs[i] = irqs[i]; - } - } + (void) of_get_property(dp, "reg", &len); + dev->num_addrs = len / sizeof(struct linux_prom_registers); + + for (i = 0; i < dev->num_addrs; i++) + memcpy(&dev->resource[i], + &op->resource[i], + sizeof(struct resource)); + + dev->num_irqs = op->num_irqs; + for (i = 0; i < dev->num_irqs; i++) + dev->irqs[i] = op->irqs[i]; } dev->ofdev.node = dp; @@ -490,7 +406,7 @@ probe_interrupts: child->next = NULL; child->parent = dev; child->bus = dev->bus; - fill_ebus_child(dp, regs, child, + fill_ebus_child(dp, child, child_regs_nonstandard(dev)); while ((dp = dp->sibling) != NULL) { @@ -500,7 +416,7 @@ probe_interrupts: child->next = NULL; child->parent = dev; child->bus = dev->bus; - fill_ebus_child(dp, regs, child, + fill_ebus_child(dp, child, child_regs_nonstandard(dev)); } } diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index ab9e640df228..eebe02f3f4cb 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -414,6 +414,10 @@ void irq_install_pre_handler(int virt_irq, data->pre_handler_arg1 = arg1; data->pre_handler_arg2 = arg2; + if (desc->chip == &sun4u_irq_ack || + desc->chip == &sun4v_irq_ack) + return; + desc->chip = (desc->chip == &sun4u_irq ? &sun4u_irq_ack : &sun4v_irq_ack); } diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c index 6f16dee280a8..0f3aec72ef5f 100644 --- a/arch/sparc64/kernel/isa.c +++ b/arch/sparc64/kernel/isa.c @@ -3,6 +3,8 @@ #include <linux/pci.h> #include <linux/slab.h> #include <asm/oplib.h> +#include <asm/prom.h> +#include <asm/of_device.h> #include <asm/isa.h> struct sparc_isa_bridge *isa_chain; @@ -46,107 +48,16 @@ isa_dev_get_resource(struct sparc_isa_device *isa_dev) return pregs; } -/* I can't believe they didn't put a real INO in the isa device - * interrupts property. The whole point of the OBP properties - * is to shield the kernel from IRQ routing details. - * - * The P1275 standard for ISA devices seems to also have been - * totally ignored. - * - * On later systems, an interrupt-map and interrupt-map-mask scheme - * akin to EBUS is used. - */ -static struct { - int obp_irq; - int pci_ino; -} grover_irq_table[] = { - { 1, 0x00 }, /* dma, unknown ino at this point */ - { 2, 0x27 }, /* floppy */ - { 3, 0x22 }, /* parallel */ - { 4, 0x2b }, /* serial */ - { 5, 0x25 }, /* acpi power management */ - - { 0, 0x00 } /* end of table */ -}; - -static int __init isa_dev_get_irq_using_imap(struct sparc_isa_device *isa_dev, - struct sparc_isa_bridge *isa_br, - int *interrupt, - struct linux_prom_registers *reg) -{ - struct linux_prom_ebus_intmap *imap; - struct linux_prom_ebus_intmap *imask; - unsigned int hi, lo, irq; - int i, len, n_imap; - - imap = of_get_property(isa_br->prom_node, "interrupt-map", &len); - if (!imap) - return 0; - n_imap = len / sizeof(imap[0]); - - imask = of_get_property(isa_br->prom_node, "interrupt-map-mask", NULL); - if (!imask) - return 0; - - hi = reg->which_io & imask->phys_hi; - lo = reg->phys_addr & imask->phys_lo; - irq = *interrupt & imask->interrupt; - for (i = 0; i < n_imap; i++) { - if ((imap[i].phys_hi == hi) && - (imap[i].phys_lo == lo) && - (imap[i].interrupt == irq)) { - *interrupt = imap[i].cinterrupt; - return 0; - } - } - return -1; -} - static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev, struct linux_prom_registers *pregs) { - int irq_prop; + struct of_device *op = of_find_device_by_node(isa_dev->prom_node); - irq_prop = of_getintprop_default(isa_dev->prom_node, - "interrupts", -1); - if (irq_prop <= 0) { - goto no_irq; + if (!op || !op->num_irqs) { + isa_dev->irq = PCI_IRQ_NONE; } else { - struct pci_controller_info *pcic; - struct pci_pbm_info *pbm; - int i; - - if (of_find_property(isa_dev->bus->prom_node, - "interrupt-map", NULL)) { - if (!isa_dev_get_irq_using_imap(isa_dev, - isa_dev->bus, - &irq_prop, - pregs)) - goto route_irq; - } - - for (i = 0; grover_irq_table[i].obp_irq != 0; i++) { - if (grover_irq_table[i].obp_irq == irq_prop) { - int ino = grover_irq_table[i].pci_ino; - - if (ino == 0) - goto no_irq; - - irq_prop = ino; - goto route_irq; - } - } - goto no_irq; - -route_irq: - pbm = isa_dev->bus->parent; - pcic = pbm->parent; - isa_dev->irq = pcic->irq_build(pbm, NULL, irq_prop); - return; + isa_dev->irq = op->irqs[0]; } - -no_irq: - isa_dev->irq = PCI_IRQ_NONE; } static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev) diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 768475bbce82..3670dc8a7d5f 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -129,6 +129,43 @@ static int of_device_resume(struct device * dev) return error; } +void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name) +{ + unsigned long ret = res->start + offset; + + if (!request_region(ret, size, name)) + ret = 0; + + return (void __iomem *) ret; +} +EXPORT_SYMBOL(of_ioremap); + +void of_iounmap(void __iomem *base, unsigned long size) +{ + release_region((unsigned long) base, size); +} +EXPORT_SYMBOL(of_iounmap); + +static int node_match(struct device *dev, void *data) +{ + struct of_device *op = to_of_device(dev); + struct device_node *dp = data; + + return (op->node == dp); +} + +struct of_device *of_find_device_by_node(struct device_node *dp) +{ + struct device *dev = bus_find_device(&of_bus_type, NULL, + dp, node_match); + + if (dev) + return to_of_device(dev); + + return NULL; +} +EXPORT_SYMBOL(of_find_device_by_node); + #ifdef CONFIG_PCI struct bus_type isa_bus_type = { .name = "isa", @@ -163,10 +200,654 @@ struct bus_type sbus_bus_type = { EXPORT_SYMBOL(sbus_bus_type); #endif +struct bus_type of_bus_type = { + .name = "of", + .match = of_platform_bus_match, + .probe = of_device_probe, + .remove = of_device_remove, + .suspend = of_device_suspend, + .resume = of_device_resume, +}; +EXPORT_SYMBOL(of_bus_type); + +static inline u64 of_read_addr(u32 *cell, int size) +{ + u64 r = 0; + while (size--) + r = (r << 32) | *(cell++); + return r; +} + +static void __init get_cells(struct device_node *dp, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = of_n_addr_cells(dp); + if (sizec) + *sizec = of_n_size_cells(dp); +} + +/* Max address size we deal with */ +#define OF_MAX_ADDR_CELLS 4 + +struct of_bus { + const char *name; + const char *addr_prop_name; + int (*match)(struct device_node *parent); + void (*count_cells)(struct device_node *child, + int *addrc, int *sizec); + u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna); + int (*translate)(u32 *addr, u64 offset, int na); + unsigned int (*get_flags)(u32 *addr); +}; + +/* + * Default translator (generic bus) + */ + +static void of_bus_default_count_cells(struct device_node *dev, + int *addrc, int *sizec) +{ + get_cells(dev, addrc, sizec); +} + +static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna) +{ + u64 cp, s, da; + + cp = of_read_addr(range, na); + s = of_read_addr(range + na + pna, ns); + da = of_read_addr(addr, na); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_default_translate(u32 *addr, u64 offset, int na) +{ + u64 a = of_read_addr(addr, na); + memset(addr, 0, na * 4); + a += offset; + if (na > 1) + addr[na - 2] = a >> 32; + addr[na - 1] = a & 0xffffffffu; + + return 0; +} + +static unsigned int of_bus_default_get_flags(u32 *addr) +{ + return IORESOURCE_MEM; +} + +/* + * PCI bus specific translator + */ + +static int of_bus_pci_match(struct device_node *np) +{ + return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex"); +} + +static void of_bus_pci_count_cells(struct device_node *np, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 3; + if (sizec) + *sizec = 2; +} + +static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna) +{ + u64 cp, s, da; + + /* Check address type match */ + if ((addr[0] ^ range[0]) & 0x03000000) + return OF_BAD_ADDR; + + /* Read address values, skipping high cell */ + cp = of_read_addr(range + 1, na - 1); + s = of_read_addr(range + na + pna, ns); + da = of_read_addr(addr + 1, na - 1); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_pci_translate(u32 *addr, u64 offset, int na) +{ + return of_bus_default_translate(addr + 1, offset, na - 1); +} + +static unsigned int of_bus_pci_get_flags(u32 *addr) +{ + unsigned int flags = 0; + u32 w = addr[0]; + + switch((w >> 24) & 0x03) { + case 0x01: + flags |= IORESOURCE_IO; + case 0x02: /* 32 bits */ + case 0x03: /* 64 bits */ + flags |= IORESOURCE_MEM; + } + if (w & 0x40000000) + flags |= IORESOURCE_PREFETCH; + return flags; +} + +/* + * ISA bus specific translator + */ + +static int of_bus_isa_match(struct device_node *np) +{ + return !strcmp(np->name, "isa"); +} + +static void of_bus_isa_count_cells(struct device_node *child, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 2; + if (sizec) + *sizec = 1; +} + +static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna) +{ + u64 cp, s, da; + + /* Check address type match */ + if ((addr[0] ^ range[0]) & 0x00000001) + return OF_BAD_ADDR; + + /* Read address values, skipping high cell */ + cp = of_read_addr(range + 1, na - 1); + s = of_read_addr(range + na + pna, ns); + da = of_read_addr(addr + 1, na - 1); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_isa_translate(u32 *addr, u64 offset, int na) +{ + return of_bus_default_translate(addr + 1, offset, na - 1); +} + +static unsigned int of_bus_isa_get_flags(u32 *addr) +{ + unsigned int flags = 0; + u32 w = addr[0]; + + if (w & 1) + flags |= IORESOURCE_IO; + else + flags |= IORESOURCE_MEM; + return flags; +} + +/* + * SBUS bus specific translator + */ + +static int of_bus_sbus_match(struct device_node *np) +{ + return !strcmp(np->name, "sbus") || + !strcmp(np->name, "sbi"); +} + +static void of_bus_sbus_count_cells(struct device_node *child, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 2; + if (sizec) + *sizec = 1; +} + +static u64 of_bus_sbus_map(u32 *addr, u32 *range, int na, int ns, int pna) +{ + return of_bus_default_map(addr, range, na, ns, pna); +} + +static int of_bus_sbus_translate(u32 *addr, u64 offset, int na) +{ + return of_bus_default_translate(addr, offset, na); +} + +static unsigned int of_bus_sbus_get_flags(u32 *addr) +{ + return IORESOURCE_MEM; +} + + +/* + * Array of bus specific translators + */ + +static struct of_bus of_busses[] = { + /* PCI */ + { + .name = "pci", + .addr_prop_name = "assigned-addresses", + .match = of_bus_pci_match, + .count_cells = of_bus_pci_count_cells, + .map = of_bus_pci_map, + .translate = of_bus_pci_translate, + .get_flags = of_bus_pci_get_flags, + }, + /* ISA */ + { + .name = "isa", + .addr_prop_name = "reg", + .match = of_bus_isa_match, + .count_cells = of_bus_isa_count_cells, + .map = of_bus_isa_map, + .translate = of_bus_isa_translate, + .get_flags = of_bus_isa_get_flags, + }, + /* SBUS */ + { + .name = "sbus", + .addr_prop_name = "reg", + .match = of_bus_sbus_match, + .count_cells = of_bus_sbus_count_cells, + .map = of_bus_sbus_map, + .translate = of_bus_sbus_translate, + .get_flags = of_bus_sbus_get_flags, + }, + /* Default */ + { + .name = "default", + .addr_prop_name = "reg", + .match = NULL, + .count_cells = of_bus_default_count_cells, + .map = of_bus_default_map, + .translate = of_bus_default_translate, + .get_flags = of_bus_default_get_flags, + }, +}; + +static struct of_bus *of_match_bus(struct device_node *np) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(of_busses); i ++) + if (!of_busses[i].match || of_busses[i].match(np)) + return &of_busses[i]; + BUG(); + return NULL; +} + +static int __init build_one_resource(struct device_node *parent, + struct of_bus *bus, + struct of_bus *pbus, + u32 *addr, + int na, int ns, int pna) +{ + u32 *ranges; + unsigned int rlen; + int rone; + u64 offset = OF_BAD_ADDR; + + ranges = of_get_property(parent, "ranges", &rlen); + if (ranges == NULL || rlen == 0) { + offset = of_read_addr(addr, na); + memset(addr, 0, pna * 4); + goto finish; + } + + /* Now walk through the ranges */ + rlen /= 4; + rone = na + pna + ns; + for (; rlen >= rone; rlen -= rone, ranges += rone) { + offset = bus->map(addr, ranges, na, ns, pna); + if (offset != OF_BAD_ADDR) + break; + } + if (offset == OF_BAD_ADDR) + return 1; + + memcpy(addr, ranges + na, 4 * pna); + +finish: + /* Translate it into parent bus space */ + return pbus->translate(addr, offset, pna); +} + +static void __init build_device_resources(struct of_device *op, + struct device *parent) +{ + struct of_device *p_op; + struct of_bus *bus; + int na, ns; + int index, num_reg; + void *preg; + + if (!parent) + return; + + p_op = to_of_device(parent); + bus = of_match_bus(p_op->node); + bus->count_cells(op->node, &na, &ns); + + preg = of_get_property(op->node, bus->addr_prop_name, &num_reg); + if (!preg || num_reg == 0) + return; + + /* Convert to num-cells. */ + num_reg /= 4; + + /* Conver to num-entries. */ + num_reg /= na + ns; + + for (index = 0; index < num_reg; index++) { + struct resource *r = &op->resource[index]; + u32 addr[OF_MAX_ADDR_CELLS]; + u32 *reg = (preg + (index * ((na + ns) * 4))); + struct device_node *dp = op->node; + struct device_node *pp = p_op->node; + struct of_bus *pbus; + u64 size, result = OF_BAD_ADDR; + unsigned long flags; + int dna, dns; + int pna, pns; + + size = of_read_addr(reg + na, ns); + flags = bus->get_flags(reg); + + memcpy(addr, reg, na * 4); + + /* If the immediate parent has no ranges property to apply, + * just use a 1<->1 mapping. Unless it is the 'dma' child + * of an isa bus, which must be passed up towards the root. + * + * Also, don't try to translate PMU bus device registers. + */ + if ((of_find_property(pp, "ranges", NULL) == NULL && + strcmp(pp->name, "dma") != 0) || + !strcmp(pp->name, "pmu")) { + result = of_read_addr(addr, na); + goto build_res; + } + + dna = na; + dns = ns; + + while (1) { + dp = pp; + pp = dp->parent; + if (!pp) { + result = of_read_addr(addr, dna); + break; + } + + pbus = of_match_bus(pp); + pbus->count_cells(dp, &pna, &pns); + + if (build_one_resource(dp, bus, pbus, addr, dna, dns, pna)) + break; + + dna = pna; + dns = pns; + bus = pbus; + } + + build_res: + memset(r, 0, sizeof(*r)); + if (result != OF_BAD_ADDR) { + r->start = result; + r->end = result + size - 1; + r->flags = flags; + } else { + r->start = ~0UL; + r->end = ~0UL; + } + r->name = op->node->name; + } +} + +static struct device_node * __init +apply_interrupt_map(struct device_node *dp, struct device_node *pp, + u32 *imap, int imlen, u32 *imask, + unsigned int *irq_p) +{ + struct device_node *cp; + unsigned int irq = *irq_p; + struct of_bus *bus; + phandle handle; + u32 *reg; + int na, num_reg, i; + + bus = of_match_bus(pp); + bus->count_cells(dp, &na, NULL); + + reg = of_get_property(dp, "reg", &num_reg); + if (!reg || !num_reg) + return NULL; + + imlen /= ((na + 3) * 4); + handle = 0; + for (i = 0; i < imlen; i++) { + int j; + + for (j = 0; j < na; j++) { + if ((reg[j] & imask[j]) != imap[j]) + goto next; + } + if (imap[na] == irq) { + handle = imap[na + 1]; + irq = imap[na + 2]; + break; + } + + next: + imap += (na + 3); + } + if (i == imlen) + return NULL; + + *irq_p = irq; + cp = of_find_node_by_phandle(handle); + + return cp; +} + +static unsigned int __init pci_irq_swizzle(struct device_node *dp, + struct device_node *pp, + unsigned int irq) +{ + struct linux_prom_pci_registers *regs; + unsigned int devfn, slot, ret; + + if (irq < 1 || irq > 4) + return irq; + + regs = of_get_property(dp, "reg", NULL); + if (!regs) + return irq; + + devfn = (regs->phys_hi >> 8) & 0xff; + slot = (devfn >> 3) & 0x1f; + + ret = ((irq - 1 + (slot & 3)) & 3) + 1; + + return ret; +} + +static unsigned int __init build_one_device_irq(struct of_device *op, + struct device *parent, + unsigned int irq) +{ + struct device_node *dp = op->node; + struct device_node *pp, *ip; + unsigned int orig_irq = irq; + + if (irq == 0xffffffff) + return irq; + + if (dp->irq_trans) { + irq = dp->irq_trans->irq_build(dp, irq, + dp->irq_trans->data); +#if 1 + printk("%s: direct translate %x --> %x\n", + dp->full_name, orig_irq, irq); +#endif + return irq; + } + + /* Something more complicated. Walk up to the root, applying + * interrupt-map or bus specific translations, until we hit + * an IRQ translator. + * + * If we hit a bus type or situation we cannot handle, we + * stop and assume that the original IRQ number was in a + * format which has special meaning to it's immediate parent. + */ + pp = dp->parent; + ip = NULL; + while (pp) { + void *imap, *imsk; + int imlen; + + imap = of_get_property(pp, "interrupt-map", &imlen); + imsk = of_get_property(pp, "interrupt-map-mask", NULL); + if (imap && imsk) { + struct device_node *iret; + int this_orig_irq = irq; + + iret = apply_interrupt_map(dp, pp, + imap, imlen, imsk, + &irq); +#if 1 + printk("%s: Apply [%s:%x] imap --> [%s:%x]\n", + op->node->full_name, + pp->full_name, this_orig_irq, + (iret ? iret->full_name : "NULL"), irq); +#endif + if (!iret) + break; + + if (iret->irq_trans) { + ip = iret; + break; + } + } else { + if (!strcmp(pp->type, "pci") || + !strcmp(pp->type, "pciex")) { + unsigned int this_orig_irq = irq; + + irq = pci_irq_swizzle(dp, pp, irq); +#if 1 + printk("%s: PCI swizzle [%s] %x --> %x\n", + op->node->full_name, + pp->full_name, this_orig_irq, irq); +#endif + } + + if (pp->irq_trans) { + ip = pp; + break; + } + } + dp = pp; + pp = pp->parent; + } + if (!ip) + return orig_irq; + + irq = ip->irq_trans->irq_build(op->node, irq, + ip->irq_trans->data); +#if 1 + printk("%s: Apply IRQ trans [%s] %x --> %x\n", + op->node->full_name, ip->full_name, orig_irq, irq); +#endif + + return irq; +} + +static struct of_device * __init scan_one_device(struct device_node *dp, + struct device *parent) +{ + struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); + unsigned int *irq; + int len, i; + + if (!op) + return NULL; + + op->node = dp; + + op->clock_freq = of_getintprop_default(dp, "clock-frequency", + (25*1000*1000)); + op->portid = of_getintprop_default(dp, "upa-portid", -1); + if (op->portid == -1) + op->portid = of_getintprop_default(dp, "portid", -1); + + irq = of_get_property(dp, "interrupts", &len); + if (irq) { + memcpy(op->irqs, irq, len); + op->num_irqs = len / 4; + } else { + op->num_irqs = 0; + } + + build_device_resources(op, parent); + for (i = 0; i < op->num_irqs; i++) + op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]); + + op->dev.parent = parent; + op->dev.bus = &of_bus_type; + if (!parent) + strcpy(op->dev.bus_id, "root"); + else + strcpy(op->dev.bus_id, dp->path_component_name); + + if (of_device_register(op)) { + printk("%s: Could not register of device.\n", + dp->full_name); + kfree(op); + op = NULL; + } + + return op; +} + +static void __init scan_tree(struct device_node *dp, struct device *parent) +{ + while (dp) { + struct of_device *op = scan_one_device(dp, parent); + + if (op) + scan_tree(dp->child, &op->dev); + + dp = dp->sibling; + } +} + +static void __init scan_of_devices(void) +{ + struct device_node *root = of_find_node_by_path("/"); + struct of_device *parent; + + parent = scan_one_device(root, NULL); + if (!parent) + return; + + scan_tree(root->child, &parent->dev); +} + static int __init of_bus_driver_init(void) { - int err = 0; + int err; + err = bus_register(&of_bus_type); #ifdef CONFIG_PCI if (!err) err = bus_register(&isa_bus_type); @@ -177,7 +858,11 @@ static int __init of_bus_driver_init(void) if (!err) err = bus_register(&sbus_bus_type); #endif - return 0; + + if (!err) + scan_of_devices(); + + return err; } postcore_initcall(of_bus_driver_init); diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 20ca9ec8fd3b..04ea6c2eb7a1 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -307,7 +307,6 @@ static void __init pci_scan_each_controller_bus(void) p->scan_bus(p); } -extern void clock_probe(void); extern void power_init(void); static int __init pcibios_init(void) @@ -320,7 +319,6 @@ static int __init pcibios_init(void) isa_init(); ebus_init(); - clock_probe(); power_init(); return 0; @@ -406,14 +404,8 @@ void pcibios_bus_to_resource(struct pci_dev *pdev, struct resource *res, } EXPORT_SYMBOL(pcibios_bus_to_resource); -extern int pci_irq_verbose; - char * __init pcibios_setup(char *str) { - if (!strcmp(str, "irq_verbose")) { - pci_irq_verbose = 1; - return NULL; - } return str; } diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index b06a2955bf5f..7a59cc72c844 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -10,12 +10,10 @@ #include <asm/pbm.h> #include <asm/prom.h> +#include <asm/of_device.h> #include "pci_impl.h" -/* Pass "pci=irq_verbose" on the kernel command line to enable this. */ -int pci_irq_verbose; - /* Fix self device of BUS and hook it into BUS->self. * The pci_scan_bus does not do this for the host bridge. */ @@ -169,6 +167,7 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm, } pcp->pbm = pbm; pcp->prom_node = dp; + pcp->op = of_find_device_by_node(dp); memcpy(pcp->prom_regs, pregs, nregs * sizeof(struct linux_prom_pci_registers)); pcp->num_prom_regs = nregs; @@ -549,296 +548,18 @@ void __init pci_assign_unassigned(struct pci_pbm_info *pbm, pci_assign_unassigned(pbm, bus); } -static inline unsigned int pci_slot_swivel(struct pci_pbm_info *pbm, - struct pci_dev *toplevel_pdev, - struct pci_dev *pdev, - unsigned int interrupt) -{ - unsigned int ret; - - if (unlikely(interrupt < 1 || interrupt > 4)) { - printk("%s: Device %s interrupt value of %u is strange.\n", - pbm->name, pci_name(pdev), interrupt); - return interrupt; - } - - ret = ((interrupt - 1 + (PCI_SLOT(pdev->devfn) & 3)) & 3) + 1; - - if (pci_irq_verbose) - printk("%s: %s IRQ Swivel %s [%x:%x] -> [%x]\n", - pbm->name, pci_name(toplevel_pdev), pci_name(pdev), - interrupt, PCI_SLOT(pdev->devfn), ret); - - return ret; -} - -static inline unsigned int pci_apply_intmap(struct pci_pbm_info *pbm, - struct pci_dev *toplevel_pdev, - struct pci_dev *pbus, - struct pci_dev *pdev, - unsigned int interrupt, - struct device_node **cnode) -{ - struct linux_prom_pci_intmap *imap; - struct linux_prom_pci_intmask *imask; - struct pcidev_cookie *pbus_pcp = pbus->sysdata; - struct pcidev_cookie *pdev_pcp = pdev->sysdata; - struct linux_prom_pci_registers *pregs = pdev_pcp->prom_regs; - struct property *prop; - int plen, num_imap, i; - unsigned int hi, mid, lo, irq, orig_interrupt; - - *cnode = pbus_pcp->prom_node; - - prop = of_find_property(pbus_pcp->prom_node, "interrupt-map", &plen); - if (!prop || - (plen % sizeof(struct linux_prom_pci_intmap)) != 0) { - printk("%s: Device %s interrupt-map has bad len %d\n", - pbm->name, pci_name(pbus), plen); - goto no_intmap; - } - imap = prop->value; - num_imap = plen / sizeof(struct linux_prom_pci_intmap); - - prop = of_find_property(pbus_pcp->prom_node, "interrupt-map-mask", &plen); - if (!prop || - (plen % sizeof(struct linux_prom_pci_intmask)) != 0) { - printk("%s: Device %s interrupt-map-mask has bad len %d\n", - pbm->name, pci_name(pbus), plen); - goto no_intmap; - } - imask = prop->value; - - orig_interrupt = interrupt; - - hi = pregs->phys_hi & imask->phys_hi; - mid = pregs->phys_mid & imask->phys_mid; - lo = pregs->phys_lo & imask->phys_lo; - irq = interrupt & imask->interrupt; - - for (i = 0; i < num_imap; i++) { - if (imap[i].phys_hi == hi && - imap[i].phys_mid == mid && - imap[i].phys_lo == lo && - imap[i].interrupt == irq) { - *cnode = of_find_node_by_phandle(imap[i].cnode); - interrupt = imap[i].cinterrupt; - } - } - - if (pci_irq_verbose) - printk("%s: %s MAP BUS %s DEV %s [%x] -> [%x]\n", - pbm->name, pci_name(toplevel_pdev), - pci_name(pbus), pci_name(pdev), - orig_interrupt, interrupt); - -no_intmap: - return interrupt; -} - -/* For each PCI bus on the way to the root: - * 1) If it has an interrupt-map property, apply it. - * 2) Else, swivel the interrupt number based upon the PCI device number. - * - * Return the "IRQ controller" node. If this is the PBM's device node, - * all interrupt translations are complete, else we should use that node's - * "reg" property to apply the PBM's "interrupt-{map,mask}" to the interrupt. - */ -static struct device_node * __init -pci_intmap_match_to_root(struct pci_pbm_info *pbm, - struct pci_dev *pdev, - unsigned int *interrupt) -{ - struct pci_dev *toplevel_pdev = pdev; - struct pcidev_cookie *toplevel_pcp = toplevel_pdev->sysdata; - struct device_node *cnode = toplevel_pcp->prom_node; - - while (pdev->bus->number != pbm->pci_first_busno) { - struct pci_dev *pbus = pdev->bus->self; - struct pcidev_cookie *pcp = pbus->sysdata; - struct property *prop; - - prop = of_find_property(pcp->prom_node, "interrupt-map", NULL); - if (!prop) { - *interrupt = pci_slot_swivel(pbm, toplevel_pdev, - pdev, *interrupt); - cnode = pcp->prom_node; - } else { - *interrupt = pci_apply_intmap(pbm, toplevel_pdev, - pbus, pdev, - *interrupt, &cnode); - - while (pcp->prom_node != cnode && - pbus->bus->number != pbm->pci_first_busno) { - pbus = pbus->bus->self; - pcp = pbus->sysdata; - } - } - pdev = pbus; - - if (cnode == pbm->prom_node) - break; - } - - return cnode; -} - -static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt) -{ - struct pcidev_cookie *dev_pcp = pdev->sysdata; - struct pci_pbm_info *pbm = dev_pcp->pbm; - struct linux_prom_pci_registers *reg; - struct device_node *cnode; - struct property *prop; - unsigned int hi, mid, lo, irq; - int i, plen; - - cnode = pci_intmap_match_to_root(pbm, pdev, interrupt); - if (cnode == pbm->prom_node) - goto success; - - prop = of_find_property(cnode, "reg", &plen); - if (!prop || - (plen % sizeof(struct linux_prom_pci_registers)) != 0) { - printk("%s: OBP node %s reg property has bad len %d\n", - pbm->name, cnode->full_name, plen); - goto fail; - } - reg = prop->value; - - hi = reg[0].phys_hi & pbm->pbm_intmask->phys_hi; - mid = reg[0].phys_mid & pbm->pbm_intmask->phys_mid; - lo = reg[0].phys_lo & pbm->pbm_intmask->phys_lo; - irq = *interrupt & pbm->pbm_intmask->interrupt; - - for (i = 0; i < pbm->num_pbm_intmap; i++) { - struct linux_prom_pci_intmap *intmap; - - intmap = &pbm->pbm_intmap[i]; - - if (intmap->phys_hi == hi && - intmap->phys_mid == mid && - intmap->phys_lo == lo && - intmap->interrupt == irq) { - *interrupt = intmap->cinterrupt; - goto success; - } - } - -fail: - return 0; - -success: - if (pci_irq_verbose) - printk("%s: Routing bus[%2x] slot[%2x] to INO[%02x]\n", - pbm->name, - pdev->bus->number, PCI_SLOT(pdev->devfn), - *interrupt); - return 1; -} - static void __init pdev_fixup_irq(struct pci_dev *pdev) { struct pcidev_cookie *pcp = pdev->sysdata; - struct pci_pbm_info *pbm = pcp->pbm; - struct pci_controller_info *p = pbm->parent; - unsigned int portid = pbm->portid; - unsigned int prom_irq; - struct device_node *dp = pcp->prom_node; - struct property *prop; - - /* If this is an empty EBUS device, sometimes OBP fails to - * give it a valid fully specified interrupts property. - * The EBUS hooked up to SunHME on PCI I/O boards of - * Ex000 systems is one such case. - * - * The interrupt is not important so just ignore it. - */ - if (pdev->vendor == PCI_VENDOR_ID_SUN && - pdev->device == PCI_DEVICE_ID_SUN_EBUS && - !dp->child) { - pdev->irq = 0; - return; - } + struct of_device *op = pcp->op; - prop = of_find_property(dp, "interrupts", NULL); - if (!prop) { - pdev->irq = 0; + if (op->irqs[0] == 0xffffffff) { + pdev->irq = PCI_IRQ_NONE; return; } - prom_irq = *(unsigned int *) prop->value; - - if (tlb_type != hypervisor) { - /* Fully specified already? */ - if (((prom_irq & PCI_IRQ_IGN) >> 6) == portid) { - pdev->irq = p->irq_build(pbm, pdev, prom_irq); - goto have_irq; - } - - /* An onboard device? (bit 5 set) */ - if ((prom_irq & PCI_IRQ_INO) & 0x20) { - pdev->irq = p->irq_build(pbm, pdev, (portid << 6 | prom_irq)); - goto have_irq; - } - } - - /* Can we find a matching entry in the interrupt-map? */ - if (pci_intmap_match(pdev, &prom_irq)) { - pdev->irq = p->irq_build(pbm, pdev, (portid << 6) | prom_irq); - goto have_irq; - } - - /* Ok, we have to do it the hard way. */ - { - unsigned int bus, slot, line; - - bus = (pbm == &pbm->parent->pbm_B) ? (1 << 4) : 0; - - /* If we have a legal interrupt property, use it as - * the IRQ line. - */ - if (prom_irq > 0 && prom_irq < 5) { - line = ((prom_irq - 1) & 3); - } else { - u8 pci_irq_line; - /* Else just directly consult PCI config space. */ - pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pci_irq_line); - line = ((pci_irq_line - 1) & 3); - } - - /* Now figure out the slot. - * - * Basically, device number zero on the top-level bus is - * always the PCI host controller. Slot 0 is then device 1. - * PBM A supports two external slots (0 and 1), and PBM B - * supports 4 external slots (0, 1, 2, and 3). On-board PCI - * devices are wired to device numbers outside of these - * ranges. -DaveM - */ - if (pdev->bus->number == pbm->pci_first_busno) { - slot = PCI_SLOT(pdev->devfn) - pbm->pci_first_slot; - } else { - struct pci_dev *bus_dev; - - /* Underneath a bridge, use slot number of parent - * bridge which is closest to the PBM. - */ - bus_dev = pdev->bus->self; - while (bus_dev->bus && - bus_dev->bus->number != pbm->pci_first_busno) - bus_dev = bus_dev->bus->self; - - slot = PCI_SLOT(bus_dev->devfn) - pbm->pci_first_slot; - } - slot = slot << 2; - - pdev->irq = p->irq_build(pbm, pdev, - ((portid << 6) & PCI_IRQ_IGN) | - (bus | slot | line)); - } + pdev->irq = op->irqs[0]; -have_irq: pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, pdev->irq & PCI_IRQ_INO); } diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 5b2261ebda6f..bf7b32b36705 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -18,6 +18,7 @@ #include <asm/irq.h> #include <asm/starfire.h> #include <asm/prom.h> +#include <asm/of_device.h> #include "pci_impl.h" #include "iommu_common.h" @@ -208,110 +209,6 @@ static struct pci_ops psycho_ops = { .write = psycho_write_pci_cfg, }; -/* PSYCHO interrupt mapping support. */ -#define PSYCHO_IMAP_A_SLOT0 0x0c00UL -#define PSYCHO_IMAP_B_SLOT0 0x0c20UL -static unsigned long psycho_pcislot_imap_offset(unsigned long ino) -{ - unsigned int bus = (ino & 0x10) >> 4; - unsigned int slot = (ino & 0x0c) >> 2; - - if (bus == 0) - return PSYCHO_IMAP_A_SLOT0 + (slot * 8); - else - return PSYCHO_IMAP_B_SLOT0 + (slot * 8); -} - -#define PSYCHO_IMAP_SCSI 0x1000UL -#define PSYCHO_IMAP_ETH 0x1008UL -#define PSYCHO_IMAP_BPP 0x1010UL -#define PSYCHO_IMAP_AU_REC 0x1018UL -#define PSYCHO_IMAP_AU_PLAY 0x1020UL -#define PSYCHO_IMAP_PFAIL 0x1028UL -#define PSYCHO_IMAP_KMS 0x1030UL -#define PSYCHO_IMAP_FLPY 0x1038UL -#define PSYCHO_IMAP_SHW 0x1040UL -#define PSYCHO_IMAP_KBD 0x1048UL -#define PSYCHO_IMAP_MS 0x1050UL -#define PSYCHO_IMAP_SER 0x1058UL -#define PSYCHO_IMAP_TIM0 0x1060UL -#define PSYCHO_IMAP_TIM1 0x1068UL -#define PSYCHO_IMAP_UE 0x1070UL -#define PSYCHO_IMAP_CE 0x1078UL -#define PSYCHO_IMAP_A_ERR 0x1080UL -#define PSYCHO_IMAP_B_ERR 0x1088UL -#define PSYCHO_IMAP_PMGMT 0x1090UL -#define PSYCHO_IMAP_GFX 0x1098UL -#define PSYCHO_IMAP_EUPA 0x10a0UL - -static unsigned long __onboard_imap_off[] = { -/*0x20*/ PSYCHO_IMAP_SCSI, -/*0x21*/ PSYCHO_IMAP_ETH, -/*0x22*/ PSYCHO_IMAP_BPP, -/*0x23*/ PSYCHO_IMAP_AU_REC, -/*0x24*/ PSYCHO_IMAP_AU_PLAY, -/*0x25*/ PSYCHO_IMAP_PFAIL, -/*0x26*/ PSYCHO_IMAP_KMS, -/*0x27*/ PSYCHO_IMAP_FLPY, -/*0x28*/ PSYCHO_IMAP_SHW, -/*0x29*/ PSYCHO_IMAP_KBD, -/*0x2a*/ PSYCHO_IMAP_MS, -/*0x2b*/ PSYCHO_IMAP_SER, -/*0x2c*/ PSYCHO_IMAP_TIM0, -/*0x2d*/ PSYCHO_IMAP_TIM1, -/*0x2e*/ PSYCHO_IMAP_UE, -/*0x2f*/ PSYCHO_IMAP_CE, -/*0x30*/ PSYCHO_IMAP_A_ERR, -/*0x31*/ PSYCHO_IMAP_B_ERR, -/*0x32*/ PSYCHO_IMAP_PMGMT -}; -#define PSYCHO_ONBOARD_IRQ_BASE 0x20 -#define PSYCHO_ONBOARD_IRQ_LAST 0x32 -#define psycho_onboard_imap_offset(__ino) \ - __onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE] - -#define PSYCHO_ICLR_A_SLOT0 0x1400UL -#define PSYCHO_ICLR_SCSI 0x1800UL - -#define psycho_iclr_offset(ino) \ - ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ - (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) - -static unsigned int psycho_irq_build(struct pci_pbm_info *pbm, - struct pci_dev *pdev, - unsigned int ino) -{ - unsigned long imap, iclr; - unsigned long imap_off, iclr_off; - int inofixup = 0; - - ino &= PCI_IRQ_INO; - if (ino < PSYCHO_ONBOARD_IRQ_BASE) { - /* PCI slot */ - imap_off = psycho_pcislot_imap_offset(ino); - } else { - /* Onboard device */ - if (ino > PSYCHO_ONBOARD_IRQ_LAST) { - prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino); - prom_halt(); - } - imap_off = psycho_onboard_imap_offset(ino); - } - - /* Now build the IRQ bucket. */ - imap = pbm->controller_regs + imap_off; - imap += 4; - - iclr_off = psycho_iclr_offset(ino); - iclr = pbm->controller_regs + iclr_off; - iclr += 4; - - if ((ino & 0x20) == 0) - inofixup = ino & 0x03; - - return build_irq(inofixup, iclr, imap); -} - /* PSYCHO error handling support. */ enum psycho_error_type { UE_ERR, CE_ERR, PCI_ERR @@ -944,51 +841,34 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id, struct pt_regs *reg #define PSYCHO_ECCCTRL_EE 0x8000000000000000UL /* Enable ECC Checking */ #define PSYCHO_ECCCTRL_UE 0x4000000000000000UL /* Enable UE Interrupts */ #define PSYCHO_ECCCTRL_CE 0x2000000000000000UL /* Enable CE INterrupts */ -#define PSYCHO_UE_INO 0x2e -#define PSYCHO_CE_INO 0x2f -#define PSYCHO_PCIERR_A_INO 0x30 -#define PSYCHO_PCIERR_B_INO 0x31 static void psycho_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */ + struct of_device *op = of_find_device_by_node(pbm->prom_node); unsigned long base = p->pbm_A.controller_regs; - unsigned int irq, portid = pbm->portid; u64 tmp; - /* Build IRQs and register handlers. */ - irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_UE_INO); - if (request_irq(irq, psycho_ue_intr, - SA_SHIRQ, "PSYCHO UE", p) < 0) { - prom_printf("PSYCHO%d: Cannot register UE interrupt.\n", - p->index); - prom_halt(); - } + if (!op) + return; - irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_CE_INO); - if (request_irq(irq, psycho_ce_intr, - SA_SHIRQ, "PSYCHO CE", p) < 0) { - prom_printf("PSYCHO%d: Cannot register CE interrupt.\n", - p->index); - prom_halt(); - } + /* Psycho interrupt property order is: + * 0: PCIERR PBM B INO + * 1: UE ERR + * 2: CE ERR + * 3: POWER FAIL + * 4: SPARE HARDWARE + * 5: PCIERR PBM A INO + */ - pbm = &p->pbm_A; - irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_PCIERR_A_INO); - if (request_irq(irq, psycho_pcierr_intr, - SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_A) < 0) { - prom_printf("PSYCHO%d(PBMA): Cannot register PciERR interrupt.\n", - p->index); - prom_halt(); - } + if (op->num_irqs < 6) + return; - pbm = &p->pbm_B; - irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_PCIERR_B_INO); - if (request_irq(irq, psycho_pcierr_intr, - SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_B) < 0) { - prom_printf("PSYCHO%d(PBMB): Cannot register PciERR interrupt.\n", - p->index); - prom_halt(); - } + request_irq(op->irqs[1], psycho_ue_intr, SA_SHIRQ, "PSYCHO UE", p); + request_irq(op->irqs[2], psycho_ce_intr, SA_SHIRQ, "PSYCHO CE", p); + request_irq(op->irqs[5], psycho_pcierr_intr, SA_SHIRQ, + "PSYCHO PCIERR-A", &p->pbm_A); + request_irq(op->irqs[0], psycho_pcierr_intr, SA_SHIRQ, + "PSYCHO PCIERR-B", &p->pbm_B); /* Enable UE and CE interrupts for controller. */ psycho_write(base + PSYCHO_ECC_CTRL, @@ -1171,9 +1051,7 @@ static void psycho_iommu_init(struct pci_controller_info *p) /* If necessary, hook us up for starfire IRQ translations. */ if (this_is_starfire) - p->starfire_cookie = starfire_hookup(p->pbm_A.portid); - else - p->starfire_cookie = NULL; + starfire_hookup(p->pbm_A.portid); } #define PSYCHO_IRQ_RETRY 0x1a00UL @@ -1408,7 +1286,6 @@ void psycho_init(struct device_node *dp, char *model_name) p->index = pci_num_controllers++; p->pbms_same_domain = 0; p->scan_bus = psycho_scan_bus; - p->irq_build = psycho_irq_build; p->base_address_update = psycho_base_address_update; p->resource_adjust = psycho_resource_adjust; p->pci_ops = &psycho_ops; diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 26f194ce4400..5e087b0fb4c9 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -485,114 +485,6 @@ static struct pci_ops sabre_ops = { .write = sabre_write_pci_cfg, }; -static unsigned long sabre_pcislot_imap_offset(unsigned long ino) -{ - unsigned int bus = (ino & 0x10) >> 4; - unsigned int slot = (ino & 0x0c) >> 2; - - if (bus == 0) - return SABRE_IMAP_A_SLOT0 + (slot * 8); - else - return SABRE_IMAP_B_SLOT0 + (slot * 8); -} - -static unsigned long __onboard_imap_off[] = { -/*0x20*/ SABRE_IMAP_SCSI, -/*0x21*/ SABRE_IMAP_ETH, -/*0x22*/ SABRE_IMAP_BPP, -/*0x23*/ SABRE_IMAP_AU_REC, -/*0x24*/ SABRE_IMAP_AU_PLAY, -/*0x25*/ SABRE_IMAP_PFAIL, -/*0x26*/ SABRE_IMAP_KMS, -/*0x27*/ SABRE_IMAP_FLPY, -/*0x28*/ SABRE_IMAP_SHW, -/*0x29*/ SABRE_IMAP_KBD, -/*0x2a*/ SABRE_IMAP_MS, -/*0x2b*/ SABRE_IMAP_SER, -/*0x2c*/ 0 /* reserved */, -/*0x2d*/ 0 /* reserved */, -/*0x2e*/ SABRE_IMAP_UE, -/*0x2f*/ SABRE_IMAP_CE, -/*0x30*/ SABRE_IMAP_PCIERR, -}; -#define SABRE_ONBOARD_IRQ_BASE 0x20 -#define SABRE_ONBOARD_IRQ_LAST 0x30 -#define sabre_onboard_imap_offset(__ino) \ - __onboard_imap_off[(__ino) - SABRE_ONBOARD_IRQ_BASE] - -#define sabre_iclr_offset(ino) \ - ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ - (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) - -/* When a device lives behind a bridge deeper in the PCI bus topology - * than APB, a special sequence must run to make sure all pending DMA - * transfers at the time of IRQ delivery are visible in the coherency - * domain by the cpu. This sequence is to perform a read on the far - * side of the non-APB bridge, then perform a read of Sabre's DMA - * write-sync register. - */ -static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) -{ - struct pci_dev *pdev = _arg1; - unsigned long sync_reg = (unsigned long) _arg2; - u16 _unused; - - pci_read_config_word(pdev, PCI_VENDOR_ID, &_unused); - sabre_read(sync_reg); -} - -static unsigned int sabre_irq_build(struct pci_pbm_info *pbm, - struct pci_dev *pdev, - unsigned int ino) -{ - unsigned long imap, iclr; - unsigned long imap_off, iclr_off; - int inofixup = 0; - int virt_irq; - - ino &= PCI_IRQ_INO; - if (ino < SABRE_ONBOARD_IRQ_BASE) { - /* PCI slot */ - imap_off = sabre_pcislot_imap_offset(ino); - } else { - /* onboard device */ - if (ino > SABRE_ONBOARD_IRQ_LAST) { - prom_printf("sabre_irq_build: Wacky INO [%x]\n", ino); - prom_halt(); - } - imap_off = sabre_onboard_imap_offset(ino); - } - - /* Now build the IRQ bucket. */ - imap = pbm->controller_regs + imap_off; - imap += 4; - - iclr_off = sabre_iclr_offset(ino); - iclr = pbm->controller_regs + iclr_off; - iclr += 4; - - if ((ino & 0x20) == 0) - inofixup = ino & 0x03; - - virt_irq = build_irq(inofixup, iclr, imap); - - if (pdev) { - struct pcidev_cookie *pcp = pdev->sysdata; - - if (pdev->bus->number != pcp->pbm->pci_first_busno) { - struct pci_controller_info *p = pcp->pbm->parent; - - irq_install_pre_handler(virt_irq, - sabre_wsync_handler, - pdev, - (void *) - p->pbm_A.controller_regs + - SABRE_WRSYNC); - } - } - return virt_irq; -} - /* SABRE error handling support. */ static void sabre_check_iommu_error(struct pci_controller_info *p, unsigned long afsr, @@ -929,17 +821,30 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs return IRQ_HANDLED; } -/* XXX What about PowerFail/PowerManagement??? -DaveM */ -#define SABRE_UE_INO 0x2e -#define SABRE_CE_INO 0x2f -#define SABRE_PCIERR_INO 0x30 static void sabre_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */ + struct device_node *dp = pbm->prom_node; + struct of_device *op; unsigned long base = pbm->controller_regs; - unsigned long irq, portid = pbm->portid; u64 tmp; + if (pbm->chip_type == PBM_CHIP_TYPE_SABRE) + dp = dp->parent; + + op = of_find_device_by_node(dp); + if (!op) + return; + + /* Sabre/Hummingbird IRQ property layout is: + * 0: PCI ERR + * 1: UE ERR + * 2: CE ERR + * 3: POWER FAIL + */ + if (op->num_irqs < 4) + return; + /* We clear the error bits in the appropriate AFSR before * registering the handler so that we don't get spurious * interrupts. @@ -948,32 +853,16 @@ static void sabre_register_error_handlers(struct pci_controller_info *p) (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR | SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR | SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE)); - irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_UE_INO); - if (request_irq(irq, sabre_ue_intr, - SA_SHIRQ, "SABRE UE", p) < 0) { - prom_printf("SABRE%d: Cannot register UE interrupt.\n", - p->index); - prom_halt(); - } + + request_irq(op->irqs[1], sabre_ue_intr, SA_SHIRQ, "SABRE UE", p); sabre_write(base + SABRE_CE_AFSR, (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR | SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR)); - irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_CE_INO); - if (request_irq(irq, sabre_ce_intr, - SA_SHIRQ, "SABRE CE", p) < 0) { - prom_printf("SABRE%d: Cannot register CE interrupt.\n", - p->index); - prom_halt(); - } - irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_PCIERR_INO); - if (request_irq(irq, sabre_pcierr_intr, - SA_SHIRQ, "SABRE PCIERR", p) < 0) { - prom_printf("SABRE%d: Cannot register PciERR interrupt.\n", - p->index); - prom_halt(); - } + request_irq(op->irqs[2], sabre_ce_intr, SA_SHIRQ, "SABRE CE", p); + request_irq(op->irqs[0], sabre_pcierr_intr, SA_SHIRQ, + "SABRE PCIERR", p); tmp = sabre_read(base + SABRE_PCICTRL); tmp |= SABRE_PCICTRL_ERREN; @@ -1492,7 +1381,6 @@ void sabre_init(struct device_node *dp, char *model_name) p->index = pci_num_controllers++; p->pbms_same_domain = 1; p->scan_bus = sabre_scan_bus; - p->irq_build = sabre_irq_build; p->base_address_update = sabre_base_address_update; p->resource_adjust = sabre_resource_adjust; p->pci_ops = &sabre_ops; diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index f16449ccd7bc..5c6e2a9b91f8 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -217,116 +217,6 @@ static struct pci_ops schizo_ops = { .write = schizo_write_pci_cfg, }; -/* SCHIZO interrupt mapping support. Unlike Psycho, for this controller the - * imap/iclr registers are per-PBM. - */ -#define SCHIZO_IMAP_BASE 0x1000UL -#define SCHIZO_ICLR_BASE 0x1400UL - -static unsigned long schizo_imap_offset(unsigned long ino) -{ - return SCHIZO_IMAP_BASE + (ino * 8UL); -} - -static unsigned long schizo_iclr_offset(unsigned long ino) -{ - return SCHIZO_ICLR_BASE + (ino * 8UL); -} - -static void tomatillo_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) -{ - unsigned long sync_reg = (unsigned long) _arg2; - u64 mask = 1UL << (ino & IMAP_INO); - u64 val; - int limit; - - schizo_write(sync_reg, mask); - - limit = 100000; - val = 0; - while (--limit) { - val = schizo_read(sync_reg); - if (!(val & mask)) - break; - } - if (limit <= 0) { - printk("tomatillo_wsync_handler: DMA won't sync [%lx:%lx]\n", - val, mask); - } - - if (_arg1) { - static unsigned char cacheline[64] - __attribute__ ((aligned (64))); - - __asm__ __volatile__("rd %%fprs, %0\n\t" - "or %0, %4, %1\n\t" - "wr %1, 0x0, %%fprs\n\t" - "stda %%f0, [%5] %6\n\t" - "wr %0, 0x0, %%fprs\n\t" - "membar #Sync" - : "=&r" (mask), "=&r" (val) - : "0" (mask), "1" (val), - "i" (FPRS_FEF), "r" (&cacheline[0]), - "i" (ASI_BLK_COMMIT_P)); - } -} - -static unsigned long schizo_ino_to_iclr(struct pci_pbm_info *pbm, - unsigned int ino) -{ - ino &= PCI_IRQ_INO; - return pbm->pbm_regs + schizo_iclr_offset(ino) + 4; -} - -static unsigned long schizo_ino_to_imap(struct pci_pbm_info *pbm, - unsigned int ino) -{ - ino &= PCI_IRQ_INO; - return pbm->pbm_regs + schizo_imap_offset(ino) + 4; -} - -static unsigned int schizo_irq_build(struct pci_pbm_info *pbm, - struct pci_dev *pdev, - unsigned int ino) -{ - unsigned long imap, iclr; - int ign_fixup; - int virt_irq; - - ino &= PCI_IRQ_INO; - - /* Now build the IRQ bucket. */ - imap = schizo_ino_to_imap(pbm, ino); - iclr = schizo_ino_to_iclr(pbm, ino); - - /* On Schizo, no inofixup occurs. This is because each - * INO has it's own IMAP register. On Psycho and Sabre - * there is only one IMAP register for each PCI slot even - * though four different INOs can be generated by each - * PCI slot. - * - * But, for JBUS variants (essentially, Tomatillo), we have - * to fixup the lowest bit of the interrupt group number. - */ - ign_fixup = 0; - if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { - if (pbm->portid & 1) - ign_fixup = (1 << 6); - } - - virt_irq = build_irq(ign_fixup, iclr, imap); - - if (pdev && pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { - irq_install_pre_handler(virt_irq, - tomatillo_wsync_handler, - ((pbm->chip_version <= 4) ? - (void *) 1 : (void *) 0), - (void *) pbm->sync_reg); - } - - return virt_irq; -} - /* SCHIZO error handling support. */ enum schizo_error_type { UE_ERR, CE_ERR, PCI_ERR, SAFARI_ERR @@ -362,34 +252,6 @@ struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino) return &p->pbm_A; } -static void schizo_clear_other_err_intr(struct pci_controller_info *p, int irq) -{ - struct pci_pbm_info *pbm; - unsigned long iclr; - - /* Do not clear the interrupt for the other PCI bus. - * - * This "ACK both PBM IRQs" only needs to be performed - * for chip-wide error interrupts. - */ - if ((irq & IMAP_INO) == SCHIZO_PCIERR_A_INO || - (irq & IMAP_INO) == SCHIZO_PCIERR_B_INO) - return; - - pbm = pbm_for_ino(p, irq); - if (pbm == &p->pbm_A) - pbm = &p->pbm_B; - else - pbm = &p->pbm_A; - - schizo_irq_build(pbm, NULL, - (pbm->portid << 6) | (irq & IMAP_INO)); - - iclr = schizo_ino_to_iclr(pbm, - (pbm->portid << 6) | (irq & IMAP_INO)); - upa_writel(ICLR_IDLE, iclr); -} - #define SCHIZO_STC_ERR 0xb800UL /* --> 0xba00 */ #define SCHIZO_STC_TAG 0xba00UL /* --> 0xba80 */ #define SCHIZO_STC_LINE 0xbb00UL /* --> 0xbb80 */ @@ -720,8 +582,6 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id, struct pt_regs *regs) /* Interrogate IOMMU for error status. */ schizo_check_iommu_error(p, UE_ERR); - schizo_clear_other_err_intr(p, irq); - return IRQ_HANDLED; } @@ -811,8 +671,6 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id, struct pt_regs *regs) printk("(none)"); printk("]\n"); - schizo_clear_other_err_intr(p, irq); - return IRQ_HANDLED; } @@ -1033,8 +891,6 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id, struct pt_regs *reg if (error_bits & (SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_SPERR)) pci_scan_for_parity_error(p, pbm, pbm->pci_bus); - schizo_clear_other_err_intr(p, irq); - return IRQ_HANDLED; } @@ -1090,7 +946,6 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs * printk("PCI%d: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n", p->index, errlog); - schizo_clear_other_err_intr(p, irq); return IRQ_HANDLED; } @@ -1098,7 +953,6 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs * p->index); schizo_check_iommu_error(p, SAFARI_ERR); - schizo_clear_other_err_intr(p, irq); return IRQ_HANDLED; } @@ -1130,74 +984,47 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs * static void tomatillo_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm; - unsigned int irq; + struct of_device *op; u64 tmp, err_mask, err_no_mask; - /* Build IRQs and register handlers. */ + /* Tomatillo IRQ property layout is: + * 0: PCIERR + * 1: UE ERR + * 2: CE ERR + * 3: SERR + * 4: POWER FAIL? + */ + pbm = pbm_for_ino(p, SCHIZO_UE_INO); - irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_UE_INO); - if (request_irq(irq, schizo_ue_intr, - SA_SHIRQ, "TOMATILLO UE", p) < 0) { - prom_printf("%s: Cannot register UE interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_UE_INO)); - upa_writel(tmp, (pbm->pbm_regs + - schizo_imap_offset(SCHIZO_UE_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[1], schizo_ue_intr, SA_SHIRQ, + "TOMATILLO_UE", p); pbm = pbm_for_ino(p, SCHIZO_CE_INO); - irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_CE_INO); - if (request_irq(irq, schizo_ce_intr, - SA_SHIRQ, "TOMATILLO CE", p) < 0) { - prom_printf("%s: Cannot register CE interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_CE_INO)); - upa_writel(tmp, (pbm->pbm_regs + - schizo_imap_offset(SCHIZO_CE_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[2], schizo_ce_intr, SA_SHIRQ, + "TOMATILLO CE", p); pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO); - irq = schizo_irq_build(pbm, NULL, ((pbm->portid << 6) | - SCHIZO_PCIERR_A_INO)); - if (request_irq(irq, schizo_pcierr_intr, - SA_SHIRQ, "TOMATILLO PCIERR", pbm) < 0) { - prom_printf("%s: Cannot register PBM A PciERR interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) | - SCHIZO_PCIERR_A_INO))); - upa_writel(tmp, (pbm->pbm_regs + - schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[0], schizo_pcierr_intr, SA_SHIRQ, + "TOMATILLO PCIERR-A", pbm); + pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO); - irq = schizo_irq_build(pbm, NULL, ((pbm->portid << 6) | - SCHIZO_PCIERR_B_INO)); - if (request_irq(irq, schizo_pcierr_intr, - SA_SHIRQ, "TOMATILLO PCIERR", pbm) < 0) { - prom_printf("%s: Cannot register PBM B PciERR interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) | - SCHIZO_PCIERR_B_INO))); - upa_writel(tmp, (pbm->pbm_regs + - schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[0], schizo_pcierr_intr, SA_SHIRQ, + "TOMATILLO PCIERR-B", pbm); pbm = pbm_for_ino(p, SCHIZO_SERR_INO); - irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_SERR_INO); - if (request_irq(irq, schizo_safarierr_intr, - SA_SHIRQ, "TOMATILLO SERR", p) < 0) { - prom_printf("%s: Cannot register SafariERR interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, ((pbm->portid << 6) | - SCHIZO_SERR_INO))); - upa_writel(tmp, (pbm->pbm_regs + - schizo_imap_offset(SCHIZO_SERR_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[3], schizo_safarierr_intr, SA_SHIRQ, + "TOMATILLO SERR", p); /* Enable UE and CE interrupts for controller. */ schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL, @@ -1265,64 +1092,47 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p) static void schizo_register_error_handlers(struct pci_controller_info *p) { struct pci_pbm_info *pbm; - unsigned int irq; + struct of_device *op; u64 tmp, err_mask, err_no_mask; - /* Build IRQs and register handlers. */ + /* Schizo IRQ property layout is: + * 0: PCIERR + * 1: UE ERR + * 2: CE ERR + * 3: SERR + * 4: POWER FAIL? + */ + pbm = pbm_for_ino(p, SCHIZO_UE_INO); - irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_UE_INO); - if (request_irq(irq, schizo_ue_intr, - SA_SHIRQ, "SCHIZO UE", p) < 0) { - prom_printf("%s: Cannot register UE interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_UE_INO)); - upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_UE_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[1], schizo_ue_intr, SA_SHIRQ, + "SCHIZO_UE", p); pbm = pbm_for_ino(p, SCHIZO_CE_INO); - irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_CE_INO); - if (request_irq(irq, schizo_ce_intr, - SA_SHIRQ, "SCHIZO CE", p) < 0) { - prom_printf("%s: Cannot register CE interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_CE_INO)); - upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_CE_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[2], schizo_ce_intr, SA_SHIRQ, + "SCHIZO CE", p); pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO); - irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_PCIERR_A_INO); - if (request_irq(irq, schizo_pcierr_intr, - SA_SHIRQ, "SCHIZO PCIERR", pbm) < 0) { - prom_printf("%s: Cannot register PBM A PciERR interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_PCIERR_A_INO)); - upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[0], schizo_pcierr_intr, SA_SHIRQ, + "SCHIZO PCIERR-A", pbm); + pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO); - irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_PCIERR_B_INO); - if (request_irq(irq, schizo_pcierr_intr, - SA_SHIRQ, "SCHIZO PCIERR", &p->pbm_B) < 0) { - prom_printf("%s: Cannot register PBM B PciERR interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_PCIERR_B_INO)); - upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[0], schizo_pcierr_intr, SA_SHIRQ, + "SCHIZO PCIERR-B", pbm); pbm = pbm_for_ino(p, SCHIZO_SERR_INO); - irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_SERR_INO); - if (request_irq(irq, schizo_safarierr_intr, - SA_SHIRQ, "SCHIZO SERR", p) < 0) { - prom_printf("%s: Cannot register SafariERR interrupt.\n", - pbm->name); - prom_halt(); - } - tmp = upa_readl(schizo_ino_to_imap(pbm, (pbm->portid << 6) | SCHIZO_SERR_INO)); - upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_SERR_INO) + 4)); + op = of_find_device_by_node(pbm->prom_node); + if (op) + request_irq(op->irqs[3], schizo_safarierr_intr, SA_SHIRQ, + "SCHIZO SERR", p); /* Enable UE and CE interrupts for controller. */ schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL, @@ -2022,7 +1832,6 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ p->scan_bus = (chip_type == PBM_CHIP_TYPE_TOMATILLO ? tomatillo_scan_bus : schizo_scan_bus); - p->irq_build = schizo_irq_build; p->base_address_update = schizo_base_address_update; p->resource_adjust = schizo_resource_adjust; p->pci_ops = &schizo_ops; diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index b69e2270a721..03ad4c06758e 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -843,15 +843,6 @@ static void pci_sun4v_scan_bus(struct pci_controller_info *p) /* XXX register error interrupt handlers XXX */ } -static unsigned int pci_sun4v_irq_build(struct pci_pbm_info *pbm, - struct pci_dev *pdev, - unsigned int devino) -{ - u32 devhandle = pbm->devhandle; - - return sun4v_build_irq(devhandle, devino); -} - static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource) { struct pcidev_cookie *pcp = pdev->sysdata; @@ -1200,7 +1191,6 @@ void sun4v_pci_init(struct device_node *dp, char *model_name) p->pbms_same_domain = 0; p->scan_bus = pci_sun4v_scan_bus; - p->irq_build = pci_sun4v_irq_build; p->base_address_update = pci_sun4v_base_address_update; p->resource_adjust = pci_sun4v_resource_adjust; p->pci_ops = &pci_sun4v_ops; diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c index 9496c7734014..4febeda958a3 100644 --- a/arch/sparc64/kernel/power.c +++ b/arch/sparc64/kernel/power.c @@ -17,9 +17,10 @@ #include <linux/pm.h> #include <asm/system.h> -#include <asm/ebus.h> -#include <asm/isa.h> #include <asm/auxio.h> +#include <asm/prom.h> +#include <asm/of_device.h> +#include <asm/io.h> #include <linux/unistd.h> @@ -30,6 +31,7 @@ int scons_pwroff = 1; #ifdef CONFIG_PCI +#include <linux/pci.h> static void __iomem *power_reg; static DECLARE_WAIT_QUEUE_HEAD(powerd_wait); @@ -115,27 +117,33 @@ static int __init has_button_interrupt(unsigned int irq, struct device_node *dp) return 1; } -static void __devinit power_probe_common(struct of_device *dev, struct resource *res, unsigned int irq) +static int __devinit power_probe(struct of_device *op, const struct of_device_id *match) { - power_reg = ioremap(res->start, 0x4); + struct resource *res = &op->resource[0]; + unsigned int irq= op->irqs[0]; - printk("power: Control reg at %p ... ", power_reg); + power_reg = of_ioremap(res, 0, 0x4, "power"); + + printk("%s: Control reg at %lx ... ", + op->node->name, res->start); poweroff_method = machine_halt; /* able to use the standard halt */ - if (has_button_interrupt(irq, dev->node)) { + if (has_button_interrupt(irq, op->node)) { if (kernel_thread(powerd, NULL, CLONE_FS) < 0) { printk("Failed to start power daemon.\n"); - return; + return 0; } printk("powerd running.\n"); if (request_irq(irq, - power_handler, SA_SHIRQ, "power", NULL) < 0) + power_handler, 0, "power", NULL) < 0) printk("power: Error, cannot register IRQ handler.\n"); } else { printk("not using powerd.\n"); } + + return 0; } static struct of_device_id power_match[] = { @@ -145,44 +153,15 @@ static struct of_device_id power_match[] = { {}, }; -static int __devinit ebus_power_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct linux_ebus_device *edev = to_ebus_device(&dev->dev); - struct resource *res = &edev->resource[0]; - unsigned int irq = edev->irqs[0]; - - power_probe_common(dev, res,irq); - - return 0; -} - -static struct of_platform_driver ebus_power_driver = { - .name = "power", - .match_table = power_match, - .probe = ebus_power_probe, -}; - -static int __devinit isa_power_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct sparc_isa_device *idev = to_isa_device(&dev->dev); - struct resource *res = &idev->resource; - unsigned int irq = idev->irq; - - power_probe_common(dev, res,irq); - - return 0; -} - -static struct of_platform_driver isa_power_driver = { +static struct of_platform_driver power_driver = { .name = "power", .match_table = power_match, - .probe = isa_power_probe, + .probe = power_probe, }; void __init power_init(void) { - of_register_driver(&ebus_power_driver, &ebus_bus_type); - of_register_driver(&isa_power_driver, &isa_bus_type); + of_register_driver(&power_driver, &of_bus_type); return; } #endif /* CONFIG_PCI */ diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 8e87e7ea0325..8a70c52c0447 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -15,6 +15,7 @@ * 2 of the License, or (at your option) any later version. */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/string.h> @@ -23,7 +24,11 @@ #include <linux/module.h> #include <asm/prom.h> +#include <asm/of_device.h> #include <asm/oplib.h> +#include <asm/irq.h> +#include <asm/asi.h> +#include <asm/upa.h> static struct device_node *allnodes; @@ -190,6 +195,36 @@ int of_getintprop_default(struct device_node *np, const char *name, int def) } EXPORT_SYMBOL(of_getintprop_default); +int of_n_addr_cells(struct device_node *np) +{ + int* ip; + do { + if (np->parent) + np = np->parent; + ip = of_get_property(np, "#address-cells", NULL); + if (ip != NULL) + return *ip; + } while (np->parent); + /* No #address-cells property for the root node, default to 2 */ + return 2; +} +EXPORT_SYMBOL(of_n_addr_cells); + +int of_n_size_cells(struct device_node *np) +{ + int* ip; + do { + if (np->parent) + np = np->parent; + ip = of_get_property(np, "#size-cells", NULL); + if (ip != NULL) + return *ip; + } while (np->parent); + /* No #size-cells property for the root node, default to 1 */ + return 1; +} +EXPORT_SYMBOL(of_n_size_cells); + int of_set_property(struct device_node *dp, const char *name, void *val, int len) { struct property **prevp; @@ -253,6 +288,754 @@ static void * __init prom_early_alloc(unsigned long size) return ret; } +#ifdef CONFIG_PCI +/* PSYCHO interrupt mapping support. */ +#define PSYCHO_IMAP_A_SLOT0 0x0c00UL +#define PSYCHO_IMAP_B_SLOT0 0x0c20UL +static unsigned long psycho_pcislot_imap_offset(unsigned long ino) +{ + unsigned int bus = (ino & 0x10) >> 4; + unsigned int slot = (ino & 0x0c) >> 2; + + if (bus == 0) + return PSYCHO_IMAP_A_SLOT0 + (slot * 8); + else + return PSYCHO_IMAP_B_SLOT0 + (slot * 8); +} + +#define PSYCHO_IMAP_SCSI 0x1000UL +#define PSYCHO_IMAP_ETH 0x1008UL +#define PSYCHO_IMAP_BPP 0x1010UL +#define PSYCHO_IMAP_AU_REC 0x1018UL +#define PSYCHO_IMAP_AU_PLAY 0x1020UL +#define PSYCHO_IMAP_PFAIL 0x1028UL +#define PSYCHO_IMAP_KMS 0x1030UL +#define PSYCHO_IMAP_FLPY 0x1038UL +#define PSYCHO_IMAP_SHW 0x1040UL +#define PSYCHO_IMAP_KBD 0x1048UL +#define PSYCHO_IMAP_MS 0x1050UL +#define PSYCHO_IMAP_SER 0x1058UL +#define PSYCHO_IMAP_TIM0 0x1060UL +#define PSYCHO_IMAP_TIM1 0x1068UL +#define PSYCHO_IMAP_UE 0x1070UL +#define PSYCHO_IMAP_CE 0x1078UL +#define PSYCHO_IMAP_A_ERR 0x1080UL +#define PSYCHO_IMAP_B_ERR 0x1088UL +#define PSYCHO_IMAP_PMGMT 0x1090UL +#define PSYCHO_IMAP_GFX 0x1098UL +#define PSYCHO_IMAP_EUPA 0x10a0UL + +static unsigned long __psycho_onboard_imap_off[] = { +/*0x20*/ PSYCHO_IMAP_SCSI, +/*0x21*/ PSYCHO_IMAP_ETH, +/*0x22*/ PSYCHO_IMAP_BPP, +/*0x23*/ PSYCHO_IMAP_AU_REC, +/*0x24*/ PSYCHO_IMAP_AU_PLAY, +/*0x25*/ PSYCHO_IMAP_PFAIL, +/*0x26*/ PSYCHO_IMAP_KMS, +/*0x27*/ PSYCHO_IMAP_FLPY, +/*0x28*/ PSYCHO_IMAP_SHW, +/*0x29*/ PSYCHO_IMAP_KBD, +/*0x2a*/ PSYCHO_IMAP_MS, +/*0x2b*/ PSYCHO_IMAP_SER, +/*0x2c*/ PSYCHO_IMAP_TIM0, +/*0x2d*/ PSYCHO_IMAP_TIM1, +/*0x2e*/ PSYCHO_IMAP_UE, +/*0x2f*/ PSYCHO_IMAP_CE, +/*0x30*/ PSYCHO_IMAP_A_ERR, +/*0x31*/ PSYCHO_IMAP_B_ERR, +/*0x32*/ PSYCHO_IMAP_PMGMT +}; +#define PSYCHO_ONBOARD_IRQ_BASE 0x20 +#define PSYCHO_ONBOARD_IRQ_LAST 0x32 +#define psycho_onboard_imap_offset(__ino) \ + __psycho_onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE] + +#define PSYCHO_ICLR_A_SLOT0 0x1400UL +#define PSYCHO_ICLR_SCSI 0x1800UL + +#define psycho_iclr_offset(ino) \ + ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ + (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) + +static unsigned int psycho_irq_build(struct device_node *dp, + unsigned int ino, + void *_data) +{ + unsigned long controller_regs = (unsigned long) _data; + unsigned long imap, iclr; + unsigned long imap_off, iclr_off; + int inofixup = 0; + + ino &= 0x3f; + if (ino < PSYCHO_ONBOARD_IRQ_BASE) { + /* PCI slot */ + imap_off = psycho_pcislot_imap_offset(ino); + } else { + /* Onboard device */ + if (ino > PSYCHO_ONBOARD_IRQ_LAST) { + prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino); + prom_halt(); + } + imap_off = psycho_onboard_imap_offset(ino); + } + + /* Now build the IRQ bucket. */ + imap = controller_regs + imap_off; + imap += 4; + + iclr_off = psycho_iclr_offset(ino); + iclr = controller_regs + iclr_off; + iclr += 4; + + if ((ino & 0x20) == 0) + inofixup = ino & 0x03; + + return build_irq(inofixup, iclr, imap); +} + +static void psycho_irq_trans_init(struct device_node *dp) +{ + struct linux_prom64_registers *regs; + + dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); + dp->irq_trans->irq_build = psycho_irq_build; + + regs = of_get_property(dp, "reg", NULL); + dp->irq_trans->data = (void *) regs[2].phys_addr; +} + +#define sabre_read(__reg) \ +({ u64 __ret; \ + __asm__ __volatile__("ldxa [%1] %2, %0" \ + : "=r" (__ret) \ + : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory"); \ + __ret; \ +}) + +struct sabre_irq_data { + unsigned long controller_regs; + unsigned int pci_first_busno; +}; +#define SABRE_CONFIGSPACE 0x001000000UL +#define SABRE_WRSYNC 0x1c20UL + +#define SABRE_CONFIG_BASE(CONFIG_SPACE) \ + (CONFIG_SPACE | (1UL << 24)) +#define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG) \ + (((unsigned long)(BUS) << 16) | \ + ((unsigned long)(DEVFN) << 8) | \ + ((unsigned long)(REG))) + +/* When a device lives behind a bridge deeper in the PCI bus topology + * than APB, a special sequence must run to make sure all pending DMA + * transfers at the time of IRQ delivery are visible in the coherency + * domain by the cpu. This sequence is to perform a read on the far + * side of the non-APB bridge, then perform a read of Sabre's DMA + * write-sync register. + */ +static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) +{ + unsigned int phys_hi = (unsigned int) (unsigned long) _arg1; + struct sabre_irq_data *irq_data = _arg2; + unsigned long controller_regs = irq_data->controller_regs; + unsigned long sync_reg = controller_regs + SABRE_WRSYNC; + unsigned long config_space = controller_regs + SABRE_CONFIGSPACE; + unsigned int bus, devfn; + u16 _unused; + + config_space = SABRE_CONFIG_BASE(config_space); + + bus = (phys_hi >> 16) & 0xff; + devfn = (phys_hi >> 8) & 0xff; + + config_space |= SABRE_CONFIG_ENCODE(bus, devfn, 0x00); + + __asm__ __volatile__("membar #Sync\n\t" + "lduha [%1] %2, %0\n\t" + "membar #Sync" + : "=r" (_unused) + : "r" ((u16 *) config_space), + "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + + sabre_read(sync_reg); +} + +#define SABRE_IMAP_A_SLOT0 0x0c00UL +#define SABRE_IMAP_B_SLOT0 0x0c20UL +#define SABRE_IMAP_SCSI 0x1000UL +#define SABRE_IMAP_ETH 0x1008UL +#define SABRE_IMAP_BPP 0x1010UL +#define SABRE_IMAP_AU_REC 0x1018UL +#define SABRE_IMAP_AU_PLAY 0x1020UL +#define SABRE_IMAP_PFAIL 0x1028UL +#define SABRE_IMAP_KMS 0x1030UL +#define SABRE_IMAP_FLPY 0x1038UL +#define SABRE_IMAP_SHW 0x1040UL +#define SABRE_IMAP_KBD 0x1048UL +#define SABRE_IMAP_MS 0x1050UL +#define SABRE_IMAP_SER 0x1058UL +#define SABRE_IMAP_UE 0x1070UL +#define SABRE_IMAP_CE 0x1078UL +#define SABRE_IMAP_PCIERR 0x1080UL +#define SABRE_IMAP_GFX 0x1098UL +#define SABRE_IMAP_EUPA 0x10a0UL +#define SABRE_ICLR_A_SLOT0 0x1400UL +#define SABRE_ICLR_B_SLOT0 0x1480UL +#define SABRE_ICLR_SCSI 0x1800UL +#define SABRE_ICLR_ETH 0x1808UL +#define SABRE_ICLR_BPP 0x1810UL +#define SABRE_ICLR_AU_REC 0x1818UL +#define SABRE_ICLR_AU_PLAY 0x1820UL +#define SABRE_ICLR_PFAIL 0x1828UL +#define SABRE_ICLR_KMS 0x1830UL +#define SABRE_ICLR_FLPY 0x1838UL +#define SABRE_ICLR_SHW 0x1840UL +#define SABRE_ICLR_KBD 0x1848UL +#define SABRE_ICLR_MS 0x1850UL +#define SABRE_ICLR_SER 0x1858UL +#define SABRE_ICLR_UE 0x1870UL +#define SABRE_ICLR_CE 0x1878UL +#define SABRE_ICLR_PCIERR 0x1880UL + +static unsigned long sabre_pcislot_imap_offset(unsigned long ino) +{ + unsigned int bus = (ino & 0x10) >> 4; + unsigned int slot = (ino & 0x0c) >> 2; + + if (bus == 0) + return SABRE_IMAP_A_SLOT0 + (slot * 8); + else + return SABRE_IMAP_B_SLOT0 + (slot * 8); +} + +static unsigned long __sabre_onboard_imap_off[] = { +/*0x20*/ SABRE_IMAP_SCSI, +/*0x21*/ SABRE_IMAP_ETH, +/*0x22*/ SABRE_IMAP_BPP, +/*0x23*/ SABRE_IMAP_AU_REC, +/*0x24*/ SABRE_IMAP_AU_PLAY, +/*0x25*/ SABRE_IMAP_PFAIL, +/*0x26*/ SABRE_IMAP_KMS, +/*0x27*/ SABRE_IMAP_FLPY, +/*0x28*/ SABRE_IMAP_SHW, +/*0x29*/ SABRE_IMAP_KBD, +/*0x2a*/ SABRE_IMAP_MS, +/*0x2b*/ SABRE_IMAP_SER, +/*0x2c*/ 0 /* reserved */, +/*0x2d*/ 0 /* reserved */, +/*0x2e*/ SABRE_IMAP_UE, +/*0x2f*/ SABRE_IMAP_CE, +/*0x30*/ SABRE_IMAP_PCIERR, +}; +#define SABRE_ONBOARD_IRQ_BASE 0x20 +#define SABRE_ONBOARD_IRQ_LAST 0x30 +#define sabre_onboard_imap_offset(__ino) \ + __sabre_onboard_imap_off[(__ino) - SABRE_ONBOARD_IRQ_BASE] + +#define sabre_iclr_offset(ino) \ + ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ + (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) + +static unsigned int sabre_irq_build(struct device_node *dp, + unsigned int ino, + void *_data) +{ + struct sabre_irq_data *irq_data = _data; + unsigned long controller_regs = irq_data->controller_regs; + struct linux_prom_pci_registers *regs; + unsigned long imap, iclr; + unsigned long imap_off, iclr_off; + int inofixup = 0; + int virt_irq; + + ino &= 0x3f; + if (ino < SABRE_ONBOARD_IRQ_BASE) { + /* PCI slot */ + imap_off = sabre_pcislot_imap_offset(ino); + } else { + /* onboard device */ + if (ino > SABRE_ONBOARD_IRQ_LAST) { + prom_printf("sabre_irq_build: Wacky INO [%x]\n", ino); + prom_halt(); + } + imap_off = sabre_onboard_imap_offset(ino); + } + + /* Now build the IRQ bucket. */ + imap = controller_regs + imap_off; + imap += 4; + + iclr_off = sabre_iclr_offset(ino); + iclr = controller_regs + iclr_off; + iclr += 4; + + if ((ino & 0x20) == 0) + inofixup = ino & 0x03; + + virt_irq = build_irq(inofixup, iclr, imap); + + regs = of_get_property(dp, "reg", NULL); + if (regs && + ((regs->phys_hi >> 16) & 0xff) != irq_data->pci_first_busno) { + irq_install_pre_handler(virt_irq, + sabre_wsync_handler, + (void *) (long) regs->phys_hi, + (void *) + controller_regs + + SABRE_WRSYNC); + } + + return virt_irq; +} + +static void sabre_irq_trans_init(struct device_node *dp) +{ + struct linux_prom64_registers *regs; + struct sabre_irq_data *irq_data; + u32 *busrange; + + dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); + dp->irq_trans->irq_build = sabre_irq_build; + + irq_data = prom_early_alloc(sizeof(struct sabre_irq_data)); + + regs = of_get_property(dp, "reg", NULL); + irq_data->controller_regs = regs[0].phys_addr; + + busrange = of_get_property(dp, "bus-range", NULL); + irq_data->pci_first_busno = busrange[0]; + + dp->irq_trans->data = irq_data; +} + +/* SCHIZO interrupt mapping support. Unlike Psycho, for this controller the + * imap/iclr registers are per-PBM. + */ +#define SCHIZO_IMAP_BASE 0x1000UL +#define SCHIZO_ICLR_BASE 0x1400UL + +static unsigned long schizo_imap_offset(unsigned long ino) +{ + return SCHIZO_IMAP_BASE + (ino * 8UL); +} + +static unsigned long schizo_iclr_offset(unsigned long ino) +{ + return SCHIZO_ICLR_BASE + (ino * 8UL); +} + +static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs, + unsigned int ino) +{ + return pbm_regs + schizo_iclr_offset(ino) + 4; +} + +static unsigned long schizo_ino_to_imap(unsigned long pbm_regs, + unsigned int ino) +{ + return pbm_regs + schizo_imap_offset(ino) + 4; +} + +#define schizo_read(__reg) \ +({ u64 __ret; \ + __asm__ __volatile__("ldxa [%1] %2, %0" \ + : "=r" (__ret) \ + : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory"); \ + __ret; \ +}) +#define schizo_write(__reg, __val) \ + __asm__ __volatile__("stxa %0, [%1] %2" \ + : /* no outputs */ \ + : "r" (__val), "r" (__reg), \ + "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory") + +static void tomatillo_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) +{ + unsigned long sync_reg = (unsigned long) _arg2; + u64 mask = 1UL << (ino & IMAP_INO); + u64 val; + int limit; + + schizo_write(sync_reg, mask); + + limit = 100000; + val = 0; + while (--limit) { + val = schizo_read(sync_reg); + if (!(val & mask)) + break; + } + if (limit <= 0) { + printk("tomatillo_wsync_handler: DMA won't sync [%lx:%lx]\n", + val, mask); + } + + if (_arg1) { + static unsigned char cacheline[64] + __attribute__ ((aligned (64))); + + __asm__ __volatile__("rd %%fprs, %0\n\t" + "or %0, %4, %1\n\t" + "wr %1, 0x0, %%fprs\n\t" + "stda %%f0, [%5] %6\n\t" + "wr %0, 0x0, %%fprs\n\t" + "membar #Sync" + : "=&r" (mask), "=&r" (val) + : "0" (mask), "1" (val), + "i" (FPRS_FEF), "r" (&cacheline[0]), + "i" (ASI_BLK_COMMIT_P)); + } +} + +struct schizo_irq_data { + unsigned long pbm_regs; + unsigned long sync_reg; + u32 portid; + int chip_version; +}; + +static unsigned int schizo_irq_build(struct device_node *dp, + unsigned int ino, + void *_data) +{ + struct schizo_irq_data *irq_data = _data; + unsigned long pbm_regs = irq_data->pbm_regs; + unsigned long imap, iclr; + int ign_fixup; + int virt_irq; + int is_tomatillo; + + ino &= 0x3f; + + /* Now build the IRQ bucket. */ + imap = schizo_ino_to_imap(pbm_regs, ino); + iclr = schizo_ino_to_iclr(pbm_regs, ino); + + /* On Schizo, no inofixup occurs. This is because each + * INO has it's own IMAP register. On Psycho and Sabre + * there is only one IMAP register for each PCI slot even + * though four different INOs can be generated by each + * PCI slot. + * + * But, for JBUS variants (essentially, Tomatillo), we have + * to fixup the lowest bit of the interrupt group number. + */ + ign_fixup = 0; + + is_tomatillo = (irq_data->sync_reg != 0UL); + + if (is_tomatillo) { + if (irq_data->portid & 1) + ign_fixup = (1 << 6); + } + + virt_irq = build_irq(ign_fixup, iclr, imap); + + if (is_tomatillo) { + irq_install_pre_handler(virt_irq, + tomatillo_wsync_handler, + ((irq_data->chip_version <= 4) ? + (void *) 1 : (void *) 0), + (void *) irq_data->sync_reg); + } + + return virt_irq; +} + +static void schizo_irq_trans_init(struct device_node *dp) +{ + struct linux_prom64_registers *regs; + struct schizo_irq_data *irq_data; + + dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); + dp->irq_trans->irq_build = schizo_irq_build; + + irq_data = prom_early_alloc(sizeof(struct schizo_irq_data)); + + regs = of_get_property(dp, "reg", NULL); + dp->irq_trans->data = irq_data; + + irq_data->pbm_regs = regs[0].phys_addr; + irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL; + irq_data->portid = of_getintprop_default(dp, "portid", 0); + irq_data->chip_version = of_getintprop_default(dp, "version#", 0); +} + +static unsigned int pci_sun4v_irq_build(struct device_node *dp, + unsigned int devino, + void *_data) +{ + u32 devhandle = (u32) (unsigned long) _data; + + return sun4v_build_irq(devhandle, devino); +} + +static void pci_sun4v_irq_trans_init(struct device_node *dp) +{ + struct linux_prom64_registers *regs; + + dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); + dp->irq_trans->irq_build = pci_sun4v_irq_build; + + regs = of_get_property(dp, "reg", NULL); + dp->irq_trans->data = (void *) (unsigned long) + ((regs->phys_addr >> 32UL) & 0x0fffffff); +} +#endif /* CONFIG_PCI */ + +#ifdef CONFIG_SBUS +/* INO number to IMAP register offset for SYSIO external IRQ's. + * This should conform to both Sunfire/Wildfire server and Fusion + * desktop designs. + */ +#define SYSIO_IMAP_SLOT0 0x2c04UL +#define SYSIO_IMAP_SLOT1 0x2c0cUL +#define SYSIO_IMAP_SLOT2 0x2c14UL +#define SYSIO_IMAP_SLOT3 0x2c1cUL +#define SYSIO_IMAP_SCSI 0x3004UL +#define SYSIO_IMAP_ETH 0x300cUL +#define SYSIO_IMAP_BPP 0x3014UL +#define SYSIO_IMAP_AUDIO 0x301cUL +#define SYSIO_IMAP_PFAIL 0x3024UL +#define SYSIO_IMAP_KMS 0x302cUL +#define SYSIO_IMAP_FLPY 0x3034UL +#define SYSIO_IMAP_SHW 0x303cUL +#define SYSIO_IMAP_KBD 0x3044UL +#define SYSIO_IMAP_MS 0x304cUL +#define SYSIO_IMAP_SER 0x3054UL +#define SYSIO_IMAP_TIM0 0x3064UL +#define SYSIO_IMAP_TIM1 0x306cUL +#define SYSIO_IMAP_UE 0x3074UL +#define SYSIO_IMAP_CE 0x307cUL +#define SYSIO_IMAP_SBERR 0x3084UL +#define SYSIO_IMAP_PMGMT 0x308cUL +#define SYSIO_IMAP_GFX 0x3094UL +#define SYSIO_IMAP_EUPA 0x309cUL + +#define bogon ((unsigned long) -1) +static unsigned long sysio_irq_offsets[] = { + /* SBUS Slot 0 --> 3, level 1 --> 7 */ + SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, + SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, + SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, + SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, + SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, + SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, + SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, + SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, + + /* Onboard devices (not relevant/used on SunFire). */ + SYSIO_IMAP_SCSI, + SYSIO_IMAP_ETH, + SYSIO_IMAP_BPP, + bogon, + SYSIO_IMAP_AUDIO, + SYSIO_IMAP_PFAIL, + bogon, + bogon, + SYSIO_IMAP_KMS, + SYSIO_IMAP_FLPY, + SYSIO_IMAP_SHW, + SYSIO_IMAP_KBD, + SYSIO_IMAP_MS, + SYSIO_IMAP_SER, + bogon, + bogon, + SYSIO_IMAP_TIM0, + SYSIO_IMAP_TIM1, + bogon, + bogon, + SYSIO_IMAP_UE, + SYSIO_IMAP_CE, + SYSIO_IMAP_SBERR, + SYSIO_IMAP_PMGMT, +}; + +#undef bogon + +#define NUM_SYSIO_OFFSETS ARRAY_SIZE(sysio_irq_offsets) + +/* Convert Interrupt Mapping register pointer to associated + * Interrupt Clear register pointer, SYSIO specific version. + */ +#define SYSIO_ICLR_UNUSED0 0x3400UL +#define SYSIO_ICLR_SLOT0 0x340cUL +#define SYSIO_ICLR_SLOT1 0x344cUL +#define SYSIO_ICLR_SLOT2 0x348cUL +#define SYSIO_ICLR_SLOT3 0x34ccUL +static unsigned long sysio_imap_to_iclr(unsigned long imap) +{ + unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0; + return imap + diff; +} + +static unsigned int sbus_of_build_irq(struct device_node *dp, + unsigned int ino, + void *_data) +{ + unsigned long reg_base = (unsigned long) _data; + struct linux_prom_registers *regs; + unsigned long imap, iclr; + int sbus_slot = 0; + int sbus_level = 0; + + ino &= 0x3f; + + regs = of_get_property(dp, "reg", NULL); + if (regs) + sbus_slot = regs->which_io; + + if (ino < 0x20) + ino += (sbus_slot * 8); + + imap = sysio_irq_offsets[ino]; + if (imap == ((unsigned long)-1)) { + prom_printf("get_irq_translations: Bad SYSIO INO[%x]\n", + ino); + prom_halt(); + } + imap += reg_base; + + /* SYSIO inconsistency. For external SLOTS, we have to select + * the right ICLR register based upon the lower SBUS irq level + * bits. + */ + if (ino >= 0x20) { + iclr = sysio_imap_to_iclr(imap); + } else { + sbus_level = ino & 0x7; + + switch(sbus_slot) { + case 0: + iclr = reg_base + SYSIO_ICLR_SLOT0; + break; + case 1: + iclr = reg_base + SYSIO_ICLR_SLOT1; + break; + case 2: + iclr = reg_base + SYSIO_ICLR_SLOT2; + break; + default: + case 3: + iclr = reg_base + SYSIO_ICLR_SLOT3; + break; + }; + + iclr += ((unsigned long)sbus_level - 1UL) * 8UL; + } + return build_irq(sbus_level, iclr, imap); +} + +static void sbus_irq_trans_init(struct device_node *dp) +{ + struct linux_prom64_registers *regs; + + dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); + dp->irq_trans->irq_build = sbus_of_build_irq; + + regs = of_get_property(dp, "reg", NULL); + dp->irq_trans->data = (void *) (unsigned long) regs->phys_addr; +} +#endif /* CONFIG_SBUS */ + + +static unsigned int central_build_irq(struct device_node *dp, + unsigned int ino, + void *_data) +{ + struct device_node *central_dp = _data; + struct of_device *central_op = of_find_device_by_node(central_dp); + struct resource *res; + unsigned long imap, iclr; + u32 tmp; + + if (!strcmp(dp->name, "eeprom")) { + res = ¢ral_op->resource[5]; + } else if (!strcmp(dp->name, "zs")) { + res = ¢ral_op->resource[4]; + } else if (!strcmp(dp->name, "clock-board")) { + res = ¢ral_op->resource[3]; + } else { + return ino; + } + + imap = res->start + 0x00UL; + iclr = res->start + 0x10UL; + + /* Set the INO state to idle, and disable. */ + upa_writel(0, iclr); + upa_readl(iclr); + + tmp = upa_readl(imap); + tmp &= ~0x80000000; + upa_writel(tmp, imap); + + return build_irq(0, iclr, imap); +} + +static void central_irq_trans_init(struct device_node *dp) +{ + dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller)); + dp->irq_trans->irq_build = central_build_irq; + + dp->irq_trans->data = dp; +} + +struct irq_trans { + const char *name; + void (*init)(struct device_node *); +}; + +#ifdef CONFIG_PCI +static struct irq_trans pci_irq_trans_table[] = { + { "SUNW,sabre", sabre_irq_trans_init }, + { "pci108e,a000", sabre_irq_trans_init }, + { "pci108e,a001", sabre_irq_trans_init }, + { "SUNW,psycho", psycho_irq_trans_init }, + { "pci108e,8000", psycho_irq_trans_init }, + { "SUNW,schizo", schizo_irq_trans_init }, + { "pci108e,8001", schizo_irq_trans_init }, + { "SUNW,schizo+", schizo_irq_trans_init }, + { "pci108e,8002", schizo_irq_trans_init }, + { "SUNW,tomatillo", schizo_irq_trans_init }, + { "pci108e,a801", schizo_irq_trans_init }, + { "SUNW,sun4v-pci", pci_sun4v_irq_trans_init }, +}; +#endif + +static void irq_trans_init(struct device_node *dp) +{ + const char *model; + int i; + + model = of_get_property(dp, "model", NULL); + if (!model) + model = of_get_property(dp, "compatible", NULL); + if (!model) + return; + +#ifdef CONFIG_PCI + for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) { + struct irq_trans *t = &pci_irq_trans_table[i]; + + if (!strcmp(model, t->name)) + return t->init(dp); + } +#endif +#ifdef CONFIG_SBUS + if (!strcmp(dp->name, "sbus") || + !strcmp(dp->name, "sbi")) + return sbus_irq_trans_init(dp); +#endif + if (!strcmp(dp->name, "central")) + return central_irq_trans_init(dp->child); +} + static int is_root_node(const struct device_node *dp) { if (!dp) @@ -676,10 +1459,10 @@ static struct device_node * __init create_node(phandle node) dp->type = get_one_property(node, "device_type"); dp->node = node; - /* Build interrupts later... */ - dp->properties = build_prop_list(node); + irq_trans_init(dp); + return dp; } diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index ac05e0f692ef..ef68aa4fec65 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -1221,9 +1221,7 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) /* Now some Xfire specific grot... */ if (this_is_starfire) - sbus->starfire_cookie = starfire_hookup(sbus->portid); - else - sbus->starfire_cookie = NULL; + starfire_hookup(sbus->portid); sysio_register_error_handlers(sbus); } @@ -1269,8 +1267,6 @@ int __init sbus_arch_preinit(void) void __init sbus_arch_postinit(void) { extern void firetruck_init(void); - extern void clock_probe(void); firetruck_init(); - clock_probe(); } diff --git a/arch/sparc64/kernel/starfire.c b/arch/sparc64/kernel/starfire.c index ae859d40771e..b930fee7708a 100644 --- a/arch/sparc64/kernel/starfire.c +++ b/arch/sparc64/kernel/starfire.c @@ -54,7 +54,7 @@ struct starfire_irqinfo { static struct starfire_irqinfo *sflist = NULL; /* Beam me up Scott(McNeil)y... */ -void *starfire_hookup(int upaid) +void starfire_hookup(int upaid) { struct starfire_irqinfo *p; unsigned long treg_base, hwmid, i; @@ -81,8 +81,6 @@ void *starfire_hookup(int upaid) p->upaid = upaid; p->next = sflist; sflist = p; - - return (void *) p; } unsigned int starfire_translate(unsigned long imap, diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 348b82035561..5f3dd4d800cd 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -38,11 +38,8 @@ #include <asm/timer.h> #include <asm/irq.h> #include <asm/io.h> -#include <asm/sbus.h> -#include <asm/fhc.h> -#include <asm/pbm.h> -#include <asm/ebus.h> -#include <asm/isa.h> +#include <asm/prom.h> +#include <asm/of_device.h> #include <asm/starfire.h> #include <asm/smp.h> #include <asm/sections.h> @@ -770,237 +767,106 @@ static int __init clock_model_matches(char *model) return 1; } -static void __init __clock_assign_common(void __iomem *addr, char *model) +static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match) { - if (model[5] == '0' && model[6] == '2') { - mstk48t02_regs = addr; - } else if(model[5] == '0' && model[6] == '8') { - mstk48t08_regs = addr; - mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02; - } else { - mstk48t59_regs = addr; - mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; - } -} - -static void __init clock_assign_clk_reg(struct linux_prom_registers *clk_reg, - char *model) -{ - unsigned long addr; - - addr = ((unsigned long) clk_reg[0].phys_addr | - (((unsigned long) clk_reg[0].which_io) << 32UL)); - - __clock_assign_common((void __iomem *) addr, model); -} - -static int __init clock_probe_central(void) -{ - struct linux_prom_registers clk_reg[2], *pr; - struct device_node *dp; - char *model; + struct device_node *dp = op->node; + char *model = of_get_property(dp, "model", NULL); + unsigned long size, flags; + void __iomem *regs; - if (!central_bus) - return 0; - - /* Get Central FHC's prom node. */ - dp = central_bus->child->prom_node; - - /* Then get the first child device below it. */ - dp = dp->child; - - while (dp) { - model = of_get_property(dp, "model", NULL); - if (!model || !clock_model_matches(model)) - goto next_sibling; - - pr = of_get_property(dp, "reg", NULL); - memcpy(clk_reg, pr, sizeof(clk_reg)); - - apply_fhc_ranges(central_bus->child, clk_reg, 1); - apply_central_ranges(central_bus, clk_reg, 1); - - clock_assign_clk_reg(clk_reg, model); - return 1; + if (!model || !clock_model_matches(model)) + return -ENODEV; - next_sibling: - dp = dp->sibling; - } + /* On an Enterprise system there can be multiple mostek clocks. + * We should only match the one that is on the central FHC bus. + */ + if (!strcmp(dp->parent->name, "fhc") && + strcmp(dp->parent->parent->name, "central") != 0) + return -ENODEV; - return 0; -} + size = (op->resource[0].end - op->resource[0].start) + 1; + regs = of_ioremap(&op->resource[0], 0, size, "clock"); + if (!regs) + return -ENOMEM; -#ifdef CONFIG_PCI -static void __init clock_isa_ebus_assign_regs(struct resource *res, char *model) -{ if (!strcmp(model, "ds1287") || !strcmp(model, "m5819") || !strcmp(model, "m5819p") || !strcmp(model, "m5823")) { - ds1287_regs = res->start; + ds1287_regs = (unsigned long) regs; + } else if (model[5] == '0' && model[6] == '2') { + mstk48t02_regs = regs; + } else if(model[5] == '0' && model[6] == '8') { + mstk48t08_regs = regs; + mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02; } else { - mstk48t59_regs = (void __iomem *) res->start; + mstk48t59_regs = regs; mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; } -} - -static int __init clock_probe_one_ebus_dev(struct linux_ebus_device *edev) -{ - struct device_node *dp = edev->prom_node; - char *model; - - model = of_get_property(dp, "model", NULL); - if (!clock_model_matches(model)) - return 0; - clock_isa_ebus_assign_regs(&edev->resource[0], model); + printk(KERN_INFO "%s: Clock regs at %p\n", dp->full_name, regs); - return 1; -} - -static int __init clock_probe_ebus(void) -{ - struct linux_ebus *ebus; + local_irq_save(flags); - for_each_ebus(ebus) { - struct linux_ebus_device *edev; + if (mstk48t02_regs != NULL) { + /* Report a low battery voltage condition. */ + if (has_low_battery()) + prom_printf("NVRAM: Low battery voltage!\n"); - for_each_ebusdev(edev, ebus) { - if (clock_probe_one_ebus_dev(edev)) - return 1; - } + /* Kick start the clock if it is completely stopped. */ + if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) + kick_start_clock(); } - return 0; -} - -static int __init clock_probe_one_isa_dev(struct sparc_isa_device *idev) -{ - struct device_node *dp = idev->prom_node; - char *model; - - model = of_get_property(dp, "model", NULL); - if (!clock_model_matches(model)) - return 0; - - clock_isa_ebus_assign_regs(&idev->resource, model); - - return 1; -} - -static int __init clock_probe_isa(void) -{ - struct sparc_isa_bridge *isa_br; - - for_each_isa(isa_br) { - struct sparc_isa_device *isa_dev; - - for_each_isadev(isa_dev, isa_br) { - if (clock_probe_one_isa_dev(isa_dev)) - return 1; - } - } + set_system_time(); + + local_irq_restore(flags); return 0; } -#endif /* CONFIG_PCI */ - -#ifdef CONFIG_SBUS -static int __init clock_probe_one_sbus_dev(struct sbus_bus *sbus, struct sbus_dev *sdev) -{ - struct resource *res; - char model[64]; - void __iomem *addr; - - prom_getstring(sdev->prom_node, "model", model, sizeof(model)); - if (!clock_model_matches(model)) - return 0; - - res = &sdev->resource[0]; - addr = sbus_ioremap(res, 0, 0x800UL, "eeprom"); - __clock_assign_common(addr, model); - - return 1; -} - -static int __init clock_probe_sbus(void) -{ - struct sbus_bus *sbus; - - for_each_sbus(sbus) { - struct sbus_dev *sdev; - - for_each_sbusdev(sdev, sbus) { - if (clock_probe_one_sbus_dev(sbus, sdev)) - return 1; - } - } +static struct of_device_id clock_match[] = { + { + .name = "eeprom", + }, + { + .name = "rtc", + }, + {}, +}; - return 0; -} -#endif +static struct of_platform_driver clock_driver = { + .name = "clock", + .match_table = clock_match, + .probe = clock_probe, +}; -void __init clock_probe(void) +static int __init clock_init(void) { - static int invoked; - unsigned long flags; - - if (invoked) - return; - invoked = 1; - if (this_is_starfire) { xtime.tv_sec = starfire_get_time(); xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); - return; + return 0; } if (tlb_type == hypervisor) { xtime.tv_sec = hypervisor_get_time(); xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); - return; - } - - /* Check FHC Central then EBUSs then ISA bridges then SBUSs. - * That way we handle the presence of multiple properly. - * - * As a special case, machines with Central must provide the - * timer chip there. - */ - if (!clock_probe_central() && -#ifdef CONFIG_PCI - !clock_probe_ebus() && - !clock_probe_isa() && -#endif -#ifdef CONFIG_SBUS - !clock_probe_sbus() -#endif - ) { - printk(KERN_WARNING "No clock chip found.\n"); - return; - } - - local_irq_save(flags); - - if (mstk48t02_regs != NULL) { - /* Report a low battery voltage condition. */ - if (has_low_battery()) - prom_printf("NVRAM: Low battery voltage!\n"); - - /* Kick start the clock if it is completely stopped. */ - if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) - kick_start_clock(); + return 0; } - set_system_time(); - - local_irq_restore(flags); + return of_register_driver(&clock_driver, &of_bus_type); } +/* Must be after subsys_initcall() so that busses are probed. Must + * be before device_initcall() because things like the RTC driver + * need to see the clock registers. + */ +fs_initcall(clock_init); + /* This is gets the master TICK_INT timer going. */ static unsigned long sparc64_init_timers(void) { diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index bb2d68577855..a9b765271b85 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c @@ -20,6 +20,7 @@ #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/bitops.h> +#include <linux/kallsyms.h> #include <asm/fpumacro.h> /* #define DEBUG_MNA */ @@ -291,7 +292,8 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) if (count < 5) { last_time = jiffies; count++; - printk("Kernel unaligned access at TPC[%lx]\n", regs->tpc); + printk("Kernel unaligned access at TPC[%lx] ", regs->tpc); + print_symbol("%s\n", regs->tpc); } if (!ok_for_kernel(insn) || dir == both) { diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c index fc6669e8dde1..bc3df95bc057 100644 --- a/arch/sparc64/solaris/socksys.c +++ b/arch/sparc64/solaris/socksys.c @@ -26,7 +26,6 @@ #include <linux/slab.h> #include <linux/syscalls.h> #include <linux/in.h> -#include <linux/devfs_fs_kernel.h> #include <net/sock.h> @@ -190,8 +189,6 @@ init_socksys(void) return ret; } - devfs_mk_cdev(MKDEV(30, 0), S_IFCHR|S_IRUSR|S_IWUSR, "socksys"); - file = fcheck(ret); /* N.B. Is this valid? Suppose the f_ops are in a module ... */ socksys_file_ops = *file->f_op; @@ -207,5 +204,4 @@ cleanup_socksys(void) { if (unregister_chrdev(30, "socksys")) printk ("Couldn't unregister socksys character device\n"); - devfs_remove ("socksys"); } diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 6c2d4ccaf20f..5ca57ca33713 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -8,7 +8,6 @@ #include "linux/list.h" #include "linux/kd.h" #include "linux/interrupt.h" -#include "linux/devfs_fs_kernel.h" #include "asm/uaccess.h" #include "chan_kern.h" #include "irq_user.h" @@ -655,7 +654,6 @@ struct tty_driver *line_register_devfs(struct lines *set, driver->driver_name = line_driver->name; driver->name = line_driver->device_name; - driver->devfs_name = line_driver->devfs_name; driver->major = line_driver->major; driver->minor_start = line_driver->minor_start; driver->type = line_driver->type; diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index a4d6415bc8c4..6dafd6fbfdae 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -54,7 +54,6 @@ static int ssl_remove(int n); static struct line_driver driver = { .name = "UML serial line", .device_name = "ttyS", - .devfs_name = "tts/", .major = TTY_MAJOR, .minor_start = 64, .type = TTY_DRIVER_TYPE_SERIAL, diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 61db8b2fc83f..856f568c2687 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -60,7 +60,6 @@ static int con_remove(int n); static struct line_driver driver = { .name = "UML console", .device_name = "tty", - .devfs_name = "vc/", .major = TTY_MAJOR, .minor_start = 0, .type = TTY_DRIVER_TYPE_CONSOLE, diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 290cec6d69e2..0345e2551247 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -25,7 +25,6 @@ #include "linux/blkdev.h" #include "linux/hdreg.h" #include "linux/init.h" -#include "linux/devfs_fs_kernel.h" #include "linux/cdrom.h" #include "linux/proc_fs.h" #include "linux/ctype.h" @@ -628,7 +627,6 @@ static int ubd_new_disk(int major, u64 size, int unit, { struct gendisk *disk; - char from[sizeof("ubd/nnnnn\0")], to[sizeof("discnnnnn/disc\0")]; int err; disk = alloc_disk(1 << UBD_SHIFT); @@ -639,20 +637,10 @@ static int ubd_new_disk(int major, u64 size, int unit, disk->first_minor = unit << UBD_SHIFT; disk->fops = &ubd_blops; set_capacity(disk, size / 512); - if(major == MAJOR_NR){ + if(major == MAJOR_NR) sprintf(disk->disk_name, "ubd%c", 'a' + unit); - sprintf(disk->devfs_name, "ubd/disc%d", unit); - sprintf(from, "ubd/%d", unit); - sprintf(to, "disc%d/disc", unit); - err = devfs_mk_symlink(from, to); - if(err) - printk("ubd_new_disk failed to make link from %s to " - "%s, error = %d\n", from, to, err); - } - else { + else sprintf(disk->disk_name, "ubd_fake%d", unit); - sprintf(disk->devfs_name, "ubd_fake/disc%d", unit); - } /* sysfs register (not for ide fake devices) */ if (major == MAJOR_NR) { @@ -841,7 +829,6 @@ int ubd_init(void) { int i; - devfs_mk_dir("ubd"); if (register_blkdev(MAJOR_NR, "ubd")) return -1; @@ -855,7 +842,6 @@ int ubd_init(void) char name[sizeof("ubd_nnn\0")]; snprintf(name, sizeof(name), "ubd_%d", fake_major); - devfs_mk_dir(name); if (register_blkdev(fake_major, "ubd")) return -1; } diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 6ac0f8252e21..27bf2f6fbc05 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h @@ -17,7 +17,6 @@ struct line_driver { char *name; char *device_name; - char *devfs_name; short major; short minor_start; short type; diff --git a/arch/x86_64/kernel/functionlist b/arch/x86_64/kernel/functionlist index 2bcebdc3eedb..01fa23580c85 100644 --- a/arch/x86_64/kernel/functionlist +++ b/arch/x86_64/kernel/functionlist @@ -384,7 +384,6 @@ *(.text.__end_that_request_first) *(.text.wake_up_bit) *(.text.unuse_mm) -*(.text.skb_release_data) *(.text.shrink_icache_memory) *(.text.sched_balance_self) *(.text.__pmd_alloc) diff --git a/drivers/atm/he.c b/drivers/atm/he.c index fde9334059af..a486eb1f1640 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -1018,7 +1018,7 @@ he_init_irq(struct he_dev *he_dev) return 0; } -static int __init +static int __devinit he_start(struct atm_dev *dev) { struct he_dev *he_dev; diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c index 0aabfc2a59d9..325325afabec 100644 --- a/drivers/atm/idt77105.c +++ b/drivers/atm/idt77105.c @@ -358,7 +358,7 @@ static const struct atmphy_ops idt77105_ops = { }; -int idt77105_init(struct atm_dev *dev) +int __devinit idt77105_init(struct atm_dev *dev) { dev->phy = &idt77105_ops; return 0; diff --git a/drivers/atm/idt77105.h b/drivers/atm/idt77105.h index 8ba8218aaefe..3fd2bc899761 100644 --- a/drivers/atm/idt77105.h +++ b/drivers/atm/idt77105.h @@ -76,7 +76,7 @@ #define IDT77105_CTRSEL_RHEC 0x01 /* W, Rx HEC Error Counter */ #ifdef __KERNEL__ -int idt77105_init(struct atm_dev *dev) __init; +int idt77105_init(struct atm_dev *dev); #endif /* diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 2e2e50e1167a..333a7bc609d2 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -2284,7 +2284,7 @@ static int reset_sar(struct atm_dev *dev) } -static int __init ia_init(struct atm_dev *dev) +static int __devinit ia_init(struct atm_dev *dev) { IADEV *iadev; unsigned long real_base; @@ -2480,7 +2480,7 @@ static void ia_free_rx(IADEV *iadev) iadev->rx_dle_dma); } -static int __init ia_start(struct atm_dev *dev) +static int __devinit ia_start(struct atm_dev *dev) { IADEV *iadev; int error; diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c index b1d063cc4fbe..f04f39c00833 100644 --- a/drivers/atm/suni.c +++ b/drivers/atm/suni.c @@ -289,7 +289,7 @@ static const struct atmphy_ops suni_ops = { }; -int suni_init(struct atm_dev *dev) +int __devinit suni_init(struct atm_dev *dev) { unsigned char mri; diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index dd8a1501142f..50ca1aa4ee3b 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -2530,7 +2530,6 @@ static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) blk_queue_max_sectors(RequestQueue, Controller->MaxBlocksPerCommand); disk->queue = RequestQueue; sprintf(disk->disk_name, "rd/c%dd%d", Controller->ControllerNumber, n); - sprintf(disk->devfs_name, "rd/host%d/target%d", Controller->ControllerNumber, n); disk->major = MajorNumber; disk->first_minor = n << DAC960_MaxPartitionsBits; disk->fops = &DAC960_BlockDeviceOperations; diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index 196c0ec9cd54..a317e4303952 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -1732,13 +1732,10 @@ int acsi_init( void ) struct gendisk *disk = acsi_gendisk[i]; sprintf(disk->disk_name, "ad%c", 'a'+i); aip = &acsi_info[NDevices]; - sprintf(disk->devfs_name, "ad/target%d/lun%d", aip->target, aip->lun); disk->major = ACSI_MAJOR; disk->first_minor = i << 4; - if (acsi_info[i].type != HARDDISK) { + if (acsi_info[i].type != HARDDISK) disk->minors = 1; - strcat(disk->devfs_name, "/disc"); - } disk->fops = &acsi_fops; disk->private_data = &acsi_info[i]; set_capacity(disk, acsi_info[i].size); diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c index 4cb9c1336287..4030a8fd1187 100644 --- a/drivers/block/acsi_slm.c +++ b/drivers/block/acsi_slm.c @@ -65,7 +65,6 @@ not be guaranteed. There are several ways to assure this: #include <linux/time.h> #include <linux/mm.h> #include <linux/slab.h> -#include <linux/devfs_fs_kernel.h> #include <linux/smp_lock.h> #include <asm/pgtable.h> @@ -1005,11 +1004,6 @@ int slm_init( void ) BufferP = SLMBuffer; SLMState = IDLE; - devfs_mk_dir("slm"); - for (i = 0; i < MAX_SLM; i++) { - devfs_mk_cdev(MKDEV(ACSI_MAJOR, i), - S_IFCHR|S_IRUSR|S_IWUSR, "slm/%d", i); - } return 0; } @@ -1032,10 +1026,6 @@ int init_module(void) void cleanup_module(void) { - int i; - for (i = 0; i < MAX_SLM; i++) - devfs_remove("slm/%d", i); - devfs_remove("slm"); if (unregister_chrdev( ACSI_MAJOR, "slm" ) != 0) printk( KERN_ERR "acsi_slm: cleanup_module failed\n"); atari_stram_free( SLMBuffer ); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 39b0f53186e8..05fb08312c01 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -3248,7 +3248,6 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, q->queuedata = hba[i]; sprintf(disk->disk_name, "cciss/c%dd%d", i, j); - sprintf(disk->devfs_name, "cciss/host%d/target%d", i, j); disk->major = hba[i]->major; disk->first_minor = j << NWD_SHIFT; disk->fops = &cciss_fops; diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 5eb6fb7b5cfa..bfd245df0a8c 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -33,7 +33,6 @@ #include <linux/blkpg.h> #include <linux/timer.h> #include <linux/proc_fs.h> -#include <linux/devfs_fs_kernel.h> #include <linux/init.h> #include <linux/hdreg.h> #include <linux/spinlock.h> @@ -348,7 +347,6 @@ static void __devexit cpqarray_remove_one(int i) for(j = 0; j < NWD; j++) { if (ida_gendisk[i][j]->flags & GENHD_FL_UP) del_gendisk(ida_gendisk[i][j]); - devfs_remove("ida/c%dd%d",i,j); put_disk(ida_gendisk[i][j]); } blk_cleanup_queue(hba[i]->queue); @@ -1807,8 +1805,6 @@ static void getgeometry(int ctlr) } - sprintf(disk->devfs_name, "ida/c%dd%d", ctlr, log_unit); - info_p->phys_drives = sense_config_buf->ctlr_phys_drv; info_p->drv_assign_map @@ -1844,7 +1840,6 @@ static void __exit cpqarray_exit(void) } } - devfs_remove("ida"); remove_proc_entry("cpqarray", proc_root_driver); } diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index dff1e67b1dd4..0242cbb86a87 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -177,7 +177,6 @@ static int print_unex = 1; #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/init.h> -#include <linux/devfs_fs_kernel.h> #include <linux/platform_device.h> #include <linux/buffer_head.h> /* for invalidate_buffers() */ #include <linux/mutex.h> @@ -224,7 +223,6 @@ static struct completion device_release; static unsigned short virtual_dma_port = 0x3f0; irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int set_dor(int fdc, char mask, char data); -static void register_devfs_entries(int drive) __init; #define K_64 0x10000 /* 64KB */ @@ -3676,7 +3674,6 @@ static void __init config_types(void) first = 0; } printk("%s fd%d is %s", prepend, drive, name); - register_devfs_entries(drive); } *UDP = *params; } @@ -3954,37 +3951,6 @@ static struct block_device_operations floppy_fops = { .media_changed = check_floppy_change, .revalidate_disk = floppy_revalidate, }; -static char *table[] = { - "", "d360", "h1200", "u360", "u720", "h360", "h720", - "u1440", "u2880", "CompaQ", "h1440", "u1680", "h410", - "u820", "h1476", "u1722", "h420", "u830", "h1494", "u1743", - "h880", "u1040", "u1120", "h1600", "u1760", "u1920", - "u3200", "u3520", "u3840", "u1840", "u800", "u1600", - NULL -}; -static int t360[] = { 1, 0 }, - t1200[] = { 2, 5, 6, 10, 12, 14, 16, 18, 20, 23, 0 }, - t3in[] = { 8, 9, 26, 27, 28, 7, 11, 15, 19, 24, 25, 29, 31, 3, 4, 13, - 17, 21, 22, 30, 0 }; -static int *table_sup[] = - { NULL, t360, t1200, t3in + 5 + 8, t3in + 5, t3in, t3in }; - -static void __init register_devfs_entries(int drive) -{ - int base_minor = (drive < 4) ? drive : (124 + drive); - - if (UDP->cmos < ARRAY_SIZE(default_drive_params)) { - int i = 0; - do { - int minor = base_minor + (table_sup[UDP->cmos][i] << 2); - - devfs_mk_bdev(MKDEV(FLOPPY_MAJOR, minor), - S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP | - S_IWGRP, "floppy/%d%s", drive, - table[table_sup[UDP->cmos][i]]); - } while (table_sup[UDP->cmos][i++]); - } -} /* * Floppy Driver initialization @@ -4261,11 +4227,9 @@ static int __init floppy_init(void) motor_off_timer[dr].function = motor_off_callback; } - devfs_mk_dir("floppy"); - err = register_blkdev(FLOPPY_MAJOR, "fd"); if (err) - goto out_devfs_remove; + goto out_put_disk; floppy_queue = blk_init_queue(do_fd_request, &floppy_lock); if (!floppy_queue) { @@ -4424,8 +4388,6 @@ out_unreg_region: blk_cleanup_queue(floppy_queue); out_unreg_blkdev: unregister_blkdev(FLOPPY_MAJOR, "fd"); -out_devfs_remove: - devfs_remove("floppy"); out_put_disk: while (dr--) { del_timer(&motor_off_timer[dr]); @@ -4586,19 +4548,6 @@ static void floppy_release_irq_and_dma(void) static char *floppy; -static void unregister_devfs_entries(int drive) -{ - int i; - - if (UDP->cmos < ARRAY_SIZE(default_drive_params)) { - i = 0; - do { - devfs_remove("floppy/%d%s", drive, - table[table_sup[UDP->cmos][i]]); - } while (table_sup[UDP->cmos][i++]); - } -} - static void __init parse_floppy_cfg_string(char *cfg) { char *ptr; @@ -4635,13 +4584,11 @@ void cleanup_module(void) if ((allowed_drive_mask & (1 << drive)) && fdc_state[FDC(drive)].version != FDC_NONE) { del_gendisk(disks[drive]); - unregister_devfs_entries(drive); device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos); platform_device_unregister(&floppy_device[drive]); } put_disk(disks[drive]); } - devfs_remove("floppy"); del_timer_sync(&fd_timeout); del_timer_sync(&fd_timer); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 18dd026f470d..013c5daddb0b 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -63,7 +63,6 @@ #include <linux/blkdev.h> #include <linux/blkpg.h> #include <linux/init.h> -#include <linux/devfs_fs_kernel.h> #include <linux/smp_lock.h> #include <linux/swap.h> #include <linux/slab.h> @@ -1277,8 +1276,6 @@ static int __init loop_init(void) goto out_mem3; } - devfs_mk_dir("loop"); - for (i = 0; i < max_loop; i++) { struct loop_device *lo = &loop_dev[i]; struct gendisk *disk = disks[i]; @@ -1296,7 +1293,6 @@ static int __init loop_init(void) disk->first_minor = i; disk->fops = &lo_fops; sprintf(disk->disk_name, "loop%d", i); - sprintf(disk->devfs_name, "loop/%d", i); disk->private_data = lo; disk->queue = lo->lo_queue; } @@ -1310,7 +1306,6 @@ static int __init loop_init(void) out_mem4: while (i--) blk_cleanup_queue(loop_dev[i].lo_queue); - devfs_remove("loop"); i = max_loop; out_mem3: while (i--) @@ -1333,7 +1328,6 @@ static void loop_exit(void) blk_cleanup_queue(loop_dev[i].lo_queue); put_disk(disks[i]); } - devfs_remove("loop"); if (unregister_blkdev(LOOP_MAJOR, "loop")) printk(KERN_WARNING "loop: cannot unregister blkdev\n"); diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 7f554f2ed079..39662f0c9cce 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -29,8 +29,6 @@ #include <linux/kernel.h> #include <net/sock.h> -#include <linux/devfs_fs_kernel.h> - #include <asm/uaccess.h> #include <asm/system.h> #include <asm/types.h> @@ -642,7 +640,6 @@ static int __init nbd_init(void) printk(KERN_INFO "nbd: registered device at major %d\n", NBD_MAJOR); dprintk(DBG_INIT, "nbd: debugflags=0x%x\n", debugflags); - devfs_mk_dir("nbd"); for (i = 0; i < nbds_max; i++) { struct gendisk *disk = nbd_dev[i].disk; nbd_dev[i].file = NULL; @@ -660,7 +657,6 @@ static int __init nbd_init(void) disk->private_data = &nbd_dev[i]; disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO; sprintf(disk->disk_name, "nbd%d", i); - sprintf(disk->devfs_name, "nbd/%d", i); set_capacity(disk, 0x7ffffc00ULL << 1); /* 2 TB */ add_disk(disk); } @@ -686,7 +682,6 @@ static void __exit nbd_cleanup(void) put_disk(disk); } } - devfs_remove("nbd"); unregister_blkdev(NBD_MAJOR, "nbd"); printk(KERN_INFO "nbd: unregistered device at major %d\n", NBD_MAJOR); } diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c index 79b868254032..13f998aa1cd3 100644 --- a/drivers/block/paride/pg.c +++ b/drivers/block/paride/pg.c @@ -156,7 +156,6 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY}; #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> -#include <linux/devfs_fs_kernel.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/mtio.h> @@ -674,25 +673,15 @@ static int __init pg_init(void) err = PTR_ERR(pg_class); goto out_chrdev; } - devfs_mk_dir("pg"); for (unit = 0; unit < PG_UNITS; unit++) { struct pg *dev = &devices[unit]; - if (dev->present) { + if (dev->present) class_device_create(pg_class, NULL, MKDEV(major, unit), NULL, "pg%u", unit); - err = devfs_mk_cdev(MKDEV(major, unit), - S_IFCHR | S_IRUSR | S_IWUSR, "pg/%u", - unit); - if (err) - goto out_class; - } } err = 0; goto out; -out_class: - class_device_destroy(pg_class, MKDEV(major, unit)); - class_destroy(pg_class); out_chrdev: unregister_chrdev(major, "pg"); out: @@ -705,13 +694,10 @@ static void __exit pg_exit(void) for (unit = 0; unit < PG_UNITS; unit++) { struct pg *dev = &devices[unit]; - if (dev->present) { + if (dev->present) class_device_destroy(pg_class, MKDEV(major, unit)); - devfs_remove("pg/%u", unit); - } } class_destroy(pg_class); - devfs_remove("pg"); unregister_chrdev(major, name); for (unit = 0; unit < PG_UNITS; unit++) { diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index d2013d362403..35fb26636721 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -141,7 +141,6 @@ static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3}; #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> -#include <linux/devfs_fs_kernel.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/mtio.h> @@ -971,32 +970,15 @@ static int __init pt_init(void) goto out_chrdev; } - devfs_mk_dir("pt"); for (unit = 0; unit < PT_UNITS; unit++) if (pt[unit].present) { class_device_create(pt_class, NULL, MKDEV(major, unit), NULL, "pt%d", unit); - err = devfs_mk_cdev(MKDEV(major, unit), - S_IFCHR | S_IRUSR | S_IWUSR, - "pt/%d", unit); - if (err) { - class_device_destroy(pt_class, MKDEV(major, unit)); - goto out_class; - } class_device_create(pt_class, NULL, MKDEV(major, unit + 128), NULL, "pt%dn", unit); - err = devfs_mk_cdev(MKDEV(major, unit + 128), - S_IFCHR | S_IRUSR | S_IWUSR, - "pt/%dn", unit); - if (err) { - class_device_destroy(pt_class, MKDEV(major, unit + 128)); - goto out_class; - } } goto out; -out_class: - class_destroy(pt_class); out_chrdev: unregister_chrdev(major, "pt"); out: @@ -1009,12 +991,9 @@ static void __exit pt_exit(void) for (unit = 0; unit < PT_UNITS; unit++) if (pt[unit].present) { class_device_destroy(pt_class, MKDEV(major, unit)); - devfs_remove("pt/%d", unit); class_device_destroy(pt_class, MKDEV(major, unit + 128)); - devfs_remove("pt/%dn", unit); } class_destroy(pt_class); - devfs_remove("pt"); unregister_chrdev(major, name); for (unit = 0; unit < PT_UNITS; unit++) if (pt[unit].present) diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index a04f60693c39..3e4cce5e4736 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2612,7 +2612,6 @@ static struct file_operations pkt_ctl_fops = { static struct miscdevice pkt_misc = { .minor = MISC_DYNAMIC_MINOR, .name = "pktcdvd", - .devfs_name = "pktcdvd/control", .fops = &pkt_ctl_fops }; diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index bea75f2cb211..a729013a3973 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -421,7 +421,6 @@ static int __init ps2esdi_geninit(void) disk->major = PS2ESDI_MAJOR; disk->first_minor = i<<6; sprintf(disk->disk_name, "ed%c", 'a'+i); - sprintf(disk->devfs_name, "ed/target%d", i); disk->fops = &ps2esdi_fops; ps2esdi_gendisk[i] = disk; } diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 0378da04cfa2..a9e1c2524c2a 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -50,7 +50,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> -#include <linux/devfs_fs_kernel.h> #include <linux/pagemap.h> #include <linux/blkdev.h> #include <linux/genhd.h> @@ -412,7 +411,6 @@ static void __exit rd_cleanup(void) put_disk(rd_disks[i]); blk_cleanup_queue(rd_queue[i]); } - devfs_remove("rd"); unregister_blkdev(RAMDISK_MAJOR, "ramdisk"); } @@ -442,8 +440,6 @@ static int __init rd_init(void) goto out; } - devfs_mk_dir("rd"); - for (i = 0; i < CONFIG_BLK_DEV_RAM_COUNT; i++) { struct gendisk *disk = rd_disks[i]; @@ -461,7 +457,6 @@ static int __init rd_init(void) disk->queue = rd_queue[i]; disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO; sprintf(disk->disk_name, "ram%d", i); - sprintf(disk->devfs_name, "rd/%d", i); set_capacity(disk, rd_size * 2); add_disk(rd_disks[i]); } diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 01f042f6f1c4..628877945f9b 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -25,7 +25,6 @@ #include <linux/fd.h> #include <linux/ioctl.h> #include <linux/blkdev.h> -#include <linux/devfs_fs_kernel.h> #include <linux/interrupt.h> #include <linux/module.h> #include <linux/spinlock.h> @@ -1019,8 +1018,6 @@ int swim3_init(void) int err = -ENOMEM; int i; - devfs_mk_dir("floppy"); - swim = find_devices("floppy"); while (swim && (floppy_count < MAX_FLOPPIES)) { @@ -1064,7 +1061,6 @@ int swim3_init(void) disk->queue = swim3_queue; disk->flags |= GENHD_FL_REMOVABLE; sprintf(disk->disk_name, "fd%d", i); - sprintf(disk->devfs_name, "floppy/%d", i); set_capacity(disk, 2880); add_disk(disk); } diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index 8144ce9f4df0..10a4aa5fb54d 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -18,7 +18,6 @@ #include <linux/spinlock.h> #include <linux/blkdev.h> #include <linux/sched.h> -#include <linux/devfs_fs_kernel.h> #include <linux/interrupt.h> #include <linux/compiler.h> #include <linux/workqueue.h> @@ -1510,7 +1509,6 @@ static int carm_init_disks(struct carm_host *host) port->disk = disk; sprintf(disk->disk_name, DRV_NAME "/%u", (unsigned int) (host->id * CARM_MAX_PORTS) + i); - sprintf(disk->devfs_name, DRV_NAME "/%u_%u", host->id, i); disk->major = host->major; disk->first_minor = i * CARM_MINORS_PER_MAJOR; disk->fops = &carm_bd_ops; @@ -1672,8 +1670,6 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (host->flags & FL_DYN_MAJOR) host->major = rc; - devfs_mk_dir(DRV_NAME); - rc = carm_init_disks(host); if (rc) goto err_out_blkdev_disks; @@ -1739,7 +1735,6 @@ static void carm_remove_one (struct pci_dev *pdev) free_irq(pdev->irq, host); carm_free_disks(host); - devfs_remove(DRV_NAME); unregister_blkdev(host->major, host->name); if (host->major == 160) clear_bit(0, &carm_major_alloc); diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 60e9a9457c6b..d62b49fbf10c 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -24,12 +24,10 @@ #include <linux/usb.h> #include <linux/usb_usual.h> #include <linux/blkdev.h> -#include <linux/devfs_fs_kernel.h> #include <linux/timer.h> #include <scsi/scsi.h> #define DRV_NAME "ub" -#define DEVFS_NAME DRV_NAME #define UB_MAJOR 180 @@ -2291,7 +2289,6 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum) goto err_diskalloc; sprintf(disk->disk_name, DRV_NAME "%c", lun->id + 'a'); - sprintf(disk->devfs_name, DEVFS_NAME "/%c", lun->id + 'a'); disk->major = UB_MAJOR; disk->first_minor = lun->id * UB_PARTS_PER_LUN; disk->fops = &ub_bd_fops; @@ -2445,7 +2442,6 @@ static int __init ub_init(void) if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0) goto err_regblkdev; - devfs_mk_dir(DEVFS_NAME); if ((rc = usb_register(&ub_driver)) != 0) goto err_register; @@ -2454,7 +2450,6 @@ static int __init ub_init(void) return 0; err_register: - devfs_remove(DEVFS_NAME); unregister_blkdev(UB_MAJOR, DRV_NAME); err_regblkdev: return rc; @@ -2464,7 +2459,6 @@ static void __exit ub_exit(void) { usb_deregister(&ub_driver); - devfs_remove(DEVFS_NAME); unregister_blkdev(UB_MAJOR, DRV_NAME); usb_usual_clear_present(USB_US_TYPE_UB); } diff --git a/drivers/block/umem.c b/drivers/block/umem.c index f7d4c65a7b8c..585197b95af7 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -1192,7 +1192,6 @@ static int __init mm_init(void) for (i = 0; i < num_cards; i++) { struct gendisk *disk = mm_gendisk[i]; sprintf(disk->disk_name, "umem%c", 'a'+i); - sprintf(disk->devfs_name, "umem/card%d", i); spin_lock_init(&cards[i].lock); disk->major = major_nr; disk->first_minor = i << MM_SHIFT; diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index b0df4f5ab97a..ec5a1b90a0a2 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -59,7 +59,6 @@ MODULE_LICENSE("GPL"); * numbers 0-255 we get a maximum of 32 disks. */ #define VIOD_GENHD_NAME "iseries/vd" -#define VIOD_GENHD_DEVFS_NAME "iseries/disc" #define VIOD_VERS "1.64" @@ -523,8 +522,6 @@ retry: else snprintf(g->disk_name, sizeof(g->disk_name), VIOD_GENHD_NAME "%c", 'a' + (dev_no % 26)); - snprintf(g->devfs_name, sizeof(g->devfs_name), - "%s%d", VIOD_GENHD_DEVFS_NAME, dev_no); g->fops = &viodasd_fops; g->queue = q; g->private_data = d; diff --git a/drivers/block/xd.c b/drivers/block/xd.c index cbce7c5e9445..e828e4cbd3e1 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -215,7 +215,6 @@ static int __init xd_init(void) disk->major = XT_DISK_MAJOR; disk->first_minor = i<<6; sprintf(disk->disk_name, "xd%c", i+'a'); - sprintf(disk->devfs_name, "xd/target%d", i); disk->fops = &xd_fops; disk->private_data = p; disk->queue = xd_queue; diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index bb5e8d665a2a..82ddbdd7bd4b 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -354,7 +354,6 @@ z2_init(void) z2ram_gendisk->first_minor = 0; z2ram_gendisk->fops = &z2_fops; sprintf(z2ram_gendisk->disk_name, "z2ram"); - strcpy(z2ram_gendisk->devfs_name, z2ram_gendisk->disk_name); z2ram_gendisk->queue = z2_queue; add_disk(z2ram_gendisk); diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c index ec004897b634..ec469497c10f 100644 --- a/drivers/cdrom/aztcd.c +++ b/drivers/cdrom/aztcd.c @@ -1918,7 +1918,6 @@ static int __init aztcd_init(void) azt_disk->first_minor = 0; azt_disk->fops = &azt_fops; sprintf(azt_disk->disk_name, "aztcd"); - sprintf(azt_disk->devfs_name, "aztcd"); azt_disk->queue = azt_queue; add_disk(azt_disk); azt_invalidate_buffers(); diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c index 72ffd64e8b1e..5f0f2027f29e 100644 --- a/drivers/cdrom/cdu31a.c +++ b/drivers/cdrom/cdu31a.c @@ -161,7 +161,6 @@ #include <linux/hdreg.h> #include <linux/genhd.h> #include <linux/ioport.h> -#include <linux/devfs_fs_kernel.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/init.h> diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c index f43a988dd413..4ee288688fed 100644 --- a/drivers/cdrom/cm206.c +++ b/drivers/cdrom/cm206.c @@ -187,7 +187,6 @@ History: #include <linux/interrupt.h> #include <linux/timer.h> #include <linux/cdrom.h> -#include <linux/devfs_fs_kernel.h> #include <linux/ioport.h> #include <linux/mm.h> #include <linux/slab.h> diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c index ad5464ab99bc..b6ee50a2916d 100644 --- a/drivers/cdrom/gscd.c +++ b/drivers/cdrom/gscd.c @@ -955,7 +955,6 @@ static int __init gscd_init(void) gscd_disk->first_minor = 0; gscd_disk->fops = &gscd_fops; sprintf(gscd_disk->disk_name, "gscd"); - sprintf(gscd_disk->devfs_name, "gscd"); if (register_blkdev(MAJOR_NR, "gscd")) { ret = -EIO; diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c index 0f6e7aab8d2c..788c7a0b2fe3 100644 --- a/drivers/cdrom/mcdx.c +++ b/drivers/cdrom/mcdx.c @@ -74,7 +74,6 @@ static const char *mcdx_c_version #include <linux/major.h> #define MAJOR_NR MITSUMI_X_CDROM_MAJOR #include <linux/blkdev.h> -#include <linux/devfs_fs_kernel.h> #include "mcdx.h" diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c index 0b0eab4f40fa..25032d7edc55 100644 --- a/drivers/cdrom/optcd.c +++ b/drivers/cdrom/optcd.c @@ -2033,7 +2033,6 @@ static int __init optcd_init(void) optcd_disk->first_minor = 0; optcd_disk->fops = &opt_fops; sprintf(optcd_disk->disk_name, "optcd"); - sprintf(optcd_disk->devfs_name, "optcd"); if (!request_region(optcd_port, 4, "optcd")) { printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n", diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c index 05c9e865ecaf..2fc966c65a0e 100644 --- a/drivers/cdrom/sbpcd.c +++ b/drivers/cdrom/sbpcd.c @@ -371,7 +371,6 @@ #include <linux/kernel.h> #include <linux/cdrom.h> #include <linux/ioport.h> -#include <linux/devfs_fs_kernel.h> #include <linux/major.h> #include <linux/string.h> #include <linux/vmalloc.h> @@ -5808,8 +5807,6 @@ int __init sbpcd_init(void) return -ENOMEM; } - devfs_mk_dir("sbp"); - for (j=0;j<NR_SBPCD;j++) { struct cdrom_device_info * sbpcd_infop; @@ -5871,7 +5868,6 @@ int __init sbpcd_init(void) disk->fops = &sbpcd_bdops; strcpy(disk->disk_name, sbpcd_infop->name); disk->flags = GENHD_FL_CD; - sprintf(disk->devfs_name, "sbp/c0t%d", p->drv_id); p->disk = disk; if (register_cdrom(sbpcd_infop)) { @@ -5906,7 +5902,6 @@ static void sbpcd_exit(void) if (D_S[j].drv_id==-1) continue; del_gendisk(D_S[j].disk); put_disk(D_S[j].disk); - devfs_remove("sbp/c0t%d", j); vfree(D_S[j].sbp_buf); if (D_S[j].sbp_audsiz>0) vfree(D_S[j].aud_buf); @@ -5917,7 +5912,6 @@ static void sbpcd_exit(void) } vfree(D_S[j].sbpcd_infop); } - devfs_remove("sbp"); msg(DBG_INF, "%s module released.\n", major_name); } diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c index 74b1cadbf161..bf5aef4e555b 100644 --- a/drivers/cdrom/sjcd.c +++ b/drivers/cdrom/sjcd.c @@ -1695,7 +1695,6 @@ static int __init sjcd_init(void) sjcd_disk->first_minor = 0, sjcd_disk->fops = &sjcd_fops, sprintf(sjcd_disk->disk_name, "sjcd"); - sprintf(sjcd_disk->devfs_name, "sjcd"); if (!request_region(sjcd_base, 4,"sjcd")) { printk diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c index e65659926432..8f7cc452af8d 100644 --- a/drivers/cdrom/sonycd535.c +++ b/drivers/cdrom/sonycd535.c @@ -1589,7 +1589,6 @@ static int __init sony535_init(void) cdu_disk->first_minor = 0; cdu_disk->fops = &cdu_fops; sprintf(cdu_disk->disk_name, "cdu"); - sprintf(cdu_disk->devfs_name, "cdu535"); if (!request_region(sony535_cd_base_io, 4, CDU535_HANDLE)) { printk(KERN_WARNING"sonycd535: Unable to request region 0x%x\n", diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index af6b3bfd169b..54ca931e19ea 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -49,7 +49,6 @@ #include <asm/iseries/vio.h> #define VIOCD_DEVICE "iseries/vcd" -#define VIOCD_DEVICE_DEVFS "iseries/vcd" #define VIOCD_VERS "1.06" @@ -688,8 +687,6 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) gendisk->first_minor = deviceno; strncpy(gendisk->disk_name, c->name, sizeof(gendisk->disk_name)); - snprintf(gendisk->devfs_name, sizeof(gendisk->devfs_name), - VIOCD_DEVICE_DEVFS "%d", deviceno); blk_queue_max_hw_segments(q, 1); blk_queue_max_phys_segments(q, 1); blk_queue_max_sectors(q, 4096 / 512); diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index 9826a399fa02..22f8cf218cc6 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig @@ -1,6 +1,7 @@ config AGP tristate "/dev/agpgart (AGP Support)" depends on ALPHA || IA64 || PPC || X86 + depends on PCI ---help--- AGP (Accelerated Graphics Port) is a bus system mainly used to connect graphics cards to the rest of the system. diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index f690ee8cb732..f74eeeb8e377 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -734,7 +734,7 @@ int __init agp_amd64_init(void) if (agp_off) return -EINVAL; - if (pci_register_driver(&agp_amd64_pci_driver) > 0) { + if (pci_register_driver(&agp_amd64_pci_driver) < 0) { struct pci_dev *dev; if (!agp_try_unsupported && !agp_try_unsupported_boot) { printk(KERN_INFO PFX "No supported AGP bridge found.\n"); diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 160564345993..f244c6682738 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -41,7 +41,6 @@ static struct gatt_mask ati_generic_masks[] = }; - typedef struct _ati_page_map { unsigned long *real; unsigned long __iomem *remapped; @@ -141,7 +140,8 @@ static int ati_create_gatt_pages(int nr_tables) ati_generic_private.num_tables = nr_tables; ati_generic_private.gatt_pages = tables; - if (retval != 0) ati_free_gatt_pages(); + if (retval != 0) + ati_free_gatt_pages(); return retval; } @@ -219,16 +219,16 @@ static int ati_configure(void) ati_generic_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096); if (is_r200()) - pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000); + pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000); else pci_write_config_dword(agp_bridge->dev, ATI_RS300_IG_AGPMODE, 0x20000); /* address to map too */ - /* + /* pci_read_config_dword(agp_bridge.dev, AGP_APBASE, &temp); agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); printk(KERN_INFO PFX "IGP320 gart_bus_addr: %x\n", agp_bridge.gart_bus_addr); - */ + */ writel(0x60000, ati_generic_private.registers+ATI_GART_FEATURE_ID); readl(ati_generic_private.registers+ATI_GART_FEATURE_ID); /* PCI Posting.*/ @@ -245,18 +245,20 @@ static int ati_configure(void) #ifdef CONFIG_PM -static int agp_ati_resume(struct pci_dev *dev) +static int agp_ati_suspend(struct pci_dev *dev, pm_message_t state) { - pci_restore_state(dev); + pci_save_state(dev); + pci_set_power_state(dev, 3); - return ati_configure(); + return 0; } -static int agp_ati_suspend(struct pci_dev *dev, pm_message_t state) +static int agp_ati_resume(struct pci_dev *dev) { - pci_save_state(dev); + pci_set_power_state(dev, 0); + pci_restore_state(dev); - return 0; + return ati_configure(); } #endif @@ -321,9 +323,9 @@ static int ati_remove_memory(struct agp_memory * mem, off_t pg_start, unsigned long __iomem *cur_gatt; unsigned long addr; - if (type != 0 || mem->type != 0) { + if (type != 0 || mem->type != 0) return -EINVAL; - } + for (i = pg_start; i < (mem->page_count + pg_start); i++) { addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); @@ -502,9 +504,8 @@ found: bridge->dev = pdev; bridge->capndx = cap_ptr; - - bridge->driver = &ati_generic_bridge; + bridge->driver = &ati_generic_bridge; printk(KERN_INFO PFX "Detected Ati %s chipset\n", devs[j].chipset_name); @@ -546,8 +547,8 @@ static struct pci_driver agp_ati_pci_driver = { .probe = agp_ati_probe, .remove = agp_ati_remove, #ifdef CONFIG_PM - .resume = agp_ati_resume, .suspend = agp_ati_suspend, + .resume = agp_ati_resume, #endif }; diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index 4c67135c12d8..df7f37b2739a 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -376,6 +376,29 @@ static void __devexit agp_nvidia_remove(struct pci_dev *pdev) agp_put_bridge(bridge); } +#ifdef CONFIG_PM +static int agp_nvidia_suspend(struct pci_dev *pdev, pm_message_t state) +{ + pci_save_state (pdev); + pci_set_power_state (pdev, 3); + + return 0; +} + +static int agp_nvidia_resume(struct pci_dev *pdev) +{ + /* set power state 0 and restore PCI space */ + pci_set_power_state (pdev, 0); + pci_restore_state(pdev); + + /* reconfigure AGP hardware again */ + nvidia_configure(); + + return 0; +} +#endif + + static struct pci_device_id agp_nvidia_pci_table[] = { { .class = (PCI_CLASS_BRIDGE_HOST << 8), @@ -403,6 +426,10 @@ static struct pci_driver agp_nvidia_pci_driver = { .id_table = agp_nvidia_pci_table, .probe = agp_nvidia_probe, .remove = agp_nvidia_remove, +#ifdef CONFIG_PM + .suspend = agp_nvidia_suspend, + .resume = agp_nvidia_resume, +#endif }; static int __init agp_nvidia_init(void) diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 122e7a72a4e1..2657eeba7da6 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -5250,7 +5250,6 @@ cy_init(void) cy_serial_driver->owner = THIS_MODULE; cy_serial_driver->driver_name = "cyclades"; cy_serial_driver->name = "ttyC"; - cy_serial_driver->devfs_name = "tts/C"; cy_serial_driver->major = CYCLADES_MAJOR; cy_serial_driver->minor_start = 0; cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL; diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index e233cf280bc0..09b413618b57 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -33,7 +33,6 @@ #include <linux/fs.h> #include <linux/mm.h> #include <linux/init.h> -#include <linux/devfs_fs_kernel.h> #include <linux/smp_lock.h> #include <linux/device.h> @@ -518,17 +517,9 @@ static int __init dsp56k_init_driver(void) } class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k"); - err = devfs_mk_cdev(MKDEV(DSP56K_MAJOR, 0), - S_IFCHR | S_IRUSR | S_IWUSR, "dsp56k"); - if(err) - goto out_class; - printk(banner); goto out; -out_class: - class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); - class_destroy(dsp56k_class); out_chrdev: unregister_chrdev(DSP56K_MAJOR, "dsp56k"); out: @@ -541,7 +532,6 @@ static void __exit dsp56k_cleanup_driver(void) class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); class_destroy(dsp56k_class); unregister_chrdev(DSP56K_MAJOR, "dsp56k"); - devfs_remove("dsp56k"); } module_exit(dsp56k_cleanup_driver); diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c index 87dcaa237f07..da2c89f1b8bc 100644 --- a/drivers/char/dtlk.c +++ b/drivers/char/dtlk.c @@ -62,7 +62,6 @@ #include <linux/init.h> /* for __init, module_{init,exit} */ #include <linux/poll.h> /* for POLLIN, etc. */ #include <linux/dtlk.h> /* local header file for DoubleTalk values */ -#include <linux/devfs_fs_kernel.h> #include <linux/smp_lock.h> #ifdef TRACING @@ -337,9 +336,6 @@ static int __init dtlk_init(void) if (dtlk_dev_probe() == 0) printk(", MAJOR %d\n", dtlk_major); - devfs_mk_cdev(MKDEV(dtlk_major, DTLK_MINOR), - S_IFCHR | S_IRUSR | S_IWUSR, "dtlk"); - init_timer(&dtlk_timer); dtlk_timer.function = dtlk_timer_tick; init_waitqueue_head(&dtlk_process_list); @@ -357,7 +353,6 @@ static void __exit dtlk_cleanup (void) dtlk_write_tts(DTLK_CLEAR); unregister_chrdev(dtlk_major, "dtlk"); - devfs_remove("dtlk"); release_region(dtlk_port_lpc, DTLK_IO_EXTENT); } diff --git a/drivers/char/epca.c b/drivers/char/epca.c index dc0602ae8503..d0b3890d9302 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -1232,7 +1232,6 @@ static int __init pc_init(void) pc_driver->owner = THIS_MODULE; pc_driver->name = "ttyD"; - pc_driver->devfs_name = "tts/D"; pc_driver->major = DIGI_MAJOR; pc_driver->minor_start = 0; pc_driver->type = TTY_DRIVER_TYPE_SERIAL; diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 922174d527ae..9827d170ca17 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -2449,7 +2449,6 @@ static int __init espserial_init(void) esp_driver->owner = THIS_MODULE; esp_driver->name = "ttyP"; - esp_driver->devfs_name = "tts/P"; esp_driver->major = ESP_IN_MAJOR; esp_driver->minor_start = 0; esp_driver->type = TTY_DRIVER_TYPE_SERIAL; diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c index 821357ce7e0e..3eeb869a9a11 100644 --- a/drivers/char/ftape/zftape/zftape-init.c +++ b/drivers/char/ftape/zftape/zftape-init.c @@ -33,7 +33,6 @@ #endif #include <linux/fcntl.h> #include <linux/smp_lock.h> -#include <linux/devfs_fs_kernel.h> #include <linux/zftape.h> #include <linux/init.h> @@ -332,29 +331,11 @@ KERN_INFO zft_class = class_create(THIS_MODULE, "zft"); for (i = 0; i < 4; i++) { class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i); - devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i), - S_IFCHR | S_IRUSR | S_IWUSR, - "qft%i", i); class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i); - devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 4), - S_IFCHR | S_IRUSR | S_IWUSR, - "nqft%i", i); class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i); - devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 16), - S_IFCHR | S_IRUSR | S_IWUSR, - "zqft%i", i); class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i); - devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 20), - S_IFCHR | S_IRUSR | S_IWUSR, - "nzqft%i", i); class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i); - devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 32), - S_IFCHR | S_IRUSR | S_IWUSR, - "rawqft%i", i); class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i); - devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 36), - S_IFCHR | S_IRUSR | S_IWUSR, - "nrawqft%i", i); } #ifdef CONFIG_ZFT_COMPRESSOR @@ -380,17 +361,11 @@ static void zft_exit(void) TRACE(ft_t_info, "successful"); } for (i = 0; i < 4; i++) { - devfs_remove("qft%i", i); class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i)); - devfs_remove("nqft%i", i); class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4)); - devfs_remove("zqft%i", i); class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16)); - devfs_remove("nzqft%i", i); class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20)); - devfs_remove("rawqft%i", i); class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32)); - devfs_remove("nrawqft%i", i); class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36)); } class_destroy(zft_class); diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index a5c6a9d7ff08..6e380aecea6a 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -820,7 +820,6 @@ int __init hvc_init(void) return -ENOMEM; drv->owner = THIS_MODULE; - drv->devfs_name = "hvc/"; drv->driver_name = "hvc"; drv->name = "hvc"; drv->major = HVC_MAJOR; diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index afa26b65dac3..130dedc37568 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -1363,7 +1363,6 @@ static int __init hvcs_module_init(void) hvcs_tty_driver->driver_name = hvcs_driver_name; hvcs_tty_driver->name = hvcs_device_node; - hvcs_tty_driver->devfs_name = hvcs_device_node; /* * We'll let the system assign us a major number, indicated by leaving diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index a0370ed752ce..7b04eb153205 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -1154,7 +1154,6 @@ static int __init hvsi_init(void) return -ENOMEM; hvsi_driver->owner = THIS_MODULE; - hvsi_driver->devfs_name = "hvsi/"; hvsi_driver->driver_name = "hvsi"; hvsi_driver->name = "hvsi"; hvsi_driver->major = HVSI_MAJOR; diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 9ab33c3d359f..8619542766cb 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -91,7 +91,6 @@ #include <linux/module.h> #include <linux/signal.h> #include <linux/sched.h> -#include <linux/devfs_fs_kernel.h> #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/pci.h> @@ -414,9 +413,7 @@ cleanup_module(void) /* free io addresses and Tibet */ release_region( ip2config.addr[i], 8 ); class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); - devfs_remove("ip2/ipl%d", i); class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); - devfs_remove("ip2/stat%d", i); } /* Disable and remove interrupt handler. */ if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { @@ -425,7 +422,6 @@ cleanup_module(void) } } class_destroy(ip2_class); - devfs_remove("ip2"); if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) { printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err); } @@ -675,7 +671,6 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) ip2_tty_driver->owner = THIS_MODULE; ip2_tty_driver->name = "ttyF"; - ip2_tty_driver->devfs_name = "tts/F"; ip2_tty_driver->driver_name = pcDriver_name; ip2_tty_driver->major = IP2_TTY_MAJOR; ip2_tty_driver->minor_start = 0; @@ -683,7 +678,7 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) ip2_tty_driver->subtype = SERIAL_TYPE_NORMAL; ip2_tty_driver->init_termios = tty_std_termios; ip2_tty_driver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; - ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(ip2_tty_driver, &ip2_ops); ip2trace (ITRC_NO_PORT, ITRC_INIT, 3, 0 ); @@ -724,26 +719,9 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) class_device_create(ip2_class, NULL, MKDEV(IP2_IPL_MAJOR, 4 * i), NULL, "ipl%d", i); - err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i), - S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, - "ip2/ipl%d", i); - if (err) { - class_device_destroy(ip2_class, - MKDEV(IP2_IPL_MAJOR, 4 * i)); - goto out_class; - } - class_device_create(ip2_class, NULL, MKDEV(IP2_IPL_MAJOR, 4 * i + 1), NULL, "stat%d", i); - err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i + 1), - S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, - "ip2/stat%d", i); - if (err) { - class_device_destroy(ip2_class, - MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); - goto out_class; - } for ( box = 0; box < ABS_MAX_BOXES; ++box ) { diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index e1c95374984c..da637adbbfaa 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -40,7 +40,6 @@ #include <linux/poll.h> #include <linux/spinlock.h> #include <linux/slab.h> -#include <linux/devfs_fs_kernel.h> #include <linux/ipmi.h> #include <linux/mutex.h> #include <linux/init.h> @@ -804,9 +803,6 @@ static void ipmi_new_smi(int if_num, struct device *device) dev_t dev = MKDEV(ipmi_major, if_num); struct ipmi_reg_list *entry; - devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, - "ipmidev/%d", if_num); - entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { printk(KERN_ERR "ipmi_devintf: Unable to create the" @@ -836,7 +832,6 @@ static void ipmi_smi_gone(int if_num) } class_device_destroy(ipmi_class, dev); mutex_unlock(®_list_mutex); - devfs_remove("ipmidev/%d", if_num); } static struct ipmi_smi_watcher smi_watcher = @@ -872,8 +867,6 @@ static __init int init_ipmi_devintf(void) ipmi_major = rv; } - devfs_mk_dir(DEVICE_NAME); - rv = ipmi_smi_watcher_register(&smi_watcher); if (rv) { unregister_chrdev(ipmi_major, DEVICE_NAME); @@ -898,7 +891,6 @@ static __exit void cleanup_ipmi(void) mutex_unlock(®_list_mutex); class_destroy(ipmi_class); ipmi_smi_watcher_unregister(&smi_watcher); - devfs_remove(DEVICE_NAME); unregister_chrdev(ipmi_major, DEVICE_NAME); } module_exit(cleanup_ipmi); diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index efaaa1937ab6..478bf4d7d065 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -1581,7 +1581,6 @@ static int __devinit isicom_register_tty_driver(void) isicom_normal->owner = THIS_MODULE; isicom_normal->name = "ttyM"; - isicom_normal->devfs_name = "isicom/"; isicom_normal->major = ISICOM_NMAJOR; isicom_normal->minor_start = 0; isicom_normal->type = TTY_DRIVER_TYPE_SERIAL; diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 216c79256de3..c74e5660a9b7 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -39,7 +39,6 @@ #include <linux/ioport.h> #include <linux/delay.h> #include <linux/init.h> -#include <linux/devfs_fs_kernel.h> #include <linux/device.h> #include <linux/wait.h> #include <linux/eisa.h> @@ -826,11 +825,8 @@ static void __exit istallion_module_exit(void) return; } put_tty_driver(stli_serial); - for (i = 0; i < 4; i++) { - devfs_remove("staliomem/%d", i); + for (i = 0; i < 4; i++) class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, i)); - } - devfs_remove("staliomem"); class_destroy(istallion_class); if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"))) printk("STALLION: failed to un-register serial memory device, " @@ -4728,16 +4724,11 @@ int __init stli_init(void) printk(KERN_ERR "STALLION: failed to register serial memory " "device\n"); - devfs_mk_dir("staliomem"); istallion_class = class_create(THIS_MODULE, "staliomem"); - for (i = 0; i < 4; i++) { - devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i), - S_IFCHR | S_IRUSR | S_IWUSR, - "staliomem/%d", i); + for (i = 0; i < 4; i++) class_device_create(istallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i), NULL, "staliomem%d", i); - } /* * Set up the tty driver structure and register us as a driver. diff --git a/drivers/char/lp.c b/drivers/char/lp.c index e57260525293..b11a390581ba 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -120,7 +120,6 @@ #include <linux/major.h> #include <linux/sched.h> #include <linux/smp_lock.h> -#include <linux/devfs_fs_kernel.h> #include <linux/slab.h> #include <linux/fcntl.h> #include <linux/delay.h> @@ -807,8 +806,6 @@ static int lp_register(int nr, struct parport *port) class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), NULL, "lp%d", nr); - devfs_mk_cdev(MKDEV(LP_MAJOR, nr), S_IFCHR | S_IRUGO | S_IWUGO, - "printers/%d", nr); printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven"); @@ -907,7 +904,6 @@ static int __init lp_init (void) return -EIO; } - devfs_mk_dir("printers"); lp_class = class_create(THIS_MODULE, "printer"); if (IS_ERR(lp_class)) { err = PTR_ERR(lp_class); @@ -933,7 +929,6 @@ static int __init lp_init (void) out_class: class_destroy(lp_class); out_devfs: - devfs_remove("printers"); unregister_chrdev(LP_MAJOR, "lp"); return err; } @@ -981,10 +976,8 @@ static void lp_cleanup_module (void) if (lp_table[offset].dev == NULL) continue; parport_unregister_device(lp_table[offset].dev); - devfs_remove("printers/%d", offset); class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset)); } - devfs_remove("printers"); class_destroy(lp_class); } diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 1fa9fa157c12..6fe7b6c6c462 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -20,7 +20,6 @@ #include <linux/tty.h> #include <linux/capability.h> #include <linux/smp_lock.h> -#include <linux/devfs_fs_kernel.h> #include <linux/ptrace.h> #include <linux/device.h> #include <linux/highmem.h> @@ -941,13 +940,10 @@ static int __init chr_dev_init(void) printk("unable to get major %d for memory devs\n", MEM_MAJOR); mem_class = class_create(THIS_MODULE, "mem"); - for (i = 0; i < ARRAY_SIZE(devlist); i++) { + for (i = 0; i < ARRAY_SIZE(devlist); i++) class_device_create(mem_class, NULL, MKDEV(MEM_MAJOR, devlist[i].minor), NULL, devlist[i].name); - devfs_mk_cdev(MKDEV(MEM_MAJOR, devlist[i].minor), - S_IFCHR | devlist[i].mode, devlist[i].name); - } return 0; } diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 96eb2a709e21..dfe1cede3916 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -44,7 +44,6 @@ #include <linux/slab.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> -#include <linux/devfs_fs_kernel.h> #include <linux/stat.h> #include <linux/init.h> #include <linux/device.h> @@ -204,7 +203,7 @@ int misc_register(struct miscdevice * misc) { struct miscdevice *c; dev_t dev; - int err; + int err = 0; down(&misc_sem); list_for_each_entry(c, &misc_list, list) { @@ -228,10 +227,6 @@ int misc_register(struct miscdevice * misc) if (misc->minor < DYNAMIC_MINORS) misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7); - if (misc->devfs_name[0] == '\0') { - snprintf(misc->devfs_name, sizeof(misc->devfs_name), - "misc/%s", misc->name); - } dev = MKDEV(MISC_MAJOR, misc->minor); misc->class = class_device_create(misc_class, NULL, dev, misc->dev, @@ -241,13 +236,6 @@ int misc_register(struct miscdevice * misc) goto out; } - err = devfs_mk_cdev(dev, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP, - misc->devfs_name); - if (err) { - class_device_destroy(misc_class, dev); - goto out; - } - /* * Add it to the front, so that later devices can "override" * earlier defaults @@ -278,7 +266,6 @@ int misc_deregister(struct miscdevice * misc) down(&misc_sem); list_del(&misc->list); class_device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); - devfs_remove(misc->devfs_name); if (i < DYNAMIC_MINORS && i>0) { misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); } diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c index d65b3109318a..95e8122b8068 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c @@ -25,7 +25,6 @@ #include <linux/init.h> #include <linux/errno.h> #include <linux/mm.h> -#include <linux/devfs_fs_kernel.h> #include <linux/mmtimer.h> #include <linux/miscdevice.h> #include <linux/posix-timers.h> @@ -694,7 +693,6 @@ static int __init mmtimer_init(void) return -1; } - strcpy(mmtimer_miscdev.devfs_name, MMTIMER_NAME); if (misc_register(&mmtimer_miscdev)) { printk(KERN_ERR "%s: failed to register device\n", MMTIMER_NAME); diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 01247cccb89f..52ef61f54ba0 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -342,7 +342,6 @@ static int __init moxa_init(void) init_MUTEX(&moxaBuffSem); moxaDriver->owner = THIS_MODULE; moxaDriver->name = "ttyMX"; - moxaDriver->devfs_name = "tts/a"; moxaDriver->major = ttymajor; moxaDriver->minor_start = 0; moxaDriver->type = TTY_DRIVER_TYPE_SERIAL; diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index bee6c47b45bd..24231d9743dc 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -60,7 +60,6 @@ #include <linux/init.h> #include <linux/sched.h> #include <linux/device.h> -#include <linux/devfs_fs_kernel.h> #include <linux/ioctl.h> #include <linux/parport.h> #include <linux/ctype.h> @@ -770,7 +769,7 @@ static struct parport_driver pp_driver = { static int __init ppdev_init (void) { - int i, err = 0; + int err = 0; if (register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) { printk (KERN_WARNING CHRDEV ": unable to get major %d\n", @@ -782,11 +781,6 @@ static int __init ppdev_init (void) err = PTR_ERR(ppdev_class); goto out_chrdev; } - devfs_mk_dir("parports"); - for (i = 0; i < PARPORT_MAX; i++) { - devfs_mk_cdev(MKDEV(PP_MAJOR, i), - S_IFCHR | S_IRUGO | S_IWUGO, "parports/%d", i); - } if (parport_register_driver(&pp_driver)) { printk (KERN_WARNING CHRDEV ": unable to register with parport\n"); goto out_class; @@ -796,9 +790,6 @@ static int __init ppdev_init (void) goto out; out_class: - for (i = 0; i < PARPORT_MAX; i++) - devfs_remove("parports/%d", i); - devfs_remove("parports"); class_destroy(ppdev_class); out_chrdev: unregister_chrdev(PP_MAJOR, CHRDEV); @@ -808,12 +799,8 @@ out: static void __exit ppdev_cleanup (void) { - int i; /* Clean up all parport stuff */ - for (i = 0; i < PARPORT_MAX; i++) - devfs_remove("parports/%d", i); parport_unregister_driver(&pp_driver); - devfs_remove("parports"); class_destroy(ppdev_class); unregister_chrdev (PP_MAJOR, CHRDEV); } diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 0c17f61549b4..9491e4307566 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -24,7 +24,6 @@ #include <linux/major.h> #include <linux/mm.h> #include <linux/init.h> -#include <linux/devfs_fs_kernel.h> #include <linux/sysctl.h> #include <asm/uaccess.h> @@ -265,7 +264,6 @@ static void __init legacy_pty_init(void) pty_driver->owner = THIS_MODULE; pty_driver->driver_name = "pty_master"; pty_driver->name = "pty"; - pty_driver->devfs_name = "pty/m"; pty_driver->major = PTY_MASTER_MAJOR; pty_driver->minor_start = 0; pty_driver->type = TTY_DRIVER_TYPE_PTY; @@ -283,7 +281,6 @@ static void __init legacy_pty_init(void) pty_slave_driver->owner = THIS_MODULE; pty_slave_driver->driver_name = "pty_slave"; pty_slave_driver->name = "ttyp"; - pty_slave_driver->devfs_name = "pty/s"; pty_slave_driver->major = PTY_SLAVE_MAJOR; pty_slave_driver->minor_start = 0; pty_slave_driver->type = TTY_DRIVER_TYPE_PTY; @@ -351,7 +348,6 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file, static void __init unix98_pty_init(void) { - devfs_mk_dir("pts"); ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX); if (!ptm_driver) panic("Couldn't allocate Unix98 ptm driver"); @@ -372,7 +368,7 @@ static void __init unix98_pty_init(void) ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; ptm_driver->init_termios.c_lflag = 0; ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | - TTY_DRIVER_NO_DEVFS | TTY_DRIVER_DEVPTS_MEM; + TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; ptm_driver->other = pts_driver; tty_set_operations(ptm_driver, &pty_ops); ptm_driver->ioctl = pty_unix98_ioctl; @@ -387,7 +383,7 @@ static void __init unix98_pty_init(void) pts_driver->init_termios = tty_std_termios; pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | - TTY_DRIVER_NO_DEVFS | TTY_DRIVER_DEVPTS_MEM; + TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; pts_driver->other = ptm_driver; tty_set_operations(pts_driver, &pty_ops); diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 15a7b4086524..9bf97c5e38c0 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -10,7 +10,6 @@ #include <linux/init.h> #include <linux/fs.h> -#include <linux/devfs_fs_kernel.h> #include <linux/major.h> #include <linux/blkdev.h> #include <linux/module.h> @@ -288,7 +287,6 @@ static struct cdev raw_cdev = { static int __init raw_init(void) { - int i; dev_t dev = MKDEV(RAW_MAJOR, 0); if (register_chrdev_region(dev, MAX_RAW_MINORS, "raw")) @@ -310,13 +308,6 @@ static int __init raw_init(void) } class_device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); - devfs_mk_cdev(MKDEV(RAW_MAJOR, 0), - S_IFCHR | S_IRUGO | S_IWUGO, - "raw/rawctl"); - for (i = 1; i < MAX_RAW_MINORS; i++) - devfs_mk_cdev(MKDEV(RAW_MAJOR, i), - S_IFCHR | S_IRUGO | S_IWUGO, - "raw/raw%d", i); return 0; error: @@ -326,12 +317,6 @@ error: static void __exit raw_exit(void) { - int i; - - for (i = 1; i < MAX_RAW_MINORS; i++) - devfs_remove("raw/raw%d", i); - devfs_remove("raw/rawctl"); - devfs_remove("raw"); class_device_destroy(raw_class, MKDEV(RAW_MAJOR, 0)); class_destroy(raw_class); cdev_del(&raw_cdev); diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 657c0d88f48c..c84c3c3f10c3 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -1634,7 +1634,6 @@ static inline int rc_init_drivers(void) memset(IRQ_to_board, 0, sizeof(IRQ_to_board)); riscom_driver->owner = THIS_MODULE; riscom_driver->name = "ttyL"; - riscom_driver->devfs_name = "tts/L"; riscom_driver->major = RISCOM8_NORMAL_MAJOR; riscom_driver->type = TTY_DRIVER_TYPE_SERIAL; riscom_driver->subtype = SERIAL_TYPE_NORMAL; diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 0708c5164c83..0ac131881322 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -2426,8 +2426,7 @@ static int __init rp_init(void) */ rocket_driver->owner = THIS_MODULE; - rocket_driver->flags = TTY_DRIVER_NO_DEVFS; - rocket_driver->devfs_name = "tts/R"; + rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV; rocket_driver->name = "ttyR"; rocket_driver->driver_name = "Comtrol RocketPort"; rocket_driver->major = TTY_ROCKET_MAJOR; @@ -2438,7 +2437,7 @@ static int __init rp_init(void) rocket_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; #ifdef ROCKET_SOFT_FLOW - rocket_driver->flags |= TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + rocket_driver->flags |= TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; #endif tty_set_operations(rocket_driver, &rocket_ops); diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index 037c940ac71b..c851eeaa4069 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -2235,7 +2235,6 @@ scrn[1] = '\0'; /* Initialize the tty_driver structure */ cy_serial_driver->owner = THIS_MODULE; - cy_serial_driver->devfs_name = "tts/"; cy_serial_driver->name = "ttyS"; cy_serial_driver->major = TTY_MAJOR; cy_serial_driver->minor_start = 64; diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 00b4a2187164..0f7a542d9041 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -40,7 +40,6 @@ #include <linux/ioport.h> #include <linux/init.h> #include <linux/smp_lock.h> -#include <linux/devfs_fs_kernel.h> #include <linux/device.h> #include <linux/delay.h> @@ -757,11 +756,8 @@ static void __exit stallion_module_exit(void) "errno=%d\n", -i); return; } - for (i = 0; i < 4; i++) { - devfs_remove("staliomem/%d", i); + for (i = 0; i < 4; i++) class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); - } - devfs_remove("staliomem"); if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"))) printk("STALLION: failed to un-register serial memory device, " "errno=%d\n", -i); @@ -3044,22 +3040,16 @@ static int __init stl_init(void) */ if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem)) printk("STALLION: failed to register serial board device\n"); - devfs_mk_dir("staliomem"); stallion_class = class_create(THIS_MODULE, "staliomem"); - for (i = 0; i < 4; i++) { - devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i), - S_IFCHR|S_IRUSR|S_IWUSR, - "staliomem/%d", i); + for (i = 0; i < 4; i++) class_device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i), NULL, "staliomem%d", i); - } stl_serial->owner = THIS_MODULE; stl_serial->driver_name = stl_drvname; stl_serial->name = "ttyE"; - stl_serial->devfs_name = "tts/E"; stl_serial->major = STL_SERIALMAJOR; stl_serial->minor_start = 0; stl_serial->type = TTY_DRIVER_TYPE_SERIAL; diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c index 079db5a935a1..f7802e5bd7ca 100644 --- a/drivers/char/tipar.c +++ b/drivers/char/tipar.c @@ -56,7 +56,6 @@ #include <linux/ioport.h> #include <asm/io.h> #include <linux/bitops.h> -#include <linux/devfs_fs_kernel.h> /* DevFs support */ #include <linux/parport.h> /* Our code depend on parport */ #include <linux/device.h> @@ -443,12 +442,6 @@ tipar_register(int nr, struct parport *port) class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr), NULL, "par%d", nr); - /* Use devfs, tree: /dev/ticables/par/[0..2] */ - err = devfs_mk_cdev(MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr), - S_IFCHR | S_IRUGO | S_IWUGO, - "ticables/par/%d", nr); - if (err) - goto out_class; /* Display informations */ pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq == @@ -460,11 +453,7 @@ tipar_register(int nr, struct parport *port) pr_info("tipar%d: link cable not found\n", nr); err = 0; - goto out; -out_class: - class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr)); - class_destroy(tipar_class); out: return err; } @@ -507,9 +496,6 @@ tipar_init_module(void) goto out; } - /* Use devfs with tree: /dev/ticables/par/[0..2] */ - devfs_mk_dir("ticables/par"); - tipar_class = class_create(THIS_MODULE, "ticables"); if (IS_ERR(tipar_class)) { err = PTR_ERR(tipar_class); @@ -528,7 +514,6 @@ out_class: class_destroy(tipar_class); out_chrdev: - devfs_remove("ticables/par"); unregister_chrdev(TIPAR_MAJOR, "tipar"); out: return err; @@ -549,10 +534,8 @@ tipar_cleanup_module(void) continue; parport_unregister_device(table[i].dev); class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i)); - devfs_remove("ticables/par/%d", i); } class_destroy(tipar_class); - devfs_remove("ticables/par"); pr_info("tipar: module unloaded\n"); } diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 8d19f7281f0b..a1143238feca 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -102,7 +102,6 @@ #include <linux/kbd_kern.h> #include <linux/vt_kern.h> #include <linux/selection.h> -#include <linux/devfs_fs_kernel.h> #include <linux/kmod.h> @@ -2955,8 +2954,8 @@ static struct class *tty_class; * Returns a pointer to the class device (or ERR_PTR(-EFOO) on error). * * This call is required to be made to register an individual tty device if - * the tty driver's flags have the TTY_DRIVER_NO_DEVFS bit set. If that - * bit is not set, this function should not be called. + * the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If that + * bit is not set, this function should not be called by a tty driver. */ struct class_device *tty_register_device(struct tty_driver *driver, unsigned index, struct device *device) @@ -2970,9 +2969,6 @@ struct class_device *tty_register_device(struct tty_driver *driver, return ERR_PTR(-EINVAL); } - devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, - "%s%d", driver->devfs_name, index + driver->name_base); - if (driver->type == TTY_DRIVER_TYPE_PTY) pty_line_name(driver, index, name); else @@ -2991,7 +2987,6 @@ struct class_device *tty_register_device(struct tty_driver *driver, */ void tty_unregister_device(struct tty_driver *driver, unsigned index) { - devfs_remove("%s%d", driver->devfs_name, index + driver->name_base); class_device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); } @@ -3113,7 +3108,7 @@ int tty_register_driver(struct tty_driver *driver) list_add(&driver->tty_drivers, &tty_drivers); - if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) { + if ( !(driver->flags & TTY_DRIVER_DYNAMIC_DEV) ) { for(i = 0; i < driver->num; i++) tty_register_device(driver, i, NULL); } @@ -3156,7 +3151,7 @@ int tty_unregister_driver(struct tty_driver *driver) driver->termios_locked[i] = NULL; kfree(tp); } - if (!(driver->flags & TTY_DRIVER_NO_DEVFS)) + if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) tty_unregister_device(driver, i); } p = driver->ttys; @@ -3232,14 +3227,12 @@ static int __init tty_init(void) if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) panic("Couldn't register /dev/tty driver\n"); - devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty"); class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); cdev_init(&console_cdev, &console_fops); if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) panic("Couldn't register /dev/console driver\n"); - devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console"); class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); #ifdef CONFIG_UNIX98_PTYS @@ -3247,7 +3240,6 @@ static int __init tty_init(void) if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) panic("Couldn't register /dev/ptmx driver\n"); - devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx"); class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); #endif @@ -3256,7 +3248,6 @@ static int __init tty_init(void) if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) panic("Couldn't register /dev/tty0 driver\n"); - devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0"); class_device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); vty_init(); diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index 3c1dafaa3441..234d7f3fb114 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -26,7 +26,6 @@ #include <linux/major.h> #include <linux/errno.h> #include <linux/tty.h> -#include <linux/devfs_fs_kernel.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/mm.h> @@ -478,12 +477,6 @@ static struct class *vc_class; void vcs_make_devfs(struct tty_struct *tty) { - devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 1), - S_IFCHR|S_IRUSR|S_IWUSR, - "vcc/%u", tty->index + 1); - devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 129), - S_IFCHR|S_IRUSR|S_IWUSR, - "vcc/a%u", tty->index + 1); class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1), NULL, "vcs%u", tty->index + 1); class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129), @@ -491,8 +484,6 @@ void vcs_make_devfs(struct tty_struct *tty) } void vcs_remove_devfs(struct tty_struct *tty) { - devfs_remove("vcc/%u", tty->index + 1); - devfs_remove("vcc/a%u", tty->index + 1); class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1)); class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129)); } @@ -503,8 +494,6 @@ int __init vcs_init(void) panic("unable to get major %d for vcs device", VCS_MAJOR); vc_class = class_create(THIS_MODULE, "vc"); - devfs_mk_cdev(MKDEV(VCS_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/0"); - devfs_mk_cdev(MKDEV(VCS_MAJOR, 128), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a0"); class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); return 0; diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c index 4e5360388748..07f5ce4b28e3 100644 --- a/drivers/char/viocons.c +++ b/drivers/char/viocons.c @@ -1152,7 +1152,6 @@ static int __init viocons_init2(void) viotty_driver = alloc_tty_driver(VTTY_PORTS); viotty_driver->owner = THIS_MODULE; viotty_driver->driver_name = "vioconsole"; - viotty_driver->devfs_name = "vcs/"; viotty_driver->name = "tty"; viotty_driver->name_base = 1; viotty_driver->major = TTY_MAJOR; diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index 11c7e9de5958..198f1505ae23 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -43,7 +43,6 @@ #include <linux/dma-mapping.h> #include <linux/fs.h> #include <linux/cdev.h> -#include <linux/devfs_fs_kernel.h> #include <linux/major.h> #include <linux/completion.h> #include <linux/proc_fs.h> @@ -246,7 +245,6 @@ static struct device *tape_device[VIOTAPE_MAX_TAPE]; */ static struct { unsigned char cur_part; - int dev_handle; unsigned char part_stat_rwi[MAX_PARTITIONS]; } state[VIOTAPE_MAX_TAPE]; @@ -959,12 +957,7 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) "iseries!vt%d", i); class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), NULL, "iseries!nvt%d", i); - devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, - "iseries/vt%d", i); - devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i | 0x80), - S_IFCHR | S_IRUSR | S_IWUSR, "iseries/nvt%d", i); sprintf(tapename, "iseries/vt%d", i); - state[i].dev_handle = devfs_register_tape(tapename); printk(VIOTAPE_KERN_INFO "tape %s is iSeries " "resource %10.10s type %4.4s, model %3.3s\n", tapename, viotape_unitinfo[i].rsrcname, @@ -976,9 +969,6 @@ static int viotape_remove(struct vio_dev *vdev) { int i = vdev->unit_address; - devfs_remove("iseries/nvt%d", i); - devfs_remove("iseries/vt%d", i); - devfs_unregister_tape(state[i].dev_handle); class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); return 0; diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c index fd00822ac145..fe99fc1aba45 100644 --- a/drivers/char/vme_scc.c +++ b/drivers/char/vme_scc.c @@ -147,7 +147,6 @@ static int scc_init_drivers(void) scc_driver->owner = THIS_MODULE; scc_driver->driver_name = "scc"; scc_driver->name = "ttyS"; - scc_driver->devfs_name = "tts/"; scc_driver->major = TTY_MAJOR; scc_driver->minor_start = SCC_MINOR_BASE; scc_driver->type = TTY_DRIVER_TYPE_SERIAL; diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 714d95ff2f1e..d6f65032649a 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -79,7 +79,6 @@ #include <linux/mm.h> #include <linux/console.h> #include <linux/init.h> -#include <linux/devfs_fs_kernel.h> #include <linux/vt_kern.h> #include <linux/selection.h> #include <linux/tiocl.h> @@ -2663,7 +2662,6 @@ int __init vty_init(void) if (!console_driver) panic("Couldn't allocate console driver\n"); console_driver->owner = THIS_MODULE; - console_driver->devfs_name = "vc/"; console_driver->name = "tty"; console_driver->name_base = 1; console_driver->major = TTY_MAJOR; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 99fa42402e71..bfafd4846a08 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -3527,8 +3527,6 @@ static int ide_cd_probe(ide_drive_t *drive) drive->driver_data = info; g->minors = 1; - snprintf(g->devfs_name, sizeof(g->devfs_name), - "%s/cd", drive->devfs_name); g->driverfs_dev = &drive->gendev; g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE; if (ide_cdrom_setup(drive)) { diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index f033d732f387..d0227c39ced1 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -1018,7 +1018,6 @@ static void ide_disk_release(struct kref *kref) struct gendisk *g = idkp->disk; drive->driver_data = NULL; - drive->devfs_name[0] = '\0'; g->private_data = NULL; put_disk(g); kfree(idkp); @@ -1222,7 +1221,6 @@ static int ide_disk_probe(ide_drive_t *drive) drive->attach = 1; g->minors = 1 << PARTN_BITS; - strcpy(g->devfs_name, drive->devfs_name); g->driverfs_dev = &drive->gendev; g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0; set_capacity(g, idedisk_capacity(drive)); diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 4656587aa2f7..68628327c0f5 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -2176,7 +2176,6 @@ static int ide_floppy_probe(ide_drive_t *drive) g->minors = 1 << PARTN_BITS; g->driverfs_dev = &drive->gendev; - strcpy(g->devfs_name, drive->devfs_name); g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0; g->fops = &idefloppy_ops; drive->attach = 1; diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 9ebf8ae2a5e3..0d5038a28560 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -47,7 +47,6 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/ide.h> -#include <linux/devfs_fs_kernel.h> #include <linux/spinlock.h> #include <linux/kmod.h> #include <linux/pci.h> @@ -1279,10 +1278,6 @@ static void drive_release_dev (struct device *dev) ide_drive_t *drive = container_of(dev, ide_drive_t, gendev); spin_lock_irq(&ide_lock); - if (drive->devfs_name[0] != '\0') { - devfs_remove(drive->devfs_name); - drive->devfs_name[0] = '\0'; - } ide_remove_drive_from_hwgroup(drive); kfree(drive->id); drive->id = NULL; @@ -1316,12 +1311,6 @@ static void init_gendisk (ide_hwif_t *hwif) drive->gendev.bus = &ide_bus_type; drive->gendev.driver_data = drive; drive->gendev.release = drive_release_dev; - if (drive->present) { - sprintf(drive->devfs_name, "ide/host%d/bus%d/target%d/lun%d", - (hwif->channel && hwif->mate) ? - hwif->mate->index : hwif->index, - hwif->channel, unit, drive->lun); - } } blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS, THIS_MODULE, ata_probe, ata_lock, hwif); diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 09f3a7dab28a..4b91101e12b7 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -435,7 +435,6 @@ #include <linux/interrupt.h> #include <linux/jiffies.h> #include <linux/major.h> -#include <linux/devfs_fs_kernel.h> #include <linux/errno.h> #include <linux/genhd.h> #include <linux/slab.h> @@ -4726,9 +4725,6 @@ static void ide_tape_release(struct kref *kref) MKDEV(IDETAPE_MAJOR, tape->minor)); class_device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor + 128)); - devfs_remove("%s/mt", drive->devfs_name); - devfs_remove("%s/mtn", drive->devfs_name); - devfs_unregister_tape(g->number); idetape_devs[tape->minor] = NULL; g->private_data = NULL; put_disk(g); @@ -4902,14 +4898,6 @@ static int ide_tape_probe(ide_drive_t *drive) class_device_create(idetape_sysfs_class, NULL, MKDEV(IDETAPE_MAJOR, minor + 128), &drive->gendev, "n%s", tape->name); - devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor), - S_IFCHR | S_IRUGO | S_IWUGO, - "%s/mt", drive->devfs_name); - devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor + 128), - S_IFCHR | S_IRUGO | S_IWUGO, - "%s/mtn", drive->devfs_name); - - g->number = devfs_register_tape(drive->devfs_name); g->fops = &idetape_block_ops; ide_register_region(g); diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 59fe358048b3..1cdf44205162 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -147,7 +147,6 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/ide.h> -#include <linux/devfs_fs_kernel.h> #include <linux/completion.h> #include <linux/reboot.h> #include <linux/cdrom.h> @@ -592,13 +591,8 @@ void ide_unregister(unsigned int index) goto abort; for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &hwif->drives[unit]; - if (!drive->present) { - if (drive->devfs_name[0] != '\0') { - devfs_remove(drive->devfs_name); - drive->devfs_name[0] = '\0'; - } + if (!drive->present) continue; - } spin_unlock_irq(&ide_lock); device_unregister(&drive->gendev); wait_for_completion(&drive->gendev_rel_comp); @@ -1996,7 +1990,6 @@ EXPORT_SYMBOL_GPL(ide_bus_type); static int __init ide_init(void) { printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n"); - devfs_mk_dir("ide"); system_bus_speed = ide_system_bus_speed(); bus_register(&ide_bus_type); @@ -2074,7 +2067,6 @@ void cleanup_module (void) #ifdef CONFIG_PROC_FS proc_ide_destroy(); #endif - devfs_remove("ide"); bus_unregister(&ide_bus_type); } diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index 6d66351805a2..9cad197a4e68 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -3,11 +3,9 @@ #include <linux/config.h> #include <asm/io.h> - -#ifdef CONFIG_PCI #include <asm/oplib.h> -#include <asm/ebus.h> -#endif +#include <asm/prom.h> +#include <asm/of_device.h> static int i8042_kbd_irq = -1; static int i8042_aux_irq = -1; @@ -48,54 +46,83 @@ static inline void i8042_write_command(int val) #define OBP_PS2MS_NAME1 "kdmouse" #define OBP_PS2MS_NAME2 "mouse" +static int __devinit sparc_i8042_probe(struct of_device *op, const struct of_device_id *match) +{ + struct device_node *dp = op->node; + + dp = dp->child; + while (dp) { + if (!strcmp(dp->name, OBP_PS2KBD_NAME1) || + !strcmp(dp->name, OBP_PS2KBD_NAME2)) { + struct of_device *kbd = of_find_device_by_node(dp); + unsigned int irq = kbd->irqs[0]; + if (irq == 0xffffffff) + irq = op->irqs[0]; + i8042_kbd_irq = irq; + kbd_iobase = of_ioremap(&kbd->resource[0], + 0, 8, "kbd"); + } else if (!strcmp(dp->name, OBP_PS2MS_NAME1) || + !strcmp(dp->name, OBP_PS2MS_NAME2)) { + struct of_device *ms = of_find_device_by_node(dp); + unsigned int irq = ms->irqs[0]; + if (irq == 0xffffffff) + irq = op->irqs[0]; + i8042_aux_irq = irq; + } + + dp = dp->sibling; + } + + return 0; +} + +static int __devexit sparc_i8042_remove(struct of_device *op) +{ + of_iounmap(kbd_iobase, 8); + + return 0; +} + +static struct of_device_id sparc_i8042_match[] = { + { + .name = "8042", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, i8042_match); + +static struct of_platform_driver sparc_i8042_driver = { + .name = "i8042", + .match_table = sparc_i8042_match, + .probe = sparc_i8042_probe, + .remove = __devexit_p(sparc_i8042_remove), +}; + static int __init i8042_platform_init(void) { #ifndef CONFIG_PCI return -ENODEV; #else - char prop[128]; - int len; + struct device_node *root = of_find_node_by_path("/"); - len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop)); - if (len < 0) { - printk("i8042: Cannot get name property of root OBP node.\n"); - return -ENODEV; - } - if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) { + if (!strcmp(root->name, "SUNW,JavaStation-1")) { /* Hardcoded values for MrCoffee. */ i8042_kbd_irq = i8042_aux_irq = 13 | 0x20; kbd_iobase = ioremap(0x71300060, 8); if (!kbd_iobase) return -ENODEV; } else { - struct linux_ebus *ebus; - struct linux_ebus_device *edev; - struct linux_ebus_child *child; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_node->name, "8042")) - goto edev_found; - } - } - return -ENODEV; - - edev_found: - for_each_edevchild(edev, child) { - if (!strcmp(child->prom_node->name, OBP_PS2KBD_NAME1) || - !strcmp(child->prom_node->name, OBP_PS2KBD_NAME2)) { - i8042_kbd_irq = child->irqs[0]; - kbd_iobase = - ioremap(child->resource[0].start, 8); - } - if (!strcmp(child->prom_node->name, OBP_PS2MS_NAME1) || - !strcmp(child->prom_node->name, OBP_PS2MS_NAME2)) - i8042_aux_irq = child->irqs[0]; - } + int err = of_register_driver(&sparc_i8042_driver, + &of_bus_type); + if (err) + return err; + if (i8042_kbd_irq == -1 || i8042_aux_irq == -1) { - printk("i8042: Error, 8042 device lacks both kbd and " - "mouse nodes.\n"); + if (kbd_iobase) { + of_iounmap(kbd_iobase, 8); + kbd_iobase = (void __iomem *) NULL; + } return -ENODEV; } } @@ -109,7 +136,10 @@ static int __init i8042_platform_init(void) static inline void i8042_platform_exit(void) { #ifdef CONFIG_PCI - iounmap(kbd_iobase); + struct device_node *root = of_find_node_by_path("/"); + + if (strcmp(root->name, "SUNW,JavaStation-1")) + of_unregister_driver(&sparc_i8042_driver); #endif } diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 5a2703b536dc..71a8eea816cb 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -16,7 +16,6 @@ #include <linux/init.h> #include <linux/major.h> #include <linux/device.h> -#include <linux/devfs_fs_kernel.h> #include <linux/miscdevice.h> #include <linux/wait.h> #include <linux/mutex.h> diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 2e541fa02024..a518ec531021 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -39,7 +39,6 @@ #include <linux/init.h> #include <linux/device.h> #include <linux/moduleparam.h> -#include <linux/devfs_fs_kernel.h> #include <linux/isdn/capiutil.h> #include <linux/isdn/capicmd.h> #if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE) @@ -1337,7 +1336,6 @@ static int capinc_tty_init(void) drv->owner = THIS_MODULE; drv->driver_name = "capi_nc"; - drv->devfs_name = "capi/"; drv->name = "capi"; drv->major = capi_ttymajor; drv->minor_start = 0; @@ -1516,8 +1514,6 @@ static int __init capi_init(void) } class_device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi"); - devfs_mk_cdev(MKDEV(capi_major, 0), S_IFCHR | S_IRUSR | S_IWUSR, - "isdn/capi20"); #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE if (capinc_tty_init() < 0) { @@ -1552,7 +1548,6 @@ static void __exit capi_exit(void) class_device_destroy(capi_class, MKDEV(capi_major, 0)); class_destroy(capi_class); unregister_chrdev(capi_major, "capi20"); - devfs_remove("isdn/capi20"); #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE capinc_tty_exit(); diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 8a45715dd4c1..3845defd4901 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -41,7 +41,6 @@ MODULE_PARM_DESC(cidmode, "Call-ID mode"); #define GIGASET_MINORS 1 #define GIGASET_MINOR 16 #define GIGASET_MODULENAME "bas_gigaset" -#define GIGASET_DEVFSNAME "gig/bas/" #define GIGASET_DEVNAME "ttyGB" /* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */ @@ -2349,8 +2348,7 @@ static int __init bas_gigaset_init(void) /* allocate memory for our driver state and intialize it */ if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, GIGASET_MODULENAME, GIGASET_DEVNAME, - GIGASET_DEVFSNAME, &gigops, - THIS_MODULE)) == NULL) + &gigops, THIS_MODULE)) == NULL) goto error; /* allocate memory for our device state and intialize it */ diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 2a56bf33a673..aca165d43aa0 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -1092,14 +1092,12 @@ EXPORT_SYMBOL_GPL(gigaset_freedriver); * minors Number of minors this driver can handle * procname Name of the driver * devname Name of the device files (prefix without minor number) - * devfsname Devfs name of the device files without %d * return value: * Pointer to the gigaset_driver structure on success, NULL on failure. */ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, const char *procname, const char *devname, - const char *devfsname, const struct gigaset_ops *ops, struct module *owner) { @@ -1139,7 +1137,7 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, drv->cs[i].minor_index = i; } - gigaset_if_initdriver(drv, procname, devname, devfsname); + gigaset_if_initdriver(drv, procname, devname); spin_lock_irqsave(&driver_lock, flags); list_add(&drv->list, &drivers); diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 8d63d822104f..1ca3bfdef51d 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -769,7 +769,6 @@ void gigaset_block_channels(struct cardstate *cs); struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, const char *procname, const char *devname, - const char *devfsname, const struct gigaset_ops *ops, struct module *owner); @@ -892,7 +891,7 @@ int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src, /* initialize interface */ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, - const char *devname, const char *devfsname); + const char *devname); /* release interface */ void gigaset_if_freedriver(struct gigaset_driver *drv); /* add minor */ diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index 74fd234956c8..bd2e4267528e 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -673,10 +673,9 @@ EXPORT_SYMBOL_GPL(gigaset_if_receive); * drv Driver * procname Name of the driver (e.g. for /proc/tty/drivers) * devname Name of the device files (prefix without minor number) - * devfsname Devfs name of the device files without %d */ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, - const char *devname, const char *devfsname) + const char *devname) { unsigned minors = drv->minors; int ret; @@ -692,7 +691,7 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, tty->major = GIG_MAJOR, tty->type = TTY_DRIVER_TYPE_SERIAL, tty->subtype = SERIAL_TYPE_NORMAL, - tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS, + tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty->driver_name = procname; tty->name = devname; @@ -700,7 +699,6 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, tty->num = drv->minors; tty->owner = THIS_MODULE; - tty->devfs_name = devfsname; tty->init_termios = tty_std_termios; //FIXME tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; //FIXME diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index d86ab68114b0..6e05d9d4a51a 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -41,7 +41,6 @@ MODULE_PARM_DESC(cidmode, "Call-ID mode"); #define GIGASET_MINORS 1 #define GIGASET_MINOR 8 #define GIGASET_MODULENAME "usb_gigaset" -#define GIGASET_DEVFSNAME "gig/usb/" #define GIGASET_DEVNAME "ttyGU" #define IF_WRITEBUF 2000 //FIXME // WAKEUP_CHARS: 256 @@ -896,8 +895,7 @@ static int __init usb_gigaset_init(void) /* allocate memory for our driver state and intialize it */ if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, GIGASET_MODULENAME, GIGASET_DEVNAME, - GIGASET_DEVFSNAME, &ops, - THIS_MODULE)) == NULL) + &ops, THIS_MODULE)) == NULL) goto error; /* allocate memory for our device state and intialize it */ diff --git a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c index 6146f7633be5..b163c5909182 100644 --- a/drivers/isdn/hardware/eicon/divamnt.c +++ b/drivers/isdn/hardware/eicon/divamnt.c @@ -17,7 +17,6 @@ #include <linux/sched.h> #include <linux/smp_lock.h> #include <linux/poll.h> -#include <linux/devfs_fs_kernel.h> #include <asm/uaccess.h> #include "platform.h" @@ -178,7 +177,6 @@ static struct file_operations divas_maint_fops = { static void divas_maint_unregister_chrdev(void) { - devfs_remove(DEVNAME); unregister_chrdev(major, DEVNAME); } @@ -190,7 +188,6 @@ static int DIVA_INIT_FUNCTION divas_maint_register_chrdev(void) DRIVERLNAME); return (0); } - devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DEVNAME); return (1); } diff --git a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c index df715b47e2b4..6e7d89a31c1d 100644 --- a/drivers/isdn/hardware/eicon/divasi.c +++ b/drivers/isdn/hardware/eicon/divasi.c @@ -19,7 +19,6 @@ #include <linux/poll.h> #include <linux/proc_fs.h> #include <linux/skbuff.h> -#include <linux/devfs_fs_kernel.h> #include <asm/uaccess.h> #include "platform.h" @@ -145,7 +144,6 @@ static struct file_operations divas_idi_fops = { static void divas_idi_unregister_chrdev(void) { - devfs_remove(DEVNAME); unregister_chrdev(major, DEVNAME); } @@ -157,7 +155,6 @@ static int DIVA_INIT_FUNCTION divas_idi_register_chrdev(void) DRIVERLNAME); return (0); } - devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DEVNAME); return (1); } diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c index c9b26e86d183..9dee6a39104c 100644 --- a/drivers/isdn/hardware/eicon/divasmain.c +++ b/drivers/isdn/hardware/eicon/divasmain.c @@ -14,7 +14,6 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/sched.h> -#include <linux/devfs_fs_kernel.h> #include <asm/uaccess.h> #include <asm/io.h> #include <linux/ioport.h> @@ -678,7 +677,6 @@ static struct file_operations divas_fops = { static void divas_unregister_chrdev(void) { - devfs_remove(DEVNAME); unregister_chrdev(major, DEVNAME); } @@ -690,7 +688,6 @@ static int DIVA_INIT_FUNCTION divas_register_chrdev(void) DRIVERLNAME); return (0); } - devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DEVNAME); return (1); } diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 433389daedb2..0a53a990c100 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1890,14 +1890,13 @@ isdn_tty_modem_init(void) if (!m->tty_modem) return -ENOMEM; m->tty_modem->name = "ttyI"; - m->tty_modem->devfs_name = "isdn/ttyI"; m->tty_modem->major = ISDN_TTY_MAJOR; m->tty_modem->minor_start = 0; m->tty_modem->type = TTY_DRIVER_TYPE_SERIAL; m->tty_modem->subtype = SERIAL_TYPE_NORMAL; m->tty_modem->init_termios = tty_std_termios; m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; m->tty_modem->driver_name = "isdn_tty"; tty_set_operations(m->tty_modem, &modem_ops); retval = tty_register_driver(m->tty_modem); diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 259fd8973ce9..9f1a049dc226 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -36,7 +36,6 @@ #include <linux/spinlock.h> #include <linux/completion.h> #include <linux/device.h> -#include <linux/devfs_fs_kernel.h> #include <asm/uaccess.h> #include <asm/semaphore.h> @@ -904,8 +903,6 @@ adbdev_init(void) return; } - devfs_mk_cdev(MKDEV(ADB_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR, "adb"); - adb_dev_class = class_create(THIS_MODULE, "adb"); if (IS_ERR(adb_dev_class)) return; diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 3edb3477f987..d13bb15a8a02 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -13,7 +13,6 @@ #include <linux/init.h> #include <linux/wait.h> #include <linux/slab.h> -#include <linux/devfs_fs_kernel.h> #include <linux/dm-ioctl.h> #include <linux/hdreg.h> @@ -68,14 +67,12 @@ static int dm_hash_init(void) { init_buckets(_name_buckets); init_buckets(_uuid_buckets); - devfs_mk_dir(DM_DIR); return 0; } static void dm_hash_exit(void) { dm_hash_remove_all(0); - devfs_remove(DM_DIR); } /*----------------------------------------------------------------- @@ -172,25 +169,6 @@ static void free_cell(struct hash_cell *hc) } /* - * devfs stuff. - */ -static int register_with_devfs(struct hash_cell *hc) -{ - struct gendisk *disk = dm_disk(hc->md); - - devfs_mk_bdev(MKDEV(disk->major, disk->first_minor), - S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, - DM_DIR "/%s", hc->name); - return 0; -} - -static int unregister_with_devfs(struct hash_cell *hc) -{ - devfs_remove(DM_DIR"/%s", hc->name); - return 0; -} - -/* * The kdev_t and uuid of a device can never change once it is * initially inserted. */ @@ -226,7 +204,6 @@ static int dm_hash_insert(const char *name, const char *uuid, struct mapped_devi } list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid)); } - register_with_devfs(cell); dm_get(md); dm_set_mdptr(md, cell); up_write(&_hash_lock); @@ -246,7 +223,6 @@ static void __hash_remove(struct hash_cell *hc) /* remove from the dev hash */ list_del(&hc->uuid_list); list_del(&hc->name_list); - unregister_with_devfs(hc); dm_set_mdptr(hc->md, NULL); table = dm_get_table(hc->md); @@ -342,16 +318,11 @@ static int dm_hash_rename(const char *old, const char *new) /* * rename and move the name cell. */ - unregister_with_devfs(hc); - list_del(&hc->name_list); old_name = hc->name; hc->name = new_name; list_add(&hc->name_list, _name_buckets + hash_str(new_name)); - /* rename the device node in devfs */ - register_with_devfs(hc); - /* * Wake up any dm event waiters. */ @@ -1501,7 +1472,6 @@ static struct file_operations _ctl_fops = { static struct miscdevice _dm_misc = { .minor = MISC_DYNAMIC_MINOR, .name = DM_NAME, - .devfs_name = "mapper/control", .fops = &_ctl_fops }; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 3ed2e53b9eb6..c99bf9f01759 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -167,7 +167,7 @@ static void local_exit(void) bioset_free(dm_set); if (unregister_blkdev(_major, _name) < 0) - DMERR("devfs_unregister_blkdev failed"); + DMERR("unregister_blkdev failed"); _major = 0; diff --git a/drivers/md/md.c b/drivers/md/md.c index 306268ec99ff..2ec1b3520a0b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -39,7 +39,6 @@ #include <linux/raid/md.h> #include <linux/raid/bitmap.h> #include <linux/sysctl.h> -#include <linux/devfs_fs_kernel.h> #include <linux/buffer_head.h> /* for invalidate_bdev */ #include <linux/suspend.h> #include <linux/poll.h> @@ -2911,13 +2910,10 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) } disk->major = MAJOR(dev); disk->first_minor = unit << shift; - if (partitioned) { + if (partitioned) sprintf(disk->disk_name, "md_d%d", unit); - sprintf(disk->devfs_name, "md/d%d", unit); - } else { + else sprintf(disk->disk_name, "md%d", unit); - sprintf(disk->devfs_name, "md/%d", unit); - } disk->fops = &md_fops; disk->private_data = mddev; disk->queue = mddev->queue; @@ -5538,8 +5534,6 @@ static void md_geninit(void) static int __init md_init(void) { - int minor; - printk(KERN_INFO "md: md driver %d.%d.%d MAX_MD_DEVS=%d," " MD_SB_DISKS=%d\n", MD_MAJOR_VERSION, MD_MINOR_VERSION, @@ -5553,23 +5547,11 @@ static int __init md_init(void) unregister_blkdev(MAJOR_NR, "md"); return -1; } - devfs_mk_dir("md"); blk_register_region(MKDEV(MAJOR_NR, 0), MAX_MD_DEVS, THIS_MODULE, md_probe, NULL, NULL); blk_register_region(MKDEV(mdp_major, 0), MAX_MD_DEVS<<MdpMinorShift, THIS_MODULE, md_probe, NULL, NULL); - for (minor=0; minor < MAX_MD_DEVS; ++minor) - devfs_mk_bdev(MKDEV(MAJOR_NR, minor), - S_IFBLK|S_IRUSR|S_IWUSR, - "md/%d", minor); - - for (minor=0; minor < MAX_MD_DEVS; ++minor) - devfs_mk_bdev(MKDEV(mdp_major, minor<<MdpMinorShift), - S_IFBLK|S_IRUSR|S_IWUSR, - "md/mdp%d", minor); - - register_reboot_notifier(&md_notifier); raid_table_header = register_sysctl_table(raid_root_table, 1); @@ -5625,15 +5607,9 @@ static __exit void md_exit(void) { mddev_t *mddev; struct list_head *tmp; - int i; + blk_unregister_region(MKDEV(MAJOR_NR,0), MAX_MD_DEVS); blk_unregister_region(MKDEV(mdp_major,0), MAX_MD_DEVS << MdpMinorShift); - for (i=0; i < MAX_MD_DEVS; i++) - devfs_remove("md/%d", i); - for (i=0; i < MAX_MD_DEVS; i++) - devfs_remove("md/d%d", i); - - devfs_remove("md"); unregister_blkdev(MAJOR_NR,"md"); unregister_blkdev(mdp_major, "mdp"); diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 134c2bbbeeb5..40774feb8953 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -231,10 +231,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, mutex_unlock(&dvbdev_register_lock); - devfs_mk_cdev(MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), - S_IFCHR | S_IRUSR | S_IWUSR, - "dvb/adapter%d/%s%d", adap->num, dnames[type], id); - class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), adap->device, "dvb%d.%s%d", adap->num, dnames[type], id); @@ -252,9 +248,6 @@ void dvb_unregister_device(struct dvb_device *dvbdev) if (!dvbdev) return; - devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num, - dnames[dvbdev->type], dvbdev->id); - class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, dvbdev->type, dvbdev->id))); @@ -302,7 +295,6 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct modu printk ("DVB: registering new adapter (%s).\n", name); - devfs_mk_dir("dvb/adapter%d", num); adap->num = num; adap->name = name; adap->module = module; @@ -319,8 +311,6 @@ EXPORT_SYMBOL(dvb_register_adapter); int dvb_unregister_adapter(struct dvb_adapter *adap) { - devfs_remove("dvb/adapter%d", adap->num); - if (mutex_lock_interruptible(&dvbdev_register_lock)) return -ERESTARTSYS; list_del (&adap->list_head); @@ -410,8 +400,6 @@ static int __init init_dvbdev(void) goto error; } - devfs_mk_dir("dvb"); - dvb_class = class_create(THIS_MODULE, "dvb"); if (IS_ERR(dvb_class)) { retval = PTR_ERR(dvb_class); @@ -428,7 +416,6 @@ error: static void __exit exit_dvbdev(void) { - devfs_remove("dvb"); class_destroy(dvb_class); cdev_del(&dvb_device_cdev); unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS); diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h index d7a976d040d7..7a7f75fd168c 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.h +++ b/drivers/media/dvb/dvb-core/dvbdev.h @@ -27,7 +27,6 @@ #include <linux/poll.h> #include <linux/fs.h> #include <linux/list.h> -#include <linux/devfs_fs_kernel.h> #include <linux/smp_lock.h> #define DVB_MAJOR 212 diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index 3e2e12124bae..9c79696da08a 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -6,10 +6,6 @@ #include <linux/netdevice.h> #include <linux/i2c.h> -#ifdef CONFIG_DEVFS_FS -#include <linux/devfs_fs_kernel.h> -#endif - #include <linux/dvb/video.h> #include <linux/dvb/audio.h> #include <linux/dvb/dmx.h> diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index 14559ef6153c..336b2fe1a5f2 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -126,10 +126,6 @@ struct ttusb { int revision; -#if 0 - devfs_handle_t stc_devfs_handle; -#endif - struct dvb_frontend* fe; }; @@ -1746,13 +1742,6 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i return -ENODEV; } -#if 0 - ttusb->stc_devfs_handle = - devfs_register(ttusb->adapter->devfs_handle, TTUSB_BUDGET_NAME, - DEVFS_FL_DEFAULT, 0, 192, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP - | S_IROTH | S_IWOTH, &stc_fops, ttusb); -#endif usb_set_intfdata(intf, (void *) ttusb); frontend_init(ttusb); diff --git a/drivers/media/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c index 87b37b7691da..c1b1db65e668 100644 --- a/drivers/media/radio/miropcm20-rds.c +++ b/drivers/media/radio/miropcm20-rds.c @@ -115,7 +115,6 @@ static struct file_operations rds_fops = { static struct miscdevice rds_miscdev = { .minor = MISC_DYNAMIC_MINOR, .name = "radiotext", - .devfs_name = "v4l/rds/radiotext", .fops = &rds_fops, }; diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index 6e08e32346eb..ae14f5f32039 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c @@ -20,7 +20,6 @@ #include <linux/config.h> #include <linux/init.h> -#include <linux/devfs_fs_kernel.h> #include <linux/module.h> #include <linux/delay.h> #include <linux/errno.h> diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 2dfa7f23d0ca..b26ebaff226f 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -37,7 +37,6 @@ #include <linux/init.h> #include <linux/kmod.h> #include <linux/slab.h> -#include <linux/devfs_fs_kernel.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -1563,10 +1562,6 @@ int video_register_device(struct video_device *vfd, int type, int nr) video_device[i]=vfd; vfd->minor=i; mutex_unlock(&videodev_lock); - - sprintf(vfd->devfs_name, "v4l/%s%d", name_base, i - base); - devfs_mk_cdev(MKDEV(VIDEO_MAJOR, vfd->minor), - S_IFCHR | S_IRUSR | S_IWUSR, vfd->devfs_name); mutex_init(&vfd->lock); /* sysfs class */ @@ -1575,7 +1570,7 @@ int video_register_device(struct video_device *vfd, int type, int nr) vfd->class_dev.dev = vfd->dev; vfd->class_dev.class = &video_class; vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); - strlcpy(vfd->class_dev.class_id, vfd->devfs_name + 4, BUS_ID_SIZE); + sprintf(vfd->class_dev.class_id, "%s%d", name_base, i - base); class_device_register(&vfd->class_dev); class_device_create_file(&vfd->class_dev, &class_device_attr_name); @@ -1604,7 +1599,6 @@ void video_unregister_device(struct video_device *vfd) if(video_device[vfd->minor]!=vfd) panic("videodev: bad unregister"); - devfs_remove(vfd->devfs_name); video_device[vfd->minor]=NULL; class_device_unregister(&vfd->class_dev); mutex_unlock(&videodev_lock); diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 7d4c5497785b..1ddc2fb429d5 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -1089,7 +1089,6 @@ static int i2o_block_probe(struct device *dev) gd = i2o_blk_dev->gd; gd->first_minor = unit << 4; sprintf(gd->disk_name, "i2o/hd%c", 'a' + unit); - sprintf(gd->devfs_name, "i2o/hd%c", 'a' + unit); gd->driverfs_dev = &i2o_dev->device; /* setup request queue */ diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index 587458b370b9..115cc21094b9 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -27,7 +27,6 @@ #include <linux/hdreg.h> #include <linux/kdev_t.h> #include <linux/blkdev.h> -#include <linux/devfs_fs_kernel.h> #include <linux/mutex.h> #include <linux/mmc/card.h> @@ -409,7 +408,6 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) */ sprintf(md->disk->disk_name, "mmcblk%d", devidx); - sprintf(md->disk->devfs_name, "mmc/blk%d", devidx); blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits); @@ -555,7 +553,6 @@ static int __init mmc_blk_init(void) if (major == 0) major = res; - devfs_mk_dir("mmc"); return mmc_register_driver(&mmc_driver); out: @@ -565,7 +562,6 @@ static int __init mmc_blk_init(void) static void __exit mmc_blk_exit(void) { mmc_unregister_driver(&mmc_driver); - devfs_remove("mmc"); unregister_blkdev(major, "mmc"); } diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 7635736cc791..d55b0f7939a6 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -57,8 +57,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.4.42" -#define DRV_MODULE_RELDATE "June 12, 2006" +#define DRV_MODULE_VERSION "1.4.43" +#define DRV_MODULE_RELDATE "June 28, 2006" #define RUN_AT(x) (jiffies + (x)) @@ -1676,7 +1676,7 @@ bnx2_tx_int(struct bnx2 *bp) tx_free_bd += last + 1; - dev_kfree_skb_irq(skb); + dev_kfree_skb(skb); hw_cons = bp->hw_tx_cons = sblk->status_tx_quick_consumer_index0; @@ -1824,7 +1824,7 @@ reuse_rx: if ((len > (bp->dev->mtu + ETH_HLEN)) && (ntohs(skb->protocol) != 0x8100)) { - dev_kfree_skb_irq(skb); + dev_kfree_skb(skb); goto next_rx; } @@ -3643,7 +3643,7 @@ bnx2_free_tx_skbs(struct bnx2 *bp) skb_shinfo(skb)->frags[j].size, PCI_DMA_TODEVICE); } - dev_kfree_skb_any(skb); + dev_kfree_skb(skb); i += j + 1; } @@ -3669,7 +3669,7 @@ bnx2_free_rx_skbs(struct bnx2 *bp) rx_buf->skb = NULL; - dev_kfree_skb_any(skb); + dev_kfree_skb(skb); } } @@ -3999,7 +3999,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) udelay(5); pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skb); + dev_kfree_skb(skb); if (bp->status_blk->status_tx_quick_consumer_index0 != bp->tx_prod) { goto loopback_test_done; @@ -4541,7 +4541,7 @@ bnx2_close(struct net_device *dev) bnx2_netif_stop(bp); del_timer_sync(&bp->timer); if (bp->flags & NO_WOL_FLAG) - reset_code = BNX2_DRV_MSG_CODE_UNLOAD; + reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; else if (bp->wol) reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL; else @@ -5128,6 +5128,16 @@ bnx2_set_rx_csum(struct net_device *dev, u32 data) return 0; } +static int +bnx2_set_tso(struct net_device *dev, u32 data) +{ + if (data) + dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; + else + dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN); + return 0; +} + #define BNX2_NUM_STATS 46 static struct { @@ -5445,7 +5455,7 @@ static struct ethtool_ops bnx2_ethtool_ops = { .set_sg = ethtool_op_set_sg, #ifdef BCM_TSO .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, + .set_tso = bnx2_set_tso, #endif .self_test_count = bnx2_self_test_count, .self_test = bnx2_self_test, @@ -5926,7 +5936,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; #endif #ifdef BCM_TSO - dev->features |= NETIF_F_TSO; + dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; #endif netif_carrier_off(bp->dev); @@ -5968,7 +5978,7 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state) netif_device_detach(dev); del_timer_sync(&bp->timer); if (bp->flags & NO_WOL_FLAG) - reset_code = BNX2_DRV_MSG_CODE_UNLOAD; + reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; else if (bp->wol) reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL; else diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 5845e334941b..658c5ee95c73 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -4174,6 +4174,7 @@ struct fw_info { #define BNX2_DRV_MSG_CODE_PULSE 0x06000000 #define BNX2_DRV_MSG_CODE_DIAG 0x07000000 #define BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL 0x09000000 +#define BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN 0x0b000000 #define BNX2_DRV_MSG_DATA 0x00ff0000 #define BNX2_DRV_MSG_DATA_WAIT0 0x00010000 diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index d2ce4896abff..e9e6d99a9add 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -350,7 +350,7 @@ config TOSHIBA_FIR config AU1000_FIR tristate "Alchemy Au1000 SIR/FIR" - depends on MIPS_AU1000 && IRDA + depends on SOC_AU1000 && IRDA config SMC_IRCC_FIR tristate "SMSC IrCC (EXPERIMENTAL)" diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index 754297fc8f22..47f6f64d604c 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -101,7 +101,7 @@ static int transceiver_type = MCS_TSC_VISHAY; module_param(transceiver_type, int, 0444); MODULE_PARM_DESC(transceiver_type, "IR transceiver type, see mcs7780.h."); -struct usb_driver mcs_driver = { +static struct usb_driver mcs_driver = { .name = "mcs7780", .probe = mcs_probe, .disconnect = mcs_disconnect, diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index d643a097faa5..425ff5b117f1 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -28,7 +28,6 @@ #include <linux/kmod.h> #include <linux/init.h> #include <linux/list.h> -#include <linux/devfs_fs_kernel.h> #include <linux/netdevice.h> #include <linux/poll.h> #include <linux/ppp_defs.h> @@ -863,10 +862,6 @@ static int __init ppp_init(void) goto out_chrdev; } class_device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); - err = devfs_mk_cdev(MKDEV(PPP_MAJOR, 0), - S_IFCHR|S_IRUSR|S_IWUSR, "ppp"); - if (err) - goto out_class; } out: @@ -874,9 +869,6 @@ out: printk(KERN_ERR "failed to register PPP device (%d)\n", err); return err; -out_class: - class_device_destroy(ppp_class, MKDEV(PPP_MAJOR,0)); - class_destroy(ppp_class); out_chrdev: unregister_chrdev(PPP_MAJOR, "ppp"); goto out; @@ -2681,7 +2673,6 @@ static void __exit ppp_cleanup(void) cardmap_destroy(&all_ppp_units); if (unregister_chrdev(PPP_MAJOR, "ppp") != 0) printk(KERN_ERR "PPP: failed to unregister PPP device\n"); - devfs_remove("ppp"); class_device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); class_destroy(ppp_class); } diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index c33ead3470db..9b246e44f756 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2523,7 +2523,7 @@ static struct ethtool_ops hme_ethtool_ops = { static int hme_version_printed; #ifdef CONFIG_SBUS -void __init quattro_get_ranges(struct quattro *qp) +void __devinit quattro_get_ranges(struct quattro *qp) { struct sbus_dev *sdev = qp->quattro_dev; int err; @@ -2539,7 +2539,7 @@ void __init quattro_get_ranges(struct quattro *qp) qp->nranges = (err / sizeof(struct linux_prom_ranges)); } -static void __init quattro_apply_ranges(struct quattro *qp, struct happy_meal *hp) +static void __devinit quattro_apply_ranges(struct quattro *qp, struct happy_meal *hp) { struct sbus_dev *sdev = hp->happy_dev; int rng; @@ -2566,7 +2566,7 @@ static void __init quattro_apply_ranges(struct quattro *qp, struct happy_meal *h * * Return NULL on failure. */ -static struct quattro * __init quattro_sbus_find(struct sbus_dev *goal_sdev) +static struct quattro * __devinit quattro_sbus_find(struct sbus_dev *goal_sdev) { struct sbus_dev *sdev; struct quattro *qp; @@ -2618,7 +2618,7 @@ static void __init quattro_sbus_register_irqs(void) } } -static void __devexit quattro_sbus_free_irqs(void) +static void quattro_sbus_free_irqs(void) { struct quattro *qp; @@ -2662,7 +2662,7 @@ static struct quattro * __init quattro_pci_find(struct pci_dev *pdev) #endif /* CONFIG_PCI */ #ifdef CONFIG_SBUS -static int __init happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe) +static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe) { struct device_node *dp = sdev->ofdev.node; struct quattro *qp = NULL; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 6c62d5c88268..732c5edec2e5 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -780,7 +780,6 @@ static struct miscdevice tun_miscdev = { .minor = TUN_MINOR, .name = "tun", .fops = &tun_fops, - .devfs_name = "net/tun", }; /* ethtool interface */ diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index e392ee8b37a1..be5e33814cb1 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -85,7 +85,6 @@ #include <linux/slab.h> #include <linux/poll.h> #include <linux/fs.h> -#include <linux/devfs_fs_kernel.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/errno.h> @@ -393,7 +392,6 @@ static int __init cosa_init(void) err = -ENODEV; goto out; } - devfs_mk_dir("cosa"); cosa_class = class_create(THIS_MODULE, "cosa"); if (IS_ERR(cosa_class)) { err = PTR_ERR(cosa_class); @@ -402,13 +400,6 @@ static int __init cosa_init(void) for (i=0; i<nr_cards; i++) { class_device_create(cosa_class, NULL, MKDEV(cosa_major, i), NULL, "cosa%d", i); - err = devfs_mk_cdev(MKDEV(cosa_major, i), - S_IFCHR|S_IRUSR|S_IWUSR, - "cosa/%d", i); - if (err) { - class_device_destroy(cosa_class, MKDEV(cosa_major, i)); - goto out_chrdev; - } } err = 0; goto out; @@ -426,12 +417,9 @@ static void __exit cosa_exit(void) int i; printk(KERN_INFO "Unloading the cosa module\n"); - for (i=0; i<nr_cards; i++) { + for (i=0; i<nr_cards; i++) class_device_destroy(cosa_class, MKDEV(cosa_major, i)); - devfs_remove("cosa/%d", i); - } class_destroy(cosa_class); - devfs_remove("cosa"); for (cosa=cosa_cards; nr_cards--; cosa++) { /* Clean up the per-channel data */ for (i=0; i<cosa->nchannels; i++) { diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index bafcd2f20ae2..2dc179b14ce6 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1834,7 +1834,6 @@ dasd_exit(void) } dasd_gendisk_exit(); dasd_devmap_exit(); - devfs_remove("dasd"); if (dasd_debug_area != NULL) { debug_unregister(dasd_debug_area); dasd_debug_area = NULL; @@ -2107,9 +2106,6 @@ dasd_init(void) dasd_diag_discipline_pointer = NULL; - rc = devfs_mk_dir("dasd"); - if (rc) - goto failed; rc = dasd_devmap_init(); if (rc) goto failed; diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index fce2835e7d19..61ffde718a7a 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -68,8 +68,6 @@ dasd_gendisk_alloc(struct dasd_device *device) } len += sprintf(gdp->disk_name + len, "%c", 'a'+(device->devindex%26)); - sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id); - if (device->features & DASD_FEATURE_READONLY) set_disk_ro(gdp, 1); gdp->private_data = device; diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 03a83efc34c4..3ccf06d28ba1 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -54,7 +54,6 @@ #include <linux/module.h> #include <linux/wait.h> #include <linux/blkdev.h> -#include <linux/devfs_fs_kernel.h> #include <linux/genhd.h> #include <linux/hdreg.h> #include <linux/interrupt.h> diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 54ecd548c318..4c1e56b9b98d 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -36,7 +36,6 @@ #include <linux/hdreg.h> /* HDIO_GETGEO */ #include <linux/sysdev.h> #include <linux/bio.h> -#include <linux/devfs_fs_kernel.h> #include <asm/uaccess.h> #define XPRAM_NAME "xpram" @@ -439,8 +438,6 @@ static int __init xpram_setup_blkdev(void) if (rc < 0) goto out; - devfs_mk_dir("slram"); - /* * Assign the other needed values: make request function, sizes and * hardsect size. All the minor devices feature the same value. @@ -469,14 +466,12 @@ static int __init xpram_setup_blkdev(void) disk->private_data = &xpram_devices[i]; disk->queue = xpram_queue; sprintf(disk->disk_name, "slram%d", i); - sprintf(disk->devfs_name, "slram/%d", i); set_capacity(disk, xpram_sizes[i] << 1); add_disk(disk); } return 0; out_unreg: - devfs_remove("slram"); unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); out: while (i--) @@ -495,7 +490,6 @@ static void __exit xpram_exit(void) put_disk(xpram_disks[i]); } unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); - devfs_remove("slram"); blk_cleanup_queue(xpram_queue); sysdev_unregister(&xpram_sys_device); sysdev_class_unregister(&xpram_sysclass); diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index fb7bc9e5eebc..a138b1510093 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -586,7 +586,6 @@ static struct file_operations mon_fops = { static struct miscdevice mon_dev = { .name = "monreader", - .devfs_name = "monreader", .fops = &mon_fops, .minor = MISC_DYNAMIC_MINOR, }; diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 9a141776873f..7d26a3e4cb80 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -1785,7 +1785,6 @@ tty3270_init(void) * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc */ driver->owner = THIS_MODULE; - driver->devfs_name = "ttyTUB/"; driver->driver_name = "ttyTUB"; driver->name = "ttyTUB"; driver->major = IBM_TTY3270_MAJOR; @@ -1793,7 +1792,7 @@ tty3270_init(void) driver->type = TTY_DRIVER_TYPE_SYSTEM; driver->subtype = SYSTEM_TYPE_TTY; driver->init_termios = tty_std_termios; - driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_NO_DEVFS; + driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(driver, &tty3270_ops); ret = tty_register_driver(driver); if (ret) { diff --git a/drivers/s390/crypto/z90main.c b/drivers/s390/crypto/z90main.c index 982acc7303ea..b2f20ab8431a 100644 --- a/drivers/s390/crypto/z90main.c +++ b/drivers/s390/crypto/z90main.c @@ -411,7 +411,6 @@ static struct miscdevice z90crypt_misc_device = { .minor = Z90CRYPT_MINOR, .name = DEV_NAME, .fops = &z90crypt_fops, - .devfs_name = DEV_NAME }; /** diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c index ccb20a6f5f36..385f4f768311 100644 --- a/drivers/sbus/char/bpp.c +++ b/drivers/sbus/char/bpp.c @@ -20,7 +20,6 @@ #include <linux/timer.h> #include <linux/ioport.h> #include <linux/major.h> -#include <linux/devfs_fs_kernel.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -1031,11 +1030,6 @@ static int __init bpp_init(void) instances[idx].opened = 0; probeLptPort(idx); } - devfs_mk_dir("bpp"); - for (idx = 0; idx < BPP_NO; idx++) { - devfs_mk_cdev(MKDEV(BPP_MAJOR, idx), - S_IFCHR | S_IRUSR | S_IWUSR, "bpp/%d", idx); - } return 0; } @@ -1044,9 +1038,6 @@ static void __exit bpp_cleanup(void) { unsigned idx; - for (idx = 0; idx < BPP_NO; idx++) - devfs_remove("bpp/%d", idx); - devfs_remove("bpp"); unregister_chrdev(BPP_MAJOR, dev_name); for (idx = 0; idx < BPP_NO; idx++) { diff --git a/drivers/sbus/char/vfc.h b/drivers/sbus/char/vfc.h index 8045cd5e7cb3..63941a259b92 100644 --- a/drivers/sbus/char/vfc.h +++ b/drivers/sbus/char/vfc.h @@ -1,8 +1,6 @@ #ifndef _LINUX_VFC_H_ #define _LINUX_VFC_H_ -#include <linux/devfs_fs_kernel.h> - /* * The control register for the vfc is at offset 0x4000 * The first field ram bank is located at offset 0x5000 diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c index ddcd330b9e89..55b2b31bd7ab 100644 --- a/drivers/sbus/char/vfc_dev.c +++ b/drivers/sbus/char/vfc_dev.c @@ -164,10 +164,6 @@ int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev, int instance) return -EINVAL; if (init_vfc_hw(dev)) return -EIO; - - devfs_mk_cdev(MKDEV(VFC_MAJOR, instance), - S_IFCHR | S_IRUSR | S_IWUSR, - "vfc/%d", instance); return 0; } @@ -677,7 +673,6 @@ static int vfc_probe(void) kfree(vfc_dev_lst); return -EIO; } - devfs_mk_dir("vfc"); instance = 0; for_all_sbusdev(sdev, sbus) { if (strcmp(sdev->prom_name, "vfc") == 0) { @@ -717,7 +712,6 @@ static void deinit_vfc_device(struct vfc_dev *dev) { if(dev == NULL) return; - devfs_remove("vfc/%d", dev->instance); sbus_iounmap(dev->regs, sizeof(struct vfc_regs)); kfree(dev); } @@ -731,7 +725,6 @@ void cleanup_module(void) for (devp = vfc_dev_lst; *devp; devp++) deinit_vfc_device(*devp); - devfs_remove("vfc"); kfree(vfc_dev_lst); return; } diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c index 7572665a8855..9fd0de4b7afd 100644 --- a/drivers/serial/21285.c +++ b/drivers/serial/21285.c @@ -479,7 +479,6 @@ static struct uart_driver serial21285_reg = { .owner = THIS_MODULE, .driver_name = "ttyFB", .dev_name = "ttyFB", - .devfs_name = "ttyFB", .major = SERIAL_21285_MAJOR, .minor = SERIAL_21285_MINOR, .nr = 1, diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index bbf78aaf9e01..f361b356bd1d 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2354,7 +2354,6 @@ int __init serial8250_start_console(struct uart_port *port, char *options) static struct uart_driver serial8250_reg = { .owner = THIS_MODULE, .driver_name = "serial", - .devfs_name = "tts/", .dev_name = "ttyS", .major = TTY_MAJOR, .minor = 64, diff --git a/drivers/serial/at91_serial.c b/drivers/serial/at91_serial.c index db5b25fafed4..df9500bdaded 100644 --- a/drivers/serial/at91_serial.c +++ b/drivers/serial/at91_serial.c @@ -863,7 +863,6 @@ static struct uart_driver at91_uart = { .owner = THIS_MODULE, .driver_name = "at91_serial", .dev_name = AT91_DEVICENAME, - .devfs_name = AT91_DEVICENAME, .major = SERIAL_AT91_MAJOR, .minor = MINOR_START, .nr = AT91_NR_UART, diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c index 5cacc5e74a92..b84137cdeb2b 100644 --- a/drivers/serial/crisv10.c +++ b/drivers/serial/crisv10.c @@ -4878,7 +4878,7 @@ rs_init(void) driver->init_termios = tty_std_termios; driver->init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */ - driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; driver->termios = serial_termios; driver->termios_locked = serial_termios_locked; diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c index bf71bad5c34f..466d06cc7d37 100644 --- a/drivers/serial/dz.c +++ b/drivers/serial/dz.c @@ -768,11 +768,7 @@ void __init dz_serial_console_init(void) static struct uart_driver dz_reg = { .owner = THIS_MODULE, .driver_name = "serial", -#ifdef CONFIG_DEVFS - .dev_name = "tts/%d", -#else .dev_name = "ttyS%d", -#endif .major = TTY_MAJOR, .minor = 64, .nr = DZ_NB_PORT, diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index d202eb4f3848..da85bafa0942 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -888,7 +888,6 @@ static struct uart_driver imx_reg = { .owner = THIS_MODULE, .driver_name = DRIVER_NAME, .dev_name = "ttySMX", - .devfs_name = "ttsmx/", .major = SERIAL_IMX_MAJOR, .minor = MINOR_START, .nr = ARRAY_SIZE(imx_ports), diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c index 651772474ac1..56b093ecd779 100644 --- a/drivers/serial/ip22zilog.c +++ b/drivers/serial/ip22zilog.c @@ -1085,7 +1085,6 @@ static struct console ip22zilog_console = { static struct uart_driver ip22zilog_reg = { .owner = THIS_MODULE, .driver_name = "serial", - .devfs_name = "tts/", .dev_name = "ttyS", .major = TTY_MAJOR, .minor = 64, diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c index 321a40f33b50..6a2a25d9b596 100644 --- a/drivers/serial/m32r_sio.c +++ b/drivers/serial/m32r_sio.c @@ -1131,7 +1131,6 @@ console_initcall(m32r_sio_console_init); static struct uart_driver m32r_sio_reg = { .owner = THIS_MODULE, .driver_name = "sio", - .devfs_name = "tts/", .dev_name = "ttyS", .major = TTY_MAJOR, .minor = 64, diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c index 8ad242934368..29c0630e3e64 100644 --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -1713,7 +1713,6 @@ mcfrs_init(void) /* Initialize the tty_driver structure */ mcfrs_serial_driver->owner = THIS_MODULE; mcfrs_serial_driver->name = "ttyS"; - mcfrs_serial_driver->devfs_name = "ttys/"; mcfrs_serial_driver->driver_name = "serial"; mcfrs_serial_driver->major = TTY_MAJOR; mcfrs_serial_driver->minor_start = 64; diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 6459edc7f5c5..1aa34844218c 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -693,7 +693,6 @@ static struct uart_driver mpc52xx_uart_driver = { .owner = THIS_MODULE, .driver_name = "mpc52xx_psc_uart", .dev_name = "ttyPSC", - .devfs_name = "ttyPSC", .major = SERIAL_PSC_MAJOR, .minor = SERIAL_PSC_MINOR, .nr = MPC52xx_PSC_MAXNUM, diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c index 94681922ea0a..1cd102f84bfa 100644 --- a/drivers/serial/mpsc.c +++ b/drivers/serial/mpsc.c @@ -315,7 +315,6 @@ struct mpsc_port_info *mpsc_device_remove(int index); #define MPSC_MAJOR 204 #define MPSC_MINOR_START 44 #define MPSC_DRIVER_NAME "MPSC" -#define MPSC_DEVFS_NAME "ttymm/" #define MPSC_DEV_NAME "ttyMM" #define MPSC_VERSION "1.00" @@ -1863,7 +1862,6 @@ static struct platform_driver mpsc_shared_driver = { static struct uart_driver mpsc_reg = { .owner = THIS_MODULE, .driver_name = MPSC_DRIVER_NAME, - .devfs_name = MPSC_DEVFS_NAME, .dev_name = MPSC_DEV_NAME, .major = MPSC_MAJOR, .minor = MPSC_MINOR_START, diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c index 513ff8597707..e3ba7e17a240 100644 --- a/drivers/serial/pmac_zilog.c +++ b/drivers/serial/pmac_zilog.c @@ -101,7 +101,6 @@ static DEFINE_MUTEX(pmz_irq_mutex); static struct uart_driver pmz_uart_reg = { .owner = THIS_MODULE, .driver_name = "ttyS", - .devfs_name = "tts/", .dev_name = "ttyS", .major = TTY_MAJOR, }; diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index ae3649568541..0fa0ccc9ed27 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -780,7 +780,6 @@ static struct uart_pxa_port serial_pxa_ports[] = { static struct uart_driver serial_pxa_reg = { .owner = THIS_MODULE, .driver_name = "PXA serial", - .devfs_name = "tts/", .dev_name = "ttyS", .major = TTY_MAJOR, .minor = 64, diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 837b6da520b3..4c62ab949ecc 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -149,7 +149,6 @@ s3c24xx_serial_dbg(const char *fmt, ...) /* UART name and device definitions */ #define S3C24XX_SERIAL_NAME "ttySAC" -#define S3C24XX_SERIAL_DEVFS "tts/" #define S3C24XX_SERIAL_MAJOR 204 #define S3C24XX_SERIAL_MINOR 64 @@ -952,7 +951,6 @@ static struct uart_driver s3c24xx_uart_drv = { .nr = 3, .cons = S3C24XX_SERIAL_CONSOLE, .driver_name = S3C24XX_SERIAL_NAME, - .devfs_name = S3C24XX_SERIAL_DEVFS, .major = S3C24XX_SERIAL_MAJOR, .minor = S3C24XX_SERIAL_MINOR, }; diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index c2d9068b491d..8bbd8567669c 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -816,7 +816,6 @@ static struct uart_driver sa1100_reg = { .owner = THIS_MODULE, .driver_name = "ttySA", .dev_name = "ttySA", - .devfs_name = "ttySA", .major = SERIAL_SA1100_MAJOR, .minor = MINOR_START, .nr = NR_PORTS, diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 17839e753e4c..7dc1e67b6851 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -2153,7 +2153,6 @@ int uart_register_driver(struct uart_driver *drv) normal->owner = drv->owner; normal->driver_name = drv->driver_name; - normal->devfs_name = drv->devfs_name; normal->name = drv->dev_name; normal->major = drv->major; normal->minor_start = drv->minor; @@ -2161,7 +2160,7 @@ int uart_register_driver(struct uart_driver *drv) normal->subtype = SERIAL_TYPE_NORMAL; normal->init_termios = tty_std_termios; normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; normal->driver_state = drv; tty_set_operations(normal, &uart_ops); @@ -2312,7 +2311,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) mutex_unlock(&state->mutex); /* - * Remove the devices from devfs + * Remove the devices from the tty layer */ tty_unregister_device(drv->tty_driver, port->line); diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c index 3bdee64d1a99..a901a7e446f3 100644 --- a/drivers/serial/serial_txx9.c +++ b/drivers/serial/serial_txx9.c @@ -69,12 +69,10 @@ static char *serial_name = "TX39/49 Serial driver"; #if !defined(CONFIG_SERIAL_TXX9_STDSERIAL) /* "ttyS" is used for standard serial driver */ #define TXX9_TTY_NAME "ttyTX" -#define TXX9_TTY_DEVFS_NAME "tttx/" #define TXX9_TTY_MINOR_START (64 + 64) /* ttyTX0(128), ttyTX1(129) */ #else /* acts like standard serial driver */ #define TXX9_TTY_NAME "ttyS" -#define TXX9_TTY_DEVFS_NAME "tts/" #define TXX9_TTY_MINOR_START 64 #endif #define TXX9_TTY_MAJOR TTY_MAJOR @@ -971,7 +969,6 @@ console_initcall(serial_txx9_console_init); static struct uart_driver serial_txx9_reg = { .owner = THIS_MODULE, .driver_name = "serial_txx9", - .devfs_name = TXX9_TTY_DEVFS_NAME, .dev_name = TXX9_TTY_NAME, .major = TXX9_TTY_MAJOR, .minor = TXX9_TTY_MINOR_START, diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 44f6bf79bbe1..d97f3ca6cc29 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -1699,9 +1699,6 @@ static char banner[] __initdata = static struct uart_driver sci_uart_driver = { .owner = THIS_MODULE, .driver_name = "sci", -#ifdef CONFIG_DEVFS_FS - .devfs_name = "ttsc/", -#endif .dev_name = "ttySC", .major = SCI_MAJOR, .minor = SCI_MINOR_START, diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index ba22e256c6f7..d36bc4003399 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -353,7 +353,6 @@ static struct uart_ops sunhv_pops = { static struct uart_driver sunhv_reg = { .owner = THIS_MODULE, .driver_name = "serial", - .devfs_name = "tts/", .dev_name = "ttyS", .major = TTY_MAJOR, }; diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index e4c0fd2d6a9d..141fedbefbc4 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -1,7 +1,7 @@ /* sunsab.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 2002 David S. Miller (davem@redhat.com) + * Copyright (C) 2002, 2006 David S. Miller (davem@davemloft.net) * * Rewrote buffer handling to use CIRC(Circular Buffer) macros. * Maxim Krasnyanskiy <maxk@qualcomm.com> @@ -12,7 +12,7 @@ * Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12 * * Ported to new 2.5.x UART layer. - * David S. Miller <davem@redhat.com> + * David S. Miller <davem@davemloft.net> */ #include <linux/config.h> @@ -37,8 +37,8 @@ #include <asm/io.h> #include <asm/irq.h> -#include <asm/oplib.h> -#include <asm/ebus.h> +#include <asm/prom.h> +#include <asm/of_device.h> #if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -851,7 +851,6 @@ static struct uart_ops sunsab_pops = { static struct uart_driver sunsab_reg = { .owner = THIS_MODULE, .driver_name = "serial", - .devfs_name = "tts/", .dev_name = "ttyS", .major = TTY_MAJOR, }; @@ -977,199 +976,188 @@ static inline struct console *SUNSAB_CONSOLE(void) #define sunsab_console_init() do { } while (0) #endif -static void __init for_each_sab_edev(void (*callback)(struct linux_ebus_device *, void *), void *arg) +static int __devinit sunsab_init_one(struct uart_sunsab_port *up, + struct of_device *op, + unsigned long offset, + int line) { - struct linux_ebus *ebus; - struct linux_ebus_device *edev = NULL; - - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_node->name, "se")) { - callback(edev, arg); - continue; - } else if (!strcmp(edev->prom_node->name, "serial")) { - char *compat; - int clen; - - /* On RIO this can be an SE, check it. We could - * just check ebus->is_rio, but this is more portable. - */ - compat = of_get_property(edev->prom_node, - "compatible", &clen); - if (compat && clen > 0) { - if (strncmp(compat, "sab82532", 8) == 0) { - callback(edev, arg); - continue; - } - } - } - } - } -} + up->port.line = line; + up->port.dev = &op->dev; + + up->port.mapbase = op->resource[0].start + offset; + up->port.membase = of_ioremap(&op->resource[0], offset, + sizeof(union sab82532_async_regs), + "sab"); + if (!up->port.membase) + return -ENOMEM; + up->regs = (union sab82532_async_regs __iomem *) up->port.membase; -static void __init sab_count_callback(struct linux_ebus_device *edev, void *arg) -{ - int *count_p = arg; + up->port.irq = op->irqs[0]; - (*count_p)++; -} + up->port.fifosize = SAB82532_XMIT_FIFO_SIZE; + up->port.iotype = UPIO_MEM; -static void __init sab_attach_callback(struct linux_ebus_device *edev, void *arg) -{ - int *instance_p = arg; - struct uart_sunsab_port *up; - unsigned long regs, offset; - int i; + writeb(SAB82532_IPC_IC_ACT_LOW, &up->regs->w.ipc); - /* Note: ports are located in reverse order */ - regs = edev->resource[0].start; - offset = sizeof(union sab82532_async_regs); - for (i = 0; i < 2; i++) { - up = &sunsab_ports[(*instance_p * 2) + 1 - i]; + up->port.ops = &sunsab_pops; + up->port.type = PORT_SUNSAB; + up->port.uartclk = SAB_BASE_BAUD; - memset(up, 0, sizeof(*up)); - up->regs = ioremap(regs + offset, sizeof(union sab82532_async_regs)); - up->port.irq = edev->irqs[0]; - up->port.fifosize = SAB82532_XMIT_FIFO_SIZE; - up->port.mapbase = (unsigned long)up->regs; - up->port.iotype = UPIO_MEM; + up->type = readb(&up->regs->r.vstr) & 0x0f; + writeb(~((1 << 1) | (1 << 2) | (1 << 4)), &up->regs->w.pcr); + writeb(0xff, &up->regs->w.pim); + if ((up->port.line & 0x1) == 0) { + up->pvr_dsr_bit = (1 << 0); + up->pvr_dtr_bit = (1 << 1); + } else { + up->pvr_dsr_bit = (1 << 3); + up->pvr_dtr_bit = (1 << 2); + } + up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4); + writeb(up->cached_pvr, &up->regs->w.pvr); + up->cached_mode = readb(&up->regs->rw.mode); + up->cached_mode |= SAB82532_MODE_FRTS; + writeb(up->cached_mode, &up->regs->rw.mode); + up->cached_mode |= SAB82532_MODE_RTS; + writeb(up->cached_mode, &up->regs->rw.mode); - writeb(SAB82532_IPC_IC_ACT_LOW, &up->regs->w.ipc); + up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; + up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; - offset -= sizeof(union sab82532_async_regs); + if (!(up->port.line & 0x01)) { + int err; + + err = request_irq(up->port.irq, sunsab_interrupt, + SA_SHIRQ, "sab", up); + if (err) { + of_iounmap(up->port.membase, + sizeof(union sab82532_async_regs)); + return err; + } } - - (*instance_p)++; + + return 0; } -static int __init probe_for_sabs(void) +static int __devinit sab_probe(struct of_device *op, const struct of_device_id *match) { - int this_sab = 0; + static int inst; + struct uart_sunsab_port *up; + int err; + + up = &sunsab_ports[inst * 2]; + + err = sunsab_init_one(&up[0], op, + sizeof(union sab82532_async_regs), + (inst * 2) + 0); + if (err) + return err; + + err = sunsab_init_one(&up[0], op, 0, + (inst * 2) + 1); + if (err) { + of_iounmap(up[0].port.membase, + sizeof(union sab82532_async_regs)); + free_irq(up[0].port.irq, &up[0]); + return err; + } - /* Find device instances. */ - for_each_sab_edev(&sab_count_callback, &this_sab); - if (!this_sab) - return -ENODEV; + uart_add_one_port(&sunsab_reg, &up[0].port); + uart_add_one_port(&sunsab_reg, &up[1].port); - /* Allocate tables. */ - sunsab_ports = kmalloc(sizeof(struct uart_sunsab_port) * this_sab * 2, - GFP_KERNEL); - if (!sunsab_ports) - return -ENOMEM; + dev_set_drvdata(&op->dev, &up[0]); - num_channels = this_sab * 2; + inst++; - this_sab = 0; - for_each_sab_edev(&sab_attach_callback, &this_sab); return 0; } -static void __init sunsab_init_hw(void) +static void __devexit sab_remove_one(struct uart_sunsab_port *up) { - int i; - - for (i = 0; i < num_channels; i++) { - struct uart_sunsab_port *up = &sunsab_ports[i]; - - up->port.line = i; - up->port.ops = &sunsab_pops; - up->port.type = PORT_SUNSAB; - up->port.uartclk = SAB_BASE_BAUD; - - up->type = readb(&up->regs->r.vstr) & 0x0f; - writeb(~((1 << 1) | (1 << 2) | (1 << 4)), &up->regs->w.pcr); - writeb(0xff, &up->regs->w.pim); - if (up->port.line == 0) { - up->pvr_dsr_bit = (1 << 0); - up->pvr_dtr_bit = (1 << 1); - } else { - up->pvr_dsr_bit = (1 << 3); - up->pvr_dtr_bit = (1 << 2); - } - up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4); - writeb(up->cached_pvr, &up->regs->w.pvr); - up->cached_mode = readb(&up->regs->rw.mode); - up->cached_mode |= SAB82532_MODE_FRTS; - writeb(up->cached_mode, &up->regs->rw.mode); - up->cached_mode |= SAB82532_MODE_RTS; - writeb(up->cached_mode, &up->regs->rw.mode); - - up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; - up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; - - if (!(up->port.line & 0x01)) { - if (request_irq(up->port.irq, sunsab_interrupt, - SA_SHIRQ, "serial(sab82532)", up)) { - printk("sunsab%d: can't get IRQ %x\n", - i, up->port.irq); - continue; - } - } - } + uart_remove_one_port(&sunsab_reg, &up->port); + if (!(up->port.line & 1)) + free_irq(up->port.irq, up); + of_iounmap(up->port.membase, + sizeof(union sab82532_async_regs)); } -static int __init sunsab_init(void) +static int __devexit sab_remove(struct of_device *op) { - int ret = probe_for_sabs(); - int i; - - if (ret < 0) - return ret; + struct uart_sunsab_port *up = dev_get_drvdata(&op->dev); - sunsab_init_hw(); + sab_remove_one(&up[0]); + sab_remove_one(&up[1]); - sunsab_reg.minor = sunserial_current_minor; - sunsab_reg.nr = num_channels; + dev_set_drvdata(&op->dev, NULL); - ret = uart_register_driver(&sunsab_reg); - if (ret < 0) { - int i; + return 0; +} - for (i = 0; i < num_channels; i++) { - struct uart_sunsab_port *up = &sunsab_ports[i]; +static struct of_device_id sab_match[] = { + { + .name = "se", + }, + { + .name = "serial", + .compatible = "sab82532", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, sab_match); - if (!(up->port.line & 0x01)) - free_irq(up->port.irq, up); - iounmap(up->regs); - } - kfree(sunsab_ports); - sunsab_ports = NULL; +static struct of_platform_driver sab_driver = { + .name = "sab", + .match_table = sab_match, + .probe = sab_probe, + .remove = __devexit_p(sab_remove), +}; - return ret; +static int __init sunsab_init(void) +{ + struct device_node *dp; + int err; + + num_channels = 0; + for_each_node_by_name(dp, "su") + num_channels += 2; + for_each_node_by_name(dp, "serial") { + if (of_device_is_compatible(dp, "sab82532")) + num_channels += 2; } - sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64; + if (num_channels) { + sunsab_ports = kzalloc(sizeof(struct uart_sunsab_port) * + num_channels, GFP_KERNEL); + if (!sunsab_ports) + return -ENOMEM; - sunsab_reg.cons = SUNSAB_CONSOLE(); + sunsab_reg.minor = sunserial_current_minor; + sunsab_reg.nr = num_channels; - sunserial_current_minor += num_channels; - - for (i = 0; i < num_channels; i++) { - struct uart_sunsab_port *up = &sunsab_ports[i]; + err = uart_register_driver(&sunsab_reg); + if (err) { + kfree(sunsab_ports); + sunsab_ports = NULL; - uart_add_one_port(&sunsab_reg, &up->port); + return err; + } + + sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64; + sunsab_reg.cons = SUNSAB_CONSOLE(); + sunserial_current_minor += num_channels; } - return 0; + return of_register_driver(&sab_driver, &of_bus_type); } static void __exit sunsab_exit(void) { - int i; - - for (i = 0; i < num_channels; i++) { - struct uart_sunsab_port *up = &sunsab_ports[i]; - - uart_remove_one_port(&sunsab_reg, &up->port); - - if (!(up->port.line & 0x01)) - free_irq(up->port.irq, up); - iounmap(up->regs); + of_unregister_driver(&sab_driver); + if (num_channels) { + sunserial_current_minor -= num_channels; + uart_unregister_driver(&sunsab_reg); } - sunserial_current_minor -= num_channels; - uart_unregister_driver(&sunsab_reg); - kfree(sunsab_ports); sunsab_ports = NULL; } diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 0268b307c01e..73a043b914ef 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -12,7 +12,7 @@ * Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12 * * Converted to new 2.5.x UART layer. - * David S. Miller (davem@redhat.com), 2002-Jul-29 + * David S. Miller (davem@davemloft.net), 2002-Jul-29 */ #include <linux/config.h> @@ -40,11 +40,8 @@ #include <asm/io.h> #include <asm/irq.h> -#include <asm/oplib.h> -#include <asm/ebus.h> -#ifdef CONFIG_SPARC64 -#include <asm/isa.h> -#endif +#include <asm/prom.h> +#include <asm/of_device.h> #if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -94,10 +91,10 @@ struct uart_sunsu_port { /* Probing information. */ enum su_type su_type; unsigned int type_probed; /* XXX Stupid */ - int port_node; + unsigned long reg_size; #ifdef CONFIG_SERIO - struct serio *serio; + struct serio serio; int serio_open; #endif }; @@ -509,7 +506,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg /* Stop-A is handled by drivers/char/keyboard.c now. */ if (up->su_type == SU_PORT_KBD) { #ifdef CONFIG_SERIO - serio_interrupt(up->serio, ch, 0, regs); + serio_interrupt(&up->serio, ch, 0, regs); #endif } else if (up->su_type == SU_PORT_MS) { int ret = suncore_mouse_baud_detection(ch, is_break); @@ -523,7 +520,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg case 0: #ifdef CONFIG_SERIO - serio_interrupt(up->serio, ch, 0, regs); + serio_interrupt(&up->serio, ch, 0, regs); #endif break; }; @@ -1031,99 +1028,14 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up) { unsigned char status1, status2, scratch, scratch2, scratch3; unsigned char save_lcr, save_mcr; - struct linux_ebus_device *dev = NULL; - struct linux_ebus *ebus; -#ifdef CONFIG_SPARC64 - struct sparc_isa_bridge *isa_br; - struct sparc_isa_device *isa_dev; -#endif -#ifndef CONFIG_SPARC64 - struct linux_prom_registers reg0; -#endif unsigned long flags; - if (!up->port_node || !up->su_type) + if (up->su_type == SU_PORT_NONE) return; up->type_probed = PORT_UNKNOWN; up->port.iotype = UPIO_MEM; - /* - * First we look for Ebus-bases su's - */ - for_each_ebus(ebus) { - for_each_ebusdev(dev, ebus) { - if (dev->prom_node->node == up->port_node) { - /* - * The EBus is broken on sparc; it delivers - * virtual addresses in resources. Oh well... - * This is correct on sparc64, though. - */ - up->port.membase = (char *) dev->resource[0].start; - /* - * This is correct on both architectures. - */ - up->port.mapbase = dev->resource[0].start; - up->port.irq = dev->irqs[0]; - goto ebus_done; - } - } - } - -#ifdef CONFIG_SPARC64 - for_each_isa(isa_br) { - for_each_isadev(isa_dev, isa_br) { - if (isa_dev->prom_node->node == up->port_node) { - /* Same on sparc64. Cool architecure... */ - up->port.membase = (char *) isa_dev->resource.start; - up->port.mapbase = isa_dev->resource.start; - up->port.irq = isa_dev->irq; - goto ebus_done; - } - } - } -#endif - -#ifdef CONFIG_SPARC64 - /* - * Not on Ebus, bailing. - */ - return; -#else - /* - * Not on Ebus, must be OBIO. - */ - if (prom_getproperty(up->port_node, "reg", - (char *)®0, sizeof(reg0)) == -1) { - prom_printf("sunsu: no \"reg\" property\n"); - return; - } - prom_apply_obio_ranges(®0, 1); - if (reg0.which_io != 0) { /* Just in case... */ - prom_printf("sunsu: bus number nonzero: 0x%x:%x\n", - reg0.which_io, reg0.phys_addr); - return; - } - up->port.mapbase = reg0.phys_addr; - if ((up->port.membase = ioremap(reg0.phys_addr, reg0.reg_size)) == 0) { - prom_printf("sunsu: Cannot map registers.\n"); - return; - } - - /* - * 0x20 is sun4m thing, Dave Redman heritage. - * See arch/sparc/kernel/irq.c. - */ -#define IRQ_4M(n) ((n)|0x20) - - /* - * There is no intr property on MrCoffee, so hardwire it. - */ - up->port.irq = IRQ_4M(13); -#endif - -ebus_done: - spin_lock_irqsave(&up->port.lock, flags); if (!(up->port.flags & UPF_BUGGY_UART)) { @@ -1265,23 +1177,17 @@ out: static struct uart_driver sunsu_reg = { .owner = THIS_MODULE, .driver_name = "serial", - .devfs_name = "tts/", .dev_name = "ttyS", .major = TTY_MAJOR, }; -static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel) +static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up) { int quot, baud; #ifdef CONFIG_SERIO struct serio *serio; #endif - spin_lock_init(&up->port.lock); - up->port.line = channel; - up->port.type = PORT_UNKNOWN; - up->port.uartclk = (SU_BASE_BAUD * 16); - if (up->su_type == SU_PORT_KBD) { up->cflag = B1200 | CS8 | CLOCAL | CREAD; baud = 1200; @@ -1293,41 +1199,31 @@ static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel) sunsu_autoconfig(up); if (up->port.type == PORT_UNKNOWN) - return -1; - - printk(KERN_INFO "su%d at 0x%p (irq = %d) is a %s\n", - channel, - up->port.membase, up->port.irq, - sunsu_type(&up->port)); + return -ENODEV; #ifdef CONFIG_SERIO - up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL); - if (serio) { - memset(serio, 0, sizeof(*serio)); - - serio->port_data = up; - - serio->id.type = SERIO_RS232; - if (up->su_type == SU_PORT_KBD) { - serio->id.proto = SERIO_SUNKBD; - strlcpy(serio->name, "sukbd", sizeof(serio->name)); - } else { - serio->id.proto = SERIO_SUN; - serio->id.extra = 1; - strlcpy(serio->name, "sums", sizeof(serio->name)); - } - strlcpy(serio->phys, (channel == 0 ? "su/serio0" : "su/serio1"), - sizeof(serio->phys)); - - serio->write = sunsu_serio_write; - serio->open = sunsu_serio_open; - serio->close = sunsu_serio_close; + serio = &up->serio; + serio->port_data = up; - serio_register_port(serio); + serio->id.type = SERIO_RS232; + if (up->su_type == SU_PORT_KBD) { + serio->id.proto = SERIO_SUNKBD; + strlcpy(serio->name, "sukbd", sizeof(serio->name)); } else { - printk(KERN_WARNING "su%d: not enough memory for serio port\n", - channel); + serio->id.proto = SERIO_SUN; + serio->id.extra = 1; + strlcpy(serio->name, "sums", sizeof(serio->name)); } + strlcpy(serio->phys, + (!(up->port.line & 1) ? "su/serio0" : "su/serio1"), + sizeof(serio->phys)); + + serio->write = sunsu_serio_write; + serio->open = sunsu_serio_open; + serio->close = sunsu_serio_close; + serio->dev.parent = up->port.dev; + + serio_register_port(serio); #endif sunsu_change_speed(&up->port, up->cflag, 0, quot); @@ -1459,22 +1355,20 @@ static struct console sunsu_cons = { * Register console. */ -static inline struct console *SUNSU_CONSOLE(void) +static inline struct console *SUNSU_CONSOLE(int num_uart) { int i; if (con_is_present()) return NULL; - for (i = 0; i < UART_NR; i++) { + for (i = 0; i < num_uart; i++) { int this_minor = sunsu_reg.minor + i; if ((this_minor - 64) == (serial_console - 1)) break; } - if (i == UART_NR) - return NULL; - if (sunsu_ports[i].port_node == 0) + if (i == num_uart) return NULL; sunsu_cons.index = i; @@ -1482,252 +1376,184 @@ static inline struct console *SUNSU_CONSOLE(void) return &sunsu_cons; } #else -#define SUNSU_CONSOLE() (NULL) +#define SUNSU_CONSOLE(num_uart) (NULL) #define sunsu_serial_console_init() do { } while (0) #endif -static int __init sunsu_serial_init(void) +static enum su_type __devinit su_get_type(struct device_node *dp) { - int instance, ret, i; + struct device_node *ap = of_find_node_by_path("/aliases"); - /* How many instances do we need? */ - instance = 0; - for (i = 0; i < UART_NR; i++) { - struct uart_sunsu_port *up = &sunsu_ports[i]; + if (ap) { + char *keyb = of_get_property(ap, "keyboard", NULL); + char *ms = of_get_property(ap, "mouse", NULL); - if (up->su_type == SU_PORT_MS || - up->su_type == SU_PORT_KBD) - continue; - - spin_lock_init(&up->port.lock); - up->port.flags |= UPF_BOOT_AUTOCONF; - up->port.type = PORT_UNKNOWN; - up->port.uartclk = (SU_BASE_BAUD * 16); + if (keyb) { + if (dp == of_find_node_by_path(keyb)) + return SU_PORT_KBD; + } + if (ms) { + if (dp == of_find_node_by_path(ms)) + return SU_PORT_MS; + } + } - sunsu_autoconfig(up); - if (up->port.type == PORT_UNKNOWN) - continue; + return SU_PORT_PORT; +} - up->port.line = instance++; - up->port.ops = &sunsu_pops; - } +static int __devinit su_probe(struct of_device *op, const struct of_device_id *match) +{ + static int inst; + struct device_node *dp = op->node; + struct uart_sunsu_port *up; + struct resource *rp; + int err; - sunsu_reg.minor = sunserial_current_minor; + if (inst >= UART_NR) + return -EINVAL; - sunsu_reg.nr = instance; + up = &sunsu_ports[inst]; + up->port.line = inst; - ret = uart_register_driver(&sunsu_reg); - if (ret < 0) - return ret; + spin_lock_init(&up->port.lock); - sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64; + up->su_type = su_get_type(dp); - sunserial_current_minor += instance; + rp = &op->resource[0]; + up->port.mapbase = op->resource[0].start; - sunsu_reg.cons = SUNSU_CONSOLE(); + up->reg_size = (rp->end - rp->start) + 1; + up->port.membase = of_ioremap(rp, 0, up->reg_size, "su"); + if (!up->port.membase) + return -ENOMEM; - for (i = 0; i < UART_NR; i++) { - struct uart_sunsu_port *up = &sunsu_ports[i]; + up->port.irq = op->irqs[0]; - /* Do not register Keyboard/Mouse lines with UART - * layer. - */ - if (up->su_type == SU_PORT_MS || - up->su_type == SU_PORT_KBD) - continue; + up->port.dev = &op->dev; - if (up->port.type == PORT_UNKNOWN) - continue; + up->port.type = PORT_UNKNOWN; + up->port.uartclk = (SU_BASE_BAUD * 16); - uart_add_one_port(&sunsu_reg, &up->port); + err = 0; + if (up->su_type == SU_PORT_KBD || up->su_type == SU_PORT_MS) { + err = sunsu_kbd_ms_init(up); + if (err) + goto out_unmap; } - return 0; -} + up->port.flags |= UPF_BOOT_AUTOCONF; -static int su_node_ok(int node, char *name, int namelen) -{ - if (strncmp(name, "su", namelen) == 0 || - strncmp(name, "su_pnp", namelen) == 0) - return 1; - - if (strncmp(name, "serial", namelen) == 0) { - char compat[32]; - int clen; - - /* Is it _really_ a 'su' device? */ - clen = prom_getproperty(node, "compatible", compat, sizeof(compat)); - if (clen > 0) { - if (strncmp(compat, "sab82532", 8) == 0) { - /* Nope, Siemens serial, not for us. */ - return 0; - } - } - return 1; - } + sunsu_autoconfig(up); - return 0; -} + err = -ENODEV; + if (up->port.type == PORT_UNKNOWN) + goto out_unmap; -#define SU_PROPSIZE 128 + up->port.ops = &sunsu_pops; -/* - * Scan status structure. - * "prop" is a local variable but it eats stack to keep it in each - * stack frame of a recursive procedure. - */ -struct su_probe_scan { - int msnode, kbnode; /* PROM nodes for mouse and keyboard */ - int msx, kbx; /* minors for mouse and keyboard */ - int devices; /* scan index */ - char prop[SU_PROPSIZE]; -}; + err = uart_add_one_port(&sunsu_reg, &up->port); + if (err) + goto out_unmap; -/* - * We have several platforms which present 'su' in different parts - * of the device tree. 'su' may be found under obio, ebus, isa and pci. - * We walk over the tree and find them wherever PROM hides them. - */ -static void __init su_probe_any(struct su_probe_scan *t, int sunode) -{ - struct uart_sunsu_port *up; - int len; + dev_set_drvdata(&op->dev, up); - if (t->devices >= UART_NR) - return; + inst++; - for (; sunode != 0; sunode = prom_getsibling(sunode)) { - len = prom_getproperty(sunode, "name", t->prop, SU_PROPSIZE); - if (len <= 1) - continue; /* Broken PROM node */ - - if (su_node_ok(sunode, t->prop, len)) { - up = &sunsu_ports[t->devices]; - if (t->kbnode != 0 && sunode == t->kbnode) { - t->kbx = t->devices; - up->su_type = SU_PORT_KBD; - } else if (t->msnode != 0 && sunode == t->msnode) { - t->msx = t->devices; - up->su_type = SU_PORT_MS; - } else { -#ifdef CONFIG_SPARC64 - /* - * Do not attempt to use the truncated - * keyboard/mouse ports as serial ports - * on Ultras with PC keyboard attached. - */ - if (prom_getbool(sunode, "mouse")) - continue; - if (prom_getbool(sunode, "keyboard")) - continue; -#endif - up->su_type = SU_PORT_PORT; - } - up->port_node = sunode; - ++t->devices; - } else { - su_probe_any(t, prom_getchild(sunode)); - } - } + return 0; + +out_unmap: + of_iounmap(up->port.membase, up->reg_size); + return err; } -static int __init sunsu_probe(void) +static int __devexit su_remove(struct of_device *dev) { - int node; - int len; - struct su_probe_scan scan; + struct uart_sunsu_port *up = dev_get_drvdata(&dev->dev);; - /* - * First, we scan the tree. - */ - scan.devices = 0; - scan.msx = -1; - scan.kbx = -1; - scan.kbnode = 0; - scan.msnode = 0; + if (up->su_type == SU_PORT_MS || + up->su_type == SU_PORT_KBD) { +#ifdef CONFIG_SERIO + serio_unregister_port(&up->serio); +#endif + } else if (up->port.type != PORT_UNKNOWN) + uart_remove_one_port(&sunsu_reg, &up->port); - /* - * Get the nodes for keyboard and mouse from 'aliases'... - */ - node = prom_getchild(prom_root_node); - node = prom_searchsiblings(node, "aliases"); - if (node != 0) { - len = prom_getproperty(node, "keyboard", scan.prop, SU_PROPSIZE); - if (len > 0) { - scan.prop[len] = 0; - scan.kbnode = prom_finddevice(scan.prop); - } + return 0; +} - len = prom_getproperty(node, "mouse", scan.prop, SU_PROPSIZE); - if (len > 0) { - scan.prop[len] = 0; - scan.msnode = prom_finddevice(scan.prop); - } - } +static struct of_device_id su_match[] = { + { + .name = "su", + }, + { + .name = "su_pnp", + }, + { + .name = "serial", + .compatible = "su", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, su_match); - su_probe_any(&scan, prom_getchild(prom_root_node)); +static struct of_platform_driver su_driver = { + .name = "su", + .match_table = su_match, + .probe = su_probe, + .remove = __devexit_p(su_remove), +}; - /* - * Second, we process the special case of keyboard and mouse. - * - * Currently if we got keyboard and mouse hooked to "su" ports - * we do not use any possible remaining "su" as a serial port. - * Thus, we ignore values of .msx and .kbx, then compact ports. - */ - if (scan.msx != -1 && scan.kbx != -1) { - sunsu_ports[0].su_type = SU_PORT_MS; - sunsu_ports[0].port_node = scan.msnode; - sunsu_kbd_ms_init(&sunsu_ports[0], 0); +static int num_uart; - sunsu_ports[1].su_type = SU_PORT_KBD; - sunsu_ports[1].port_node = scan.kbnode; - sunsu_kbd_ms_init(&sunsu_ports[1], 1); +static int __init sunsu_init(void) +{ + struct device_node *dp; + int err; - return 0; + num_uart = 0; + for_each_node_by_name(dp, "su") { + if (su_get_type(dp) == SU_PORT_PORT) + num_uart++; } - - if (scan.msx != -1 || scan.kbx != -1) { - printk("sunsu_probe: cannot match keyboard and mouse, confused\n"); - return -ENODEV; + for_each_node_by_name(dp, "su_pnp") { + if (su_get_type(dp) == SU_PORT_PORT) + num_uart++; + } + for_each_node_by_name(dp, "serial") { + if (of_device_is_compatible(dp, "su")) { + if (su_get_type(dp) == SU_PORT_PORT) + num_uart++; + } } - if (scan.devices == 0) - return -ENODEV; + if (num_uart) { + sunsu_reg.minor = sunserial_current_minor; + sunsu_reg.nr = num_uart; + err = uart_register_driver(&sunsu_reg); + if (err) + return err; + sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64; + sunserial_current_minor += num_uart; + sunsu_reg.cons = SUNSU_CONSOLE(num_uart); + } - /* - * Console must be initiated after the generic initialization. - */ - sunsu_serial_init(); + err = of_register_driver(&su_driver, &of_bus_type); + if (err && num_uart) + uart_unregister_driver(&sunsu_reg); - return 0; + return err; } static void __exit sunsu_exit(void) { - int i, saw_uart; - - saw_uart = 0; - for (i = 0; i < UART_NR; i++) { - struct uart_sunsu_port *up = &sunsu_ports[i]; - - if (up->su_type == SU_PORT_MS || - up->su_type == SU_PORT_KBD) { -#ifdef CONFIG_SERIO - if (up->serio) { - serio_unregister_port(up->serio); - up->serio = NULL; - } -#endif - } else if (up->port.type != PORT_UNKNOWN) { - uart_remove_one_port(&sunsu_reg, &up->port); - saw_uart++; - } - } - - if (saw_uart) + if (num_uart) uart_unregister_driver(&sunsu_reg); } -module_init(sunsu_probe); +module_init(sunsu_init); module_exit(sunsu_exit); + +MODULE_AUTHOR("Eddie C. Dost, Peter Zaitcev, and David S. Miller"); +MODULE_DESCRIPTION("Sun SU serial port driver"); +MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 76c9bac9271f..1caa286a6be6 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1,5 +1,4 @@ -/* - * sunzilog.c +/* sunzilog.c: Zilog serial driver for Sparc systems. * * Driver for Zilog serial chips found on Sun workstations and * servers. This driver could actually be made more generic. @@ -10,7 +9,7 @@ * C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their * work there. * - * Copyright (C) 2002 David S. Miller (davem@redhat.com) + * Copyright (C) 2002, 2006 David S. Miller (davem@davemloft.net) */ #include <linux/config.h> @@ -38,10 +37,8 @@ #include <asm/io.h> #include <asm/irq.h> -#ifdef CONFIG_SPARC64 -#include <asm/fhc.h> -#endif -#include <asm/sbus.h> +#include <asm/prom.h> +#include <asm/of_device.h> #if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -65,7 +62,7 @@ #define ZSDELAY() #define ZSDELAY_LONG() #define ZS_WSYNC(__channel) \ - sbus_readb(&((__channel)->control)) + readb(&((__channel)->control)) #endif static int num_sunzilog; @@ -107,7 +104,7 @@ struct uart_sunzilog_port { unsigned char prev_status; #ifdef CONFIG_SERIO - struct serio *serio; + struct serio serio; int serio_open; #endif }; @@ -138,9 +135,9 @@ static unsigned char read_zsreg(struct zilog_channel __iomem *channel, { unsigned char retval; - sbus_writeb(reg, &channel->control); + writeb(reg, &channel->control); ZSDELAY(); - retval = sbus_readb(&channel->control); + retval = readb(&channel->control); ZSDELAY(); return retval; @@ -149,9 +146,9 @@ static unsigned char read_zsreg(struct zilog_channel __iomem *channel, static void write_zsreg(struct zilog_channel __iomem *channel, unsigned char reg, unsigned char value) { - sbus_writeb(reg, &channel->control); + writeb(reg, &channel->control); ZSDELAY(); - sbus_writeb(value, &channel->control); + writeb(value, &channel->control); ZSDELAY(); } @@ -162,17 +159,17 @@ static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel) for (i = 0; i < 32; i++) { unsigned char regval; - regval = sbus_readb(&channel->control); + regval = readb(&channel->control); ZSDELAY(); if (regval & Rx_CH_AV) break; regval = read_zsreg(channel, R1); - sbus_readb(&channel->data); + readb(&channel->data); ZSDELAY(); if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) { - sbus_writeb(ERR_RES, &channel->control); + writeb(ERR_RES, &channel->control); ZSDELAY(); ZS_WSYNC(channel); } @@ -194,7 +191,7 @@ static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char * udelay(100); } - sbus_writeb(ERR_RES, &channel->control); + writeb(ERR_RES, &channel->control); ZSDELAY(); ZS_WSYNC(channel); @@ -291,7 +288,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, /* Stop-A is handled by drivers/char/keyboard.c now. */ #ifdef CONFIG_SERIO if (up->serio_open) - serio_interrupt(up->serio, ch, 0, regs); + serio_interrupt(&up->serio, ch, 0, regs); #endif } else if (ZS_IS_MOUSE(up)) { int ret = suncore_mouse_baud_detection(ch, is_break); @@ -306,7 +303,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, case 0: #ifdef CONFIG_SERIO if (up->serio_open) - serio_interrupt(up->serio, ch, 0, regs); + serio_interrupt(&up->serio, ch, 0, regs); #endif break; }; @@ -330,12 +327,12 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up, r1 = read_zsreg(channel, R1); if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { - sbus_writeb(ERR_RES, &channel->control); + writeb(ERR_RES, &channel->control); ZSDELAY(); ZS_WSYNC(channel); } - ch = sbus_readb(&channel->control); + ch = readb(&channel->control); ZSDELAY(); /* This funny hack depends upon BRK_ABRT not interfering @@ -347,7 +344,7 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up, if (!(ch & Rx_CH_AV)) break; - ch = sbus_readb(&channel->data); + ch = readb(&channel->data); ZSDELAY(); ch &= up->parity_mask; @@ -406,10 +403,10 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up, { unsigned char status; - status = sbus_readb(&channel->control); + status = readb(&channel->control); ZSDELAY(); - sbus_writeb(RES_EXT_INT, &channel->control); + writeb(RES_EXT_INT, &channel->control); ZSDELAY(); ZS_WSYNC(channel); @@ -421,7 +418,7 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up, * confusing the PROM. */ while (1) { - status = sbus_readb(&channel->control); + status = readb(&channel->control); ZSDELAY(); if (!(status & BRK_ABRT)) break; @@ -458,7 +455,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, struct circ_buf *xmit; if (ZS_IS_CONS(up)) { - unsigned char status = sbus_readb(&channel->control); + unsigned char status = readb(&channel->control); ZSDELAY(); /* TX still busy? Just wait for the next TX done interrupt. @@ -487,7 +484,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, if (up->port.x_char) { up->flags |= SUNZILOG_FLAG_TX_ACTIVE; - sbus_writeb(up->port.x_char, &channel->data); + writeb(up->port.x_char, &channel->data); ZSDELAY(); ZS_WSYNC(channel); @@ -506,7 +503,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, goto ack_tx_int; up->flags |= SUNZILOG_FLAG_TX_ACTIVE; - sbus_writeb(xmit->buf[xmit->tail], &channel->data); + writeb(xmit->buf[xmit->tail], &channel->data); ZSDELAY(); ZS_WSYNC(channel); @@ -519,7 +516,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, return; ack_tx_int: - sbus_writeb(RES_Tx_P, &channel->control); + writeb(RES_Tx_P, &channel->control); ZSDELAY(); ZS_WSYNC(channel); } @@ -540,7 +537,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg /* Channel A */ tty = NULL; if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { - sbus_writeb(RES_H_IUS, &channel->control); + writeb(RES_H_IUS, &channel->control); ZSDELAY(); ZS_WSYNC(channel); @@ -563,7 +560,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg spin_lock(&up->port.lock); tty = NULL; if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { - sbus_writeb(RES_H_IUS, &channel->control); + writeb(RES_H_IUS, &channel->control); ZSDELAY(); ZS_WSYNC(channel); @@ -594,7 +591,7 @@ static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *p unsigned char status; channel = ZILOG_CHANNEL_FROM_PORT(port); - status = sbus_readb(&channel->control); + status = readb(&channel->control); ZSDELAY(); return status; @@ -682,7 +679,7 @@ static void sunzilog_start_tx(struct uart_port *port) up->flags |= SUNZILOG_FLAG_TX_ACTIVE; up->flags &= ~SUNZILOG_FLAG_TX_STOPPED; - status = sbus_readb(&channel->control); + status = readb(&channel->control); ZSDELAY(); /* TX busy? Just wait for the TX done interrupt. */ @@ -693,7 +690,7 @@ static void sunzilog_start_tx(struct uart_port *port) * IRQ sending engine. */ if (port->x_char) { - sbus_writeb(port->x_char, &channel->data); + writeb(port->x_char, &channel->data); ZSDELAY(); ZS_WSYNC(channel); @@ -702,7 +699,7 @@ static void sunzilog_start_tx(struct uart_port *port) } else { struct circ_buf *xmit = &port->info->xmit; - sbus_writeb(xmit->buf[xmit->tail], &channel->data); + writeb(xmit->buf[xmit->tail], &channel->data); ZSDELAY(); ZS_WSYNC(channel); @@ -779,7 +776,7 @@ static void __sunzilog_startup(struct uart_sunzilog_port *up) struct zilog_channel __iomem *channel; channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - up->prev_status = sbus_readb(&channel->control); + up->prev_status = readb(&channel->control); /* Enable receiver and transmitter. */ up->curregs[R3] |= RxENAB; @@ -963,7 +960,7 @@ sunzilog_set_termios(struct uart_port *port, struct termios *termios, static const char *sunzilog_type(struct uart_port *port) { - return "SunZilog"; + return "zs"; } /* We do not request/release mappings of the registers here, this @@ -1012,242 +1009,55 @@ static struct uart_sunzilog_port *sunzilog_port_table; static struct zilog_layout __iomem **sunzilog_chip_regs; static struct uart_sunzilog_port *sunzilog_irq_chain; -static int zilog_irq = -1; static struct uart_driver sunzilog_reg = { .owner = THIS_MODULE, .driver_name = "ttyS", - .devfs_name = "tts/", .dev_name = "ttyS", .major = TTY_MAJOR, }; -static void * __init alloc_one_table(unsigned long size) -{ - void *ret; - - ret = kmalloc(size, GFP_KERNEL); - if (ret != NULL) - memset(ret, 0, size); - - return ret; -} - -static void __init sunzilog_alloc_tables(void) -{ - sunzilog_port_table = - alloc_one_table(NUM_CHANNELS * sizeof(struct uart_sunzilog_port)); - sunzilog_chip_regs = - alloc_one_table(NUM_SUNZILOG * sizeof(struct zilog_layout __iomem *)); - - if (sunzilog_port_table == NULL || sunzilog_chip_regs == NULL) { - prom_printf("SunZilog: Cannot allocate tables.\n"); - prom_halt(); - } -} - -#ifdef CONFIG_SPARC64 - -/* We used to attempt to use the address property of the Zilog device node - * but that totally is not necessary on sparc64. - */ -static struct zilog_layout __iomem * __init get_zs_sun4u(int chip, int zsnode) +static int __init sunzilog_alloc_tables(void) { - void __iomem *mapped_addr; - unsigned int sun4u_ino; - struct sbus_bus *sbus = NULL; - struct sbus_dev *sdev = NULL; - int err; - - if (central_bus == NULL) { - for_each_sbus(sbus) { - for_each_sbusdev(sdev, sbus) { - if (sdev->prom_node == zsnode) - goto found; - } - } - } - found: - if (sdev == NULL && central_bus == NULL) { - prom_printf("SunZilog: sdev&¢ral == NULL for " - "Zilog %d in get_zs_sun4u.\n", chip); - prom_halt(); - } - if (central_bus == NULL) { - mapped_addr = - sbus_ioremap(&sdev->resource[0], 0, - PAGE_SIZE, - "Zilog Registers"); - } else { - struct linux_prom_registers zsregs[1]; - - err = prom_getproperty(zsnode, "reg", - (char *) &zsregs[0], - sizeof(zsregs)); - if (err == -1) { - prom_printf("SunZilog: Cannot map " - "Zilog %d regs on " - "central bus.\n", chip); - prom_halt(); - } - apply_fhc_ranges(central_bus->child, - &zsregs[0], 1); - apply_central_ranges(central_bus, &zsregs[0], 1); - mapped_addr = (void __iomem *) - ((((u64)zsregs[0].which_io)<<32UL) | - ((u64)zsregs[0].phys_addr)); - } - - if (zilog_irq == -1) { - if (central_bus) { - unsigned long iclr, imap; - - iclr = central_bus->child->fhc_regs.uregs - + FHC_UREGS_ICLR; - imap = central_bus->child->fhc_regs.uregs - + FHC_UREGS_IMAP; - zilog_irq = build_irq(0, iclr, imap); - } else { - err = prom_getproperty(zsnode, "interrupts", - (char *) &sun4u_ino, - sizeof(sun4u_ino)); - zilog_irq = sbus_build_irq(sbus_root, sun4u_ino); - } - } - - return (struct zilog_layout __iomem *) mapped_addr; -} -#else /* CONFIG_SPARC64 */ - -/* - * XXX The sun4d case is utterly screwed: it tries to re-walk the tree - * (for the 3rd time) in order to find bootbus and cpu. Streamline it. - */ -static struct zilog_layout __iomem * __init get_zs_sun4cmd(int chip, int node) -{ - struct linux_prom_irqs irq_info[2]; - void __iomem *mapped_addr = NULL; - int zsnode, cpunode, bbnode; - struct linux_prom_registers zsreg[4]; - struct resource res; - - if (sparc_cpu_model == sun4d) { - int walk; - - zsnode = 0; - bbnode = 0; - cpunode = 0; - for (walk = prom_getchild(prom_root_node); - (walk = prom_searchsiblings(walk, "cpu-unit")) != 0; - walk = prom_getsibling(walk)) { - bbnode = prom_getchild(walk); - if (bbnode && - (bbnode = prom_searchsiblings(bbnode, "bootbus"))) { - if ((zsnode = prom_getchild(bbnode)) == node) { - cpunode = walk; - break; - } - } - } - if (!walk) { - prom_printf("SunZilog: Cannot find the %d'th bootbus on sun4d.\n", - (chip / 2)); - prom_halt(); - } + struct uart_sunzilog_port *up; + unsigned long size; + int i; - if (prom_getproperty(zsnode, "reg", - (char *) zsreg, sizeof(zsreg)) == -1) { - prom_printf("SunZilog: Cannot map Zilog %d\n", chip); - prom_halt(); - } - /* XXX Looks like an off by one? */ - prom_apply_generic_ranges(bbnode, cpunode, zsreg, 1); - res.start = zsreg[0].phys_addr; - res.end = res.start + (8 - 1); - res.flags = zsreg[0].which_io | IORESOURCE_IO; - mapped_addr = sbus_ioremap(&res, 0, 8, "Zilog Serial"); + size = NUM_CHANNELS * sizeof(struct uart_sunzilog_port); + sunzilog_port_table = kzalloc(size, GFP_KERNEL); + if (!sunzilog_port_table) + return -ENOMEM; - } else { - zsnode = node; + for (i = 0; i < NUM_CHANNELS; i++) { + up = &sunzilog_port_table[i]; -#if 0 /* XXX When was this used? */ - if (prom_getintdefault(zsnode, "slave", -1) != chipid) { - zsnode = prom_getsibling(zsnode); - continue; - } -#endif + spin_lock_init(&up->port.lock); - /* - * "address" is only present on ports that OBP opened - * (from Mitch Bradley's "Hitchhiker's Guide to OBP"). - * We do not use it. - */ + if (i == 0) + sunzilog_irq_chain = up; - if (prom_getproperty(zsnode, "reg", - (char *) zsreg, sizeof(zsreg)) == -1) { - prom_printf("SunZilog: Cannot map Zilog %d\n", chip); - prom_halt(); - } - if (sparc_cpu_model == sun4m) /* Crude. Pass parent. XXX */ - prom_apply_obio_ranges(zsreg, 1); - res.start = zsreg[0].phys_addr; - res.end = res.start + (8 - 1); - res.flags = zsreg[0].which_io | IORESOURCE_IO; - mapped_addr = sbus_ioremap(&res, 0, 8, "Zilog Serial"); + if (i < NUM_CHANNELS - 1) + up->next = up + 1; + else + up->next = NULL; } - if (prom_getproperty(zsnode, "intr", - (char *) irq_info, sizeof(irq_info)) - % sizeof(struct linux_prom_irqs)) { - prom_printf("SunZilog: Cannot get IRQ property for Zilog %d.\n", - chip); - prom_halt(); - } - if (zilog_irq == -1) { - zilog_irq = irq_info[0].pri; - } else if (zilog_irq != irq_info[0].pri) { - /* XXX. Dumb. Should handle per-chip IRQ, for add-ons. */ - prom_printf("SunZilog: Inconsistent IRQ layout for Zilog %d.\n", - chip); - prom_halt(); + size = NUM_SUNZILOG * sizeof(struct zilog_layout __iomem *); + sunzilog_chip_regs = kzalloc(size, GFP_KERNEL); + if (!sunzilog_chip_regs) { + kfree(sunzilog_port_table); + sunzilog_irq_chain = NULL; + return -ENOMEM; } - return (struct zilog_layout __iomem *) mapped_addr; + return 0; } -#endif /* !(CONFIG_SPARC64) */ -/* Get the address of the registers for SunZilog instance CHIP. */ -static struct zilog_layout __iomem * __init get_zs(int chip, int node) +static void sunzilog_free_tables(void) { - if (chip < 0 || chip >= NUM_SUNZILOG) { - prom_printf("SunZilog: Illegal chip number %d in get_zs.\n", chip); - prom_halt(); - } - -#ifdef CONFIG_SPARC64 - return get_zs_sun4u(chip, node); -#else - - if (sparc_cpu_model == sun4) { - struct resource res; - - /* Not probe-able, hard code it. */ - switch (chip) { - case 0: - res.start = 0xf1000000; - break; - case 1: - res.start = 0xf0000000; - break; - }; - zilog_irq = 12; - res.end = (res.start + (8 - 1)); - res.flags = IORESOURCE_IO; - return sbus_ioremap(&res, 0, 8, "SunZilog"); - } - - return get_zs_sun4cmd(chip, node); -#endif + kfree(sunzilog_port_table); + sunzilog_irq_chain = NULL; + kfree(sunzilog_chip_regs); } #define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */ @@ -1261,7 +1071,7 @@ static void sunzilog_putchar(struct uart_port *port, int ch) * udelay with ZSDELAY as that is a NOP on some platforms. -DaveM */ do { - unsigned char val = sbus_readb(&channel->control); + unsigned char val = readb(&channel->control); if (val & Tx_BUF_EMP) { ZSDELAY(); break; @@ -1269,7 +1079,7 @@ static void sunzilog_putchar(struct uart_port *port, int ch) udelay(5); } while (--loops); - sbus_writeb(ch, &channel->data); + writeb(ch, &channel->data); ZSDELAY(); ZS_WSYNC(channel); } @@ -1386,28 +1196,6 @@ static struct console sunzilog_console = { .data = &sunzilog_reg, }; -static int __init sunzilog_console_init(void) -{ - int i; - - if (con_is_present()) - return 0; - - for (i = 0; i < NUM_CHANNELS; i++) { - int this_minor = sunzilog_reg.minor + i; - - if ((this_minor - 64) == (serial_console - 1)) - break; - } - if (i == NUM_CHANNELS) - return 0; - - sunzilog_console.index = i; - sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS; - register_console(&sunzilog_console); - return 0; -} - static inline struct console *SUNZILOG_CONSOLE(void) { int i; @@ -1432,101 +1220,8 @@ static inline struct console *SUNZILOG_CONSOLE(void) #else #define SUNZILOG_CONSOLE() (NULL) -#define sunzilog_console_init() do { } while (0) #endif -/* - * We scan the PROM tree recursively. This is the most reliable way - * to find Zilog nodes on various platforms. However, we face an extreme - * shortage of kernel stack, so we must be very careful. To that end, - * we scan only to a certain depth, and we use a common property buffer - * in the scan structure. - */ -#define ZS_PROPSIZE 128 -#define ZS_SCAN_DEPTH 5 - -struct zs_probe_scan { - int depth; - void (*scanner)(struct zs_probe_scan *t, int node); - - int devices; - char prop[ZS_PROPSIZE]; -}; - -static int __inline__ sunzilog_node_ok(int node, const char *name, int len) -{ - if (strncmp(name, "zs", len) == 0) - return 1; - /* Don't fold this procedure just yet. Compare to su_node_ok(). */ - return 0; -} - -static void __init sunzilog_scan(struct zs_probe_scan *t, int node) -{ - int len; - - for (; node != 0; node = prom_getsibling(node)) { - len = prom_getproperty(node, "name", t->prop, ZS_PROPSIZE); - if (len <= 1) - continue; /* Broken PROM node */ - if (sunzilog_node_ok(node, t->prop, len)) { - (*t->scanner)(t, node); - } else { - if (t->depth < ZS_SCAN_DEPTH) { - t->depth++; - sunzilog_scan(t, prom_getchild(node)); - --t->depth; - } - } - } -} - -static void __init sunzilog_prepare(void) -{ - struct uart_sunzilog_port *up; - struct zilog_layout __iomem *rp; - int channel, chip; - - /* - * Temporary fix. - */ - for (channel = 0; channel < NUM_CHANNELS; channel++) - spin_lock_init(&sunzilog_port_table[channel].port.lock); - - sunzilog_irq_chain = up = &sunzilog_port_table[0]; - for (channel = 0; channel < NUM_CHANNELS - 1; channel++) - up[channel].next = &up[channel + 1]; - up[channel].next = NULL; - - for (chip = 0; chip < NUM_SUNZILOG; chip++) { - rp = sunzilog_chip_regs[chip]; - up[(chip * 2) + 0].port.membase = (void __iomem *)&rp->channelA; - up[(chip * 2) + 1].port.membase = (void __iomem *)&rp->channelB; - - /* Channel A */ - up[(chip * 2) + 0].port.iotype = UPIO_MEM; - up[(chip * 2) + 0].port.irq = zilog_irq; - up[(chip * 2) + 0].port.uartclk = ZS_CLOCK; - up[(chip * 2) + 0].port.fifosize = 1; - up[(chip * 2) + 0].port.ops = &sunzilog_pops; - up[(chip * 2) + 0].port.type = PORT_SUNZILOG; - up[(chip * 2) + 0].port.flags = 0; - up[(chip * 2) + 0].port.line = (chip * 2) + 0; - up[(chip * 2) + 0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A; - - /* Channel B */ - up[(chip * 2) + 1].port.iotype = UPIO_MEM; - up[(chip * 2) + 1].port.irq = zilog_irq; - up[(chip * 2) + 1].port.uartclk = ZS_CLOCK; - up[(chip * 2) + 1].port.fifosize = 1; - up[(chip * 2) + 1].port.ops = &sunzilog_pops; - up[(chip * 2) + 1].port.type = PORT_SUNZILOG; - up[(chip * 2) + 1].port.flags = 0; - up[(chip * 2) + 1].port.line = (chip * 2) + 1; - up[(chip * 2) + 1].flags |= 0; - } -} - static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channel) { int baud, brg; @@ -1540,8 +1235,6 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe up->cflag = B4800 | CS8 | CLOCAL | CREAD; baud = 4800; } - printk(KERN_INFO "zs%d at 0x%p (irq = %d) is a SunZilog\n", - channel, up->port.membase, zilog_irq); up->curregs[R15] = BRKIE; brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); @@ -1553,216 +1246,268 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe #ifdef CONFIG_SERIO static void __init sunzilog_register_serio(struct uart_sunzilog_port *up, int channel) { - struct serio *serio; - - up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL); - if (serio) { - memset(serio, 0, sizeof(*serio)); - - serio->port_data = up; - - serio->id.type = SERIO_RS232; - if (channel == KEYBOARD_LINE) { - serio->id.proto = SERIO_SUNKBD; - strlcpy(serio->name, "zskbd", sizeof(serio->name)); - } else { - serio->id.proto = SERIO_SUN; - serio->id.extra = 1; - strlcpy(serio->name, "zsms", sizeof(serio->name)); - } - strlcpy(serio->phys, - (channel == KEYBOARD_LINE ? "zs/serio0" : "zs/serio1"), - sizeof(serio->phys)); + struct serio *serio = &up->serio; - serio->write = sunzilog_serio_write; - serio->open = sunzilog_serio_open; - serio->close = sunzilog_serio_close; + serio->port_data = up; - serio_register_port(serio); + serio->id.type = SERIO_RS232; + if (channel == KEYBOARD_LINE) { + serio->id.proto = SERIO_SUNKBD; + strlcpy(serio->name, "zskbd", sizeof(serio->name)); } else { - printk(KERN_WARNING "zs%d: not enough memory for serio port\n", - channel); + serio->id.proto = SERIO_SUN; + serio->id.extra = 1; + strlcpy(serio->name, "zsms", sizeof(serio->name)); } + strlcpy(serio->phys, + (channel == KEYBOARD_LINE ? "zs/serio0" : "zs/serio1"), + sizeof(serio->phys)); + + serio->write = sunzilog_serio_write; + serio->open = sunzilog_serio_open; + serio->close = sunzilog_serio_close; + serio->dev.parent = up->port.dev; + + serio_register_port(serio); } #endif -static void __init sunzilog_init_hw(void) +static void __init sunzilog_init_hw(struct uart_sunzilog_port *up) { - int i; - - for (i = 0; i < NUM_CHANNELS; i++) { - struct uart_sunzilog_port *up = &sunzilog_port_table[i]; - struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - unsigned long flags; - int baud, brg; + struct zilog_channel __iomem *channel; + unsigned long flags; + int baud, brg; - spin_lock_irqsave(&up->port.lock, flags); + channel = ZILOG_CHANNEL_FROM_PORT(&up->port); - if (ZS_IS_CHANNEL_A(up)) { - write_zsreg(channel, R9, FHWRES); - ZSDELAY_LONG(); - (void) read_zsreg(channel, R0); - } + spin_lock_irqsave(&up->port.lock, flags); + if (ZS_IS_CHANNEL_A(up)) { + write_zsreg(channel, R9, FHWRES); + ZSDELAY_LONG(); + (void) read_zsreg(channel, R0); + } - if (i == KEYBOARD_LINE || i == MOUSE_LINE) { - sunzilog_init_kbdms(up, i); - up->curregs[R9] |= (NV | MIE); - write_zsreg(channel, R9, up->curregs[R9]); - } else { - /* Normal serial TTY. */ - up->parity_mask = 0xff; - up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; - up->curregs[R4] = PAR_EVEN | X16CLK | SB1; - up->curregs[R3] = RxENAB | Rx8; - up->curregs[R5] = TxENAB | Tx8; - up->curregs[R9] = NV | MIE; - up->curregs[R10] = NRZ; - up->curregs[R11] = TCBR | RCBR; - baud = 9600; - brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); - up->curregs[R12] = (brg & 0xff); - up->curregs[R13] = (brg >> 8) & 0xff; - up->curregs[R14] = BRSRC | BRENAB; - __load_zsregs(channel, up->curregs); - write_zsreg(channel, R9, up->curregs[R9]); - } + if (up->port.line == KEYBOARD_LINE || + up->port.line == MOUSE_LINE) { + sunzilog_init_kbdms(up, up->port.line); + up->curregs[R9] |= (NV | MIE); + write_zsreg(channel, R9, up->curregs[R9]); + } else { + /* Normal serial TTY. */ + up->parity_mask = 0xff; + up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB; + up->curregs[R4] = PAR_EVEN | X16CLK | SB1; + up->curregs[R3] = RxENAB | Rx8; + up->curregs[R5] = TxENAB | Tx8; + up->curregs[R9] = NV | MIE; + up->curregs[R10] = NRZ; + up->curregs[R11] = TCBR | RCBR; + baud = 9600; + brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); + up->curregs[R12] = (brg & 0xff); + up->curregs[R13] = (brg >> 8) & 0xff; + up->curregs[R14] = BRSRC | BRENAB; + __load_zsregs(channel, up->curregs); + write_zsreg(channel, R9, up->curregs[R9]); + } - spin_unlock_irqrestore(&up->port.lock, flags); + spin_unlock_irqrestore(&up->port.lock, flags); #ifdef CONFIG_SERIO - if (i == KEYBOARD_LINE || i == MOUSE_LINE) - sunzilog_register_serio(up, i); + if (up->port.line == KEYBOARD_LINE || up->port.line == MOUSE_LINE) + sunzilog_register_serio(up, up->port.line); #endif - } -} - -static struct zilog_layout __iomem * __init get_zs(int chip, int node); - -static void __init sunzilog_scan_probe(struct zs_probe_scan *t, int node) -{ - sunzilog_chip_regs[t->devices] = get_zs(t->devices, node); - t->devices++; } -static int __init sunzilog_ports_init(void) +static int __devinit zs_get_instance(struct device_node *dp) { - struct zs_probe_scan scan; int ret; - int uart_count; - int i; - - printk(KERN_DEBUG "SunZilog: %d chips.\n", NUM_SUNZILOG); - - scan.scanner = sunzilog_scan_probe; - scan.depth = 0; - scan.devices = 0; - sunzilog_scan(&scan, prom_getchild(prom_root_node)); - - sunzilog_prepare(); - if (request_irq(zilog_irq, sunzilog_interrupt, SA_SHIRQ, - "SunZilog", sunzilog_irq_chain)) { - prom_printf("SunZilog: Unable to register zs interrupt handler.\n"); - prom_halt(); - } + ret = of_getintprop_default(dp, "slave", -1); + if (ret != -1) + return ret; - sunzilog_init_hw(); + if (of_find_property(dp, "keyboard", NULL)) + ret = 1; + else + ret = 0; - /* We can only init this once we have probed the Zilogs - * in the system. Do not count channels assigned to keyboards - * or mice when we are deciding how many ports to register. - */ - uart_count = 0; - for (i = 0; i < NUM_CHANNELS; i++) { - struct uart_sunzilog_port *up = &sunzilog_port_table[i]; + return ret; +} - if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) - continue; +static int zilog_irq = -1; - uart_count++; - } - - sunzilog_reg.nr = uart_count; - sunzilog_reg.minor = sunserial_current_minor; +static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *match) +{ + struct of_device *op = to_of_device(&dev->dev); + struct uart_sunzilog_port *up; + struct zilog_layout __iomem *rp; + int inst = zs_get_instance(dev->node); + int err; - ret = uart_register_driver(&sunzilog_reg); - if (ret == 0) { - sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64; - sunzilog_reg.cons = SUNZILOG_CONSOLE(); + sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0, + sizeof(struct zilog_layout), + "zs"); + if (!sunzilog_chip_regs[inst]) + return -ENOMEM; - sunserial_current_minor += uart_count; + rp = sunzilog_chip_regs[inst]; - for (i = 0; i < NUM_CHANNELS; i++) { - struct uart_sunzilog_port *up = &sunzilog_port_table[i]; + if (zilog_irq == -1) { + zilog_irq = op->irqs[0]; + err = request_irq(zilog_irq, sunzilog_interrupt, SA_SHIRQ, + "zs", sunzilog_irq_chain); + if (err) { + of_iounmap(rp, sizeof(struct zilog_layout)); - if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) - continue; + return err; + } + } - if (uart_add_one_port(&sunzilog_reg, &up->port)) { - printk(KERN_ERR - "SunZilog: failed to add port zs%d\n", i); - } + up = &sunzilog_port_table[inst * 2]; + + /* Channel A */ + up[0].port.mapbase = op->resource[0].start + 0x00; + up[0].port.membase = (void __iomem *) &rp->channelA; + up[0].port.iotype = UPIO_MEM; + up[0].port.irq = op->irqs[0]; + up[0].port.uartclk = ZS_CLOCK; + up[0].port.fifosize = 1; + up[0].port.ops = &sunzilog_pops; + up[0].port.type = PORT_SUNZILOG; + up[0].port.flags = 0; + up[0].port.line = (inst * 2) + 0; + up[0].port.dev = &op->dev; + up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A; + if (inst == 1) + up[0].flags |= SUNZILOG_FLAG_CONS_KEYB; + sunzilog_init_hw(&up[0]); + + /* Channel B */ + up[1].port.mapbase = op->resource[0].start + 0x04; + up[1].port.membase = (void __iomem *) &rp->channelB; + up[1].port.iotype = UPIO_MEM; + up[1].port.irq = op->irqs[0]; + up[1].port.uartclk = ZS_CLOCK; + up[1].port.fifosize = 1; + up[1].port.ops = &sunzilog_pops; + up[1].port.type = PORT_SUNZILOG; + up[1].port.flags = 0; + up[1].port.line = (inst * 2) + 1; + up[1].port.dev = &op->dev; + up[1].flags |= 0; + if (inst == 1) + up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE; + sunzilog_init_hw(&up[1]); + + if (inst != 1) { + err = uart_add_one_port(&sunzilog_reg, &up[0].port); + if (err) { + of_iounmap(rp, sizeof(struct zilog_layout)); + return err; + } + err = uart_add_one_port(&sunzilog_reg, &up[1].port); + if (err) { + uart_remove_one_port(&sunzilog_reg, &up[0].port); + of_iounmap(rp, sizeof(struct zilog_layout)); + return err; } } - return ret; + dev_set_drvdata(&dev->dev, &up[0]); + + return 0; } -static void __init sunzilog_scan_count(struct zs_probe_scan *t, int node) +static void __devexit zs_remove_one(struct uart_sunzilog_port *up) { - t->devices++; + if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { +#ifdef CONFIG_SERIO + serio_unregister_port(&up->serio); +#endif + } else + uart_remove_one_port(&sunzilog_reg, &up->port); } -static int __init sunzilog_ports_count(void) +static int __devexit zs_remove(struct of_device *dev) { - struct zs_probe_scan scan; + struct uart_sunzilog_port *up = dev_get_drvdata(&dev->dev); + struct zilog_layout __iomem *regs; - /* Sun4 Zilog setup is hard coded, no probing to do. */ - if (sparc_cpu_model == sun4) - return 2; + zs_remove_one(&up[0]); + zs_remove_one(&up[1]); - scan.scanner = sunzilog_scan_count; - scan.depth = 0; - scan.devices = 0; + regs = sunzilog_chip_regs[up[0].port.line / 2]; + of_iounmap(regs, sizeof(struct zilog_layout)); - sunzilog_scan(&scan, prom_getchild(prom_root_node)); + dev_set_drvdata(&dev->dev, NULL); - return scan.devices; + return 0; } +static struct of_device_id zs_match[] = { + { + .name = "zs", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, zs_match); + +static struct of_platform_driver zs_driver = { + .name = "zs", + .match_table = zs_match, + .probe = zs_probe, + .remove = __devexit_p(zs_remove), +}; + static int __init sunzilog_init(void) { + struct device_node *dp; + int err; - NUM_SUNZILOG = sunzilog_ports_count(); - if (NUM_SUNZILOG == 0) - return -ENODEV; + NUM_SUNZILOG = 0; + for_each_node_by_name(dp, "zs") + NUM_SUNZILOG++; - sunzilog_alloc_tables(); + if (NUM_SUNZILOG) { + int uart_count; - sunzilog_ports_init(); + err = sunzilog_alloc_tables(); + if (err) + return err; - return 0; + /* Subtract 1 for keyboard, 1 for mouse. */ + uart_count = (NUM_SUNZILOG * 2) - 2; + + sunzilog_reg.nr = uart_count; + sunzilog_reg.minor = sunserial_current_minor; + err = uart_register_driver(&sunzilog_reg); + if (err) { + sunzilog_free_tables(); + return err; + } + sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64; + sunzilog_reg.cons = SUNZILOG_CONSOLE(); + + sunserial_current_minor += uart_count; + } + + return of_register_driver(&zs_driver, &of_bus_type); } static void __exit sunzilog_exit(void) { - int i; + of_unregister_driver(&zs_driver); - for (i = 0; i < NUM_CHANNELS; i++) { - struct uart_sunzilog_port *up = &sunzilog_port_table[i]; - - if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { -#ifdef CONFIG_SERIO - if (up->serio) { - serio_unregister_port(up->serio); - up->serio = NULL; - } -#endif - } else - uart_remove_one_port(&sunzilog_reg, &up->port); + if (zilog_irq != -1) { + free_irq(zilog_irq, sunzilog_irq_chain); + zilog_irq = -1; } - uart_unregister_driver(&sunzilog_reg); + if (NUM_SUNZILOG) { + uart_unregister_driver(&sunzilog_reg); + sunzilog_free_tables(); + } } module_init(sunzilog_init); @@ -1770,4 +1515,5 @@ module_exit(sunzilog_exit); MODULE_AUTHOR("David S. Miller"); MODULE_DESCRIPTION("Sun Zilog serial port driver"); +MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/serial/v850e_uart.c b/drivers/serial/v850e_uart.c index df705fda4243..a0da2aaf71c4 100644 --- a/drivers/serial/v850e_uart.c +++ b/drivers/serial/v850e_uart.c @@ -468,7 +468,6 @@ static struct uart_ops v850e_uart_ops = { static struct uart_driver v850e_uart_driver = { .owner = THIS_MODULE, .driver_name = "v850e_uart", - .devfs_name = "tts/", .dev_name = "ttyS", .major = TTY_MAJOR, .minor = V850E_UART_MINOR_BASE, diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c index df5e8713fa31..017571ffa19c 100644 --- a/drivers/serial/vr41xx_siu.c +++ b/drivers/serial/vr41xx_siu.c @@ -911,7 +911,6 @@ static struct uart_driver siu_uart_driver = { .owner = THIS_MODULE, .driver_name = "SIU", .dev_name = "ttyVR", - .devfs_name = "ttvr/", .major = SIU_MAJOR, .minor = SIU_MINOR_BASE, .cons = SERIAL_VR41XX_CONSOLE, diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c index 2dffa8e303b2..7f27b356eaf7 100644 --- a/drivers/tc/zs.c +++ b/drivers/tc/zs.c @@ -1745,7 +1745,6 @@ int __init zs_init(void) /* Not all of this is exactly right for us. */ serial_driver->owner = THIS_MODULE; - serial_driver->devfs_name = "tts/"; serial_driver->name = "ttyS"; serial_driver->major = TTY_MAJOR; serial_driver->minor_start = 64; @@ -1754,7 +1753,7 @@ int __init zs_init(void) serial_driver->init_termios = tty_std_termios; serial_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(serial_driver, &serial_ops); if (tty_register_driver(serial_driver)) diff --git a/drivers/telephony/phonedev.c b/drivers/telephony/phonedev.c index e166fffea86b..e41f49afd0f4 100644 --- a/drivers/telephony/phonedev.c +++ b/drivers/telephony/phonedev.c @@ -28,7 +28,6 @@ #include <linux/kmod.h> #include <linux/sem.h> -#include <linux/devfs_fs_kernel.h> #include <linux/mutex.h> #define PHONE_NUM_DEVICES 256 @@ -106,8 +105,6 @@ int phone_register_device(struct phone_device *p, int unit) if (phone_device[i] == NULL) { phone_device[i] = p; p->minor = i; - devfs_mk_cdev(MKDEV(PHONE_MAJOR,i), - S_IFCHR|S_IRUSR|S_IWUSR, "phone/%d", i); mutex_unlock(&phone_lock); return 0; } @@ -125,7 +122,6 @@ void phone_unregister_device(struct phone_device *pfd) mutex_lock(&phone_lock); if (phone_device[pfd->minor] != pfd) panic("phone: bad unregister"); - devfs_remove("phone/%d", pfd->minor); phone_device[pfd->minor] = NULL; mutex_unlock(&phone_lock); } diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index d41dc67ba4cc..3670d77e912c 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1145,12 +1145,11 @@ static int __init acm_init(void) acm_tty_driver->owner = THIS_MODULE, acm_tty_driver->driver_name = "acm", acm_tty_driver->name = "ttyACM", - acm_tty_driver->devfs_name = "usb/acm/", acm_tty_driver->major = ACM_TTY_MAJOR, acm_tty_driver->minor_start = 0, acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL, acm_tty_driver->subtype = SERIAL_TYPE_NORMAL, - acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS, + acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; acm_tty_driver->init_termios = tty_std_termios; acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; tty_set_operations(acm_tty_driver, &acm_ops); diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 269ce7f4ad66..735e9dbd39fd 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -60,7 +60,7 @@ #include <linux/usb_ch9.h> #include <linux/usb_gadget.h> -#include <asm/arch/hardware/intel_udc.h> +#include <asm/arch/udc.h> /* diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 9d6e1d295528..416acac879df 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -588,12 +588,11 @@ static int __init gs_module_init(void) gs_tty_driver->owner = THIS_MODULE; gs_tty_driver->driver_name = GS_SHORT_NAME; gs_tty_driver->name = "ttygs"; - gs_tty_driver->devfs_name = "usb/ttygs/"; gs_tty_driver->major = GS_MAJOR; gs_tty_driver->minor_start = GS_MINOR_START; gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; gs_tty_driver->subtype = SERIAL_TYPE_NORMAL; - gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; gs_tty_driver->init_termios = tty_std_termios; gs_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; tty_set_operations(gs_tty_driver, &gs_tty_ops); diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index a30135c7cfe6..f466f89eeb6d 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1059,13 +1059,12 @@ static int __init usb_serial_init(void) usb_serial_tty_driver->owner = THIS_MODULE; usb_serial_tty_driver->driver_name = "usbserial"; - usb_serial_tty_driver->devfs_name = "usb/tts/"; usb_serial_tty_driver->name = "ttyUSB"; usb_serial_tty_driver->major = SERIAL_TTY_MAJOR; usb_serial_tty_driver->minor_start = 0; usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL; - usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; usb_serial_tty_driver->init_termios = tty_std_termios; usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; tty_set_operations(usb_serial_tty_driver, &serial_ops); diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index 6577fdfdfc16..c66e3d52cbf3 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -1,6 +1,6 @@ /* bw2.c: BWTWO frame buffer driver * - * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -19,14 +19,11 @@ #include <linux/mm.h> #include <asm/io.h> -#include <asm/sbus.h> #include <asm/oplib.h> +#include <asm/prom.h> +#include <asm/of_device.h> #include <asm/fbio.h> -#ifdef CONFIG_SPARC32 -#include <asm/sun4paddr.h> -#endif - #include "sbuslib.h" /* @@ -59,30 +56,30 @@ static struct fb_ops bw2_ops = { #define BWTWO_REGISTER_OFFSET 0x400000 struct bt_regs { - volatile u32 addr; - volatile u32 color_map; - volatile u32 control; - volatile u32 cursor; + u32 addr; + u32 color_map; + u32 control; + u32 cursor; }; struct bw2_regs { struct bt_regs cmap; - volatile u8 control; - volatile u8 status; - volatile u8 cursor_start; - volatile u8 cursor_end; - volatile u8 h_blank_start; - volatile u8 h_blank_end; - volatile u8 h_sync_start; - volatile u8 h_sync_end; - volatile u8 comp_sync_end; - volatile u8 v_blank_start_high; - volatile u8 v_blank_start_low; - volatile u8 v_blank_end; - volatile u8 v_sync_start; - volatile u8 v_sync_end; - volatile u8 xfer_holdoff_start; - volatile u8 xfer_holdoff_end; + u8 control; + u8 status; + u8 cursor_start; + u8 cursor_end; + u8 h_blank_start; + u8 h_blank_end; + u8 h_sync_start; + u8 h_sync_end; + u8 comp_sync_end; + u8 v_blank_start_high; + u8 v_blank_start_low; + u8 v_blank_end; + u8 v_sync_start; + u8 v_sync_end; + u8 xfer_holdoff_start; + u8 xfer_holdoff_end; }; /* Status Register Constants */ @@ -117,9 +114,8 @@ struct bw2_par { #define BW2_FLAG_BLANKED 0x00000001 unsigned long physbase; + unsigned long which_io; unsigned long fbsize; - - struct sbus_dev *sdev; }; /** @@ -174,9 +170,7 @@ static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma) return sbusfb_mmap_helper(bw2_mmap_map, par->physbase, par->fbsize, - (par->sdev ? - par->sdev->reg_addrs[0].which_io : - 0), + par->which_io, vma); } @@ -288,139 +282,124 @@ static void bw2_do_default_mode(struct bw2_par *par, struct fb_info *info, struct all_info { struct fb_info info; struct bw2_par par; - struct list_head list; }; -static LIST_HEAD(bw2_list); -static void bw2_init_one(struct sbus_dev *sdev) +static int __devinit bw2_init_one(struct of_device *op) { + struct device_node *dp = op->node; struct all_info *all; - struct resource *resp; -#ifdef CONFIG_SUN4 - struct resource res; -#endif - int linebytes; + int linebytes, err; - all = kmalloc(sizeof(*all), GFP_KERNEL); - if (!all) { - printk(KERN_ERR "bw2: Cannot allocate memory.\n"); - return; - } - memset(all, 0, sizeof(*all)); - - INIT_LIST_HEAD(&all->list); + all = kzalloc(sizeof(*all), GFP_KERNEL); + if (!all) + return -ENOMEM; spin_lock_init(&all->par.lock); - all->par.sdev = sdev; - -#ifdef CONFIG_SUN4 - if (!sdev) { - all->par.physbase = sun4_bwtwo_physaddr; - res.start = sun4_bwtwo_physaddr; - res.end = res.start + BWTWO_REGISTER_OFFSET + sizeof(struct bw2_regs) - 1; - res.flags = IORESOURCE_IO; - resp = &res; - all->info.var.xres = all->info.var.xres_virtual = 1152; - all->info.var.yres = all->info.var.yres_virtual = 900; - all->info.var.bits_per_pixel = 1; - linebytes = 1152 / 8; - } else -#else - { - BUG_ON(!sdev); - all->par.physbase = sdev->reg_addrs[0].phys_addr; - resp = &sdev->resource[0]; - sbusfb_fill_var(&all->info.var, (sdev ? sdev->prom_node : 0), 1); - linebytes = prom_getintdefault(sdev->prom_node, "linebytes", - all->info.var.xres); - } -#endif + + all->par.physbase = op->resource[0].start; + all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; + + sbusfb_fill_var(&all->info.var, dp->node, 1); + linebytes = of_getintprop_default(dp, "linebytes", + all->info.var.xres); + all->info.var.red.length = all->info.var.green.length = all->info.var.blue.length = all->info.var.bits_per_pixel; all->info.var.red.offset = all->info.var.green.offset = all->info.var.blue.offset = 0; - all->par.regs = sbus_ioremap(resp, BWTWO_REGISTER_OFFSET, - sizeof(struct bw2_regs), "bw2 regs"); + all->par.regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET, + sizeof(struct bw2_regs), "bw2 regs"); - if (sdev && !prom_getbool(sdev->prom_node, "width")) + if (!of_find_property(dp, "width", NULL)) bw2_do_default_mode(&all->par, &all->info, &linebytes); all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); all->info.flags = FBINFO_DEFAULT; all->info.fbops = &bw2_ops; -#if defined(CONFIG_SPARC32) - if (sdev) - all->info.screen_base = (char __iomem *) - prom_getintdefault(sdev->prom_node, "address", 0); -#endif - if (!all->info.screen_base) - all->info.screen_base = - sbus_ioremap(resp, 0, all->par.fbsize, "bw2 ram"); + + all->info.screen_base = + sbus_ioremap(&op->resource[0], 0, all->par.fbsize, "bw2 ram"); all->info.par = &all->par; bw2_blank(0, &all->info); bw2_init_fix(&all->info, linebytes); - if (register_framebuffer(&all->info) < 0) { - printk(KERN_ERR "bw2: Could not register framebuffer.\n"); + err= register_framebuffer(&all->info); + if (err < 0) { + of_iounmap(all->par.regs, sizeof(struct bw2_regs)); + of_iounmap(all->info.screen_base, all->par.fbsize); kfree(all); - return; + return err; } - list_add(&all->list, &bw2_list); + dev_set_drvdata(&op->dev, all); + + printk("%s: bwtwo at %lx:%lx\n", + dp->full_name, + all->par.which_io, all->par.physbase); - printk("bw2: bwtwo at %lx:%lx\n", - (long) (sdev ? sdev->reg_addrs[0].which_io : 0), - (long) all->par.physbase); + return 0; } -int __init bw2_init(void) +static int __devinit bw2_probe(struct of_device *dev, const struct of_device_id *match) { - struct sbus_bus *sbus; - struct sbus_dev *sdev; + struct of_device *op = to_of_device(&dev->dev); - if (fb_get_options("bw2fb", NULL)) - return -ENODEV; + return bw2_init_one(op); +} -#ifdef CONFIG_SUN4 - bw2_init_one(NULL); -#endif - for_all_sbusdev(sdev, sbus) { - if (!strcmp(sdev->prom_name, "bwtwo")) - bw2_init_one(sdev); - } +static int __devexit bw2_remove(struct of_device *dev) +{ + struct all_info *all = dev_get_drvdata(&dev->dev); + + unregister_framebuffer(&all->info); + + of_iounmap(all->par.regs, sizeof(struct bw2_regs)); + of_iounmap(all->info.screen_base, all->par.fbsize); + + kfree(all); + + dev_set_drvdata(&dev->dev, NULL); return 0; } -void __exit bw2_exit(void) -{ - struct list_head *pos, *tmp; +static struct of_device_id bw2_match[] = { + { + .name = "bwtwo", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, bw2_match); - list_for_each_safe(pos, tmp, &bw2_list) { - struct all_info *all = list_entry(pos, typeof(*all), list); +static struct of_platform_driver bw2_driver = { + .name = "bw2", + .match_table = bw2_match, + .probe = bw2_probe, + .remove = __devexit_p(bw2_remove), +}; - unregister_framebuffer(&all->info); - kfree(all); - } +static int __init bw2_init(void) +{ + if (fb_get_options("bw2fb", NULL)) + return -ENODEV; + + return of_register_driver(&bw2_driver, &of_bus_type); } -int __init -bw2_setup(char *arg) +static void __exit bw2_exit(void) { - /* No cmdline options yet... */ - return 0; + return of_unregister_driver(&bw2_driver); } -module_init(bw2_init); -#ifdef MODULE +module_init(bw2_init); module_exit(bw2_exit); -#endif MODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets"); -MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); +MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index 63b6c79c8a0a..7f926c619b61 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -1,6 +1,6 @@ /* cg14.c: CGFOURTEEN frame buffer driver * - * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) * @@ -18,8 +18,8 @@ #include <linux/mm.h> #include <asm/io.h> -#include <asm/sbus.h> -#include <asm/oplib.h> +#include <asm/prom.h> +#include <asm/of_device.h> #include <asm/fbio.h> #include "sbuslib.h" @@ -99,73 +99,73 @@ static struct fb_ops cg14_ops = { #define CG14_MCR_PIXMODE_32 3 struct cg14_regs{ - volatile u8 mcr; /* Master Control Reg */ - volatile u8 ppr; /* Packed Pixel Reg */ - volatile u8 tms[2]; /* Test Mode Status Regs */ - volatile u8 msr; /* Master Status Reg */ - volatile u8 fsr; /* Fault Status Reg */ - volatile u8 rev; /* Revision & Impl */ - volatile u8 ccr; /* Clock Control Reg */ - volatile u32 tmr; /* Test Mode Read Back */ - volatile u8 mod; /* Monitor Operation Data Reg */ - volatile u8 acr; /* Aux Control */ + u8 mcr; /* Master Control Reg */ + u8 ppr; /* Packed Pixel Reg */ + u8 tms[2]; /* Test Mode Status Regs */ + u8 msr; /* Master Status Reg */ + u8 fsr; /* Fault Status Reg */ + u8 rev; /* Revision & Impl */ + u8 ccr; /* Clock Control Reg */ + u32 tmr; /* Test Mode Read Back */ + u8 mod; /* Monitor Operation Data Reg */ + u8 acr; /* Aux Control */ u8 xxx0[6]; - volatile u16 hct; /* Hor Counter */ - volatile u16 vct; /* Vert Counter */ - volatile u16 hbs; /* Hor Blank Start */ - volatile u16 hbc; /* Hor Blank Clear */ - volatile u16 hss; /* Hor Sync Start */ - volatile u16 hsc; /* Hor Sync Clear */ - volatile u16 csc; /* Composite Sync Clear */ - volatile u16 vbs; /* Vert Blank Start */ - volatile u16 vbc; /* Vert Blank Clear */ - volatile u16 vss; /* Vert Sync Start */ - volatile u16 vsc; /* Vert Sync Clear */ - volatile u16 xcs; - volatile u16 xcc; - volatile u16 fsa; /* Fault Status Address */ - volatile u16 adr; /* Address Registers */ + u16 hct; /* Hor Counter */ + u16 vct; /* Vert Counter */ + u16 hbs; /* Hor Blank Start */ + u16 hbc; /* Hor Blank Clear */ + u16 hss; /* Hor Sync Start */ + u16 hsc; /* Hor Sync Clear */ + u16 csc; /* Composite Sync Clear */ + u16 vbs; /* Vert Blank Start */ + u16 vbc; /* Vert Blank Clear */ + u16 vss; /* Vert Sync Start */ + u16 vsc; /* Vert Sync Clear */ + u16 xcs; + u16 xcc; + u16 fsa; /* Fault Status Address */ + u16 adr; /* Address Registers */ u8 xxx1[0xce]; - volatile u8 pcg[0x100]; /* Pixel Clock Generator */ - volatile u32 vbr; /* Frame Base Row */ - volatile u32 vmcr; /* VBC Master Control */ - volatile u32 vcr; /* VBC refresh */ - volatile u32 vca; /* VBC Config */ + u8 pcg[0x100]; /* Pixel Clock Generator */ + u32 vbr; /* Frame Base Row */ + u32 vmcr; /* VBC Master Control */ + u32 vcr; /* VBC refresh */ + u32 vca; /* VBC Config */ }; #define CG14_CCR_ENABLE 0x04 #define CG14_CCR_SELECT 0x02 /* HW/Full screen */ struct cg14_cursor { - volatile u32 cpl0[32]; /* Enable plane 0 */ - volatile u32 cpl1[32]; /* Color selection plane */ - volatile u8 ccr; /* Cursor Control Reg */ + u32 cpl0[32]; /* Enable plane 0 */ + u32 cpl1[32]; /* Color selection plane */ + u8 ccr; /* Cursor Control Reg */ u8 xxx0[3]; - volatile u16 cursx; /* Cursor x,y position */ - volatile u16 cursy; /* Cursor x,y position */ - volatile u32 color0; - volatile u32 color1; + u16 cursx; /* Cursor x,y position */ + u16 cursy; /* Cursor x,y position */ + u32 color0; + u32 color1; u32 xxx1[0x1bc]; - volatile u32 cpl0i[32]; /* Enable plane 0 autoinc */ - volatile u32 cpl1i[32]; /* Color selection autoinc */ + u32 cpl0i[32]; /* Enable plane 0 autoinc */ + u32 cpl1i[32]; /* Color selection autoinc */ }; struct cg14_dac { - volatile u8 addr; /* Address Register */ + u8 addr; /* Address Register */ u8 xxx0[255]; - volatile u8 glut; /* Gamma table */ + u8 glut; /* Gamma table */ u8 xxx1[255]; - volatile u8 select; /* Register Select */ + u8 select; /* Register Select */ u8 xxx2[255]; - volatile u8 mode; /* Mode Register */ + u8 mode; /* Mode Register */ }; struct cg14_xlut{ - volatile u8 x_xlut [256]; - volatile u8 x_xlutd [256]; + u8 x_xlut [256]; + u8 x_xlutd [256]; u8 xxx0[0x600]; - volatile u8 x_xlut_inc [256]; - volatile u8 x_xlutd_inc [256]; + u8 x_xlut_inc [256]; + u8 x_xlutd_inc [256]; }; /* Color look up table (clut) */ @@ -204,7 +204,6 @@ struct cg14_par { int mode; int ramsize; - struct sbus_dev *sdev; }; static void __cg14_reset(struct cg14_par *par) @@ -355,14 +354,9 @@ static int cg14_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) * Initialisation */ -static void cg14_init_fix(struct fb_info *info, int linebytes) +static void cg14_init_fix(struct fb_info *info, int linebytes, struct device_node *dp) { - struct cg14_par *par = (struct cg14_par *)info->par; - const char *name; - - name = "cgfourteen"; - if (par->sdev) - name = par->sdev->prom_name; + const char *name = dp->name; strlcpy(info->fix.id, name, sizeof(info->fix.id)); @@ -456,98 +450,81 @@ static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] __initdata = { struct all_info { struct fb_info info; struct cg14_par par; - struct list_head list; }; -static LIST_HEAD(cg14_list); -static void cg14_init_one(struct sbus_dev *sdev, int node, int parent_node) +static void cg14_unmap_regs(struct all_info *all) { - struct all_info *all; - unsigned long phys, rphys; - u32 bases[6]; - int is_8mb, linebytes, i; - - if (!sdev) { - if (prom_getproperty(node, "address", - (char *) &bases[0], sizeof(bases)) <= 0 - || !bases[0]) { - printk(KERN_ERR "cg14: Device is not mapped.\n"); - return; - } - if (__get_iospace(bases[0]) != __get_iospace(bases[1])) { - printk(KERN_ERR "cg14: I/O spaces don't match.\n"); - return; - } - } + if (all->par.regs) + of_iounmap(all->par.regs, sizeof(struct cg14_regs)); + if (all->par.clut) + of_iounmap(all->par.clut, sizeof(struct cg14_clut)); + if (all->par.cursor) + of_iounmap(all->par.cursor, sizeof(struct cg14_cursor)); + if (all->info.screen_base) + of_iounmap(all->info.screen_base, all->par.fbsize); +} - all = kmalloc(sizeof(*all), GFP_KERNEL); - if (!all) { - printk(KERN_ERR "cg14: Cannot allocate memory.\n"); - return; - } - memset(all, 0, sizeof(*all)); +static int __devinit cg14_init_one(struct of_device *op) +{ + struct device_node *dp = op->node; + struct all_info *all; + int is_8mb, linebytes, i, err; - INIT_LIST_HEAD(&all->list); + all = kzalloc(sizeof(*all), GFP_KERNEL); + if (!all) + return -ENOMEM; spin_lock_init(&all->par.lock); - sbusfb_fill_var(&all->info.var, node, 8); + sbusfb_fill_var(&all->info.var, dp->node, 8); all->info.var.red.length = 8; all->info.var.green.length = 8; all->info.var.blue.length = 8; - linebytes = prom_getintdefault(node, "linebytes", - all->info.var.xres); + linebytes = of_getintprop_default(dp, "linebytes", + all->info.var.xres); all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); - all->par.sdev = sdev; - if (sdev) { - rphys = sdev->reg_addrs[0].phys_addr; - all->par.physbase = phys = sdev->reg_addrs[1].phys_addr; - all->par.iospace = sdev->reg_addrs[0].which_io; - - all->par.regs = sbus_ioremap(&sdev->resource[0], 0, - sizeof(struct cg14_regs), - "cg14 regs"); - all->par.clut = sbus_ioremap(&sdev->resource[0], CG14_CLUT1, - sizeof(struct cg14_clut), - "cg14 clut"); - all->par.cursor = sbus_ioremap(&sdev->resource[0], CG14_CURSORREGS, - sizeof(struct cg14_cursor), - "cg14 cursor"); - all->info.screen_base = sbus_ioremap(&sdev->resource[1], 0, - all->par.fbsize, "cg14 ram"); + if (!strcmp(dp->parent->name, "sbus") || + !strcmp(dp->parent->name, "sbi")) { + all->par.physbase = op->resource[0].start; + all->par.iospace = op->resource[0].flags & IORESOURCE_BITS; } else { - rphys = __get_phys(bases[0]); - all->par.physbase = phys = __get_phys(bases[1]); - all->par.iospace = __get_iospace(bases[0]); - all->par.regs = (struct cg14_regs __iomem *)(unsigned long)bases[0]; - all->par.clut = (struct cg14_clut __iomem *)((unsigned long)bases[0] + - CG14_CLUT1); - all->par.cursor = - (struct cg14_cursor __iomem *)((unsigned long)bases[0] + - CG14_CURSORREGS); - - all->info.screen_base = (char __iomem *)(unsigned long)bases[1]; + all->par.physbase = op->resource[1].start; + all->par.iospace = op->resource[0].flags & IORESOURCE_BITS; } - prom_getproperty(node, "reg", (char *) &bases[0], sizeof(bases)); - is_8mb = (bases[5] == 0x800000); + all->par.regs = of_ioremap(&op->resource[0], 0, + sizeof(struct cg14_regs), "cg14 regs"); + all->par.clut = of_ioremap(&op->resource[0], CG14_CLUT1, + sizeof(struct cg14_clut), "cg14 clut"); + all->par.cursor = of_ioremap(&op->resource[0], CG14_CURSORREGS, + sizeof(struct cg14_cursor), "cg14 cursor"); - if (sizeof(all->par.mmap_map) != sizeof(__cg14_mmap_map)) { - extern void __cg14_mmap_sized_wrongly(void); + all->info.screen_base = of_ioremap(&op->resource[1], 0, + all->par.fbsize, "cg14 ram"); - __cg14_mmap_sized_wrongly(); - } + if (!all->par.regs || !all->par.clut || !all->par.cursor || + !all->info.screen_base) + cg14_unmap_regs(all); + + is_8mb = (((op->resource[1].end - op->resource[1].start) + 1) == + (8 * 1024 * 1024)); + + BUILD_BUG_ON(sizeof(all->par.mmap_map) != sizeof(__cg14_mmap_map)); - memcpy(&all->par.mmap_map, &__cg14_mmap_map, sizeof(all->par.mmap_map)); + memcpy(&all->par.mmap_map, &__cg14_mmap_map, + sizeof(all->par.mmap_map)); + for (i = 0; i < CG14_MMAP_ENTRIES; i++) { struct sbus_mmap_map *map = &all->par.mmap_map[i]; if (!map->size) break; if (map->poff & 0x80000000) - map->poff = (map->poff & 0x7fffffff) + rphys - phys; + map->poff = (map->poff & 0x7fffffff) + + (op->resource[0].start - + op->resource[1].start); if (is_8mb && map->size >= 0x100000 && map->size <= 0x400000) @@ -564,84 +541,87 @@ static void cg14_init_one(struct sbus_dev *sdev, int node, int parent_node) __cg14_reset(&all->par); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - printk(KERN_ERR "cg14: Could not allocate color map.\n"); + cg14_unmap_regs(all); kfree(all); - return; + return -ENOMEM; } fb_set_cmap(&all->info.cmap, &all->info); - cg14_init_fix(&all->info, linebytes); + cg14_init_fix(&all->info, linebytes, dp); - if (register_framebuffer(&all->info) < 0) { - printk(KERN_ERR "cg14: Could not register framebuffer.\n"); + err = register_framebuffer(&all->info); + if (err < 0) { fb_dealloc_cmap(&all->info.cmap); + cg14_unmap_regs(all); kfree(all); - return; + return err; } - list_add(&all->list, &cg14_list); + dev_set_drvdata(&op->dev, all); - printk("cg14: cgfourteen at %lx:%lx, %dMB\n", - all->par.iospace, all->par.physbase, all->par.ramsize >> 20); + printk("%s: cgfourteen at %lx:%lx, %dMB\n", + dp->full_name, + all->par.iospace, all->par.physbase, + all->par.ramsize >> 20); + return 0; } -int __init cg14_init(void) +static int __devinit cg14_probe(struct of_device *dev, const struct of_device_id *match) { - struct sbus_bus *sbus; - struct sbus_dev *sdev; + struct of_device *op = to_of_device(&dev->dev); - if (fb_get_options("cg14fb", NULL)) - return -ENODEV; + return cg14_init_one(op); +} -#ifdef CONFIG_SPARC32 - { - int root, node; - - root = prom_getchild(prom_root_node); - root = prom_searchsiblings(root, "obio"); - if (root) { - node = prom_searchsiblings(prom_getchild(root), - "cgfourteen"); - if (node) - cg14_init_one(NULL, node, root); - } - } -#endif - for_all_sbusdev(sdev, sbus) { - if (!strcmp(sdev->prom_name, "cgfourteen")) - cg14_init_one(sdev, sdev->prom_node, sbus->prom_node); - } +static int __devexit cg14_remove(struct of_device *dev) +{ + struct all_info *all = dev_get_drvdata(&dev->dev); + + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + + cg14_unmap_regs(all); + + kfree(all); + + dev_set_drvdata(&dev->dev, NULL); return 0; } -void __exit cg14_exit(void) -{ - struct list_head *pos, *tmp; +static struct of_device_id cg14_match[] = { + { + .name = "cgfourteen", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, cg14_match); - list_for_each_safe(pos, tmp, &cg14_list) { - struct all_info *all = list_entry(pos, typeof(*all), list); +static struct of_platform_driver cg14_driver = { + .name = "cg14", + .match_table = cg14_match, + .probe = cg14_probe, + .remove = __devexit_p(cg14_remove), +}; - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); - kfree(all); - } +int __init cg14_init(void) +{ + if (fb_get_options("cg14fb", NULL)) + return -ENODEV; + + return of_register_driver(&cg14_driver, &of_bus_type); } -int __init -cg14_setup(char *arg) +void __exit cg14_exit(void) { - /* No cmdline options yet... */ - return 0; + of_unregister_driver(&cg14_driver); } module_init(cg14_init); - -#ifdef MODULE module_exit(cg14_exit); -#endif MODULE_DESCRIPTION("framebuffer driver for CGfourteen chipsets"); -MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); +MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index 3de6e1b5ab2f..9c8c753ef454 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -1,6 +1,6 @@ /* cg3.c: CGTHREE frame buffer driver * - * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -19,8 +19,9 @@ #include <linux/mm.h> #include <asm/io.h> -#include <asm/sbus.h> #include <asm/oplib.h> +#include <asm/prom.h> +#include <asm/of_device.h> #include <asm/fbio.h> #include "sbuslib.h" @@ -80,30 +81,30 @@ enum cg3_type { }; struct bt_regs { - volatile u32 addr; - volatile u32 color_map; - volatile u32 control; - volatile u32 cursor; + u32 addr; + u32 color_map; + u32 control; + u32 cursor; }; struct cg3_regs { struct bt_regs cmap; - volatile u8 control; - volatile u8 status; - volatile u8 cursor_start; - volatile u8 cursor_end; - volatile u8 h_blank_start; - volatile u8 h_blank_end; - volatile u8 h_sync_start; - volatile u8 h_sync_end; - volatile u8 comp_sync_end; - volatile u8 v_blank_start_high; - volatile u8 v_blank_start_low; - volatile u8 v_blank_end; - volatile u8 v_sync_start; - volatile u8 v_sync_end; - volatile u8 xfer_holdoff_start; - volatile u8 xfer_holdoff_end; + u8 control; + u8 status; + u8 cursor_start; + u8 cursor_end; + u8 h_blank_start; + u8 h_blank_end; + u8 h_sync_start; + u8 h_sync_end; + u8 comp_sync_end; + u8 v_blank_start_high; + u8 v_blank_start_low; + u8 v_blank_end; + u8 v_sync_start; + u8 v_sync_end; + u8 xfer_holdoff_start; + u8 xfer_holdoff_end; }; /* Offset of interesting structures in the OBIO space */ @@ -120,9 +121,8 @@ struct cg3_par { #define CG3_FLAG_RDI 0x00000002 unsigned long physbase; + unsigned long which_io; unsigned long fbsize; - - struct sbus_dev *sdev; }; /** @@ -235,7 +235,7 @@ static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma) return sbusfb_mmap_helper(cg3_mmap_map, par->physbase, par->fbsize, - par->sdev->reg_addrs[0].which_io, + par->which_io, vma); } @@ -252,11 +252,9 @@ static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) */ static void -cg3_init_fix(struct fb_info *info, int linebytes) +cg3_init_fix(struct fb_info *info, int linebytes, struct device_node *dp) { - struct cg3_par *par = (struct cg3_par *)info->par; - - strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id)); + strlcpy(info->fix.id, dp->name, sizeof(info->fix.id)); info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_PSEUDOCOLOR; @@ -267,16 +265,15 @@ cg3_init_fix(struct fb_info *info, int linebytes) } static void cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var, - struct sbus_dev *sdev) + struct device_node *dp) { - char buffer[40]; + char *params; char *p; int ww, hh; - *buffer = 0; - prom_getstring(sdev->prom_node, "params", buffer, sizeof(buffer)); - if (*buffer) { - ww = simple_strtoul(buffer, &p, 10); + params = of_get_property(dp, "params", NULL); + if (params) { + ww = simple_strtoul(params, &p, 10); if (ww && *p == 'x') { hh = simple_strtoul(p + 1, &p, 10); if (hh && *p == '-') { @@ -348,11 +345,11 @@ static void cg3_do_default_mode(struct cg3_par *par) sbus_writeb(p[1], regp); } for (p = cg3_dacvals; *p; p += 2) { - volatile u8 __iomem *regp; + u8 __iomem *regp; - regp = (volatile u8 __iomem *)&par->regs->cmap.addr; + regp = (u8 __iomem *)&par->regs->cmap.addr; sbus_writeb(p[0], regp); - regp = (volatile u8 __iomem *)&par->regs->cmap.control; + regp = (u8 __iomem *)&par->regs->cmap.control; sbus_writeb(p[1], regp); } } @@ -360,129 +357,137 @@ static void cg3_do_default_mode(struct cg3_par *par) struct all_info { struct fb_info info; struct cg3_par par; - struct list_head list; }; -static LIST_HEAD(cg3_list); -static void cg3_init_one(struct sbus_dev *sdev) +static int __devinit cg3_init_one(struct of_device *op) { + struct device_node *dp = op->node; struct all_info *all; - int linebytes; - - all = kmalloc(sizeof(*all), GFP_KERNEL); - if (!all) { - printk(KERN_ERR "cg3: Cannot allocate memory.\n"); - return; - } - memset(all, 0, sizeof(*all)); + int linebytes, err; - INIT_LIST_HEAD(&all->list); + all = kzalloc(sizeof(*all), GFP_KERNEL); + if (!all) + return -ENOMEM; spin_lock_init(&all->par.lock); - all->par.sdev = sdev; - all->par.physbase = sdev->reg_addrs[0].phys_addr; + all->par.physbase = op->resource[0].start; + all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; - sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); + sbusfb_fill_var(&all->info.var, dp->node, 8); all->info.var.red.length = 8; all->info.var.green.length = 8; all->info.var.blue.length = 8; - if (!strcmp(sdev->prom_name, "cgRDI")) + if (!strcmp(dp->name, "cgRDI")) all->par.flags |= CG3_FLAG_RDI; if (all->par.flags & CG3_FLAG_RDI) - cg3_rdi_maybe_fixup_var(&all->info.var, sdev); + cg3_rdi_maybe_fixup_var(&all->info.var, dp); - linebytes = prom_getintdefault(sdev->prom_node, "linebytes", - all->info.var.xres); + linebytes = of_getintprop_default(dp, "linebytes", + all->info.var.xres); all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); - all->par.regs = sbus_ioremap(&sdev->resource[0], CG3_REGS_OFFSET, - sizeof(struct cg3_regs), "cg3 regs"); + all->par.regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET, + sizeof(struct cg3_regs), "cg3 regs"); all->info.flags = FBINFO_DEFAULT; all->info.fbops = &cg3_ops; -#ifdef CONFIG_SPARC32 - all->info.screen_base = (char __iomem *) - prom_getintdefault(sdev->prom_node, "address", 0); -#endif - if (!all->info.screen_base) - all->info.screen_base = - sbus_ioremap(&sdev->resource[0], CG3_RAM_OFFSET, - all->par.fbsize, "cg3 ram"); + all->info.screen_base = + of_ioremap(&op->resource[0], CG3_RAM_OFFSET, + all->par.fbsize, "cg3 ram"); all->info.par = &all->par; cg3_blank(0, &all->info); - if (!prom_getbool(sdev->prom_node, "width")) + if (!of_find_property(dp, "width", NULL)) cg3_do_default_mode(&all->par); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - printk(KERN_ERR "cg3: Could not allocate color map.\n"); + of_iounmap(all->par.regs, sizeof(struct cg3_regs)); + of_iounmap(all->info.screen_base, all->par.fbsize); kfree(all); - return; + return -ENOMEM; } fb_set_cmap(&all->info.cmap, &all->info); - cg3_init_fix(&all->info, linebytes); + cg3_init_fix(&all->info, linebytes, dp); - if (register_framebuffer(&all->info) < 0) { - printk(KERN_ERR "cg3: Could not register framebuffer.\n"); + err = register_framebuffer(&all->info); + if (err < 0) { fb_dealloc_cmap(&all->info.cmap); + of_iounmap(all->par.regs, sizeof(struct cg3_regs)); + of_iounmap(all->info.screen_base, all->par.fbsize); kfree(all); - return; + return err; } - list_add(&all->list, &cg3_list); + dev_set_drvdata(&op->dev, all); + + printk("%s: cg3 at %lx:%lx\n", + dp->full_name, all->par.which_io, all->par.physbase); - printk("cg3: %s at %lx:%lx\n", - sdev->prom_name, - (long) sdev->reg_addrs[0].which_io, - (long) sdev->reg_addrs[0].phys_addr); + return 0; } -int __init cg3_init(void) +static int __devinit cg3_probe(struct of_device *dev, const struct of_device_id *match) { - struct sbus_bus *sbus; - struct sbus_dev *sdev; + struct of_device *op = to_of_device(&dev->dev); - if (fb_get_options("cg3fb", NULL)) - return -ENODEV; + return cg3_init_one(op); +} - for_all_sbusdev(sdev, sbus) { - if (!strcmp(sdev->prom_name, "cgthree") || - !strcmp(sdev->prom_name, "cgRDI")) - cg3_init_one(sdev); - } +static int __devexit cg3_remove(struct of_device *dev) +{ + struct all_info *all = dev_get_drvdata(&dev->dev); + + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + + of_iounmap(all->par.regs, sizeof(struct cg3_regs)); + of_iounmap(all->info.screen_base, all->par.fbsize); + + kfree(all); + + dev_set_drvdata(&dev->dev, NULL); return 0; } -void __exit cg3_exit(void) -{ - struct list_head *pos, *tmp; +static struct of_device_id cg3_match[] = { + { + .name = "cgthree", + }, + { + .name = "cgRDI", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, cg3_match); - list_for_each_safe(pos, tmp, &cg3_list) { - struct all_info *all = list_entry(pos, typeof(*all), list); +static struct of_platform_driver cg3_driver = { + .name = "cg3", + .match_table = cg3_match, + .probe = cg3_probe, + .remove = __devexit_p(cg3_remove), +}; - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); - kfree(all); - } +static int __init cg3_init(void) +{ + if (fb_get_options("cg3fb", NULL)) + return -ENODEV; + + return of_register_driver(&cg3_driver, &of_bus_type); } -int __init -cg3_setup(char *arg) +static void __exit cg3_exit(void) { - /* No cmdline options yet... */ - return 0; + of_unregister_driver(&cg3_driver); } module_init(cg3_init); - -#ifdef MODULE module_exit(cg3_exit); -#endif MODULE_DESCRIPTION("framebuffer driver for CGthree chipsets"); -MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); +MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 7aab91ead681..64146be2eeb0 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -1,6 +1,6 @@ /* cg6.c: CGSIX (GX, GXplus, TGX) frame buffer driver * - * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) @@ -19,8 +19,8 @@ #include <linux/mm.h> #include <asm/io.h> -#include <asm/sbus.h> -#include <asm/oplib.h> +#include <asm/prom.h> +#include <asm/of_device.h> #include <asm/fbio.h> #include "sbuslib.h" @@ -164,89 +164,89 @@ static struct fb_ops cg6_ops = { /* The contents are unknown */ struct cg6_tec { - volatile int tec_matrix; - volatile int tec_clip; - volatile int tec_vdc; + int tec_matrix; + int tec_clip; + int tec_vdc; }; struct cg6_thc { - uint thc_pad0[512]; - volatile uint thc_hs; /* hsync timing */ - volatile uint thc_hsdvs; - volatile uint thc_hd; - volatile uint thc_vs; /* vsync timing */ - volatile uint thc_vd; - volatile uint thc_refresh; - volatile uint thc_misc; - uint thc_pad1[56]; - volatile uint thc_cursxy; /* cursor x,y position (16 bits each) */ - volatile uint thc_cursmask[32]; /* cursor mask bits */ - volatile uint thc_cursbits[32]; /* what to show where mask enabled */ + u32 thc_pad0[512]; + u32 thc_hs; /* hsync timing */ + u32 thc_hsdvs; + u32 thc_hd; + u32 thc_vs; /* vsync timing */ + u32 thc_vd; + u32 thc_refresh; + u32 thc_misc; + u32 thc_pad1[56]; + u32 thc_cursxy; /* cursor x,y position (16 bits each) */ + u32 thc_cursmask[32]; /* cursor mask bits */ + u32 thc_cursbits[32]; /* what to show where mask enabled */ }; struct cg6_fbc { - u32 xxx0[1]; - volatile u32 mode; - volatile u32 clip; - u32 xxx1[1]; - volatile u32 s; - volatile u32 draw; - volatile u32 blit; - volatile u32 font; - u32 xxx2[24]; - volatile u32 x0, y0, z0, color0; - volatile u32 x1, y1, z1, color1; - volatile u32 x2, y2, z2, color2; - volatile u32 x3, y3, z3, color3; - volatile u32 offx, offy; - u32 xxx3[2]; - volatile u32 incx, incy; - u32 xxx4[2]; - volatile u32 clipminx, clipminy; - u32 xxx5[2]; - volatile u32 clipmaxx, clipmaxy; - u32 xxx6[2]; - volatile u32 fg; - volatile u32 bg; - volatile u32 alu; - volatile u32 pm; - volatile u32 pixelm; - u32 xxx7[2]; - volatile u32 patalign; - volatile u32 pattern[8]; - u32 xxx8[432]; - volatile u32 apointx, apointy, apointz; - u32 xxx9[1]; - volatile u32 rpointx, rpointy, rpointz; - u32 xxx10[5]; - volatile u32 pointr, pointg, pointb, pointa; - volatile u32 alinex, aliney, alinez; - u32 xxx11[1]; - volatile u32 rlinex, rliney, rlinez; - u32 xxx12[5]; - volatile u32 liner, lineg, lineb, linea; - volatile u32 atrix, atriy, atriz; - u32 xxx13[1]; - volatile u32 rtrix, rtriy, rtriz; - u32 xxx14[5]; - volatile u32 trir, trig, trib, tria; - volatile u32 aquadx, aquady, aquadz; - u32 xxx15[1]; - volatile u32 rquadx, rquady, rquadz; - u32 xxx16[5]; - volatile u32 quadr, quadg, quadb, quada; - volatile u32 arectx, arecty, arectz; - u32 xxx17[1]; - volatile u32 rrectx, rrecty, rrectz; - u32 xxx18[5]; - volatile u32 rectr, rectg, rectb, recta; + u32 xxx0[1]; + u32 mode; + u32 clip; + u32 xxx1[1]; + u32 s; + u32 draw; + u32 blit; + u32 font; + u32 xxx2[24]; + u32 x0, y0, z0, color0; + u32 x1, y1, z1, color1; + u32 x2, y2, z2, color2; + u32 x3, y3, z3, color3; + u32 offx, offy; + u32 xxx3[2]; + u32 incx, incy; + u32 xxx4[2]; + u32 clipminx, clipminy; + u32 xxx5[2]; + u32 clipmaxx, clipmaxy; + u32 xxx6[2]; + u32 fg; + u32 bg; + u32 alu; + u32 pm; + u32 pixelm; + u32 xxx7[2]; + u32 patalign; + u32 pattern[8]; + u32 xxx8[432]; + u32 apointx, apointy, apointz; + u32 xxx9[1]; + u32 rpointx, rpointy, rpointz; + u32 xxx10[5]; + u32 pointr, pointg, pointb, pointa; + u32 alinex, aliney, alinez; + u32 xxx11[1]; + u32 rlinex, rliney, rlinez; + u32 xxx12[5]; + u32 liner, lineg, lineb, linea; + u32 atrix, atriy, atriz; + u32 xxx13[1]; + u32 rtrix, rtriy, rtriz; + u32 xxx14[5]; + u32 trir, trig, trib, tria; + u32 aquadx, aquady, aquadz; + u32 xxx15[1]; + u32 rquadx, rquady, rquadz; + u32 xxx16[5]; + u32 quadr, quadg, quadb, quada; + u32 arectx, arecty, arectz; + u32 xxx17[1]; + u32 rrectx, rrecty, rrectz; + u32 xxx18[5]; + u32 rectr, rectg, rectb, recta; }; struct bt_regs { - volatile u32 addr; - volatile u32 color_map; - volatile u32 control; - volatile u32 cursor; + u32 addr; + u32 color_map; + u32 control; + u32 cursor; }; struct cg6_par { @@ -255,15 +255,14 @@ struct cg6_par { struct cg6_fbc __iomem *fbc; struct cg6_thc __iomem *thc; struct cg6_tec __iomem *tec; - volatile u32 __iomem *fhc; + u32 __iomem *fhc; u32 flags; #define CG6_FLAG_BLANKED 0x00000001 unsigned long physbase; + unsigned long which_io; unsigned long fbsize; - - struct sbus_dev *sdev; }; static int cg6_sync(struct fb_info *info) @@ -529,8 +528,7 @@ static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma) return sbusfb_mmap_helper(cg6_mmap_map, par->physbase, par->fbsize, - par->sdev->reg_addrs[0].which_io, - vma); + par->which_io, vma); } static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) @@ -658,62 +656,75 @@ static void cg6_chip_init(struct fb_info *info) struct all_info { struct fb_info info; struct cg6_par par; - struct list_head list; }; -static LIST_HEAD(cg6_list); -static void cg6_init_one(struct sbus_dev *sdev) +static void cg6_unmap_regs(struct all_info *all) { - struct all_info *all; - int linebytes; + if (all->par.fbc) + of_iounmap(all->par.fbc, 4096); + if (all->par.tec) + of_iounmap(all->par.tec, sizeof(struct cg6_tec)); + if (all->par.thc) + of_iounmap(all->par.thc, sizeof(struct cg6_thc)); + if (all->par.bt) + of_iounmap(all->par.bt, sizeof(struct bt_regs)); + if (all->par.fhc) + of_iounmap(all->par.fhc, sizeof(u32)); + + if (all->info.screen_base) + of_iounmap(all->info.screen_base, all->par.fbsize); +} - all = kmalloc(sizeof(*all), GFP_KERNEL); - if (!all) { - printk(KERN_ERR "cg6: Cannot allocate memory.\n"); - return; - } - memset(all, 0, sizeof(*all)); +static int __devinit cg6_init_one(struct of_device *op) +{ + struct device_node *dp = op->node; + struct all_info *all; + int linebytes, err; - INIT_LIST_HEAD(&all->list); + all = kzalloc(sizeof(*all), GFP_KERNEL); + if (!all) + return -ENOMEM; spin_lock_init(&all->par.lock); - all->par.sdev = sdev; - all->par.physbase = sdev->reg_addrs[0].phys_addr; + all->par.physbase = op->resource[0].start; + all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; - sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); + sbusfb_fill_var(&all->info.var, dp->node, 8); all->info.var.red.length = 8; all->info.var.green.length = 8; all->info.var.blue.length = 8; - linebytes = prom_getintdefault(sdev->prom_node, "linebytes", - all->info.var.xres); + linebytes = of_getintprop_default(dp, "linebytes", + all->info.var.xres); all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); - if (prom_getbool(sdev->prom_node, "dblbuf")) + if (of_find_property(dp, "dblbuf", NULL)) all->par.fbsize *= 4; - all->par.fbc = sbus_ioremap(&sdev->resource[0], CG6_FBC_OFFSET, - 4096, "cgsix fbc"); - all->par.tec = sbus_ioremap(&sdev->resource[0], CG6_TEC_OFFSET, - sizeof(struct cg6_tec), "cgsix tec"); - all->par.thc = sbus_ioremap(&sdev->resource[0], CG6_THC_OFFSET, - sizeof(struct cg6_thc), "cgsix thc"); - all->par.bt = sbus_ioremap(&sdev->resource[0], CG6_BROOKTREE_OFFSET, - sizeof(struct bt_regs), "cgsix dac"); - all->par.fhc = sbus_ioremap(&sdev->resource[0], CG6_FHC_OFFSET, - sizeof(u32), "cgsix fhc"); + all->par.fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET, + 4096, "cgsix fbc"); + all->par.tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET, + sizeof(struct cg6_tec), "cgsix tec"); + all->par.thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET, + sizeof(struct cg6_thc), "cgsix thc"); + all->par.bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET, + sizeof(struct bt_regs), "cgsix dac"); + all->par.fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET, + sizeof(u32), "cgsix fhc"); all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; all->info.fbops = &cg6_ops; -#ifdef CONFIG_SPARC32 - all->info.screen_base = (char __iomem *) - prom_getintdefault(sdev->prom_node, "address", 0); -#endif - if (!all->info.screen_base) - all->info.screen_base = - sbus_ioremap(&sdev->resource[0], CG6_RAM_OFFSET, - all->par.fbsize, "cgsix ram"); + + all->info.screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET, + all->par.fbsize, "cgsix ram"); + if (!all->par.fbc || !all->par.tec || !all->par.thc || + !all->par.bt || !all->par.fhc || !all->info.screen_base) { + cg6_unmap_regs(all); + kfree(all); + return -ENOMEM; + } + all->info.par = &all->par; all->info.var.accel_flags = FB_ACCELF_TEXT; @@ -723,72 +734,90 @@ static void cg6_init_one(struct sbus_dev *sdev) cg6_blank(0, &all->info); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - printk(KERN_ERR "cg6: Could not allocate color map.\n"); + cg6_unmap_regs(all); kfree(all); - return; + return -ENOMEM; } fb_set_cmap(&all->info.cmap, &all->info); cg6_init_fix(&all->info, linebytes); - if (register_framebuffer(&all->info) < 0) { - printk(KERN_ERR "cg6: Could not register framebuffer.\n"); + err = register_framebuffer(&all->info); + if (err < 0) { + cg6_unmap_regs(all); fb_dealloc_cmap(&all->info.cmap); kfree(all); - return; + return err; } - list_add(&all->list, &cg6_list); + dev_set_drvdata(&op->dev, all); - printk("cg6: CGsix [%s] at %lx:%lx\n", + printk("%s: CGsix [%s] at %lx:%lx\n", + dp->full_name, all->info.fix.id, - (long) sdev->reg_addrs[0].which_io, - (long) sdev->reg_addrs[0].phys_addr); + all->par.which_io, all->par.physbase); + + return 0; } -int __init cg6_init(void) +static int __devinit cg6_probe(struct of_device *dev, const struct of_device_id *match) { - struct sbus_bus *sbus; - struct sbus_dev *sdev; + struct of_device *op = to_of_device(&dev->dev); - if (fb_get_options("cg6fb", NULL)) - return -ENODEV; + return cg6_init_one(op); +} - for_all_sbusdev(sdev, sbus) { - if (!strcmp(sdev->prom_name, "cgsix") || - !strcmp(sdev->prom_name, "cgthree+")) - cg6_init_one(sdev); - } +static int __devexit cg6_remove(struct of_device *dev) +{ + struct all_info *all = dev_get_drvdata(&dev->dev); + + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + + cg6_unmap_regs(all); + + kfree(all); + + dev_set_drvdata(&dev->dev, NULL); return 0; } -void __exit cg6_exit(void) -{ - struct list_head *pos, *tmp; +static struct of_device_id cg6_match[] = { + { + .name = "cgsix", + }, + { + .name = "cgthree+", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, cg6_match); - list_for_each_safe(pos, tmp, &cg6_list) { - struct all_info *all = list_entry(pos, typeof(*all), list); +static struct of_platform_driver cg6_driver = { + .name = "cg6", + .match_table = cg6_match, + .probe = cg6_probe, + .remove = __devexit_p(cg6_remove), +}; - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); - kfree(all); - } +static int __init cg6_init(void) +{ + if (fb_get_options("cg6fb", NULL)) + return -ENODEV; + + return of_register_driver(&cg6_driver, &of_bus_type); } -int __init -cg6_setup(char *arg) +static void __exit cg6_exit(void) { - /* No cmdline options yet... */ - return 0; + of_unregister_driver(&cg6_driver); } module_init(cg6_init); - -#ifdef MODULE module_exit(cg6_exit); -#endif MODULE_DESCRIPTION("framebuffer driver for CGsix chipsets"); -MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); +MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 31143afe7c95..a171daab0ad0 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -32,7 +32,6 @@ #ifdef CONFIG_KMOD #include <linux/kmod.h> #endif -#include <linux/devfs_fs_kernel.h> #include <linux/err.h> #include <linux/device.h> #include <linux/efi.h> @@ -1331,8 +1330,6 @@ register_framebuffer(struct fb_info *fb_info) fb_add_videomode(&mode, &fb_info->modelist); registered_fb[i] = fb_info; - devfs_mk_cdev(MKDEV(FB_MAJOR, i), - S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i); event.info = fb_info; blocking_notifier_call_chain(&fb_notifier_list, FB_EVENT_FB_REGISTERED, &event); @@ -1359,7 +1356,6 @@ unregister_framebuffer(struct fb_info *fb_info) i = fb_info->node; if (!registered_fb[i]) return -EINVAL; - devfs_remove("fb/%d", i); if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) @@ -1432,7 +1428,6 @@ fbmem_init(void) { create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL); - devfs_mk_dir("fb"); if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) printk("unable to get major %d for fb devs\n", FB_MAJOR); diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index 7633e41adda1..2a0e8210d398 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c @@ -1,6 +1,6 @@ /* ffb.c: Creator/Elite3D frame buffer driver * - * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz) * * Driver layout based loosely on tgafb.c, see that file for credits. @@ -19,7 +19,8 @@ #include <asm/io.h> #include <asm/upa.h> -#include <asm/oplib.h> +#include <asm/prom.h> +#include <asm/of_device.h> #include <asm/fbio.h> #include "sbuslib.h" @@ -184,161 +185,161 @@ static struct fb_ops ffb_ops = { struct ffb_fbc { /* Next vertex registers */ - u32 xxx1[3]; - volatile u32 alpha; - volatile u32 red; - volatile u32 green; - volatile u32 blue; - volatile u32 depth; - volatile u32 y; - volatile u32 x; - u32 xxx2[2]; - volatile u32 ryf; - volatile u32 rxf; - u32 xxx3[2]; + u32 xxx1[3]; + u32 alpha; + u32 red; + u32 green; + u32 blue; + u32 depth; + u32 y; + u32 x; + u32 xxx2[2]; + u32 ryf; + u32 rxf; + u32 xxx3[2]; - volatile u32 dmyf; - volatile u32 dmxf; - u32 xxx4[2]; - volatile u32 ebyi; - volatile u32 ebxi; - u32 xxx5[2]; - volatile u32 by; - volatile u32 bx; - u32 dy; - u32 dx; - volatile u32 bh; - volatile u32 bw; - u32 xxx6[2]; + u32 dmyf; + u32 dmxf; + u32 xxx4[2]; + u32 ebyi; + u32 ebxi; + u32 xxx5[2]; + u32 by; + u32 bx; + u32 dy; + u32 dx; + u32 bh; + u32 bw; + u32 xxx6[2]; - u32 xxx7[32]; + u32 xxx7[32]; /* Setup unit vertex state register */ - volatile u32 suvtx; - u32 xxx8[63]; + u32 suvtx; + u32 xxx8[63]; /* Control registers */ - volatile u32 ppc; - volatile u32 wid; - volatile u32 fg; - volatile u32 bg; - volatile u32 consty; - volatile u32 constz; - volatile u32 xclip; - volatile u32 dcss; - volatile u32 vclipmin; - volatile u32 vclipmax; - volatile u32 vclipzmin; - volatile u32 vclipzmax; - volatile u32 dcsf; - volatile u32 dcsb; - volatile u32 dczf; - volatile u32 dczb; + u32 ppc; + u32 wid; + u32 fg; + u32 bg; + u32 consty; + u32 constz; + u32 xclip; + u32 dcss; + u32 vclipmin; + u32 vclipmax; + u32 vclipzmin; + u32 vclipzmax; + u32 dcsf; + u32 dcsb; + u32 dczf; + u32 dczb; - u32 xxx9; - volatile u32 blendc; - volatile u32 blendc1; - volatile u32 blendc2; - volatile u32 fbramitc; - volatile u32 fbc; - volatile u32 rop; - volatile u32 cmp; - volatile u32 matchab; - volatile u32 matchc; - volatile u32 magnab; - volatile u32 magnc; - volatile u32 fbcfg0; - volatile u32 fbcfg1; - volatile u32 fbcfg2; - volatile u32 fbcfg3; + u32 xxx9; + u32 blendc; + u32 blendc1; + u32 blendc2; + u32 fbramitc; + u32 fbc; + u32 rop; + u32 cmp; + u32 matchab; + u32 matchc; + u32 magnab; + u32 magnc; + u32 fbcfg0; + u32 fbcfg1; + u32 fbcfg2; + u32 fbcfg3; - u32 ppcfg; - volatile u32 pick; - volatile u32 fillmode; - volatile u32 fbramwac; - volatile u32 pmask; - volatile u32 xpmask; - volatile u32 ypmask; - volatile u32 zpmask; - volatile u32 clip0min; - volatile u32 clip0max; - volatile u32 clip1min; - volatile u32 clip1max; - volatile u32 clip2min; - volatile u32 clip2max; - volatile u32 clip3min; - volatile u32 clip3max; + u32 ppcfg; + u32 pick; + u32 fillmode; + u32 fbramwac; + u32 pmask; + u32 xpmask; + u32 ypmask; + u32 zpmask; + u32 clip0min; + u32 clip0max; + u32 clip1min; + u32 clip1max; + u32 clip2min; + u32 clip2max; + u32 clip3min; + u32 clip3max; /* New 3dRAM III support regs */ - volatile u32 rawblend2; - volatile u32 rawpreblend; - volatile u32 rawstencil; - volatile u32 rawstencilctl; - volatile u32 threedram1; - volatile u32 threedram2; - volatile u32 passin; - volatile u32 rawclrdepth; - volatile u32 rawpmask; - volatile u32 rawcsrc; - volatile u32 rawmatch; - volatile u32 rawmagn; - volatile u32 rawropblend; - volatile u32 rawcmp; - volatile u32 rawwac; - volatile u32 fbramid; + u32 rawblend2; + u32 rawpreblend; + u32 rawstencil; + u32 rawstencilctl; + u32 threedram1; + u32 threedram2; + u32 passin; + u32 rawclrdepth; + u32 rawpmask; + u32 rawcsrc; + u32 rawmatch; + u32 rawmagn; + u32 rawropblend; + u32 rawcmp; + u32 rawwac; + u32 fbramid; - volatile u32 drawop; - u32 xxx10[2]; - volatile u32 fontlpat; - u32 xxx11; - volatile u32 fontxy; - volatile u32 fontw; - volatile u32 fontinc; - volatile u32 font; - u32 xxx12[3]; - volatile u32 blend2; - volatile u32 preblend; - volatile u32 stencil; - volatile u32 stencilctl; - - u32 xxx13[4]; - volatile u32 dcss1; - volatile u32 dcss2; - volatile u32 dcss3; - volatile u32 widpmask; - volatile u32 dcs2; - volatile u32 dcs3; - volatile u32 dcs4; - u32 xxx14; - volatile u32 dcd2; - volatile u32 dcd3; - volatile u32 dcd4; - u32 xxx15; + u32 drawop; + u32 xxx10[2]; + u32 fontlpat; + u32 xxx11; + u32 fontxy; + u32 fontw; + u32 fontinc; + u32 font; + u32 xxx12[3]; + u32 blend2; + u32 preblend; + u32 stencil; + u32 stencilctl; + + u32 xxx13[4]; + u32 dcss1; + u32 dcss2; + u32 dcss3; + u32 widpmask; + u32 dcs2; + u32 dcs3; + u32 dcs4; + u32 xxx14; + u32 dcd2; + u32 dcd3; + u32 dcd4; + u32 xxx15; - volatile u32 pattern[32]; + u32 pattern[32]; - u32 xxx16[256]; + u32 xxx16[256]; - volatile u32 devid; - u32 xxx17[63]; + u32 devid; + u32 xxx17[63]; - volatile u32 ucsr; - u32 xxx18[31]; + u32 ucsr; + u32 xxx18[31]; - volatile u32 mer; + u32 mer; }; struct ffb_dac { - volatile u32 type; - volatile u32 value; - volatile u32 type2; - volatile u32 value2; + u32 type; + u32 value; + u32 type2; + u32 value2; }; struct ffb_par { spinlock_t lock; - struct ffb_fbc *fbc; - struct ffb_dac *dac; + struct ffb_fbc __iomem *fbc; + struct ffb_dac __iomem *dac; u32 flags; #define FFB_FLAG_AFB 0x00000001 @@ -353,16 +354,13 @@ struct ffb_par { unsigned long physbase; unsigned long fbsize; - char name[64]; - int prom_node; - int prom_parent_node; int dac_rev; int board_type; }; static void FFBFifo(struct ffb_par *par, int n) { - struct ffb_fbc *fbc; + struct ffb_fbc __iomem *fbc; int cache = par->fifo_cache; if (cache - n < 0) { @@ -375,7 +373,7 @@ static void FFBFifo(struct ffb_par *par, int n) static void FFBWait(struct ffb_par *par) { - struct ffb_fbc *fbc; + struct ffb_fbc __iomem *fbc; int limit = 10000; fbc = par->fbc; @@ -408,8 +406,8 @@ static __inline__ void ffb_rop(struct ffb_par *par, u32 rop) static void ffb_switch_from_graph(struct ffb_par *par) { - struct ffb_fbc *fbc = par->fbc; - struct ffb_dac *dac = par->dac; + struct ffb_fbc __iomem *fbc = par->fbc; + struct ffb_dac __iomem *dac = par->dac; unsigned long flags; spin_lock_irqsave(&par->lock, flags); @@ -462,7 +460,7 @@ static int ffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct ffb_par *par = (struct ffb_par *) info->par; - struct ffb_fbc *fbc = par->fbc; + struct ffb_fbc __iomem *fbc = par->fbc; unsigned long flags; u32 fg; @@ -505,7 +503,7 @@ static void ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area) { struct ffb_par *par = (struct ffb_par *) info->par; - struct ffb_fbc *fbc = par->fbc; + struct ffb_fbc __iomem *fbc = par->fbc; unsigned long flags; if (area->dx != area->sx || @@ -541,7 +539,7 @@ ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area) static void ffb_imageblit(struct fb_info *info, const struct fb_image *image) { struct ffb_par *par = (struct ffb_par *) info->par; - struct ffb_fbc *fbc = par->fbc; + struct ffb_fbc __iomem *fbc = par->fbc; const u8 *data = image->data; unsigned long flags; u32 fg, bg, xy; @@ -664,7 +662,7 @@ static int ffb_blank(int blank, struct fb_info *info) { struct ffb_par *par = (struct ffb_par *) info->par; - struct ffb_dac *dac = par->dac; + struct ffb_dac __iomem *dac = par->dac; unsigned long flags; u32 tmp; @@ -883,78 +881,42 @@ ffb_init_fix(struct fb_info *info) info->fix.accel = FB_ACCEL_SUN_CREATOR; } -static int ffb_apply_upa_parent_ranges(int parent, - struct linux_prom64_registers *regs) -{ - struct linux_prom64_ranges ranges[PROMREG_MAX]; - char name[128]; - int len, i; - - prom_getproperty(parent, "name", name, sizeof(name)); - if (strcmp(name, "upa") != 0) - return 0; - - len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges)); - if (len <= 0) - return 1; - - len /= sizeof(struct linux_prom64_ranges); - for (i = 0; i < len; i++) { - struct linux_prom64_ranges *rng = &ranges[i]; - u64 phys_addr = regs->phys_addr; - - if (phys_addr >= rng->ot_child_base && - phys_addr < (rng->ot_child_base + rng->or_size)) { - regs->phys_addr -= rng->ot_child_base; - regs->phys_addr += rng->ot_parent_base; - return 0; - } - } - - return 1; -} - struct all_info { struct fb_info info; struct ffb_par par; u32 pseudo_palette[256]; - struct list_head list; }; -static LIST_HEAD(ffb_list); -static void ffb_init_one(int node, int parent) +static int ffb_init_one(struct of_device *op) { - struct linux_prom64_registers regs[2*PROMREG_MAX]; - struct ffb_fbc *fbc; - struct ffb_dac *dac; + struct device_node *dp = op->node; + struct ffb_fbc __iomem *fbc; + struct ffb_dac __iomem *dac; struct all_info *all; + int err; - if (prom_getproperty(node, "reg", (void *) regs, sizeof(regs)) <= 0) { - printk("ffb: Cannot get reg device node property.\n"); - return; - } + all = kzalloc(sizeof(*all), GFP_KERNEL); + if (!all) + return -ENOMEM; - if (ffb_apply_upa_parent_ranges(parent, ®s[0])) { - printk("ffb: Cannot apply parent ranges to regs.\n"); - return; + spin_lock_init(&all->par.lock); + all->par.fbc = of_ioremap(&op->resource[2], 0, + sizeof(struct ffb_fbc), "ffb fbc"); + if (!all->par.fbc) { + kfree(all); + return -ENOMEM; } - all = kmalloc(sizeof(*all), GFP_KERNEL); - if (!all) { - printk(KERN_ERR "ffb: Cannot allocate memory.\n"); - return; + all->par.dac = of_ioremap(&op->resource[1], 0, + sizeof(struct ffb_dac), "ffb dac"); + if (!all->par.dac) { + of_iounmap(all->par.fbc, sizeof(struct ffb_fbc)); + kfree(all); + return -ENOMEM; } - memset(all, 0, sizeof(*all)); - - INIT_LIST_HEAD(&all->list); - spin_lock_init(&all->par.lock); - all->par.fbc = (struct ffb_fbc *)(regs[0].phys_addr + FFB_FBC_REGS_POFF); - all->par.dac = (struct ffb_dac *)(regs[0].phys_addr + FFB_DAC_POFF); all->par.rop_cache = FFB_ROP_NEW; - all->par.physbase = regs[0].phys_addr; - all->par.prom_node = node; - all->par.prom_parent_node = parent; + all->par.physbase = op->resource[0].start; /* Don't mention copyarea, so SCROLL_REDRAW is always * used. It is the fastest on this chip. @@ -968,7 +930,7 @@ static void ffb_init_one(int node, int parent) all->info.par = &all->par; all->info.pseudo_palette = all->pseudo_palette; - sbusfb_fill_var(&all->info.var, all->par.prom_node, 32); + sbusfb_fill_var(&all->info.var, dp->node, 32); all->par.fbsize = PAGE_ALIGN(all->info.var.xres * all->info.var.yres * 4); @@ -976,14 +938,13 @@ static void ffb_init_one(int node, int parent) all->info.var.accel_flags = FB_ACCELF_TEXT; - prom_getstring(node, "name", all->par.name, sizeof(all->par.name)); - if (!strcmp(all->par.name, "SUNW,afb")) + if (!strcmp(dp->name, "SUNW,afb")) all->par.flags |= FFB_FLAG_AFB; - all->par.board_type = prom_getintdefault(node, "board_type", 0); + all->par.board_type = of_getintprop_default(dp, "board_type", 0); fbc = all->par.fbc; - if((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) + if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr); ffb_switch_from_graph(&all->par); @@ -1008,81 +969,88 @@ static void ffb_init_one(int node, int parent) if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { printk(KERN_ERR "ffb: Could not allocate color map.\n"); kfree(all); - return; + return -ENOMEM; } ffb_init_fix(&all->info); - if (register_framebuffer(&all->info) < 0) { + err = register_framebuffer(&all->info); + if (err < 0) { printk(KERN_ERR "ffb: Could not register framebuffer.\n"); fb_dealloc_cmap(&all->info.cmap); kfree(all); - return; + return err; } - list_add(&all->list, &ffb_list); + dev_set_drvdata(&op->dev, all); - printk("ffb: %s at %016lx type %d DAC %d\n", + printk("%s: %s at %016lx, type %d, DAC revision %d\n", + dp->full_name, ((all->par.flags & FFB_FLAG_AFB) ? "AFB" : "FFB"), - regs[0].phys_addr, all->par.board_type, all->par.dac_rev); + all->par.physbase, all->par.board_type, all->par.dac_rev); + + return 0; } -static void ffb_scan_siblings(int root) +static int __devinit ffb_probe(struct of_device *dev, const struct of_device_id *match) { - int node, child; - - child = prom_getchild(root); - for (node = prom_searchsiblings(child, "SUNW,ffb"); node; - node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) - ffb_init_one(node, root); - for (node = prom_searchsiblings(child, "SUNW,afb"); node; - node = prom_searchsiblings(prom_getsibling(node), "SUNW,afb")) - ffb_init_one(node, root); + struct of_device *op = to_of_device(&dev->dev); + + return ffb_init_one(op); } -int __init ffb_init(void) +static int __devexit ffb_remove(struct of_device *dev) { - int root; + struct all_info *all = dev_get_drvdata(&dev->dev); - if (fb_get_options("ffb", NULL)) - return -ENODEV; + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); - ffb_scan_siblings(prom_root_node); + of_iounmap(all->par.fbc, sizeof(struct ffb_fbc)); + of_iounmap(all->par.dac, sizeof(struct ffb_dac)); - root = prom_getchild(prom_root_node); - for (root = prom_searchsiblings(root, "upa"); root; - root = prom_searchsiblings(prom_getsibling(root), "upa")) - ffb_scan_siblings(root); + kfree(all); + + dev_set_drvdata(&dev->dev, NULL); return 0; } -void __exit ffb_exit(void) -{ - struct list_head *pos, *tmp; +static struct of_device_id ffb_match[] = { + { + .name = "SUNW,ffb", + }, + { + .name = "SUNW,afb", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ffb_match); + +static struct of_platform_driver ffb_driver = { + .name = "ffb", + .match_table = ffb_match, + .probe = ffb_probe, + .remove = __devexit_p(ffb_remove), +}; - list_for_each_safe(pos, tmp, &ffb_list) { - struct all_info *all = list_entry(pos, typeof(*all), list); +int __init ffb_init(void) +{ + if (fb_get_options("ffb", NULL)) + return -ENODEV; - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); - kfree(all); - } + return of_register_driver(&ffb_driver, &of_bus_type); } -int __init -ffb_setup(char *arg) +void __exit ffb_exit(void) { - /* No cmdline options yet... */ - return 0; + of_unregister_driver(&ffb_driver); } module_init(ffb_init); - -#ifdef MODULE module_exit(ffb_exit); -#endif MODULE_DESCRIPTION("framebuffer driver for Creator/Elite3D chipsets"); -MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); +MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/leo.c b/drivers/video/leo.c index a23cfdb9d826..f3a24338d9ac 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -1,6 +1,6 @@ /* leo.c: LEO frame buffer driver * - * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) * Copyright (C) 1996-1999 Jakub Jelinek (jj@ultra.linux.cz) * Copyright (C) 1997 Michal Rehacek (Michal.Rehacek@st.mff.cuni.cz) * @@ -18,8 +18,8 @@ #include <linux/mm.h> #include <asm/io.h> -#include <asm/sbus.h> -#include <asm/oplib.h> +#include <asm/prom.h> +#include <asm/of_device.h> #include <asm/fbio.h> #include "sbuslib.h" @@ -80,10 +80,10 @@ static struct fb_ops leo_ops = { struct leo_cursor { u8 xxx0[16]; - volatile u32 cur_type; - volatile u32 cur_misc; - volatile u32 cur_cursxy; - volatile u32 cur_data; + u32 cur_type; + u32 cur_misc; + u32 cur_cursxy; + u32 cur_data; }; #define LEO_KRN_TYPE_CLUT0 0x00001000 @@ -99,27 +99,27 @@ struct leo_cursor { #define LEO_KRN_CSR_UNK2 0x00000001 struct leo_lx_krn { - volatile u32 krn_type; - volatile u32 krn_csr; - volatile u32 krn_value; + u32 krn_type; + u32 krn_csr; + u32 krn_value; }; struct leo_lc_ss0_krn { - volatile u32 misc; + u32 misc; u8 xxx0[0x800-4]; - volatile u32 rev; + u32 rev; }; struct leo_lc_ss0_usr { - volatile u32 csr; - volatile u32 addrspace; - volatile u32 fontmsk; - volatile u32 fontt; - volatile u32 extent; - volatile u32 src; + u32 csr; + u32 addrspace; + u32 fontmsk; + u32 fontt; + u32 extent; + u32 src; u32 dst; - volatile u32 copy; - volatile u32 fill; + u32 copy; + u32 fill; }; struct leo_lc_ss1_krn { @@ -132,47 +132,47 @@ struct leo_lc_ss1_usr { struct leo_ld { u8 xxx0[0xe00]; - volatile u32 csr; - volatile u32 wid; - volatile u32 wmask; - volatile u32 widclip; - volatile u32 vclipmin; - volatile u32 vclipmax; - volatile u32 pickmin; /* SS1 only */ - volatile u32 pickmax; /* SS1 only */ - volatile u32 fg; - volatile u32 bg; - volatile u32 src; /* Copy/Scroll (SS0 only) */ - volatile u32 dst; /* Copy/Scroll/Fill (SS0 only) */ - volatile u32 extent; /* Copy/Scroll/Fill size (SS0 only) */ + u32 csr; + u32 wid; + u32 wmask; + u32 widclip; + u32 vclipmin; + u32 vclipmax; + u32 pickmin; /* SS1 only */ + u32 pickmax; /* SS1 only */ + u32 fg; + u32 bg; + u32 src; /* Copy/Scroll (SS0 only) */ + u32 dst; /* Copy/Scroll/Fill (SS0 only) */ + u32 extent; /* Copy/Scroll/Fill size (SS0 only) */ u32 xxx1[3]; - volatile u32 setsem; /* SS1 only */ - volatile u32 clrsem; /* SS1 only */ - volatile u32 clrpick; /* SS1 only */ - volatile u32 clrdat; /* SS1 only */ - volatile u32 alpha; /* SS1 only */ + u32 setsem; /* SS1 only */ + u32 clrsem; /* SS1 only */ + u32 clrpick; /* SS1 only */ + u32 clrdat; /* SS1 only */ + u32 alpha; /* SS1 only */ u8 xxx2[0x2c]; - volatile u32 winbg; - volatile u32 planemask; - volatile u32 rop; - volatile u32 z; - volatile u32 dczf; /* SS1 only */ - volatile u32 dczb; /* SS1 only */ - volatile u32 dcs; /* SS1 only */ - volatile u32 dczs; /* SS1 only */ - volatile u32 pickfb; /* SS1 only */ - volatile u32 pickbb; /* SS1 only */ - volatile u32 dcfc; /* SS1 only */ - volatile u32 forcecol; /* SS1 only */ - volatile u32 door[8]; /* SS1 only */ - volatile u32 pick[5]; /* SS1 only */ + u32 winbg; + u32 planemask; + u32 rop; + u32 z; + u32 dczf; /* SS1 only */ + u32 dczb; /* SS1 only */ + u32 dcs; /* SS1 only */ + u32 dczs; /* SS1 only */ + u32 pickfb; /* SS1 only */ + u32 pickbb; /* SS1 only */ + u32 dcfc; /* SS1 only */ + u32 forcecol; /* SS1 only */ + u32 door[8]; /* SS1 only */ + u32 pick[5]; /* SS1 only */ }; #define LEO_SS1_MISC_ENABLE 0x00000001 #define LEO_SS1_MISC_STEREO 0x00000002 struct leo_ld_ss1 { - u8 xxx0[0xef4]; - volatile u32 ss1_misc; + u8 xxx0[0xef4]; + u32 ss1_misc; }; struct leo_ld_gbl { @@ -193,9 +193,8 @@ struct leo_par { #define LEO_FLAG_BLANKED 0x00000001 unsigned long physbase; + unsigned long which_io; unsigned long fbsize; - - struct sbus_dev *sdev; }; static void leo_wait(struct leo_lx_krn __iomem *lx_krn) @@ -368,8 +367,7 @@ static int leo_mmap(struct fb_info *info, struct vm_area_struct *vma) return sbusfb_mmap_helper(leo_mmap_map, par->physbase, par->fbsize, - par->sdev->reg_addrs[0].which_io, - vma); + par->which_io, vma); } static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) @@ -385,11 +383,9 @@ static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) */ static void -leo_init_fix(struct fb_info *info) +leo_init_fix(struct fb_info *info, struct device_node *dp) { - struct leo_par *par = (struct leo_par *)info->par; - - strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id)); + strlcpy(info->fix.id, dp->name, sizeof(info->fix.id)); info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_TRUECOLOR; @@ -532,60 +528,74 @@ static void leo_fixup_var_rgb(struct fb_var_screeninfo *var) struct all_info { struct fb_info info; struct leo_par par; - struct list_head list; }; -static LIST_HEAD(leo_list); -static void leo_init_one(struct sbus_dev *sdev) +static void leo_unmap_regs(struct all_info *all) { - struct all_info *all; - int linebytes; + if (all->par.lc_ss0_usr) + of_iounmap(all->par.lc_ss0_usr, 0x1000); + if (all->par.ld_ss0) + of_iounmap(all->par.ld_ss0, 0x1000); + if (all->par.ld_ss1) + of_iounmap(all->par.ld_ss1, 0x1000); + if (all->par.lx_krn) + of_iounmap(all->par.lx_krn, 0x1000); + if (all->par.cursor) + of_iounmap(all->par.cursor, sizeof(struct leo_cursor)); + if (all->info.screen_base) + of_iounmap(all->info.screen_base, 0x800000); +} - all = kmalloc(sizeof(*all), GFP_KERNEL); - if (!all) { - printk(KERN_ERR "leo: Cannot allocate memory.\n"); - return; - } - memset(all, 0, sizeof(*all)); +static int __devinit leo_init_one(struct of_device *op) +{ + struct device_node *dp = op->node; + struct all_info *all; + int linebytes, err; - INIT_LIST_HEAD(&all->list); + all = kzalloc(sizeof(*all), GFP_KERNEL); + if (!all) + return -ENOMEM; spin_lock_init(&all->par.lock); - all->par.sdev = sdev; - all->par.physbase = sdev->reg_addrs[0].phys_addr; + all->par.physbase = op->resource[0].start; + all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; - sbusfb_fill_var(&all->info.var, sdev->prom_node, 32); + sbusfb_fill_var(&all->info.var, dp->node, 32); leo_fixup_var_rgb(&all->info.var); - linebytes = prom_getintdefault(sdev->prom_node, "linebytes", - all->info.var.xres); + linebytes = of_getintprop_default(dp, "linebytes", + all->info.var.xres); all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); -#ifdef CONFIG_SPARC32 - all->info.screen_base = (char __iomem *) - prom_getintdefault(sdev->prom_node, "address", 0); -#endif - if (!all->info.screen_base) - all->info.screen_base = - sbus_ioremap(&sdev->resource[0], LEO_OFF_SS0, - 0x800000, "leo ram"); - all->par.lc_ss0_usr = - sbus_ioremap(&sdev->resource[0], LEO_OFF_LC_SS0_USR, - 0x1000, "leolc ss0usr"); + of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR, + 0x1000, "leolc ss0usr"); all->par.ld_ss0 = - sbus_ioremap(&sdev->resource[0], LEO_OFF_LD_SS0, - 0x1000, "leold ss0"); + of_ioremap(&op->resource[0], LEO_OFF_LD_SS0, + 0x1000, "leold ss0"); all->par.ld_ss1 = - sbus_ioremap(&sdev->resource[0], LEO_OFF_LD_SS1, - 0x1000, "leold ss1"); + of_ioremap(&op->resource[0], LEO_OFF_LD_SS1, + 0x1000, "leold ss1"); all->par.lx_krn = - sbus_ioremap(&sdev->resource[0], LEO_OFF_LX_KRN, - 0x1000, "leolx krn"); + of_ioremap(&op->resource[0], LEO_OFF_LX_KRN, + 0x1000, "leolx krn"); all->par.cursor = - sbus_ioremap(&sdev->resource[0], LEO_OFF_LX_CURSOR, - sizeof(struct leo_cursor), "leolx cursor"); + of_ioremap(&op->resource[0], LEO_OFF_LX_CURSOR, + sizeof(struct leo_cursor), "leolx cursor"); + all->info.screen_base = + of_ioremap(&op->resource[0], LEO_OFF_SS0, + 0x800000, "leo ram"); + if (!all->par.lc_ss0_usr || + !all->par.ld_ss0 || + !all->par.ld_ss1 || + !all->par.lx_krn || + !all->par.cursor || + !all->info.screen_base) { + leo_unmap_regs(all); + kfree(all); + return -ENOMEM; + } all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; all->info.fbops = &leo_ops; @@ -597,69 +607,85 @@ static void leo_init_one(struct sbus_dev *sdev) leo_blank(0, &all->info); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - printk(KERN_ERR "leo: Could not allocate color map.\n"); + leo_unmap_regs(all); kfree(all); - return; + return -ENOMEM;; } - leo_init_fix(&all->info); + leo_init_fix(&all->info, dp); - if (register_framebuffer(&all->info) < 0) { - printk(KERN_ERR "leo: Could not register framebuffer.\n"); + err = register_framebuffer(&all->info); + if (err < 0) { fb_dealloc_cmap(&all->info.cmap); + leo_unmap_regs(all); kfree(all); - return; + return err; } - list_add(&all->list, &leo_list); + dev_set_drvdata(&op->dev, all); + + printk("%s: leo at %lx:%lx\n", + dp->full_name, + all->par.which_io, all->par.physbase); - printk("leo: %s at %lx:%lx\n", - sdev->prom_name, - (long) sdev->reg_addrs[0].which_io, - (long) sdev->reg_addrs[0].phys_addr); + return 0; } -int __init leo_init(void) +static int __devinit leo_probe(struct of_device *dev, const struct of_device_id *match) { - struct sbus_bus *sbus; - struct sbus_dev *sdev; + struct of_device *op = to_of_device(&dev->dev); - if (fb_get_options("leofb", NULL)) - return -ENODEV; + return leo_init_one(op); +} - for_all_sbusdev(sdev, sbus) { - if (!strcmp(sdev->prom_name, "leo")) - leo_init_one(sdev); - } +static int __devexit leo_remove(struct of_device *dev) +{ + struct all_info *all = dev_get_drvdata(&dev->dev); + + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + + leo_unmap_regs(all); + + kfree(all); + + dev_set_drvdata(&dev->dev, NULL); return 0; } -void __exit leo_exit(void) -{ - struct list_head *pos, *tmp; +static struct of_device_id leo_match[] = { + { + .name = "leo", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, leo_match); + +static struct of_platform_driver leo_driver = { + .name = "leo", + .match_table = leo_match, + .probe = leo_probe, + .remove = __devexit_p(leo_remove), +}; - list_for_each_safe(pos, tmp, &leo_list) { - struct all_info *all = list_entry(pos, typeof(*all), list); +static int __init leo_init(void) +{ + if (fb_get_options("leofb", NULL)) + return -ENODEV; - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); - kfree(all); - } + return of_register_driver(&leo_driver, &of_bus_type); } -int __init -leo_setup(char *arg) +static void __exit leo_exit(void) { - /* No cmdline options yet... */ - return 0; + of_unregister_driver(&leo_driver); } module_init(leo_init); -#ifdef MODULE module_exit(leo_exit); -#endif MODULE_DESCRIPTION("framebuffer driver for LEO chipsets"); -MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); +MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index 0d1957505359..56ac51d6a7f3 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c @@ -1,6 +1,6 @@ /* p9100.c: P9100 frame buffer driver * - * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) * Copyright 1999 Derrick J Brashear (shadow@dementia.org) * * Driver layout based loosely on tgafb.c, see that file for credits. @@ -17,8 +17,8 @@ #include <linux/mm.h> #include <asm/io.h> -#include <asm/sbus.h> -#include <asm/oplib.h> +#include <asm/prom.h> +#include <asm/of_device.h> #include <asm/fbio.h> #include "sbuslib.h" @@ -72,60 +72,60 @@ static struct fb_ops p9100_ops = { struct p9100_regs { /* Registers for the system control */ - volatile u32 sys_base; - volatile u32 sys_config; - volatile u32 sys_intr; - volatile u32 sys_int_ena; - volatile u32 sys_alt_rd; - volatile u32 sys_alt_wr; - volatile u32 sys_xxx[58]; + u32 sys_base; + u32 sys_config; + u32 sys_intr; + u32 sys_int_ena; + u32 sys_alt_rd; + u32 sys_alt_wr; + u32 sys_xxx[58]; /* Registers for the video control */ - volatile u32 vid_base; - volatile u32 vid_hcnt; - volatile u32 vid_htotal; - volatile u32 vid_hsync_rise; - volatile u32 vid_hblank_rise; - volatile u32 vid_hblank_fall; - volatile u32 vid_hcnt_preload; - volatile u32 vid_vcnt; - volatile u32 vid_vlen; - volatile u32 vid_vsync_rise; - volatile u32 vid_vblank_rise; - volatile u32 vid_vblank_fall; - volatile u32 vid_vcnt_preload; - volatile u32 vid_screenpaint_addr; - volatile u32 vid_screenpaint_timectl1; - volatile u32 vid_screenpaint_qsfcnt; - volatile u32 vid_screenpaint_timectl2; - volatile u32 vid_xxx[15]; + u32 vid_base; + u32 vid_hcnt; + u32 vid_htotal; + u32 vid_hsync_rise; + u32 vid_hblank_rise; + u32 vid_hblank_fall; + u32 vid_hcnt_preload; + u32 vid_vcnt; + u32 vid_vlen; + u32 vid_vsync_rise; + u32 vid_vblank_rise; + u32 vid_vblank_fall; + u32 vid_vcnt_preload; + u32 vid_screenpaint_addr; + u32 vid_screenpaint_timectl1; + u32 vid_screenpaint_qsfcnt; + u32 vid_screenpaint_timectl2; + u32 vid_xxx[15]; /* Registers for the video control */ - volatile u32 vram_base; - volatile u32 vram_memcfg; - volatile u32 vram_refresh_pd; - volatile u32 vram_refresh_cnt; - volatile u32 vram_raslo_max; - volatile u32 vram_raslo_cur; - volatile u32 pwrup_cfg; - volatile u32 vram_xxx[25]; + u32 vram_base; + u32 vram_memcfg; + u32 vram_refresh_pd; + u32 vram_refresh_cnt; + u32 vram_raslo_max; + u32 vram_raslo_cur; + u32 pwrup_cfg; + u32 vram_xxx[25]; /* Registers for IBM RGB528 Palette */ - volatile u32 ramdac_cmap_wridx; - volatile u32 ramdac_palette_data; - volatile u32 ramdac_pixel_mask; - volatile u32 ramdac_palette_rdaddr; - volatile u32 ramdac_idx_lo; - volatile u32 ramdac_idx_hi; - volatile u32 ramdac_idx_data; - volatile u32 ramdac_idx_ctl; - volatile u32 ramdac_xxx[1784]; + u32 ramdac_cmap_wridx; + u32 ramdac_palette_data; + u32 ramdac_pixel_mask; + u32 ramdac_palette_rdaddr; + u32 ramdac_idx_lo; + u32 ramdac_idx_hi; + u32 ramdac_idx_data; + u32 ramdac_idx_ctl; + u32 ramdac_xxx[1784]; }; struct p9100_cmd_parameng { - volatile u32 parameng_status; - volatile u32 parameng_bltcmd; - volatile u32 parameng_quadcmd; + u32 parameng_status; + u32 parameng_bltcmd; + u32 parameng_quadcmd; }; struct p9100_par { @@ -136,9 +136,8 @@ struct p9100_par { #define P9100_FLAG_BLANKED 0x00000001 unsigned long physbase; + unsigned long which_io; unsigned long fbsize; - - struct sbus_dev *sdev; }; /** @@ -227,8 +226,7 @@ static int p9100_mmap(struct fb_info *info, struct vm_area_struct *vma) return sbusfb_mmap_helper(p9100_mmap_map, par->physbase, par->fbsize, - par->sdev->reg_addrs[0].which_io, - vma); + par->which_io, vma); } static int p9100_ioctl(struct fb_info *info, unsigned int cmd, @@ -245,12 +243,9 @@ static int p9100_ioctl(struct fb_info *info, unsigned int cmd, * Initialisation */ -static void -p9100_init_fix(struct fb_info *info, int linebytes) +static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_node *dp) { - struct p9100_par *par = (struct p9100_par *)info->par; - - strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id)); + strlcpy(info->fix.id, dp->name, sizeof(info->fix.id)); info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_PSEUDOCOLOR; @@ -263,121 +258,137 @@ p9100_init_fix(struct fb_info *info, int linebytes) struct all_info { struct fb_info info; struct p9100_par par; - struct list_head list; }; -static LIST_HEAD(p9100_list); -static void p9100_init_one(struct sbus_dev *sdev) +static int __devinit p9100_init_one(struct of_device *op) { + struct device_node *dp = op->node; struct all_info *all; - int linebytes; - - all = kmalloc(sizeof(*all), GFP_KERNEL); - if (!all) { - printk(KERN_ERR "p9100: Cannot allocate memory.\n"); - return; - } - memset(all, 0, sizeof(*all)); + int linebytes, err; - INIT_LIST_HEAD(&all->list); + all = kzalloc(sizeof(*all), GFP_KERNEL); + if (!all) + return -ENOMEM; spin_lock_init(&all->par.lock); - all->par.sdev = sdev; /* This is the framebuffer and the only resource apps can mmap. */ - all->par.physbase = sdev->reg_addrs[2].phys_addr; + all->par.physbase = op->resource[2].start; + all->par.which_io = op->resource[2].flags & IORESOURCE_BITS; - sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); + sbusfb_fill_var(&all->info.var, dp->node, 8); all->info.var.red.length = 8; all->info.var.green.length = 8; all->info.var.blue.length = 8; - linebytes = prom_getintdefault(sdev->prom_node, "linebytes", - all->info.var.xres); + linebytes = of_getintprop_default(dp, "linebytes", + all->info.var.xres); all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); - all->par.regs = sbus_ioremap(&sdev->resource[0], 0, - sizeof(struct p9100_regs), "p9100 regs"); + all->par.regs = of_ioremap(&op->resource[0], 0, + sizeof(struct p9100_regs), "p9100 regs"); + if (!all->par.regs) { + kfree(all); + return -ENOMEM; + } all->info.flags = FBINFO_DEFAULT; all->info.fbops = &p9100_ops; -#ifdef CONFIG_SPARC32 - all->info.screen_base = (char __iomem *) - prom_getintdefault(sdev->prom_node, "address", 0); -#endif - if (!all->info.screen_base) - all->info.screen_base = sbus_ioremap(&sdev->resource[2], 0, - all->par.fbsize, "p9100 ram"); + all->info.screen_base = of_ioremap(&op->resource[2], 0, + all->par.fbsize, "p9100 ram"); + if (!all->info.screen_base) { + of_iounmap(all->par.regs, sizeof(struct p9100_regs)); + kfree(all); + return -ENOMEM; + } all->info.par = &all->par; p9100_blank(0, &all->info); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - printk(KERN_ERR "p9100: Could not allocate color map.\n"); + of_iounmap(all->par.regs, sizeof(struct p9100_regs)); + of_iounmap(all->info.screen_base, all->par.fbsize); kfree(all); - return; + return -ENOMEM; } - p9100_init_fix(&all->info, linebytes); + p9100_init_fix(&all->info, linebytes, dp); - if (register_framebuffer(&all->info) < 0) { - printk(KERN_ERR "p9100: Could not register framebuffer.\n"); + err = register_framebuffer(&all->info); + if (err < 0) { fb_dealloc_cmap(&all->info.cmap); + of_iounmap(all->par.regs, sizeof(struct p9100_regs)); + of_iounmap(all->info.screen_base, all->par.fbsize); kfree(all); - return; + return err; } fb_set_cmap(&all->info.cmap, &all->info); - list_add(&all->list, &p9100_list); + dev_set_drvdata(&op->dev, all); + + printk("%s: p9100 at %lx:%lx\n", + dp->full_name, + all->par.which_io, all->par.physbase); - printk("p9100: %s at %lx:%lx\n", - sdev->prom_name, - (long) sdev->reg_addrs[0].which_io, - (long) sdev->reg_addrs[0].phys_addr); + return 0; } -int __init p9100_init(void) +static int __devinit p9100_probe(struct of_device *dev, const struct of_device_id *match) { - struct sbus_bus *sbus; - struct sbus_dev *sdev; + struct of_device *op = to_of_device(&dev->dev); - if (fb_get_options("p9100fb", NULL)) - return -ENODEV; + return p9100_init_one(op); +} - for_all_sbusdev(sdev, sbus) { - if (!strcmp(sdev->prom_name, "p9100")) - p9100_init_one(sdev); - } +static int __devexit p9100_remove(struct of_device *dev) +{ + struct all_info *all = dev_get_drvdata(&dev->dev); + + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + + of_iounmap(all->par.regs, sizeof(struct p9100_regs)); + of_iounmap(all->info.screen_base, all->par.fbsize); + + kfree(all); + + dev_set_drvdata(&dev->dev, NULL); return 0; } -void __exit p9100_exit(void) -{ - struct list_head *pos, *tmp; +static struct of_device_id p9100_match[] = { + { + .name = "p9100", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, p9100_match); - list_for_each_safe(pos, tmp, &p9100_list) { - struct all_info *all = list_entry(pos, typeof(*all), list); +static struct of_platform_driver p9100_driver = { + .name = "p9100", + .match_table = p9100_match, + .probe = p9100_probe, + .remove = __devexit_p(p9100_remove), +}; - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); - kfree(all); - } +static int __init p9100_init(void) +{ + if (fb_get_options("p9100fb", NULL)) + return -ENODEV; + + return of_register_driver(&p9100_driver, &of_bus_type); } -int __init -p9100_setup(char *arg) +static void __exit p9100_exit(void) { - /* No cmdline options yet... */ - return 0; + of_unregister_driver(&p9100_driver); } module_init(p9100_init); - -#ifdef MODULE module_exit(p9100_exit); -#endif MODULE_DESCRIPTION("framebuffer driver for P9100 chipsets"); -MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); +MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index 95b918229d9b..6990ab11cd06 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -1,6 +1,6 @@ /* tcx.c: TCX frame buffer driver * - * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) @@ -19,8 +19,8 @@ #include <linux/mm.h> #include <asm/io.h> -#include <asm/sbus.h> -#include <asm/oplib.h> +#include <asm/prom.h> +#include <asm/of_device.h> #include <asm/fbio.h> #include "sbuslib.h" @@ -77,32 +77,32 @@ static struct fb_ops tcx_ops = { /* The contents are unknown */ struct tcx_tec { - volatile u32 tec_matrix; - volatile u32 tec_clip; - volatile u32 tec_vdc; + u32 tec_matrix; + u32 tec_clip; + u32 tec_vdc; }; struct tcx_thc { - volatile u32 thc_rev; + u32 thc_rev; u32 thc_pad0[511]; - volatile u32 thc_hs; /* hsync timing */ - volatile u32 thc_hsdvs; - volatile u32 thc_hd; - volatile u32 thc_vs; /* vsync timing */ - volatile u32 thc_vd; - volatile u32 thc_refresh; - volatile u32 thc_misc; + u32 thc_hs; /* hsync timing */ + u32 thc_hsdvs; + u32 thc_hd; + u32 thc_vs; /* vsync timing */ + u32 thc_vd; + u32 thc_refresh; + u32 thc_misc; u32 thc_pad1[56]; - volatile u32 thc_cursxy; /* cursor x,y position (16 bits each) */ - volatile u32 thc_cursmask[32]; /* cursor mask bits */ - volatile u32 thc_cursbits[32]; /* what to show where mask enabled */ + u32 thc_cursxy; /* cursor x,y position (16 bits each) */ + u32 thc_cursmask[32]; /* cursor mask bits */ + u32 thc_cursbits[32]; /* what to show where mask enabled */ }; struct bt_regs { - volatile u32 addr; - volatile u32 color_map; - volatile u32 control; - volatile u32 cursor; + u32 addr; + u32 color_map; + u32 control; + u32 cursor; }; #define TCX_MMAP_ENTRIES 14 @@ -112,24 +112,23 @@ struct tcx_par { struct bt_regs __iomem *bt; struct tcx_thc __iomem *thc; struct tcx_tec __iomem *tec; - volatile u32 __iomem *cplane; + u32 __iomem *cplane; u32 flags; #define TCX_FLAG_BLANKED 0x00000001 unsigned long physbase; + unsigned long which_io; unsigned long fbsize; struct sbus_mmap_map mmap_map[TCX_MMAP_ENTRIES]; int lowdepth; - - struct sbus_dev *sdev; }; /* Reset control plane so that WID is 8-bit plane. */ static void __tcx_set_control_plane (struct tcx_par *par) { - volatile u32 __iomem *p, *pend; + u32 __iomem *p, *pend; if (par->lowdepth) return; @@ -307,8 +306,7 @@ static int tcx_mmap(struct fb_info *info, struct vm_area_struct *vma) return sbusfb_mmap_helper(par->mmap_map, par->physbase, par->fbsize, - par->sdev->reg_addrs[0].which_io, - vma); + par->which_io, vma); } static int tcx_ioctl(struct fb_info *info, unsigned int cmd, @@ -350,48 +348,71 @@ tcx_init_fix(struct fb_info *info, int linebytes) struct all_info { struct fb_info info; struct tcx_par par; - struct list_head list; }; -static LIST_HEAD(tcx_list); -static void tcx_init_one(struct sbus_dev *sdev) +static void tcx_unmap_regs(struct all_info *all) { - struct all_info *all; - int linebytes, i; + if (all->par.tec) + of_iounmap(all->par.tec, sizeof(struct tcx_tec)); + if (all->par.thc) + of_iounmap(all->par.thc, sizeof(struct tcx_thc)); + if (all->par.bt) + of_iounmap(all->par.bt, sizeof(struct bt_regs)); + if (all->par.cplane) + of_iounmap(all->par.cplane, all->par.fbsize * sizeof(u32)); + if (all->info.screen_base) + of_iounmap(all->info.screen_base, all->par.fbsize); +} - all = kmalloc(sizeof(*all), GFP_KERNEL); - if (!all) { - printk(KERN_ERR "tcx: Cannot allocate memory.\n"); - return; - } - memset(all, 0, sizeof(*all)); +static int __devinit tcx_init_one(struct of_device *op) +{ + struct device_node *dp = op->node; + struct all_info *all; + int linebytes, i, err; - INIT_LIST_HEAD(&all->list); + all = kzalloc(sizeof(*all), GFP_KERNEL); + if (!all) + return -ENOMEM; spin_lock_init(&all->par.lock); - all->par.sdev = sdev; - all->par.lowdepth = prom_getbool(sdev->prom_node, "tcx-8-bit"); + all->par.lowdepth = + (of_find_property(dp, "tcx-8-bit", NULL) != NULL); - sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); + sbusfb_fill_var(&all->info.var, dp->node, 8); all->info.var.red.length = 8; all->info.var.green.length = 8; all->info.var.blue.length = 8; - linebytes = prom_getintdefault(sdev->prom_node, "linebytes", - all->info.var.xres); + linebytes = of_getintprop_default(dp, "linebytes", + all->info.var.xres); all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); - all->par.tec = sbus_ioremap(&sdev->resource[7], 0, - sizeof(struct tcx_tec), "tcx tec"); - all->par.thc = sbus_ioremap(&sdev->resource[9], 0, - sizeof(struct tcx_thc), "tcx thc"); - all->par.bt = sbus_ioremap(&sdev->resource[8], 0, - sizeof(struct bt_regs), "tcx dac"); + all->par.tec = of_ioremap(&op->resource[7], 0, + sizeof(struct tcx_tec), "tcx tec"); + all->par.thc = of_ioremap(&op->resource[9], 0, + sizeof(struct tcx_thc), "tcx thc"); + all->par.bt = of_ioremap(&op->resource[8], 0, + sizeof(struct bt_regs), "tcx dac"); + all->info.screen_base = of_ioremap(&op->resource[0], 0, + all->par.fbsize, "tcx ram"); + if (!all->par.tec || !all->par.thc || + !all->par.bt || !all->info.screen_base) { + tcx_unmap_regs(all); + kfree(all); + return -ENOMEM; + } + memcpy(&all->par.mmap_map, &__tcx_mmap_map, sizeof(all->par.mmap_map)); if (!all->par.lowdepth) { - all->par.cplane = sbus_ioremap(&sdev->resource[4], 0, - all->par.fbsize * sizeof(u32), "tcx cplane"); + all->par.cplane = of_ioremap(&op->resource[4], 0, + all->par.fbsize * sizeof(u32), + "tcx cplane"); + if (!all->par.cplane) { + tcx_unmap_regs(all); + kfree(all); + return -ENOMEM; + } } else { all->par.mmap_map[1].size = SBUS_MMAP_EMPTY; all->par.mmap_map[4].size = SBUS_MMAP_EMPTY; @@ -400,6 +421,8 @@ static void tcx_init_one(struct sbus_dev *sdev) } all->par.physbase = 0; + all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; + for (i = 0; i < TCX_MMAP_ENTRIES; i++) { int j; @@ -416,18 +439,11 @@ static void tcx_init_one(struct sbus_dev *sdev) j = i; break; }; - all->par.mmap_map[i].poff = sdev->reg_addrs[j].phys_addr; + all->par.mmap_map[i].poff = op->resource[j].start; } all->info.flags = FBINFO_DEFAULT; all->info.fbops = &tcx_ops; -#ifdef CONFIG_SPARC32 - all->info.screen_base = (char __iomem *) - prom_getintdefault(sdev->prom_node, "address", 0); -#endif - if (!all->info.screen_base) - all->info.screen_base = sbus_ioremap(&sdev->resource[0], 0, - all->par.fbsize, "tcx ram"); all->info.par = &all->par; /* Initialize brooktree DAC. */ @@ -445,72 +461,88 @@ static void tcx_init_one(struct sbus_dev *sdev) tcx_blank(FB_BLANK_UNBLANK, &all->info); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - printk(KERN_ERR "tcx: Could not allocate color map.\n"); + tcx_unmap_regs(all); kfree(all); - return; + return -ENOMEM; } fb_set_cmap(&all->info.cmap, &all->info); tcx_init_fix(&all->info, linebytes); - if (register_framebuffer(&all->info) < 0) { - printk(KERN_ERR "tcx: Could not register framebuffer.\n"); + err = register_framebuffer(&all->info); + if (err < 0) { fb_dealloc_cmap(&all->info.cmap); + tcx_unmap_regs(all); kfree(all); - return; + return err; } - list_add(&all->list, &tcx_list); + dev_set_drvdata(&op->dev, all); - printk("tcx: %s at %lx:%lx, %s\n", - sdev->prom_name, - (long) sdev->reg_addrs[0].which_io, - (long) sdev->reg_addrs[0].phys_addr, + printk("%s: TCX at %lx:%lx, %s\n", + dp->full_name, + all->par.which_io, + op->resource[0].start, all->par.lowdepth ? "8-bit only" : "24-bit depth"); + + return 0; } -int __init tcx_init(void) +static int __devinit tcx_probe(struct of_device *dev, const struct of_device_id *match) { - struct sbus_bus *sbus; - struct sbus_dev *sdev; + struct of_device *op = to_of_device(&dev->dev); - if (fb_get_options("tcxfb", NULL)) - return -ENODEV; + return tcx_init_one(op); +} - for_all_sbusdev(sdev, sbus) { - if (!strcmp(sdev->prom_name, "SUNW,tcx")) - tcx_init_one(sdev); - } +static int __devexit tcx_remove(struct of_device *dev) +{ + struct all_info *all = dev_get_drvdata(&dev->dev); + + unregister_framebuffer(&all->info); + fb_dealloc_cmap(&all->info.cmap); + + tcx_unmap_regs(all); + + kfree(all); + + dev_set_drvdata(&dev->dev, NULL); return 0; } -void __exit tcx_exit(void) -{ - struct list_head *pos, *tmp; +static struct of_device_id tcx_match[] = { + { + .name = "SUNW,tcx", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, tcx_match); - list_for_each_safe(pos, tmp, &tcx_list) { - struct all_info *all = list_entry(pos, typeof(*all), list); +static struct of_platform_driver tcx_driver = { + .name = "tcx", + .match_table = tcx_match, + .probe = tcx_probe, + .remove = __devexit_p(tcx_remove), +}; - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); - kfree(all); - } +int __init tcx_init(void) +{ + if (fb_get_options("tcxfb", NULL)) + return -ENODEV; + + return of_register_driver(&tcx_driver, &of_bus_type); } -int __init -tcx_setup(char *arg) +void __exit tcx_exit(void) { - /* No cmdline options yet... */ - return 0; + of_unregister_driver(&tcx_driver); } module_init(tcx_init); - -#ifdef MODULE module_exit(tcx_exit); -#endif MODULE_DESCRIPTION("framebuffer driver for TCX chipsets"); -MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); +MODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); +MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); diff --git a/fs/Makefile b/fs/Makefile index d0ea6bfccf29..89135428a539 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -66,7 +66,6 @@ obj-$(CONFIG_MSDOS_FS) += msdos/ obj-$(CONFIG_VFAT_FS) += vfat/ obj-$(CONFIG_BFS_FS) += bfs/ obj-$(CONFIG_ISO9660_FS) += isofs/ -obj-$(CONFIG_DEVFS_FS) += devfs/ obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ obj-$(CONFIG_HFS_FS) += hfs/ obj-$(CONFIG_VXFS_FS) += freevxfs/ diff --git a/fs/block_dev.c b/fs/block_dev.c index 7f7600e2381c..909cb0595b4e 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -12,7 +12,6 @@ #include <linux/slab.h> #include <linux/kmod.h> #include <linux/major.h> -#include <linux/devfs_fs_kernel.h> #include <linux/smp_lock.h> #include <linux/highmem.h> #include <linux/blkdev.h> diff --git a/fs/char_dev.c b/fs/char_dev.c index f3418f7a6e9d..97986635b641 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -14,7 +14,6 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/smp_lock.h> -#include <linux/devfs_fs_kernel.h> #include <linux/seq_file.h> #include <linux/kobject.h> diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index 7caee8d8ea3b..803aacf0d49c 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c @@ -28,7 +28,6 @@ #include <linux/delay.h> #include <linux/skbuff.h> #include <linux/proc_fs.h> -#include <linux/devfs_fs_kernel.h> #include <linux/vmalloc.h> #include <linux/fs.h> #include <linux/file.h> @@ -365,22 +364,12 @@ static int init_coda_psdev(void) err = PTR_ERR(coda_psdev_class); goto out_chrdev; } - devfs_mk_dir ("coda"); - for (i = 0; i < MAX_CODADEVS; i++) { + for (i = 0; i < MAX_CODADEVS; i++) class_device_create(coda_psdev_class, NULL, MKDEV(CODA_PSDEV_MAJOR,i), NULL, "cfs%d", i); - err = devfs_mk_cdev(MKDEV(CODA_PSDEV_MAJOR, i), - S_IFCHR|S_IRUSR|S_IWUSR, "coda/%d", i); - if (err) - goto out_class; - } coda_sysctl_init(); goto out; -out_class: - for (i = 0; i < MAX_CODADEVS; i++) - class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i)); - class_destroy(coda_psdev_class); out_chrdev: unregister_chrdev(CODA_PSDEV_MAJOR, "coda"); out: @@ -419,12 +408,9 @@ static int __init init_coda(void) } return 0; out: - for (i = 0; i < MAX_CODADEVS; i++) { + for (i = 0; i < MAX_CODADEVS; i++) class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i)); - devfs_remove("coda/%d", i); - } class_destroy(coda_psdev_class); - devfs_remove("coda"); unregister_chrdev(CODA_PSDEV_MAJOR, "coda"); coda_sysctl_clean(); out1: @@ -441,12 +427,9 @@ static void __exit exit_coda(void) if ( err != 0 ) { printk("coda: failed to unregister filesystem\n"); } - for (i = 0; i < MAX_CODADEVS; i++) { + for (i = 0; i < MAX_CODADEVS; i++) class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i)); - devfs_remove("coda/%d", i); - } class_destroy(coda_psdev_class); - devfs_remove("coda"); unregister_chrdev(CODA_PSDEV_MAJOR, "coda"); coda_sysctl_clean(); coda_destroy_inodecache(); diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index d8ecfedef189..d8d50a70c58d 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -44,7 +44,6 @@ #include <linux/loop.h> #include <linux/auto_fs.h> #include <linux/auto_fs4.h> -#include <linux/devfs_fs.h> #include <linux/tty.h> #include <linux/vt_kern.h> #include <linux/fb.h> diff --git a/fs/devfs/Makefile b/fs/devfs/Makefile deleted file mode 100644 index 6dd8d1245e2c..000000000000 --- a/fs/devfs/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for the linux devfs-filesystem routines. -# - -obj-$(CONFIG_DEVFS_FS) += devfs.o - -devfs-objs := base.o util.o - diff --git a/fs/devfs/base.c b/fs/devfs/base.c deleted file mode 100644 index 51a97f132745..000000000000 --- a/fs/devfs/base.c +++ /dev/null @@ -1,2836 +0,0 @@ -/* devfs (Device FileSystem) driver. - - Copyright (C) 1998-2002 Richard Gooch - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Richard Gooch may be reached by email at rgooch@atnf.csiro.au - The postal address is: - Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia. - - ChangeLog - - 19980110 Richard Gooch <rgooch@atnf.csiro.au> - Original version. - v0.1 - 19980111 Richard Gooch <rgooch@atnf.csiro.au> - Created per-fs inode table rather than using inode->u.generic_ip - v0.2 - 19980111 Richard Gooch <rgooch@atnf.csiro.au> - Created .epoch inode which has a ctime of 0. - Fixed loss of named pipes when dentries lost. - Fixed loss of inode data when devfs_register() follows mknod(). - v0.3 - 19980111 Richard Gooch <rgooch@atnf.csiro.au> - Fix for when compiling with CONFIG_KERNELD. - 19980112 Richard Gooch <rgooch@atnf.csiro.au> - Fix for readdir() which sometimes didn't show entries. - Added <<tolerant>> option to <devfs_register>. - v0.4 - 19980113 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_fill_file> function. - v0.5 - 19980115 Richard Gooch <rgooch@atnf.csiro.au> - Added subdirectory support. Major restructuring. - 19980116 Richard Gooch <rgooch@atnf.csiro.au> - Fixed <find_by_dev> to not search major=0,minor=0. - Added symlink support. - v0.6 - 19980120 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_mk_dir> function and support directory unregister - 19980120 Richard Gooch <rgooch@atnf.csiro.au> - Auto-ownership uses real uid/gid rather than effective uid/gid. - v0.7 - 19980121 Richard Gooch <rgooch@atnf.csiro.au> - Supported creation of sockets. - v0.8 - 19980122 Richard Gooch <rgooch@atnf.csiro.au> - Added DEVFS_FL_HIDE_UNREG flag. - Interface change to <devfs_mk_symlink>. - Created <devfs_symlink> to support symlink(2). - v0.9 - 19980123 Richard Gooch <rgooch@atnf.csiro.au> - Added check to <devfs_fill_file> to check inode is in devfs. - Added optional traversal of symlinks. - v0.10 - 19980124 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_get_flags> and <devfs_set_flags>. - v0.11 - 19980125 C. Scott Ananian <cananian@alumni.princeton.edu> - Created <devfs_find_handle>. - 19980125 Richard Gooch <rgooch@atnf.csiro.au> - Allow removal of symlinks. - v0.12 - 19980125 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_set_symlink_destination>. - 19980126 Richard Gooch <rgooch@atnf.csiro.au> - Moved DEVFS_SUPER_MAGIC into header file. - Added DEVFS_FL_HIDE flag. - Created <devfs_get_maj_min>. - Created <devfs_get_handle_from_inode>. - Fixed minor bug in <find_by_dev>. - 19980127 Richard Gooch <rgooch@atnf.csiro.au> - Changed interface to <find_by_dev>, <find_entry>, - <devfs_unregister>, <devfs_fill_file> and <devfs_find_handle>. - Fixed inode times when symlink created with symlink(2). - v0.13 - 19980129 C. Scott Ananian <cananian@alumni.princeton.edu> - Exported <devfs_set_symlink_destination>, <devfs_get_maj_min> - and <devfs_get_handle_from_inode>. - 19980129 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_unlink> to support unlink(2). - v0.14 - 19980129 Richard Gooch <rgooch@atnf.csiro.au> - Fixed kerneld support for entries in devfs subdirectories. - 19980130 Richard Gooch <rgooch@atnf.csiro.au> - Bugfixes in <call_kerneld>. - v0.15 - 19980207 Richard Gooch <rgooch@atnf.csiro.au> - Call kerneld when looking up unregistered entries. - v0.16 - 19980326 Richard Gooch <rgooch@atnf.csiro.au> - Modified interface to <devfs_find_handle> for symlink traversal. - v0.17 - 19980331 Richard Gooch <rgooch@atnf.csiro.au> - Fixed persistence bug with device numbers for manually created - device files. - Fixed problem with recreating symlinks with different content. - v0.18 - 19980401 Richard Gooch <rgooch@atnf.csiro.au> - Changed to CONFIG_KMOD. - Hide entries which are manually unlinked. - Always invalidate devfs dentry cache when registering entries. - Created <devfs_rmdir> to support rmdir(2). - Ensure directories created by <devfs_mk_dir> are visible. - v0.19 - 19980402 Richard Gooch <rgooch@atnf.csiro.au> - Invalidate devfs dentry cache when making directories. - Invalidate devfs dentry cache when removing entries. - Fixed persistence bug with fifos. - v0.20 - 19980421 Richard Gooch <rgooch@atnf.csiro.au> - Print process command when debugging kerneld/kmod. - Added debugging for register/unregister/change operations. - 19980422 Richard Gooch <rgooch@atnf.csiro.au> - Added "devfs=" boot options. - v0.21 - 19980426 Richard Gooch <rgooch@atnf.csiro.au> - No longer lock/unlock superblock in <devfs_put_super>. - Drop negative dentries when they are released. - Manage dcache more efficiently. - v0.22 - 19980427 Richard Gooch <rgooch@atnf.csiro.au> - Added DEVFS_FL_AUTO_DEVNUM flag. - v0.23 - 19980430 Richard Gooch <rgooch@atnf.csiro.au> - No longer set unnecessary methods. - v0.24 - 19980504 Richard Gooch <rgooch@atnf.csiro.au> - Added PID display to <call_kerneld> debugging message. - Added "after" debugging message to <call_kerneld>. - 19980519 Richard Gooch <rgooch@atnf.csiro.au> - Added "diread" and "diwrite" boot options. - 19980520 Richard Gooch <rgooch@atnf.csiro.au> - Fixed persistence problem with permissions. - v0.25 - 19980602 Richard Gooch <rgooch@atnf.csiro.au> - Support legacy device nodes. - Fixed bug where recreated inodes were hidden. - v0.26 - 19980602 Richard Gooch <rgooch@atnf.csiro.au> - Improved debugging in <get_vfs_inode>. - 19980607 Richard Gooch <rgooch@atnf.csiro.au> - No longer free old dentries in <devfs_mk_dir>. - Free all dentries for a given entry when deleting inodes. - v0.27 - 19980627 Richard Gooch <rgooch@atnf.csiro.au> - Limit auto-device numbering to majors 128 to 239. - v0.28 - 19980629 Richard Gooch <rgooch@atnf.csiro.au> - Fixed inode times persistence problem. - v0.29 - 19980704 Richard Gooch <rgooch@atnf.csiro.au> - Fixed spelling in <devfs_readlink> debug. - Fixed bug in <devfs_setup> parsing "dilookup". - v0.30 - 19980705 Richard Gooch <rgooch@atnf.csiro.au> - Fixed devfs inode leak when manually recreating inodes. - Fixed permission persistence problem when recreating inodes. - v0.31 - 19980727 Richard Gooch <rgooch@atnf.csiro.au> - Removed harmless "unused variable" compiler warning. - Fixed modes for manually recreated device nodes. - v0.32 - 19980728 Richard Gooch <rgooch@atnf.csiro.au> - Added NULL devfs inode warning in <devfs_read_inode>. - Force all inode nlink values to 1. - v0.33 - 19980730 Richard Gooch <rgooch@atnf.csiro.au> - Added "dimknod" boot option. - Set inode nlink to 0 when freeing dentries. - Fixed modes for manually recreated symlinks. - v0.34 - 19980802 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bugs in recreated directories and symlinks. - v0.35 - 19980806 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bugs in recreated device nodes. - 19980807 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bug in currently unused <devfs_get_handle_from_inode>. - Defined new <devfs_handle_t> type. - Improved debugging when getting entries. - Fixed bug where directories could be emptied. - v0.36 - 19980809 Richard Gooch <rgooch@atnf.csiro.au> - Replaced dummy .epoch inode with .devfsd character device. - 19980810 Richard Gooch <rgooch@atnf.csiro.au> - Implemented devfsd protocol revision 0. - v0.37 - 19980819 Richard Gooch <rgooch@atnf.csiro.au> - Added soothing message to warning in <devfs_d_iput>. - v0.38 - 19980829 Richard Gooch <rgooch@atnf.csiro.au> - Use GCC extensions for structure initialisations. - Implemented async open notification. - Incremented devfsd protocol revision to 1. - v0.39 - 19980908 Richard Gooch <rgooch@atnf.csiro.au> - Moved async open notification to end of <devfs_open>. - v0.40 - 19980910 Richard Gooch <rgooch@atnf.csiro.au> - Prepended "/dev/" to module load request. - Renamed <call_kerneld> to <call_kmod>. - v0.41 - 19980910 Richard Gooch <rgooch@atnf.csiro.au> - Fixed typo "AYSNC" -> "ASYNC". - v0.42 - 19980910 Richard Gooch <rgooch@atnf.csiro.au> - Added open flag for files. - v0.43 - 19980927 Richard Gooch <rgooch@atnf.csiro.au> - Set i_blocks=0 and i_blksize=1024 in <devfs_read_inode>. - v0.44 - 19981005 Richard Gooch <rgooch@atnf.csiro.au> - Added test for empty <<name>> in <devfs_find_handle>. - Renamed <generate_path> to <devfs_generate_path> and published. - v0.45 - 19981006 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_get_fops>. - v0.46 - 19981007 Richard Gooch <rgooch@atnf.csiro.au> - Limit auto-device numbering to majors 144 to 239. - v0.47 - 19981010 Richard Gooch <rgooch@atnf.csiro.au> - Updated <devfs_follow_link> for VFS change in 2.1.125. - v0.48 - 19981022 Richard Gooch <rgooch@atnf.csiro.au> - Created DEVFS_ FL_COMPAT flag. - v0.49 - 19981023 Richard Gooch <rgooch@atnf.csiro.au> - Created "nocompat" boot option. - v0.50 - 19981025 Richard Gooch <rgooch@atnf.csiro.au> - Replaced "mount" boot option with "nomount". - v0.51 - 19981110 Richard Gooch <rgooch@atnf.csiro.au> - Created "only" boot option. - v0.52 - 19981112 Richard Gooch <rgooch@atnf.csiro.au> - Added DEVFS_FL_REMOVABLE flag. - v0.53 - 19981114 Richard Gooch <rgooch@atnf.csiro.au> - Only call <scan_dir_for_removable> on first call to - <devfs_readdir>. - v0.54 - 19981205 Richard Gooch <rgooch@atnf.csiro.au> - Updated <devfs_rmdir> for VFS change in 2.1.131. - v0.55 - 19981218 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_mk_compat>. - 19981220 Richard Gooch <rgooch@atnf.csiro.au> - Check for partitions on removable media in <devfs_lookup>. - v0.56 - 19990118 Richard Gooch <rgooch@atnf.csiro.au> - Added support for registering regular files. - Created <devfs_set_file_size>. - Update devfs inodes from entries if not changed through FS. - v0.57 - 19990124 Richard Gooch <rgooch@atnf.csiro.au> - Fixed <devfs_fill_file> to only initialise temporary inodes. - Trap for NULL fops in <devfs_register>. - Return -ENODEV in <devfs_fill_file> for non-driver inodes. - v0.58 - 19990126 Richard Gooch <rgooch@atnf.csiro.au> - Switched from PATH_MAX to DEVFS_PATHLEN. - v0.59 - 19990127 Richard Gooch <rgooch@atnf.csiro.au> - Created "nottycompat" boot option. - v0.60 - 19990318 Richard Gooch <rgooch@atnf.csiro.au> - Fixed <devfsd_read> to not overrun event buffer. - v0.61 - 19990329 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_auto_unregister>. - v0.62 - 19990330 Richard Gooch <rgooch@atnf.csiro.au> - Don't return unregistred entries in <devfs_find_handle>. - Panic in <devfs_unregister> if entry unregistered. - 19990401 Richard Gooch <rgooch@atnf.csiro.au> - Don't panic in <devfs_auto_unregister> for duplicates. - v0.63 - 19990402 Richard Gooch <rgooch@atnf.csiro.au> - Don't unregister already unregistered entries in <unregister>. - v0.64 - 19990510 Richard Gooch <rgooch@atnf.csiro.au> - Disable warning messages when unable to read partition table for - removable media. - v0.65 - 19990512 Richard Gooch <rgooch@atnf.csiro.au> - Updated <devfs_lookup> for VFS change in 2.3.1-pre1. - Created "oops-on-panic" boot option. - Improved debugging in <devfs_register> and <devfs_unregister>. - v0.66 - 19990519 Richard Gooch <rgooch@atnf.csiro.au> - Added documentation for some functions. - 19990525 Richard Gooch <rgooch@atnf.csiro.au> - Removed "oops-on-panic" boot option: now always Oops. - v0.67 - 19990531 Richard Gooch <rgooch@atnf.csiro.au> - Improved debugging in <devfs_register>. - v0.68 - 19990604 Richard Gooch <rgooch@atnf.csiro.au> - Added "diunlink" and "nokmod" boot options. - Removed superfluous warning message in <devfs_d_iput>. - v0.69 - 19990611 Richard Gooch <rgooch@atnf.csiro.au> - Took account of change to <d_alloc_root>. - v0.70 - 19990614 Richard Gooch <rgooch@atnf.csiro.au> - Created separate event queue for each mounted devfs. - Removed <devfs_invalidate_dcache>. - Created new ioctl()s. - Incremented devfsd protocol revision to 3. - Fixed bug when re-creating directories: contents were lost. - Block access to inodes until devfsd updates permissions. - 19990615 Richard Gooch <rgooch@atnf.csiro.au> - Support 2.2.x kernels. - v0.71 - 19990623 Richard Gooch <rgooch@atnf.csiro.au> - Switched to sending process uid/gid to devfsd. - Renamed <call_kmod> to <try_modload>. - Added DEVFSD_NOTIFY_LOOKUP event. - 19990624 Richard Gooch <rgooch@atnf.csiro.au> - Added DEVFSD_NOTIFY_CHANGE event. - Incremented devfsd protocol revision to 4. - v0.72 - 19990713 Richard Gooch <rgooch@atnf.csiro.au> - Return EISDIR rather than EINVAL for read(2) on directories. - v0.73 - 19990809 Richard Gooch <rgooch@atnf.csiro.au> - Changed <devfs_setup> to new __init scheme. - v0.74 - 19990901 Richard Gooch <rgooch@atnf.csiro.au> - Changed remaining function declarations to new __init scheme. - v0.75 - 19991013 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_get_info>, <devfs_set_info>, - <devfs_get_first_child> and <devfs_get_next_sibling>. - Added <<dir>> parameter to <devfs_register>, <devfs_mk_compat>, - <devfs_mk_dir> and <devfs_find_handle>. - Work sponsored by SGI. - v0.76 - 19991017 Richard Gooch <rgooch@atnf.csiro.au> - Allow multiple unregistrations. - Work sponsored by SGI. - v0.77 - 19991026 Richard Gooch <rgooch@atnf.csiro.au> - Added major and minor number to devfsd protocol. - Incremented devfsd protocol revision to 5. - Work sponsored by SGI. - v0.78 - 19991030 Richard Gooch <rgooch@atnf.csiro.au> - Support info pointer for all devfs entry types. - Added <<info>> parameter to <devfs_mk_dir> and - <devfs_mk_symlink>. - Work sponsored by SGI. - v0.79 - 19991031 Richard Gooch <rgooch@atnf.csiro.au> - Support "../" when searching devfs namespace. - Work sponsored by SGI. - v0.80 - 19991101 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_get_unregister_slave>. - Work sponsored by SGI. - v0.81 - 19991103 Richard Gooch <rgooch@atnf.csiro.au> - Exported <devfs_get_parent>. - Work sponsored by SGI. - v0.82 - 19991104 Richard Gooch <rgooch@atnf.csiro.au> - Removed unused <devfs_set_symlink_destination>. - 19991105 Richard Gooch <rgooch@atnf.csiro.au> - Do not hide entries from devfsd or children. - Removed DEVFS_ FL_TTY_COMPAT flag. - Removed "nottycompat" boot option. - Removed <devfs_mk_compat>. - Work sponsored by SGI. - v0.83 - 19991107 Richard Gooch <rgooch@atnf.csiro.au> - Added DEVFS_FL_WAIT flag. - Work sponsored by SGI. - v0.84 - 19991107 Richard Gooch <rgooch@atnf.csiro.au> - Support new "disc" naming scheme in <get_removable_partition>. - Allow NULL fops in <devfs_register>. - Work sponsored by SGI. - v0.85 - 19991110 Richard Gooch <rgooch@atnf.csiro.au> - Fall back to major table if NULL fops given to <devfs_register>. - Work sponsored by SGI. - v0.86 - 19991204 Richard Gooch <rgooch@atnf.csiro.au> - Support fifos when unregistering. - Work sponsored by SGI. - v0.87 - 19991209 Richard Gooch <rgooch@atnf.csiro.au> - Removed obsolete DEVFS_ FL_COMPAT and DEVFS_ FL_TOLERANT flags. - Work sponsored by SGI. - v0.88 - 19991214 Richard Gooch <rgooch@atnf.csiro.au> - Removed kmod support. - Work sponsored by SGI. - v0.89 - 19991216 Richard Gooch <rgooch@atnf.csiro.au> - Improved debugging in <get_vfs_inode>. - Ensure dentries created by devfsd will be cleaned up. - Work sponsored by SGI. - v0.90 - 19991223 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_get_name>. - Work sponsored by SGI. - v0.91 - 20000203 Richard Gooch <rgooch@atnf.csiro.au> - Ported to kernel 2.3.42. - Removed <devfs_fill_file>. - Work sponsored by SGI. - v0.92 - 20000306 Richard Gooch <rgooch@atnf.csiro.au> - Added DEVFS_ FL_NO_PERSISTENCE flag. - Removed unnecessary call to <update_devfs_inode_from_entry> in - <devfs_readdir>. - Work sponsored by SGI. - v0.93 - 20000413 Richard Gooch <rgooch@atnf.csiro.au> - Set inode->i_size to correct size for symlinks. - 20000414 Richard Gooch <rgooch@atnf.csiro.au> - Only give lookup() method to directories to comply with new VFS - assumptions. - Work sponsored by SGI. - 20000415 Richard Gooch <rgooch@atnf.csiro.au> - Remove unnecessary tests in symlink methods. - Don't kill existing block ops in <devfs_read_inode>. - Work sponsored by SGI. - v0.94 - 20000424 Richard Gooch <rgooch@atnf.csiro.au> - Don't create missing directories in <devfs_find_handle>. - Work sponsored by SGI. - v0.95 - 20000430 Richard Gooch <rgooch@atnf.csiro.au> - Added CONFIG_DEVFS_MOUNT. - Work sponsored by SGI. - v0.96 - 20000608 Richard Gooch <rgooch@atnf.csiro.au> - Disabled multi-mount capability (use VFS bindings instead). - Work sponsored by SGI. - v0.97 - 20000610 Richard Gooch <rgooch@atnf.csiro.au> - Switched to FS_SINGLE to disable multi-mounts. - 20000612 Richard Gooch <rgooch@atnf.csiro.au> - Removed module support. - Removed multi-mount code. - Removed compatibility macros: VFS has changed too much. - Work sponsored by SGI. - v0.98 - 20000614 Richard Gooch <rgooch@atnf.csiro.au> - Merged devfs inode into devfs entry. - Work sponsored by SGI. - v0.99 - 20000619 Richard Gooch <rgooch@atnf.csiro.au> - Removed dead code in <devfs_register> which used to call - <free_dentries>. - Work sponsored by SGI. - v0.100 - 20000621 Richard Gooch <rgooch@atnf.csiro.au> - Changed interface to <devfs_register>. - Work sponsored by SGI. - v0.101 - 20000622 Richard Gooch <rgooch@atnf.csiro.au> - Simplified interface to <devfs_mk_symlink> and <devfs_mk_dir>. - Simplified interface to <devfs_find_handle>. - Work sponsored by SGI. - v0.102 - 20010519 Richard Gooch <rgooch@atnf.csiro.au> - Ensure <devfs_generate_path> terminates string for root entry. - Exported <devfs_get_name> to modules. - 20010520 Richard Gooch <rgooch@atnf.csiro.au> - Make <devfs_mk_symlink> send events to devfsd. - Cleaned up option processing in <devfs_setup>. - 20010521 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bugs in handling symlinks: could leak or cause Oops. - 20010522 Richard Gooch <rgooch@atnf.csiro.au> - Cleaned up directory handling by separating fops. - v0.103 - 20010601 Richard Gooch <rgooch@atnf.csiro.au> - Fixed handling of inverted options in <devfs_setup>. - v0.104 - 20010604 Richard Gooch <rgooch@atnf.csiro.au> - Adjusted <try_modload> to account for <devfs_generate_path> fix. - v0.105 - 20010617 Richard Gooch <rgooch@atnf.csiro.au> - Answered question posed by Al Viro and removed his comments. - Moved setting of registered flag after other fields are changed. - Fixed race between <devfsd_close> and <devfsd_notify_one>. - Global VFS changes added bogus BKL to <devfsd_close>: removed. - Widened locking in <devfs_readlink> and <devfs_follow_link>. - Replaced <devfsd_read> stack usage with <devfsd_ioctl> kmalloc. - Simplified locking in <devfsd_ioctl> and fixed memory leak. - v0.106 - 20010709 Richard Gooch <rgooch@atnf.csiro.au> - Removed broken devnum allocation and use <devfs_alloc_devnum>. - Fixed old devnum leak by calling new <devfs_dealloc_devnum>. - v0.107 - 20010712 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bug in <devfs_setup> which could hang boot process. - v0.108 - 20010730 Richard Gooch <rgooch@atnf.csiro.au> - Added DEVFSD_NOTIFY_DELETE event. - 20010801 Richard Gooch <rgooch@atnf.csiro.au> - Removed #include <asm/segment.h>. - v0.109 - 20010807 Richard Gooch <rgooch@atnf.csiro.au> - Fixed inode table races by removing it and using - inode->u.generic_ip instead. - Moved <devfs_read_inode> into <get_vfs_inode>. - Moved <devfs_write_inode> into <devfs_notify_change>. - v0.110 - 20010808 Richard Gooch <rgooch@atnf.csiro.au> - Fixed race in <devfs_do_symlink> for uni-processor. - v0.111 - 20010818 Richard Gooch <rgooch@atnf.csiro.au> - Removed remnant of multi-mount support in <devfs_mknod>. - Removed unused DEVFS_FL_SHOW_UNREG flag. - v0.112 - 20010820 Richard Gooch <rgooch@atnf.csiro.au> - Removed nlink field from struct devfs_inode. - v0.113 - 20010823 Richard Gooch <rgooch@atnf.csiro.au> - Replaced BKL with global rwsem to protect symlink data (quick - and dirty hack). - v0.114 - 20010827 Richard Gooch <rgooch@atnf.csiro.au> - Replaced global rwsem for symlink with per-link refcount. - v0.115 - 20010919 Richard Gooch <rgooch@atnf.csiro.au> - Set inode->i_mapping->a_ops for block nodes in <get_vfs_inode>. - v0.116 - 20011008 Richard Gooch <rgooch@atnf.csiro.au> - Fixed overrun in <devfs_link> by removing function (not needed). - 20011009 Richard Gooch <rgooch@atnf.csiro.au> - Fixed buffer underrun in <try_modload>. - 20011029 Richard Gooch <rgooch@atnf.csiro.au> - Fixed race in <devfsd_ioctl> when setting event mask. - 20011114 Richard Gooch <rgooch@atnf.csiro.au> - First release of new locking code. - v1.0 - 20011117 Richard Gooch <rgooch@atnf.csiro.au> - Discard temporary buffer, now use "%s" for dentry names. - 20011118 Richard Gooch <rgooch@atnf.csiro.au> - Don't generate path in <try_modload>: use fake entry instead. - Use "existing" directory in <_devfs_make_parent_for_leaf>. - 20011122 Richard Gooch <rgooch@atnf.csiro.au> - Use slab cache rather than fixed buffer for devfsd events. - v1.1 - 20011125 Richard Gooch <rgooch@atnf.csiro.au> - Send DEVFSD_NOTIFY_REGISTERED events in <devfs_mk_dir>. - 20011127 Richard Gooch <rgooch@atnf.csiro.au> - Fixed locking bug in <devfs_d_revalidate_wait> due to typo. - Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from - devfsd or children. - v1.2 - 20011202 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bug in <devfsd_read>: was dereferencing freed pointer. - v1.3 - 20011203 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bug in <devfsd_close>: was dereferencing freed pointer. - Added process group check for devfsd privileges. - v1.4 - 20011204 Richard Gooch <rgooch@atnf.csiro.au> - Use SLAB_ATOMIC in <devfsd_notify_de> from <devfs_d_delete>. - v1.5 - 20011211 Richard Gooch <rgooch@atnf.csiro.au> - Return old entry in <devfs_mk_dir> for 2.4.x kernels. - 20011212 Richard Gooch <rgooch@atnf.csiro.au> - Increment refcount on module in <check_disc_changed>. - 20011215 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_get_handle> and exported <devfs_put>. - Increment refcount on module in <devfs_get_ops>. - Created <devfs_put_ops>. - v1.6 - 20011216 Richard Gooch <rgooch@atnf.csiro.au> - Added poisoning to <devfs_put>. - Improved debugging messages. - v1.7 - 20011221 Richard Gooch <rgooch@atnf.csiro.au> - Corrected (made useful) debugging message in <unregister>. - Moved <kmem_cache_create> in <mount_devfs_fs> to <init_devfs_fs> - 20011224 Richard Gooch <rgooch@atnf.csiro.au> - Added magic number to guard against scribbling drivers. - 20011226 Richard Gooch <rgooch@atnf.csiro.au> - Only return old entry in <devfs_mk_dir> if a directory. - Defined macros for error and debug messages. - v1.8 - 20020113 Richard Gooch <rgooch@atnf.csiro.au> - Fixed (rare, old) race in <devfs_lookup>. - v1.9 - 20020120 Richard Gooch <rgooch@atnf.csiro.au> - Fixed deadlock bug in <devfs_d_revalidate_wait>. - Tag VFS deletable in <devfs_mk_symlink> if handle ignored. - v1.10 - 20020129 Richard Gooch <rgooch@atnf.csiro.au> - Added KERN_* to remaining messages. - Cleaned up declaration of <stat_read>. - v1.11 - 20020219 Richard Gooch <rgooch@atnf.csiro.au> - Changed <devfs_rmdir> to allow later additions if not yet empty. - v1.12 - 20020406 Richard Gooch <rgooch@atnf.csiro.au> - Removed silently introduced calls to lock_kernel() and - unlock_kernel() due to recent VFS locking changes. BKL isn't - required in devfs. - v1.13 - 20020428 Richard Gooch <rgooch@atnf.csiro.au> - Removed 2.4.x compatibility code. - v1.14 - 20020510 Richard Gooch <rgooch@atnf.csiro.au> - Added BKL to <devfs_open> because drivers still need it. - v1.15 - 20020512 Richard Gooch <rgooch@atnf.csiro.au> - Protected <scan_dir_for_removable> and <get_removable_partition> - from changing directory contents. - v1.16 - 20020514 Richard Gooch <rgooch@atnf.csiro.au> - Minor cleanup of <scan_dir_for_removable>. - v1.17 - 20020721 Richard Gooch <rgooch@atnf.csiro.au> - Switched to ISO C structure field initialisers. - Switch to set_current_state() and move before add_wait_queue(). - 20020722 Richard Gooch <rgooch@atnf.csiro.au> - Fixed devfs entry leak in <devfs_readdir> when *readdir fails. - v1.18 - 20020725 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_find_and_unregister>. - v1.19 - 20020728 Richard Gooch <rgooch@atnf.csiro.au> - Removed deprecated <devfs_find_handle>. - v1.20 - 20020820 Richard Gooch <rgooch@atnf.csiro.au> - Fixed module unload race in <devfs_open>. - v1.21 - 20021013 Richard Gooch <rgooch@atnf.csiro.au> - Removed DEVFS_ FL_AUTO_OWNER. - Switched lingering structure field initialiser to ISO C. - Added locking when updating FCB flags. - v1.22 -*/ -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/time.h> -#include <linux/tty.h> -#include <linux/timer.h> -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/wait.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/ctype.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/devfs_fs.h> -#include <linux/devfs_fs_kernel.h> -#include <linux/smp_lock.h> -#include <linux/smp.h> -#include <linux/rwsem.h> -#include <linux/sched.h> -#include <linux/namei.h> -#include <linux/bitops.h> - -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/processor.h> -#include <asm/system.h> -#include <asm/pgtable.h> -#include <asm/atomic.h> - -#define DEVFS_VERSION "2004-01-31" - -#define DEVFS_NAME "devfs" - -#define FIRST_INODE 1 - -#define STRING_LENGTH 256 -#define FAKE_BLOCK_SIZE 1024 -#define POISON_PTR ( *(void **) poison_array ) -#define MAGIC_VALUE 0x327db823 - -#ifndef TRUE -# define TRUE 1 -# define FALSE 0 -#endif - -#define MODE_DIR (S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO) - -#define DEBUG_NONE 0x0000000 -#define DEBUG_MODULE_LOAD 0x0000001 -#define DEBUG_REGISTER 0x0000002 -#define DEBUG_UNREGISTER 0x0000004 -#define DEBUG_FREE 0x0000008 -#define DEBUG_SET_FLAGS 0x0000010 -#define DEBUG_S_READ 0x0000100 /* Break */ -#define DEBUG_I_LOOKUP 0x0001000 /* Break */ -#define DEBUG_I_CREATE 0x0002000 -#define DEBUG_I_GET 0x0004000 -#define DEBUG_I_CHANGE 0x0008000 -#define DEBUG_I_UNLINK 0x0010000 -#define DEBUG_I_RLINK 0x0020000 -#define DEBUG_I_FLINK 0x0040000 -#define DEBUG_I_MKNOD 0x0080000 -#define DEBUG_F_READDIR 0x0100000 /* Break */ -#define DEBUG_D_DELETE 0x1000000 /* Break */ -#define DEBUG_D_RELEASE 0x2000000 -#define DEBUG_D_IPUT 0x4000000 -#define DEBUG_ALL 0xfffffff -#define DEBUG_DISABLED DEBUG_NONE - -#define OPTION_NONE 0x00 -#define OPTION_MOUNT 0x01 - -#define PRINTK(format, args...) \ - {printk (KERN_ERR "%s" format, __FUNCTION__ , ## args);} - -#define OOPS(format, args...) \ - {printk (KERN_CRIT "%s" format, __FUNCTION__ , ## args); \ - printk ("Forcing Oops\n"); \ - BUG();} - -#ifdef CONFIG_DEVFS_DEBUG -# define VERIFY_ENTRY(de) \ - {if ((de) && (de)->magic_number != MAGIC_VALUE) \ - OOPS ("(%p): bad magic value: %x\n", (de), (de)->magic_number);} -# define WRITE_ENTRY_MAGIC(de,magic) (de)->magic_number = (magic) -# define DPRINTK(flag, format, args...) \ - {if (devfs_debug & flag) \ - printk (KERN_INFO "%s" format, __FUNCTION__ , ## args);} -#else -# define VERIFY_ENTRY(de) -# define WRITE_ENTRY_MAGIC(de,magic) -# define DPRINTK(flag, format, args...) -#endif - -typedef struct devfs_entry *devfs_handle_t; - -struct directory_type { - rwlock_t lock; /* Lock for searching(R)/updating(W) */ - struct devfs_entry *first; - struct devfs_entry *last; - unsigned char no_more_additions:1; -}; - -struct symlink_type { - unsigned int length; /* Not including the NULL-termimator */ - char *linkname; /* This is NULL-terminated */ -}; - -struct devfs_inode { /* This structure is for "persistent" inode storage */ - struct dentry *dentry; - struct timespec atime; - struct timespec mtime; - struct timespec ctime; - unsigned int ino; /* Inode number as seen in the VFS */ - uid_t uid; - gid_t gid; -}; - -struct devfs_entry { -#ifdef CONFIG_DEVFS_DEBUG - unsigned int magic_number; -#endif - void *info; - atomic_t refcount; /* When this drops to zero, it's unused */ - union { - struct directory_type dir; - dev_t dev; - struct symlink_type symlink; - const char *name; /* Only used for (mode == 0) */ - } u; - struct devfs_entry *prev; /* Previous entry in the parent directory */ - struct devfs_entry *next; /* Next entry in the parent directory */ - struct devfs_entry *parent; /* The parent directory */ - struct devfs_inode inode; - umode_t mode; - unsigned short namelen; /* I think 64k+ filenames are a way off... */ - unsigned char vfs:1; /* Whether the VFS may delete the entry */ - char name[1]; /* This is just a dummy: the allocated array - is bigger. This is NULL-terminated */ -}; - -/* The root of the device tree */ -static struct devfs_entry *root_entry; - -struct devfsd_buf_entry { - struct devfs_entry *de; /* The name is generated with this */ - unsigned short type; /* The type of event */ - umode_t mode; - uid_t uid; - gid_t gid; - struct devfsd_buf_entry *next; -}; - -struct fs_info { /* This structure is for the mounted devfs */ - struct super_block *sb; - spinlock_t devfsd_buffer_lock; /* Lock when inserting/deleting events */ - struct devfsd_buf_entry *devfsd_first_event; - struct devfsd_buf_entry *devfsd_last_event; - volatile int devfsd_sleeping; - volatile struct task_struct *devfsd_task; - volatile pid_t devfsd_pgrp; - volatile struct file *devfsd_file; - struct devfsd_notify_struct *devfsd_info; - volatile unsigned long devfsd_event_mask; - atomic_t devfsd_overrun_count; - wait_queue_head_t devfsd_wait_queue; /* Wake devfsd on input */ - wait_queue_head_t revalidate_wait_queue; /* Wake when devfsd sleeps */ -}; - -static struct fs_info fs_info = {.devfsd_buffer_lock = SPIN_LOCK_UNLOCKED }; -static kmem_cache_t *devfsd_buf_cache; -#ifdef CONFIG_DEVFS_DEBUG -static unsigned int devfs_debug_init __initdata = DEBUG_NONE; -static unsigned int devfs_debug = DEBUG_NONE; -static DEFINE_SPINLOCK(stat_lock); -static unsigned int stat_num_entries; -static unsigned int stat_num_bytes; -#endif -static unsigned char poison_array[8] = - { 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a }; - -#ifdef CONFIG_DEVFS_MOUNT -static unsigned int boot_options = OPTION_MOUNT; -#else -static unsigned int boot_options = OPTION_NONE; -#endif - -/* Forward function declarations */ -static devfs_handle_t _devfs_walk_path(struct devfs_entry *dir, - const char *name, int namelen, - int traverse_symlink); -static ssize_t devfsd_read(struct file *file, char __user *buf, size_t len, - loff_t * ppos); -static int devfsd_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); -static int devfsd_close(struct inode *inode, struct file *file); -#ifdef CONFIG_DEVFS_DEBUG -static ssize_t stat_read(struct file *file, char __user *buf, size_t len, - loff_t * ppos); -static const struct file_operations stat_fops = { - .open = nonseekable_open, - .read = stat_read, -}; -#endif - -/* Devfs daemon file operations */ -static const struct file_operations devfsd_fops = { - .open = nonseekable_open, - .read = devfsd_read, - .ioctl = devfsd_ioctl, - .release = devfsd_close, -}; - -/* Support functions follow */ - -/** - * devfs_get - Get a reference to a devfs entry. - * @de: The devfs entry. - */ - -static struct devfs_entry *devfs_get(struct devfs_entry *de) -{ - VERIFY_ENTRY(de); - if (de) - atomic_inc(&de->refcount); - return de; -} /* End Function devfs_get */ - -/** - * devfs_put - Put (release) a reference to a devfs entry. - * @de: The handle to the devfs entry. - */ - -static void devfs_put(devfs_handle_t de) -{ - if (!de) - return; - VERIFY_ENTRY(de); - if (de->info == POISON_PTR) - OOPS("(%p): poisoned pointer\n", de); - if (!atomic_dec_and_test(&de->refcount)) - return; - if (de == root_entry) - OOPS("(%p): root entry being freed\n", de); - DPRINTK(DEBUG_FREE, "(%s): de: %p, parent: %p \"%s\"\n", - de->name, de, de->parent, - de->parent ? de->parent->name : "no parent"); - if (S_ISLNK(de->mode)) - kfree(de->u.symlink.linkname); - WRITE_ENTRY_MAGIC(de, 0); -#ifdef CONFIG_DEVFS_DEBUG - spin_lock(&stat_lock); - --stat_num_entries; - stat_num_bytes -= sizeof *de + de->namelen; - if (S_ISLNK(de->mode)) - stat_num_bytes -= de->u.symlink.length + 1; - spin_unlock(&stat_lock); -#endif - de->info = POISON_PTR; - kfree(de); -} /* End Function devfs_put */ - -/** - * _devfs_search_dir - Search for a devfs entry in a directory. - * @dir: The directory to search. - * @name: The name of the entry to search for. - * @namelen: The number of characters in @name. - * - * Search for a devfs entry in a directory and returns a pointer to the entry - * on success, else %NULL. The directory must be locked already. - * An implicit devfs_get() is performed on the returned entry. - */ - -static struct devfs_entry *_devfs_search_dir(struct devfs_entry *dir, - const char *name, - unsigned int namelen) -{ - struct devfs_entry *curr; - - if (!S_ISDIR(dir->mode)) { - PRINTK("(%s): not a directory\n", dir->name); - return NULL; - } - for (curr = dir->u.dir.first; curr != NULL; curr = curr->next) { - if (curr->namelen != namelen) - continue; - if (memcmp(curr->name, name, namelen) == 0) - break; - /* Not found: try the next one */ - } - return devfs_get(curr); -} /* End Function _devfs_search_dir */ - -/** - * _devfs_alloc_entry - Allocate a devfs entry. - * @name: the name of the entry - * @namelen: the number of characters in @name - * @mode: the mode for the entry - * - * Allocate a devfs entry and returns a pointer to the entry on success, else - * %NULL. - */ - -static struct devfs_entry *_devfs_alloc_entry(const char *name, - unsigned int namelen, - umode_t mode) -{ - struct devfs_entry *new; - static unsigned long inode_counter = FIRST_INODE; - static DEFINE_SPINLOCK(counter_lock); - - if (name && (namelen < 1)) - namelen = strlen(name); - if ((new = kmalloc(sizeof *new + namelen, GFP_KERNEL)) == NULL) - return NULL; - memset(new, 0, sizeof *new + namelen); /* Will set '\0' on name */ - new->mode = mode; - if (S_ISDIR(mode)) - rwlock_init(&new->u.dir.lock); - atomic_set(&new->refcount, 1); - spin_lock(&counter_lock); - new->inode.ino = inode_counter++; - spin_unlock(&counter_lock); - if (name) - memcpy(new->name, name, namelen); - new->namelen = namelen; - WRITE_ENTRY_MAGIC(new, MAGIC_VALUE); -#ifdef CONFIG_DEVFS_DEBUG - spin_lock(&stat_lock); - ++stat_num_entries; - stat_num_bytes += sizeof *new + namelen; - spin_unlock(&stat_lock); -#endif - return new; -} /* End Function _devfs_alloc_entry */ - -/** - * _devfs_append_entry - Append a devfs entry to a directory's child list. - * @dir: The directory to add to. - * @de: The devfs entry to append. - * @old_de: If an existing entry exists, it will be written here. This may - * be %NULL. An implicit devfs_get() is performed on this entry. - * - * Append a devfs entry to a directory's list of children, checking first to - * see if an entry of the same name exists. The directory will be locked. - * The value 0 is returned on success, else a negative error code. - * On failure, an implicit devfs_put() is performed on %de. - */ - -static int _devfs_append_entry(devfs_handle_t dir, devfs_handle_t de, - devfs_handle_t * old_de) -{ - int retval; - - if (old_de) - *old_de = NULL; - if (!S_ISDIR(dir->mode)) { - PRINTK("(%s): dir: \"%s\" is not a directory\n", de->name, - dir->name); - devfs_put(de); - return -ENOTDIR; - } - write_lock(&dir->u.dir.lock); - if (dir->u.dir.no_more_additions) - retval = -ENOENT; - else { - struct devfs_entry *old; - - old = _devfs_search_dir(dir, de->name, de->namelen); - if (old_de) - *old_de = old; - else - devfs_put(old); - if (old == NULL) { - de->parent = dir; - de->prev = dir->u.dir.last; - /* Append to the directory's list of children */ - if (dir->u.dir.first == NULL) - dir->u.dir.first = de; - else - dir->u.dir.last->next = de; - dir->u.dir.last = de; - retval = 0; - } else - retval = -EEXIST; - } - write_unlock(&dir->u.dir.lock); - if (retval) - devfs_put(de); - return retval; -} /* End Function _devfs_append_entry */ - -/** - * _devfs_get_root_entry - Get the root devfs entry. - * - * Returns the root devfs entry on success, else %NULL. - * - * TODO it must be called asynchronously due to the fact - * that devfs is initialized relatively late. Proper way - * is to remove module_init from init_devfs_fs and manually - * call it early enough during system init - */ - -static struct devfs_entry *_devfs_get_root_entry(void) -{ - struct devfs_entry *new; - static DEFINE_SPINLOCK(root_lock); - - if (root_entry) - return root_entry; - - new = _devfs_alloc_entry(NULL, 0, MODE_DIR); - if (new == NULL) - return NULL; - - spin_lock(&root_lock); - if (root_entry) { - spin_unlock(&root_lock); - devfs_put(new); - return root_entry; - } - root_entry = new; - spin_unlock(&root_lock); - - return root_entry; -} /* End Function _devfs_get_root_entry */ - -/** - * _devfs_descend - Descend down a tree using the next component name. - * @dir: The directory to search. - * @name: The component name to search for. - * @namelen: The length of %name. - * @next_pos: The position of the next '/' or '\0' is written here. - * - * Descend into a directory, searching for a component. This function forms - * the core of a tree-walking algorithm. The directory will be locked. - * The devfs entry corresponding to the component is returned. If there is - * no matching entry, %NULL is returned. - * An implicit devfs_get() is performed on the returned entry. - */ - -static struct devfs_entry *_devfs_descend(struct devfs_entry *dir, - const char *name, int namelen, - int *next_pos) -{ - const char *stop, *ptr; - struct devfs_entry *entry; - - if ((namelen >= 3) && (strncmp(name, "../", 3) == 0)) { /* Special-case going to parent directory */ - *next_pos = 3; - return devfs_get(dir->parent); - } - stop = name + namelen; - /* Search for a possible '/' */ - for (ptr = name; (ptr < stop) && (*ptr != '/'); ++ptr) ; - *next_pos = ptr - name; - read_lock(&dir->u.dir.lock); - entry = _devfs_search_dir(dir, name, *next_pos); - read_unlock(&dir->u.dir.lock); - return entry; -} /* End Function _devfs_descend */ - -static devfs_handle_t _devfs_make_parent_for_leaf(struct devfs_entry *dir, - const char *name, - int namelen, int *leaf_pos) -{ - int next_pos = 0; - - if (dir == NULL) - dir = _devfs_get_root_entry(); - if (dir == NULL) - return NULL; - devfs_get(dir); - /* Search for possible trailing component and ignore it */ - for (--namelen; (namelen > 0) && (name[namelen] != '/'); --namelen) ; - *leaf_pos = (name[namelen] == '/') ? (namelen + 1) : 0; - for (; namelen > 0; name += next_pos, namelen -= next_pos) { - struct devfs_entry *de, *old = NULL; - - if ((de = - _devfs_descend(dir, name, namelen, &next_pos)) == NULL) { - de = _devfs_alloc_entry(name, next_pos, MODE_DIR); - devfs_get(de); - if (!de || _devfs_append_entry(dir, de, &old)) { - devfs_put(de); - if (!old || !S_ISDIR(old->mode)) { - devfs_put(old); - devfs_put(dir); - return NULL; - } - de = old; /* Use the existing directory */ - } - } - if (de == dir->parent) { - devfs_put(dir); - devfs_put(de); - return NULL; - } - devfs_put(dir); - dir = de; - if (name[next_pos] == '/') - ++next_pos; - } - return dir; -} /* End Function _devfs_make_parent_for_leaf */ - -static devfs_handle_t _devfs_prepare_leaf(devfs_handle_t * dir, - const char *name, umode_t mode) -{ - int namelen, leaf_pos; - struct devfs_entry *de; - - namelen = strlen(name); - if ((*dir = _devfs_make_parent_for_leaf(*dir, name, namelen, - &leaf_pos)) == NULL) { - PRINTK("(%s): could not create parent path\n", name); - return NULL; - } - if ((de = _devfs_alloc_entry(name + leaf_pos, namelen - leaf_pos, mode)) - == NULL) { - PRINTK("(%s): could not allocate entry\n", name); - devfs_put(*dir); - return NULL; - } - return de; -} /* End Function _devfs_prepare_leaf */ - -static devfs_handle_t _devfs_walk_path(struct devfs_entry *dir, - const char *name, int namelen, - int traverse_symlink) -{ - int next_pos = 0; - - if (dir == NULL) - dir = _devfs_get_root_entry(); - if (dir == NULL) - return NULL; - devfs_get(dir); - for (; namelen > 0; name += next_pos, namelen -= next_pos) { - struct devfs_entry *de, *link; - - if (!S_ISDIR(dir->mode)) { - devfs_put(dir); - return NULL; - } - - if ((de = - _devfs_descend(dir, name, namelen, &next_pos)) == NULL) { - devfs_put(dir); - return NULL; - } - if (S_ISLNK(de->mode) && traverse_symlink) { /* Need to follow the link: this is a stack chomper */ - /* FIXME what if it puts outside of mounted tree? */ - link = _devfs_walk_path(dir, de->u.symlink.linkname, - de->u.symlink.length, TRUE); - devfs_put(de); - if (!link) { - devfs_put(dir); - return NULL; - } - de = link; - } - devfs_put(dir); - dir = de; - if (name[next_pos] == '/') - ++next_pos; - } - return dir; -} /* End Function _devfs_walk_path */ - -/** - * _devfs_find_entry - Find a devfs entry. - * @dir: The handle to the parent devfs directory entry. If this is %NULL the - * name is relative to the root of the devfs. - * @name: The name of the entry. This may be %NULL. - * @traverse_symlink: If %TRUE then symbolic links are traversed. - * - * Returns the devfs_entry pointer on success, else %NULL. An implicit - * devfs_get() is performed. - */ - -static struct devfs_entry *_devfs_find_entry(devfs_handle_t dir, - const char *name, - int traverse_symlink) -{ - unsigned int namelen = strlen(name); - - if (name[0] == '/') { - /* Skip leading pathname component */ - if (namelen < 2) { - PRINTK("(%s): too short\n", name); - return NULL; - } - for (++name, --namelen; (*name != '/') && (namelen > 0); - ++name, --namelen) ; - if (namelen < 2) { - PRINTK("(%s): too short\n", name); - return NULL; - } - ++name; - --namelen; - } - return _devfs_walk_path(dir, name, namelen, traverse_symlink); -} /* End Function _devfs_find_entry */ - -static struct devfs_entry *get_devfs_entry_from_vfs_inode(struct inode *inode) -{ - if (inode == NULL) - return NULL; - VERIFY_ENTRY((struct devfs_entry *)inode->u.generic_ip); - return inode->u.generic_ip; -} /* End Function get_devfs_entry_from_vfs_inode */ - -/** - * free_dentry - Free the dentry for a device entry and invalidate inode. - * @de: The entry. - * - * This must only be called after the entry has been unhooked from its - * parent directory. - */ - -static void free_dentry(struct devfs_entry *de) -{ - struct dentry *dentry = de->inode.dentry; - - if (!dentry) - return; - spin_lock(&dcache_lock); - dget_locked(dentry); - spin_unlock(&dcache_lock); - /* Forcefully remove the inode */ - if (dentry->d_inode != NULL) - dentry->d_inode->i_nlink = 0; - d_drop(dentry); - dput(dentry); -} /* End Function free_dentry */ - -/** - * is_devfsd_or_child - Test if the current process is devfsd or one of its children. - * @fs_info: The filesystem information. - * - * Returns %TRUE if devfsd or child, else %FALSE. - */ - -static int is_devfsd_or_child(struct fs_info *fs_info) -{ - struct task_struct *p = current; - - if (p == fs_info->devfsd_task) - return (TRUE); - if (process_group(p) == fs_info->devfsd_pgrp) - return (TRUE); - read_lock(&tasklist_lock); - for (; p != &init_task; p = p->real_parent) { - if (p == fs_info->devfsd_task) { - read_unlock(&tasklist_lock); - return (TRUE); - } - } - read_unlock(&tasklist_lock); - return (FALSE); -} /* End Function is_devfsd_or_child */ - -/** - * devfsd_queue_empty - Test if devfsd has work pending in its event queue. - * @fs_info: The filesystem information. - * - * Returns %TRUE if the queue is empty, else %FALSE. - */ - -static inline int devfsd_queue_empty(struct fs_info *fs_info) -{ - return (fs_info->devfsd_last_event) ? FALSE : TRUE; -} /* End Function devfsd_queue_empty */ - -/** - * wait_for_devfsd_finished - Wait for devfsd to finish processing its event queue. - * @fs_info: The filesystem information. - * - * Returns %TRUE if no more waiting will be required, else %FALSE. - */ - -static int wait_for_devfsd_finished(struct fs_info *fs_info) -{ - DECLARE_WAITQUEUE(wait, current); - - if (fs_info->devfsd_task == NULL) - return (TRUE); - if (devfsd_queue_empty(fs_info) && fs_info->devfsd_sleeping) - return TRUE; - if (is_devfsd_or_child(fs_info)) - return (FALSE); - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&fs_info->revalidate_wait_queue, &wait); - if (!devfsd_queue_empty(fs_info) || !fs_info->devfsd_sleeping) - if (fs_info->devfsd_task) - schedule(); - remove_wait_queue(&fs_info->revalidate_wait_queue, &wait); - __set_current_state(TASK_RUNNING); - return (TRUE); -} /* End Function wait_for_devfsd_finished */ - -/** - * devfsd_notify_de - Notify the devfsd daemon of a change. - * @de: The devfs entry that has changed. This and all parent entries will - * have their reference counts incremented if the event was queued. - * @type: The type of change. - * @mode: The mode of the entry. - * @uid: The user ID. - * @gid: The group ID. - * @fs_info: The filesystem info. - * - * Returns %TRUE if an event was queued and devfsd woken up, else %FALSE. - */ - -static int devfsd_notify_de(struct devfs_entry *de, - unsigned short type, umode_t mode, - uid_t uid, gid_t gid, struct fs_info *fs_info) -{ - struct devfsd_buf_entry *entry; - struct devfs_entry *curr; - - if (!(fs_info->devfsd_event_mask & (1 << type))) - return (FALSE); - if ((entry = kmem_cache_alloc(devfsd_buf_cache, SLAB_KERNEL)) == NULL) { - atomic_inc(&fs_info->devfsd_overrun_count); - return (FALSE); - } - for (curr = de; curr != NULL; curr = curr->parent) - devfs_get(curr); - entry->de = de; - entry->type = type; - entry->mode = mode; - entry->uid = uid; - entry->gid = gid; - entry->next = NULL; - spin_lock(&fs_info->devfsd_buffer_lock); - if (!fs_info->devfsd_first_event) - fs_info->devfsd_first_event = entry; - if (fs_info->devfsd_last_event) - fs_info->devfsd_last_event->next = entry; - fs_info->devfsd_last_event = entry; - spin_unlock(&fs_info->devfsd_buffer_lock); - wake_up_interruptible(&fs_info->devfsd_wait_queue); - return (TRUE); -} /* End Function devfsd_notify_de */ - -/** - * devfsd_notify - Notify the devfsd daemon of a change. - * @de: The devfs entry that has changed. - * @type: The type of change event. - * @wait: If TRUE, the function waits for the daemon to finish processing - * the event. - */ - -static void devfsd_notify(struct devfs_entry *de, unsigned short type) -{ - devfsd_notify_de(de, type, de->mode, current->euid, - current->egid, &fs_info); -} - -static int devfs_mk_dev(dev_t dev, umode_t mode, const char *fmt, va_list args) -{ - struct devfs_entry *dir = NULL, *de; - char buf[64]; - int error, n; - - n = vsnprintf(buf, sizeof(buf), fmt, args); - if (n >= sizeof(buf) || !buf[0]) { - printk(KERN_WARNING "%s: invalid format string %s\n", - __FUNCTION__, fmt); - return -EINVAL; - } - - de = _devfs_prepare_leaf(&dir, buf, mode); - if (!de) { - printk(KERN_WARNING "%s: could not prepare leaf for %s\n", - __FUNCTION__, buf); - return -ENOMEM; /* could be more accurate... */ - } - - de->u.dev = dev; - - error = _devfs_append_entry(dir, de, NULL); - if (error) { - printk(KERN_WARNING "%s: could not append to parent for %s\n", - __FUNCTION__, buf); - goto out; - } - - devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED); - out: - devfs_put(dir); - return error; -} - -int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...) -{ - va_list args; - - if (!S_ISBLK(mode)) { - printk(KERN_WARNING "%s: invalide mode (%u) for %s\n", - __FUNCTION__, mode, fmt); - return -EINVAL; - } - - va_start(args, fmt); - return devfs_mk_dev(dev, mode, fmt, args); -} - -EXPORT_SYMBOL(devfs_mk_bdev); - -int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...) -{ - va_list args; - - if (!S_ISCHR(mode)) { - printk(KERN_WARNING "%s: invalide mode (%u) for %s\n", - __FUNCTION__, mode, fmt); - return -EINVAL; - } - - va_start(args, fmt); - return devfs_mk_dev(dev, mode, fmt, args); -} - -EXPORT_SYMBOL(devfs_mk_cdev); - -/** - * _devfs_unhook - Unhook a device entry from its parents list - * @de: The entry to unhook. - * - * Returns %TRUE if the entry was unhooked, else %FALSE if it was - * previously unhooked. - * The caller must have a write lock on the parent directory. - */ - -static int _devfs_unhook(struct devfs_entry *de) -{ - struct devfs_entry *parent; - - if (!de || (de->prev == de)) - return FALSE; - parent = de->parent; - if (de->prev == NULL) - parent->u.dir.first = de->next; - else - de->prev->next = de->next; - if (de->next == NULL) - parent->u.dir.last = de->prev; - else - de->next->prev = de->prev; - de->prev = de; /* Indicate we're unhooked */ - de->next = NULL; /* Force early termination for <devfs_readdir> */ - return TRUE; -} /* End Function _devfs_unhook */ - -/** - * _devfs_unregister - Unregister a device entry from its parent. - * @dir: The parent directory. - * @de: The entry to unregister. - * - * The caller must have a write lock on the parent directory, which is - * unlocked by this function. - */ - -static void _devfs_unregister(struct devfs_entry *dir, struct devfs_entry *de) -{ - int unhooked = _devfs_unhook(de); - - write_unlock(&dir->u.dir.lock); - if (!unhooked) - return; - devfs_get(dir); - devfsd_notify(de, DEVFSD_NOTIFY_UNREGISTERED); - free_dentry(de); - devfs_put(dir); - if (!S_ISDIR(de->mode)) - return; - while (TRUE) { /* Recursively unregister: this is a stack chomper */ - struct devfs_entry *child; - - write_lock(&de->u.dir.lock); - de->u.dir.no_more_additions = TRUE; - child = de->u.dir.first; - VERIFY_ENTRY(child); - _devfs_unregister(de, child); - if (!child) - break; - DPRINTK(DEBUG_UNREGISTER, "(%s): child: %p refcount: %d\n", - child->name, child, atomic_read(&child->refcount)); - devfs_put(child); - } -} /* End Function _devfs_unregister */ - -static int devfs_do_symlink(devfs_handle_t dir, const char *name, - const char *link, devfs_handle_t * handle) -{ - int err; - unsigned int linklength; - char *newlink; - struct devfs_entry *de; - - if (handle != NULL) - *handle = NULL; - if (name == NULL) { - PRINTK("(): NULL name pointer\n"); - return -EINVAL; - } - if (link == NULL) { - PRINTK("(%s): NULL link pointer\n", name); - return -EINVAL; - } - linklength = strlen(link); - if ((newlink = kmalloc(linklength + 1, GFP_KERNEL)) == NULL) - return -ENOMEM; - memcpy(newlink, link, linklength); - newlink[linklength] = '\0'; - if ((de = _devfs_prepare_leaf(&dir, name, S_IFLNK | S_IRUGO | S_IXUGO)) - == NULL) { - PRINTK("(%s): could not prepare leaf\n", name); - kfree(newlink); - return -ENOTDIR; - } - de->info = NULL; - de->u.symlink.linkname = newlink; - de->u.symlink.length = linklength; - if ((err = _devfs_append_entry(dir, de, NULL)) != 0) { - PRINTK("(%s): could not append to parent, err: %d\n", name, - err); - devfs_put(dir); - return err; - } - devfs_put(dir); -#ifdef CONFIG_DEVFS_DEBUG - spin_lock(&stat_lock); - stat_num_bytes += linklength + 1; - spin_unlock(&stat_lock); -#endif - if (handle != NULL) - *handle = de; - return 0; -} /* End Function devfs_do_symlink */ - -/** - * devfs_mk_symlink Create a symbolic link in the devfs namespace. - * @from: The name of the entry. - * @to: Name of the destination - * - * Returns 0 on success, else a negative error code is returned. - */ - -int devfs_mk_symlink(const char *from, const char *to) -{ - devfs_handle_t de; - int err; - - err = devfs_do_symlink(NULL, from, to, &de); - if (!err) { - de->vfs = TRUE; - devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED); - } - - return err; -} - -/** - * devfs_mk_dir - Create a directory in the devfs namespace. - * new name is relative to the root of the devfs. - * @fmt: The name of the entry. - * - * Use of this function is optional. The devfs_register() function - * will automatically create intermediate directories as needed. This function - * is provided for efficiency reasons, as it provides a handle to a directory. - * On failure %NULL is returned. - */ - -int devfs_mk_dir(const char *fmt, ...) -{ - struct devfs_entry *dir = NULL, *de = NULL, *old; - char buf[64]; - va_list args; - int error, n; - - va_start(args, fmt); - n = vsnprintf(buf, 64, fmt, args); - if (n >= 64 || !buf[0]) { - printk(KERN_WARNING "%s: invalid argument.", __FUNCTION__); - return -EINVAL; - } - - de = _devfs_prepare_leaf(&dir, buf, MODE_DIR); - if (!de) { - PRINTK("(%s): could not prepare leaf\n", buf); - return -EINVAL; - } - - error = _devfs_append_entry(dir, de, &old); - if (error == -EEXIST && S_ISDIR(old->mode)) { - /* - * devfs_mk_dir() of an already-existing directory will - * return success. - */ - error = 0; - goto out_put; - } else if (error) { - PRINTK("(%s): could not append to dir: %p \"%s\"\n", - buf, dir, dir->name); - devfs_put(old); - goto out_put; - } - - devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED); - - out_put: - devfs_put(dir); - return error; -} - -void devfs_remove(const char *fmt, ...) -{ - char buf[64]; - va_list args; - int n; - - va_start(args, fmt); - n = vsnprintf(buf, sizeof(buf), fmt, args); - if (n < sizeof(buf) && buf[0]) { - devfs_handle_t de = _devfs_find_entry(NULL, buf, 0); - - if (!de) { - printk(KERN_ERR "%s: %s not found, cannot remove\n", - __FUNCTION__, buf); - dump_stack(); - return; - } - - write_lock(&de->parent->u.dir.lock); - _devfs_unregister(de->parent, de); - devfs_put(de); - devfs_put(de); - } -} - -/** - * devfs_generate_path - Generate a pathname for an entry, relative to the devfs root. - * @de: The devfs entry. - * @path: The buffer to write the pathname to. The pathname and '\0' - * terminator will be written at the end of the buffer. - * @buflen: The length of the buffer. - * - * Returns the offset in the buffer where the pathname starts on success, - * else a negative error code. - */ - -static int devfs_generate_path(devfs_handle_t de, char *path, int buflen) -{ - int pos; -#define NAMEOF(de) ( (de)->mode ? (de)->name : (de)->u.name ) - - if (de == NULL) - return -EINVAL; - VERIFY_ENTRY(de); - if (de->namelen >= buflen) - return -ENAMETOOLONG; /* Must be first */ - path[buflen - 1] = '\0'; - if (de->parent == NULL) - return buflen - 1; /* Don't prepend root */ - pos = buflen - de->namelen - 1; - memcpy(path + pos, NAMEOF(de), de->namelen); - for (de = de->parent; de->parent != NULL; de = de->parent) { - if (pos - de->namelen - 1 < 0) - return -ENAMETOOLONG; - path[--pos] = '/'; - pos -= de->namelen; - memcpy(path + pos, NAMEOF(de), de->namelen); - } - return pos; -} /* End Function devfs_generate_path */ - -/** - * devfs_setup - Process kernel boot options. - * @str: The boot options after the "devfs=". - */ - -static int __init devfs_setup(char *str) -{ - static struct { - char *name; - unsigned int mask; - unsigned int *opt; - } devfs_options_tab[] __initdata = { -#ifdef CONFIG_DEVFS_DEBUG - { - "dall", DEBUG_ALL, &devfs_debug_init}, { - "dmod", DEBUG_MODULE_LOAD, &devfs_debug_init}, { - "dreg", DEBUG_REGISTER, &devfs_debug_init}, { - "dunreg", DEBUG_UNREGISTER, &devfs_debug_init}, { - "dfree", DEBUG_FREE, &devfs_debug_init}, { - "diget", DEBUG_I_GET, &devfs_debug_init}, { - "dchange", DEBUG_SET_FLAGS, &devfs_debug_init}, { - "dsread", DEBUG_S_READ, &devfs_debug_init}, { - "dichange", DEBUG_I_CHANGE, &devfs_debug_init}, { - "dimknod", DEBUG_I_MKNOD, &devfs_debug_init}, { - "dilookup", DEBUG_I_LOOKUP, &devfs_debug_init}, { - "diunlink", DEBUG_I_UNLINK, &devfs_debug_init}, -#endif /* CONFIG_DEVFS_DEBUG */ - { - "mount", OPTION_MOUNT, &boot_options}, { - NULL, 0, NULL} - }; - - while ((*str != '\0') && !isspace(*str)) { - int i, found = 0, invert = 0; - - if (strncmp(str, "no", 2) == 0) { - invert = 1; - str += 2; - } - for (i = 0; devfs_options_tab[i].name != NULL; i++) { - int len = strlen(devfs_options_tab[i].name); - - if (strncmp(str, devfs_options_tab[i].name, len) == 0) { - if (invert) - *devfs_options_tab[i].opt &= - ~devfs_options_tab[i].mask; - else - *devfs_options_tab[i].opt |= - devfs_options_tab[i].mask; - str += len; - found = 1; - break; - } - } - if (!found) - return 0; /* No match */ - if (*str != ',') - return 0; /* No more options */ - ++str; - } - return 1; -} /* End Function devfs_setup */ - -__setup("devfs=", devfs_setup); - -EXPORT_SYMBOL(devfs_mk_dir); -EXPORT_SYMBOL(devfs_remove); - -/** - * try_modload - Notify devfsd of an inode lookup by a non-devfsd process. - * @parent: The parent devfs entry. - * @fs_info: The filesystem info. - * @name: The device name. - * @namelen: The number of characters in @name. - * @buf: A working area that will be used. This must not go out of scope - * until devfsd is idle again. - * - * Returns 0 on success (event was queued), else a negative error code. - */ - -static int try_modload(struct devfs_entry *parent, struct fs_info *fs_info, - const char *name, unsigned namelen, - struct devfs_entry *buf) -{ - if (!(fs_info->devfsd_event_mask & (1 << DEVFSD_NOTIFY_LOOKUP))) - return -ENOENT; - if (is_devfsd_or_child(fs_info)) - return -ENOENT; - memset(buf, 0, sizeof *buf); - atomic_set(&buf->refcount, 1); - buf->parent = parent; - buf->namelen = namelen; - buf->u.name = name; - WRITE_ENTRY_MAGIC(buf, MAGIC_VALUE); - if (!devfsd_notify_de(buf, DEVFSD_NOTIFY_LOOKUP, 0, - current->euid, current->egid, fs_info)) - return -ENOENT; - /* Possible success: event has been queued */ - return 0; -} /* End Function try_modload */ - -/* Superblock operations follow */ - -static struct inode_operations devfs_iops; -static struct inode_operations devfs_dir_iops; -static const struct file_operations devfs_fops; -static const struct file_operations devfs_dir_fops; -static struct inode_operations devfs_symlink_iops; - -static int devfs_notify_change(struct dentry *dentry, struct iattr *iattr) -{ - int retval; - struct devfs_entry *de; - struct inode *inode = dentry->d_inode; - struct fs_info *fs_info = inode->i_sb->s_fs_info; - - de = get_devfs_entry_from_vfs_inode(inode); - if (de == NULL) - return -ENODEV; - retval = inode_change_ok(inode, iattr); - if (retval != 0) - return retval; - retval = inode_setattr(inode, iattr); - if (retval != 0) - return retval; - DPRINTK(DEBUG_I_CHANGE, "(%d): VFS inode: %p devfs_entry: %p\n", - (int)inode->i_ino, inode, de); - DPRINTK(DEBUG_I_CHANGE, "(): mode: 0%o uid: %d gid: %d\n", - (int)inode->i_mode, (int)inode->i_uid, (int)inode->i_gid); - /* Inode is not on hash chains, thus must save permissions here rather - than in a write_inode() method */ - de->mode = inode->i_mode; - de->inode.uid = inode->i_uid; - de->inode.gid = inode->i_gid; - de->inode.atime = inode->i_atime; - de->inode.mtime = inode->i_mtime; - de->inode.ctime = inode->i_ctime; - if ((iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) && - !is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_CHANGE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - return 0; -} /* End Function devfs_notify_change */ - -static struct super_operations devfs_sops = { - .drop_inode = generic_delete_inode, - .statfs = simple_statfs, -}; - -/** - * _devfs_get_vfs_inode - Get a VFS inode. - * @sb: The super block. - * @de: The devfs inode. - * @dentry: The dentry to register with the devfs inode. - * - * Returns the inode on success, else %NULL. An implicit devfs_get() is - * performed if the inode is created. - */ - -static struct inode *_devfs_get_vfs_inode(struct super_block *sb, - struct devfs_entry *de, - struct dentry *dentry) -{ - struct inode *inode; - - if (de->prev == de) - return NULL; /* Quick check to see if unhooked */ - if ((inode = new_inode(sb)) == NULL) { - PRINTK("(%s): new_inode() failed, de: %p\n", de->name, de); - return NULL; - } - if (de->parent) { - read_lock(&de->parent->u.dir.lock); - if (de->prev != de) - de->inode.dentry = dentry; /* Not unhooked */ - read_unlock(&de->parent->u.dir.lock); - } else - de->inode.dentry = dentry; /* Root: no locking needed */ - if (de->inode.dentry != dentry) { /* Must have been unhooked */ - iput(inode); - return NULL; - } - /* FIXME where is devfs_put? */ - inode->u.generic_ip = devfs_get(de); - inode->i_ino = de->inode.ino; - DPRINTK(DEBUG_I_GET, "(%d): VFS inode: %p devfs_entry: %p\n", - (int)inode->i_ino, inode, de); - inode->i_blocks = 0; - inode->i_blksize = FAKE_BLOCK_SIZE; - inode->i_op = &devfs_iops; - inode->i_mode = de->mode; - if (S_ISDIR(de->mode)) { - inode->i_op = &devfs_dir_iops; - inode->i_fop = &devfs_dir_fops; - } else if (S_ISLNK(de->mode)) { - inode->i_op = &devfs_symlink_iops; - inode->i_size = de->u.symlink.length; - } else if (S_ISCHR(de->mode) || S_ISBLK(de->mode)) { - init_special_inode(inode, de->mode, de->u.dev); - } else if (S_ISFIFO(de->mode) || S_ISSOCK(de->mode)) { - init_special_inode(inode, de->mode, 0); - } else { - PRINTK("(%s): unknown mode %o de: %p\n", - de->name, de->mode, de); - iput(inode); - devfs_put(de); - return NULL; - } - - inode->i_uid = de->inode.uid; - inode->i_gid = de->inode.gid; - inode->i_atime = de->inode.atime; - inode->i_mtime = de->inode.mtime; - inode->i_ctime = de->inode.ctime; - DPRINTK(DEBUG_I_GET, "(): mode: 0%o uid: %d gid: %d\n", - (int)inode->i_mode, (int)inode->i_uid, (int)inode->i_gid); - return inode; -} /* End Function _devfs_get_vfs_inode */ - -/* File operations for device entries follow */ - -static int devfs_readdir(struct file *file, void *dirent, filldir_t filldir) -{ - int err, count; - int stored = 0; - struct fs_info *fs_info; - struct devfs_entry *parent, *de, *next = NULL; - struct inode *inode = file->f_dentry->d_inode; - - fs_info = inode->i_sb->s_fs_info; - parent = get_devfs_entry_from_vfs_inode(file->f_dentry->d_inode); - if ((long)file->f_pos < 0) - return -EINVAL; - DPRINTK(DEBUG_F_READDIR, "(%s): fs_info: %p pos: %ld\n", - parent->name, fs_info, (long)file->f_pos); - switch ((long)file->f_pos) { - case 0: - err = (*filldir) (dirent, "..", 2, file->f_pos, - parent_ino(file->f_dentry), DT_DIR); - if (err == -EINVAL) - break; - if (err < 0) - return err; - file->f_pos++; - ++stored; - /* Fall through */ - case 1: - err = - (*filldir) (dirent, ".", 1, file->f_pos, inode->i_ino, - DT_DIR); - if (err == -EINVAL) - break; - if (err < 0) - return err; - file->f_pos++; - ++stored; - /* Fall through */ - default: - /* Skip entries */ - count = file->f_pos - 2; - read_lock(&parent->u.dir.lock); - for (de = parent->u.dir.first; de && (count > 0); de = de->next) - --count; - devfs_get(de); - read_unlock(&parent->u.dir.lock); - /* Now add all remaining entries */ - while (de) { - err = (*filldir) (dirent, de->name, de->namelen, - file->f_pos, de->inode.ino, - de->mode >> 12); - if (err < 0) - devfs_put(de); - else { - file->f_pos++; - ++stored; - } - if (err == -EINVAL) - break; - if (err < 0) - return err; - read_lock(&parent->u.dir.lock); - next = devfs_get(de->next); - read_unlock(&parent->u.dir.lock); - devfs_put(de); - de = next; - } - break; - } - return stored; -} /* End Function devfs_readdir */ - -/* Open devfs specific special files */ -static int devfs_open(struct inode *inode, struct file *file) -{ - int err; - int minor = MINOR(inode->i_rdev); - struct file_operations *old_fops, *new_fops; - - switch (minor) { - case 0: /* /dev/.devfsd */ - new_fops = fops_get(&devfsd_fops); - break; -#ifdef CONFIG_DEVFS_DEBUG - case 1: /* /dev/.stat */ - new_fops = fops_get(&stat_fops); - break; -#endif - default: - return -ENODEV; - } - - if (new_fops == NULL) - return -ENODEV; - old_fops = file->f_op; - file->f_op = new_fops; - err = new_fops->open ? new_fops->open(inode, file) : 0; - if (err) { - file->f_op = old_fops; - fops_put(new_fops); - } else - fops_put(old_fops); - return err; -} /* End Function devfs_open */ - -static const struct file_operations devfs_fops = { - .open = devfs_open, -}; - -static const struct file_operations devfs_dir_fops = { - .read = generic_read_dir, - .readdir = devfs_readdir, -}; - -/* Dentry operations for device entries follow */ - -/** - * devfs_d_release - Callback for when a dentry is freed. - * @dentry: The dentry. - */ - -static void devfs_d_release(struct dentry *dentry) -{ - DPRINTK(DEBUG_D_RELEASE, "(%p): inode: %p\n", dentry, dentry->d_inode); -} /* End Function devfs_d_release */ - -/** - * devfs_d_iput - Callback for when a dentry loses its inode. - * @dentry: The dentry. - * @inode: The inode. - */ - -static void devfs_d_iput(struct dentry *dentry, struct inode *inode) -{ - struct devfs_entry *de; - - de = get_devfs_entry_from_vfs_inode(inode); - DPRINTK(DEBUG_D_IPUT, - "(%s): dentry: %p inode: %p de: %p de->dentry: %p\n", de->name, - dentry, inode, de, de->inode.dentry); - if (de->inode.dentry && (de->inode.dentry != dentry)) - OOPS("(%s): de: %p dentry: %p de->dentry: %p\n", - de->name, de, dentry, de->inode.dentry); - de->inode.dentry = NULL; - iput(inode); - devfs_put(de); -} /* End Function devfs_d_iput */ - -static int devfs_d_delete(struct dentry *dentry); - -static struct dentry_operations devfs_dops = { - .d_delete = devfs_d_delete, - .d_release = devfs_d_release, - .d_iput = devfs_d_iput, -}; - -static int devfs_d_revalidate_wait(struct dentry *dentry, struct nameidata *); - -static struct dentry_operations devfs_wait_dops = { - .d_delete = devfs_d_delete, - .d_release = devfs_d_release, - .d_iput = devfs_d_iput, - .d_revalidate = devfs_d_revalidate_wait, -}; - -/** - * devfs_d_delete - Callback for when all files for a dentry are closed. - * @dentry: The dentry. - */ - -static int devfs_d_delete(struct dentry *dentry) -{ - struct inode *inode = dentry->d_inode; - - if (dentry->d_op == &devfs_wait_dops) - dentry->d_op = &devfs_dops; - /* Unhash dentry if negative (has no inode) */ - if (inode == NULL) { - DPRINTK(DEBUG_D_DELETE, "(%p): dropping negative dentry\n", - dentry); - return 1; - } - return 0; -} /* End Function devfs_d_delete */ - -struct devfs_lookup_struct { - devfs_handle_t de; - wait_queue_head_t wait_queue; -}; - -/* XXX: this doesn't handle the case where we got a negative dentry - but a devfs entry has been registered in the meanwhile */ -static int devfs_d_revalidate_wait(struct dentry *dentry, struct nameidata *nd) -{ - struct inode *dir = dentry->d_parent->d_inode; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - devfs_handle_t parent = get_devfs_entry_from_vfs_inode(dir); - struct devfs_lookup_struct *lookup_info = dentry->d_fsdata; - DECLARE_WAITQUEUE(wait, current); - int need_lock; - - /* - * FIXME HACK - * - * make sure that - * d_instantiate always runs under lock - * we release i_mutex lock before going to sleep - * - * unfortunately sometimes d_revalidate is called with - * and sometimes without i_mutex lock held. The following checks - * attempt to deduce when we need to add (and drop resp.) lock - * here. This relies on current (2.6.2) calling coventions: - * - * lookup_hash is always run under i_mutex and is passing NULL - * as nd - * - * open(...,O_CREATE,...) calls _lookup_hash under i_mutex - * and sets flags to LOOKUP_OPEN|LOOKUP_CREATE - * - * all other invocations of ->d_revalidate seem to happen - * outside of i_mutex - */ - need_lock = nd && - (!(nd->flags & LOOKUP_CREATE) || (nd->flags & LOOKUP_PARENT)); - - if (need_lock) - mutex_lock(&dir->i_mutex); - - if (is_devfsd_or_child(fs_info)) { - devfs_handle_t de = lookup_info->de; - struct inode *inode; - - DPRINTK(DEBUG_I_LOOKUP, - "(%s): dentry: %p inode: %p de: %p by: \"%s\"\n", - dentry->d_name.name, dentry, dentry->d_inode, de, - current->comm); - if (dentry->d_inode) - goto out; - if (de == NULL) { - read_lock(&parent->u.dir.lock); - de = _devfs_search_dir(parent, dentry->d_name.name, - dentry->d_name.len); - read_unlock(&parent->u.dir.lock); - if (de == NULL) - goto out; - lookup_info->de = de; - } - /* Create an inode, now that the driver information is available */ - inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry); - if (!inode) - goto out; - DPRINTK(DEBUG_I_LOOKUP, - "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n", - de->name, de->inode.ino, inode, de, current->comm); - d_instantiate(dentry, inode); - goto out; - } - if (lookup_info == NULL) - goto out; /* Early termination */ - read_lock(&parent->u.dir.lock); - if (dentry->d_fsdata) { - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&lookup_info->wait_queue, &wait); - read_unlock(&parent->u.dir.lock); - /* at this point it is always (hopefully) locked */ - mutex_unlock(&dir->i_mutex); - schedule(); - mutex_lock(&dir->i_mutex); - /* - * This does not need nor should remove wait from wait_queue. - * Wait queue head is never reused - nothing is ever added to it - * after all waiters have been waked up and head itself disappears - * very soon after it. Moreover it is local variable on stack that - * is likely to have already disappeared so any reference to it - * at this point is buggy. - */ - - } else - read_unlock(&parent->u.dir.lock); - - out: - if (need_lock) - mutex_unlock(&dir->i_mutex); - return 1; -} /* End Function devfs_d_revalidate_wait */ - -/* Inode operations for device entries follow */ - -static struct dentry *devfs_lookup(struct inode *dir, struct dentry *dentry, - struct nameidata *nd) -{ - struct devfs_entry tmp; /* Must stay in scope until devfsd idle again */ - struct devfs_lookup_struct lookup_info; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - struct devfs_entry *parent, *de; - struct inode *inode; - struct dentry *retval = NULL; - - /* Set up the dentry operations before anything else, to ensure cleaning - up on any error */ - dentry->d_op = &devfs_dops; - /* First try to get the devfs entry for this directory */ - parent = get_devfs_entry_from_vfs_inode(dir); - DPRINTK(DEBUG_I_LOOKUP, "(%s): dentry: %p parent: %p by: \"%s\"\n", - dentry->d_name.name, dentry, parent, current->comm); - if (parent == NULL) - return ERR_PTR(-ENOENT); - read_lock(&parent->u.dir.lock); - de = _devfs_search_dir(parent, dentry->d_name.name, dentry->d_name.len); - read_unlock(&parent->u.dir.lock); - lookup_info.de = de; - init_waitqueue_head(&lookup_info.wait_queue); - dentry->d_fsdata = &lookup_info; - if (de == NULL) { /* Try with devfsd. For any kind of failure, leave a negative dentry - so someone else can deal with it (in the case where the sysadmin - does a mknod()). It's important to do this before hashing the - dentry, so that the devfsd queue is filled before revalidates - can start */ - if (try_modload(parent, fs_info, dentry->d_name.name, dentry->d_name.len, &tmp) < 0) { /* Lookup event was not queued to devfsd */ - d_add(dentry, NULL); - return NULL; - } - } - dentry->d_op = &devfs_wait_dops; - d_add(dentry, NULL); /* Open the floodgates */ - /* Unlock directory semaphore, which will release any waiters. They - will get the hashed dentry, and may be forced to wait for - revalidation */ - mutex_unlock(&dir->i_mutex); - wait_for_devfsd_finished(fs_info); /* If I'm not devfsd, must wait */ - mutex_lock(&dir->i_mutex); /* Grab it again because them's the rules */ - de = lookup_info.de; - /* If someone else has been so kind as to make the inode, we go home - early */ - if (dentry->d_inode) - goto out; - if (de == NULL) { - read_lock(&parent->u.dir.lock); - de = _devfs_search_dir(parent, dentry->d_name.name, - dentry->d_name.len); - read_unlock(&parent->u.dir.lock); - if (de == NULL) - goto out; - /* OK, there's an entry now, but no VFS inode yet */ - } - /* Create an inode, now that the driver information is available */ - inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry); - if (!inode) { - retval = ERR_PTR(-ENOMEM); - goto out; - } - DPRINTK(DEBUG_I_LOOKUP, - "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n", de->name, - de->inode.ino, inode, de, current->comm); - d_instantiate(dentry, inode); - out: - write_lock(&parent->u.dir.lock); - dentry->d_op = &devfs_dops; - dentry->d_fsdata = NULL; - wake_up(&lookup_info.wait_queue); - write_unlock(&parent->u.dir.lock); - devfs_put(de); - return retval; -} /* End Function devfs_lookup */ - -static int devfs_unlink(struct inode *dir, struct dentry *dentry) -{ - int unhooked; - struct devfs_entry *de; - struct inode *inode = dentry->d_inode; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - - de = get_devfs_entry_from_vfs_inode(inode); - DPRINTK(DEBUG_I_UNLINK, "(%s): de: %p\n", dentry->d_name.name, de); - if (de == NULL) - return -ENOENT; - if (!de->vfs) - return -EPERM; - write_lock(&de->parent->u.dir.lock); - unhooked = _devfs_unhook(de); - write_unlock(&de->parent->u.dir.lock); - if (!unhooked) - return -ENOENT; - if (!is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_DELETE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - free_dentry(de); - devfs_put(de); - return 0; -} /* End Function devfs_unlink */ - -static int devfs_symlink(struct inode *dir, struct dentry *dentry, - const char *symname) -{ - int err; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - struct devfs_entry *parent, *de; - struct inode *inode; - - /* First try to get the devfs entry for this directory */ - parent = get_devfs_entry_from_vfs_inode(dir); - if (parent == NULL) - return -ENOENT; - err = devfs_do_symlink(parent, dentry->d_name.name, symname, &de); - DPRINTK(DEBUG_DISABLED, "(%s): errcode from <devfs_do_symlink>: %d\n", - dentry->d_name.name, err); - if (err < 0) - return err; - de->vfs = TRUE; - de->inode.uid = current->euid; - de->inode.gid = current->egid; - de->inode.atime = CURRENT_TIME; - de->inode.mtime = CURRENT_TIME; - de->inode.ctime = CURRENT_TIME; - if ((inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry)) == NULL) - return -ENOMEM; - DPRINTK(DEBUG_DISABLED, "(%s): new VFS inode(%u): %p dentry: %p\n", - dentry->d_name.name, de->inode.ino, inode, dentry); - d_instantiate(dentry, inode); - if (!is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_CREATE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - return 0; -} /* End Function devfs_symlink */ - -static int devfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) -{ - int err; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - struct devfs_entry *parent, *de; - struct inode *inode; - - mode = (mode & ~S_IFMT) | S_IFDIR; /* VFS doesn't pass S_IFMT part */ - parent = get_devfs_entry_from_vfs_inode(dir); - if (parent == NULL) - return -ENOENT; - de = _devfs_alloc_entry(dentry->d_name.name, dentry->d_name.len, mode); - if (!de) - return -ENOMEM; - de->vfs = TRUE; - if ((err = _devfs_append_entry(parent, de, NULL)) != 0) - return err; - de->inode.uid = current->euid; - de->inode.gid = current->egid; - de->inode.atime = CURRENT_TIME; - de->inode.mtime = CURRENT_TIME; - de->inode.ctime = CURRENT_TIME; - if ((inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry)) == NULL) - return -ENOMEM; - DPRINTK(DEBUG_DISABLED, "(%s): new VFS inode(%u): %p dentry: %p\n", - dentry->d_name.name, de->inode.ino, inode, dentry); - d_instantiate(dentry, inode); - if (!is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_CREATE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - return 0; -} /* End Function devfs_mkdir */ - -static int devfs_rmdir(struct inode *dir, struct dentry *dentry) -{ - int err = 0; - struct devfs_entry *de; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - struct inode *inode = dentry->d_inode; - - if (dir->i_sb->s_fs_info != inode->i_sb->s_fs_info) - return -EINVAL; - de = get_devfs_entry_from_vfs_inode(inode); - if (de == NULL) - return -ENOENT; - if (!S_ISDIR(de->mode)) - return -ENOTDIR; - if (!de->vfs) - return -EPERM; - /* First ensure the directory is empty and will stay that way */ - write_lock(&de->u.dir.lock); - if (de->u.dir.first) - err = -ENOTEMPTY; - else - de->u.dir.no_more_additions = TRUE; - write_unlock(&de->u.dir.lock); - if (err) - return err; - /* Now unhook the directory from its parent */ - write_lock(&de->parent->u.dir.lock); - if (!_devfs_unhook(de)) - err = -ENOENT; - write_unlock(&de->parent->u.dir.lock); - if (err) - return err; - if (!is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_DELETE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - free_dentry(de); - devfs_put(de); - return 0; -} /* End Function devfs_rmdir */ - -static int devfs_mknod(struct inode *dir, struct dentry *dentry, int mode, - dev_t rdev) -{ - int err; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - struct devfs_entry *parent, *de; - struct inode *inode; - - DPRINTK(DEBUG_I_MKNOD, "(%s): mode: 0%o dev: %u:%u\n", - dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); - parent = get_devfs_entry_from_vfs_inode(dir); - if (parent == NULL) - return -ENOENT; - de = _devfs_alloc_entry(dentry->d_name.name, dentry->d_name.len, mode); - if (!de) - return -ENOMEM; - de->vfs = TRUE; - if (S_ISCHR(mode) || S_ISBLK(mode)) - de->u.dev = rdev; - if ((err = _devfs_append_entry(parent, de, NULL)) != 0) - return err; - de->inode.uid = current->euid; - de->inode.gid = current->egid; - de->inode.atime = CURRENT_TIME; - de->inode.mtime = CURRENT_TIME; - de->inode.ctime = CURRENT_TIME; - if ((inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry)) == NULL) - return -ENOMEM; - DPRINTK(DEBUG_I_MKNOD, ": new VFS inode(%u): %p dentry: %p\n", - de->inode.ino, inode, dentry); - d_instantiate(dentry, inode); - if (!is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_CREATE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - return 0; -} /* End Function devfs_mknod */ - -static void *devfs_follow_link(struct dentry *dentry, struct nameidata *nd) -{ - struct devfs_entry *p = get_devfs_entry_from_vfs_inode(dentry->d_inode); - nd_set_link(nd, p ? p->u.symlink.linkname : ERR_PTR(-ENODEV)); - return NULL; -} /* End Function devfs_follow_link */ - -static struct inode_operations devfs_iops = { - .setattr = devfs_notify_change, -}; - -static struct inode_operations devfs_dir_iops = { - .lookup = devfs_lookup, - .unlink = devfs_unlink, - .symlink = devfs_symlink, - .mkdir = devfs_mkdir, - .rmdir = devfs_rmdir, - .mknod = devfs_mknod, - .setattr = devfs_notify_change, -}; - -static struct inode_operations devfs_symlink_iops = { - .readlink = generic_readlink, - .follow_link = devfs_follow_link, - .setattr = devfs_notify_change, -}; - -static int devfs_fill_super(struct super_block *sb, void *data, int silent) -{ - struct inode *root_inode = NULL; - - if (_devfs_get_root_entry() == NULL) - goto out_no_root; - atomic_set(&fs_info.devfsd_overrun_count, 0); - init_waitqueue_head(&fs_info.devfsd_wait_queue); - init_waitqueue_head(&fs_info.revalidate_wait_queue); - fs_info.sb = sb; - sb->s_fs_info = &fs_info; - sb->s_blocksize = 1024; - sb->s_blocksize_bits = 10; - sb->s_magic = DEVFS_SUPER_MAGIC; - sb->s_op = &devfs_sops; - sb->s_time_gran = 1; - if ((root_inode = _devfs_get_vfs_inode(sb, root_entry, NULL)) == NULL) - goto out_no_root; - sb->s_root = d_alloc_root(root_inode); - if (!sb->s_root) - goto out_no_root; - DPRINTK(DEBUG_S_READ, "(): made devfs ptr: %p\n", sb->s_fs_info); - return 0; - - out_no_root: - PRINTK("(): get root inode failed\n"); - if (root_inode) - iput(root_inode); - return -EINVAL; -} /* End Function devfs_fill_super */ - -static int devfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data, struct vfsmount *mnt) -{ - return get_sb_single(fs_type, flags, data, devfs_fill_super, mnt); -} - -static struct file_system_type devfs_fs_type = { - .name = DEVFS_NAME, - .get_sb = devfs_get_sb, - .kill_sb = kill_anon_super, -}; - -/* File operations for devfsd follow */ - -static ssize_t devfsd_read(struct file *file, char __user *buf, size_t len, - loff_t * ppos) -{ - int done = FALSE; - int ival; - loff_t pos, devname_offset, tlen, rpos; - devfs_handle_t de; - struct devfsd_buf_entry *entry; - struct fs_info *fs_info = file->f_dentry->d_inode->i_sb->s_fs_info; - struct devfsd_notify_struct *info = fs_info->devfsd_info; - DECLARE_WAITQUEUE(wait, current); - - /* Verify the task has grabbed the queue */ - if (fs_info->devfsd_task != current) - return -EPERM; - info->major = 0; - info->minor = 0; - /* Block for a new entry */ - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&fs_info->devfsd_wait_queue, &wait); - while (devfsd_queue_empty(fs_info)) { - fs_info->devfsd_sleeping = TRUE; - wake_up(&fs_info->revalidate_wait_queue); - schedule(); - fs_info->devfsd_sleeping = FALSE; - if (signal_pending(current)) { - remove_wait_queue(&fs_info->devfsd_wait_queue, &wait); - __set_current_state(TASK_RUNNING); - return -EINTR; - } - set_current_state(TASK_INTERRUPTIBLE); - } - remove_wait_queue(&fs_info->devfsd_wait_queue, &wait); - __set_current_state(TASK_RUNNING); - /* Now play with the data */ - ival = atomic_read(&fs_info->devfsd_overrun_count); - info->overrun_count = ival; - entry = fs_info->devfsd_first_event; - info->type = entry->type; - info->mode = entry->mode; - info->uid = entry->uid; - info->gid = entry->gid; - de = entry->de; - if (S_ISCHR(de->mode) || S_ISBLK(de->mode)) { - info->major = MAJOR(de->u.dev); - info->minor = MINOR(de->u.dev); - } - pos = devfs_generate_path(de, info->devname, DEVFS_PATHLEN); - if (pos < 0) - return pos; - info->namelen = DEVFS_PATHLEN - pos - 1; - if (info->mode == 0) - info->mode = de->mode; - devname_offset = info->devname - (char *)info; - rpos = *ppos; - if (rpos < devname_offset) { - /* Copy parts of the header */ - tlen = devname_offset - rpos; - if (tlen > len) - tlen = len; - if (copy_to_user(buf, (char *)info + rpos, tlen)) { - return -EFAULT; - } - rpos += tlen; - buf += tlen; - len -= tlen; - } - if ((rpos >= devname_offset) && (len > 0)) { - /* Copy the name */ - tlen = info->namelen + 1; - if (tlen > len) - tlen = len; - else - done = TRUE; - if (copy_to_user - (buf, info->devname + pos + rpos - devname_offset, tlen)) { - return -EFAULT; - } - rpos += tlen; - } - tlen = rpos - *ppos; - if (done) { - devfs_handle_t parent; - - spin_lock(&fs_info->devfsd_buffer_lock); - fs_info->devfsd_first_event = entry->next; - if (entry->next == NULL) - fs_info->devfsd_last_event = NULL; - spin_unlock(&fs_info->devfsd_buffer_lock); - for (; de != NULL; de = parent) { - parent = de->parent; - devfs_put(de); - } - kmem_cache_free(devfsd_buf_cache, entry); - if (ival > 0) - atomic_sub(ival, &fs_info->devfsd_overrun_count); - *ppos = 0; - } else - *ppos = rpos; - return tlen; -} /* End Function devfsd_read */ - -static int devfsd_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int ival; - struct fs_info *fs_info = inode->i_sb->s_fs_info; - - switch (cmd) { - case DEVFSDIOC_GET_PROTO_REV: - ival = DEVFSD_PROTOCOL_REVISION_KERNEL; - if (copy_to_user((void __user *)arg, &ival, sizeof ival)) - return -EFAULT; - break; - case DEVFSDIOC_SET_EVENT_MASK: - /* Ensure only one reader has access to the queue. This scheme will - work even if the global kernel lock were to be removed, because it - doesn't matter who gets in first, as long as only one gets it */ - if (fs_info->devfsd_task == NULL) { - static DEFINE_SPINLOCK(lock); - - if (!spin_trylock(&lock)) - return -EBUSY; - if (fs_info->devfsd_task != NULL) { /* We lost the race... */ - spin_unlock(&lock); - return -EBUSY; - } - fs_info->devfsd_task = current; - spin_unlock(&lock); - fs_info->devfsd_pgrp = - (process_group(current) == - current->pid) ? process_group(current) : 0; - fs_info->devfsd_file = file; - fs_info->devfsd_info = - kmalloc(sizeof *fs_info->devfsd_info, GFP_KERNEL); - if (!fs_info->devfsd_info) { - devfsd_close(inode, file); - return -ENOMEM; - } - } else if (fs_info->devfsd_task != current) - return -EBUSY; - fs_info->devfsd_event_mask = arg; /* Let the masses come forth */ - break; - case DEVFSDIOC_RELEASE_EVENT_QUEUE: - if (fs_info->devfsd_file != file) - return -EPERM; - return devfsd_close(inode, file); - /*break; */ -#ifdef CONFIG_DEVFS_DEBUG - case DEVFSDIOC_SET_DEBUG_MASK: - if (copy_from_user(&ival, (void __user *)arg, sizeof ival)) - return -EFAULT; - devfs_debug = ival; - break; -#endif - default: - return -ENOIOCTLCMD; - } - return 0; -} /* End Function devfsd_ioctl */ - -static int devfsd_close(struct inode *inode, struct file *file) -{ - struct devfsd_buf_entry *entry, *next; - struct fs_info *fs_info = inode->i_sb->s_fs_info; - - if (fs_info->devfsd_file != file) - return 0; - fs_info->devfsd_event_mask = 0; - fs_info->devfsd_file = NULL; - spin_lock(&fs_info->devfsd_buffer_lock); - entry = fs_info->devfsd_first_event; - fs_info->devfsd_first_event = NULL; - fs_info->devfsd_last_event = NULL; - kfree(fs_info->devfsd_info); - fs_info->devfsd_info = NULL; - spin_unlock(&fs_info->devfsd_buffer_lock); - fs_info->devfsd_pgrp = 0; - fs_info->devfsd_task = NULL; - wake_up(&fs_info->revalidate_wait_queue); - for (; entry; entry = next) { - next = entry->next; - kmem_cache_free(devfsd_buf_cache, entry); - } - return 0; -} /* End Function devfsd_close */ - -#ifdef CONFIG_DEVFS_DEBUG -static ssize_t stat_read(struct file *file, char __user *buf, size_t len, - loff_t * ppos) -{ - ssize_t num; - char txt[80]; - - num = sprintf(txt, "Number of entries: %u number of bytes: %u\n", - stat_num_entries, stat_num_bytes) + 1; - if (*ppos >= num) - return 0; - if (*ppos + len > num) - len = num - *ppos; - if (copy_to_user(buf, txt + *ppos, len)) - return -EFAULT; - *ppos += len; - return len; -} /* End Function stat_read */ -#endif - -static int __init init_devfs_fs(void) -{ - int err; - int major; - struct devfs_entry *devfsd; -#ifdef CONFIG_DEVFS_DEBUG - struct devfs_entry *stat; -#endif - - if (_devfs_get_root_entry() == NULL) - return -ENOMEM; - - printk(KERN_INFO "%s: %s Richard Gooch (rgooch@atnf.csiro.au)\n", - DEVFS_NAME, DEVFS_VERSION); - devfsd_buf_cache = kmem_cache_create("devfsd_event", - sizeof(struct devfsd_buf_entry), - 0, 0, NULL, NULL); - if (!devfsd_buf_cache) - OOPS("(): unable to allocate event slab\n"); -#ifdef CONFIG_DEVFS_DEBUG - devfs_debug = devfs_debug_init; - printk(KERN_INFO "%s: devfs_debug: 0x%0x\n", DEVFS_NAME, devfs_debug); -#endif - printk(KERN_INFO "%s: boot_options: 0x%0x\n", DEVFS_NAME, boot_options); - - /* register special device for devfsd communication */ - major = register_chrdev(0, "devfs", &devfs_fops); - if (major < 0) - return major; - - /* And create the entry for ".devfsd" */ - devfsd = _devfs_alloc_entry(".devfsd", 0, S_IFCHR | S_IRUSR | S_IWUSR); - if (devfsd == NULL) - return -ENOMEM; - devfsd->u.dev = MKDEV(major, 0); - _devfs_append_entry(root_entry, devfsd, NULL); - -#ifdef CONFIG_DEVFS_DEBUG - stat = _devfs_alloc_entry(".stat", 0, S_IFCHR | S_IRUGO); - if (stat == NULL) - return -ENOMEM; - stat->u.dev = MKDEV(major, 1); - _devfs_append_entry(root_entry, stat, NULL); -#endif - - err = register_filesystem(&devfs_fs_type); - return err; -} /* End Function init_devfs_fs */ - -void __init mount_devfs_fs(void) -{ - int err; - - if (!(boot_options & OPTION_MOUNT)) - return; - err = do_mount("none", "/dev", "devfs", 0, NULL); - if (err == 0) - printk(KERN_INFO "Mounted devfs on /dev\n"); - else - PRINTK("(): unable to mount devfs, err: %d\n", err); -} /* End Function mount_devfs_fs */ - -module_init(init_devfs_fs) diff --git a/fs/devfs/util.c b/fs/devfs/util.c deleted file mode 100644 index db06d388c9ac..000000000000 --- a/fs/devfs/util.c +++ /dev/null @@ -1,97 +0,0 @@ -/* devfs (Device FileSystem) utilities. - - Copyright (C) 1999-2002 Richard Gooch - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Richard Gooch may be reached by email at rgooch@atnf.csiro.au - The postal address is: - Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia. - - ChangeLog - - 19991031 Richard Gooch <rgooch@atnf.csiro.au> - Created. - 19991103 Richard Gooch <rgooch@atnf.csiro.au> - Created <_devfs_convert_name> and supported SCSI and IDE CD-ROMs - 20000203 Richard Gooch <rgooch@atnf.csiro.au> - Changed operations pointer type to void *. - 20000621 Richard Gooch <rgooch@atnf.csiro.au> - Changed interface to <devfs_register_series>. - 20000622 Richard Gooch <rgooch@atnf.csiro.au> - Took account of interface change to <devfs_mk_symlink>. - Took account of interface change to <devfs_mk_dir>. - 20010519 Richard Gooch <rgooch@atnf.csiro.au> - Documentation cleanup. - 20010709 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_*alloc_major> and <devfs_*alloc_devnum>. - 20010710 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_*alloc_unique_number>. - 20010730 Richard Gooch <rgooch@atnf.csiro.au> - Documentation typo fix. - 20010806 Richard Gooch <rgooch@atnf.csiro.au> - Made <block_semaphore> and <char_semaphore> private. - 20010813 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bug in <devfs_alloc_unique_number>: limited to 128 numbers - 20010818 Richard Gooch <rgooch@atnf.csiro.au> - Updated major masks up to Linus' "no new majors" proclamation. - Block: were 126 now 122 free, char: were 26 now 19 free. - 20020324 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bug in <devfs_alloc_unique_number>: was clearing beyond - bitfield. - 20020326 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bitfield data type for <devfs_*alloc_devnum>. - Made major bitfield type and initialiser 64 bit safe. - 20020413 Richard Gooch <rgooch@atnf.csiro.au> - Fixed shift warning on 64 bit machines. - 20020428 Richard Gooch <rgooch@atnf.csiro.au> - Copied and used macro for error messages from fs/devfs/base.c - 20021013 Richard Gooch <rgooch@atnf.csiro.au> - Documentation fix. - 20030101 Adam J. Richter <adam@yggdrasil.com> - Eliminate DEVFS_SPECIAL_{CHR,BLK}. Use mode_t instead. - 20030106 Christoph Hellwig <hch@infradead.org> - Rewrite devfs_{,de}alloc_devnum to look like C code. -*/ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/devfs_fs_kernel.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <linux/genhd.h> -#include <linux/bitops.h> - -int devfs_register_tape(const char *name) -{ - char tname[32], dest[64]; - static unsigned int tape_counter; - unsigned int n = tape_counter++; - - sprintf(dest, "../%s", name); - sprintf(tname, "tapes/tape%u", n); - devfs_mk_symlink(tname, dest); - - return n; -} - -EXPORT_SYMBOL(devfs_register_tape); - -void devfs_unregister_tape(int num) -{ - if (num >= 0) - devfs_remove("tapes/tape%u", num); -} - -EXPORT_SYMBOL(devfs_unregister_tape); diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile index 42c7d3878ed0..d713ce6b3e12 100644 --- a/fs/partitions/Makefile +++ b/fs/partitions/Makefile @@ -4,7 +4,6 @@ obj-y := check.o -obj-$(CONFIG_DEVFS_FS) += devfs.o obj-$(CONFIG_ACORN_PARTITION) += acorn.o obj-$(CONFIG_AMIGA_PARTITION) += amiga.o obj-$(CONFIG_ATARI_PARTITION) += atari.o diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 2ef313a96b66..839634026eb5 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -18,10 +18,8 @@ #include <linux/fs.h> #include <linux/kmod.h> #include <linux/ctype.h> -#include <linux/devfs_fs_kernel.h> #include "check.h" -#include "devfs.h" #include "acorn.h" #include "amiga.h" @@ -161,18 +159,11 @@ check_partition(struct gendisk *hd, struct block_device *bdev) if (!state) return NULL; -#ifdef CONFIG_DEVFS_FS - if (hd->devfs_name[0] != '\0') { - printk(KERN_INFO " /dev/%s:", hd->devfs_name); + disk_name(hd, 0, state->name); + printk(KERN_INFO " %s:", state->name); + if (isdigit(state->name[strlen(state->name)-1])) sprintf(state->name, "p"); - } -#endif - else { - disk_name(hd, 0, state->name); - printk(KERN_INFO " %s:", state->name); - if (isdigit(state->name[strlen(state->name)-1])) - sprintf(state->name, "p"); - } + state->limit = hd->minors; i = res = 0; while (!res && check_part[i]) { @@ -328,7 +319,6 @@ void delete_partition(struct gendisk *disk, int part) p->nr_sects = 0; p->ios[0] = p->ios[1] = 0; p->sectors[0] = p->sectors[1] = 0; - devfs_remove("%s/part%d", disk->devfs_name, part); sysfs_remove_link(&p->kobj, "subsystem"); if (p->holder_dir) kobject_unregister(p->holder_dir); @@ -350,10 +340,6 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) p->nr_sects = len; p->partno = part; - devfs_mk_bdev(MKDEV(disk->major, disk->first_minor + part), - S_IFBLK|S_IRUSR|S_IWUSR, - "%s/part%d", disk->devfs_name, part); - if (isdigit(disk->kobj.name[strlen(disk->kobj.name)-1])) snprintf(p->kobj.name,KOBJ_NAME_LEN,"%sp%d",disk->kobj.name,part); else @@ -423,14 +409,8 @@ void register_disk(struct gendisk *disk) disk_sysfs_add_subdirs(disk); /* No minors to use for partitions */ - if (disk->minors == 1) { - if (disk->devfs_name[0] != '\0') - devfs_add_disk(disk); + if (disk->minors == 1) goto exit; - } - - /* always add handle for the whole disk */ - devfs_add_partitioned(disk); /* No such device (e.g., media were just removed) */ if (!get_capacity(disk)) @@ -538,8 +518,6 @@ void del_gendisk(struct gendisk *disk) disk_stat_set_all(disk, 0); disk->stamp = 0; - devfs_remove_disk(disk); - kobject_uevent(&disk->kobj, KOBJ_REMOVE); if (disk->holder_dir) kobject_unregister(disk->holder_dir); diff --git a/fs/partitions/devfs.c b/fs/partitions/devfs.c deleted file mode 100644 index 3f0a780c9cec..000000000000 --- a/fs/partitions/devfs.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * This tries to keep block devices away from devfs as much as possible. - */ -#include <linux/fs.h> -#include <linux/devfs_fs_kernel.h> -#include <linux/vmalloc.h> -#include <linux/genhd.h> -#include <linux/bitops.h> -#include <linux/mutex.h> - - -struct unique_numspace { - u32 num_free; /* Num free in bits */ - u32 length; /* Array length in bytes */ - unsigned long *bits; - struct semaphore mutex; -}; - -static DEFINE_MUTEX(numspace_mutex); - -static int expand_numspace(struct unique_numspace *s) -{ - u32 length; - void *bits; - - if (s->length < 16) - length = 16; - else - length = s->length << 1; - - bits = vmalloc(length); - if (!bits) - return -ENOMEM; - if (s->bits) { - memcpy(bits, s->bits, s->length); - vfree(s->bits); - } - - s->num_free = (length - s->length) << 3; - s->bits = bits; - memset(bits + s->length, 0, length - s->length); - s->length = length; - - return 0; -} - -static int alloc_unique_number(struct unique_numspace *s) -{ - int rval = 0; - - mutex_lock(&numspace_mutex); - if (s->num_free < 1) - rval = expand_numspace(s); - if (!rval) { - rval = find_first_zero_bit(s->bits, s->length << 3); - --s->num_free; - __set_bit(rval, s->bits); - } - mutex_unlock(&numspace_mutex); - - return rval; -} - -static void dealloc_unique_number(struct unique_numspace *s, int number) -{ - int old_val; - - if (number >= 0) { - mutex_lock(&numspace_mutex); - old_val = __test_and_clear_bit(number, s->bits); - if (old_val) - ++s->num_free; - mutex_unlock(&numspace_mutex); - } -} - -static struct unique_numspace disc_numspace; -static struct unique_numspace cdrom_numspace; - -void devfs_add_partitioned(struct gendisk *disk) -{ - char dirname[64], symlink[16]; - - devfs_mk_dir(disk->devfs_name); - devfs_mk_bdev(MKDEV(disk->major, disk->first_minor), - S_IFBLK|S_IRUSR|S_IWUSR, - "%s/disc", disk->devfs_name); - - disk->number = alloc_unique_number(&disc_numspace); - - sprintf(symlink, "discs/disc%d", disk->number); - sprintf(dirname, "../%s", disk->devfs_name); - devfs_mk_symlink(symlink, dirname); - -} - -void devfs_add_disk(struct gendisk *disk) -{ - devfs_mk_bdev(MKDEV(disk->major, disk->first_minor), - (disk->flags & GENHD_FL_CD) ? - S_IFBLK|S_IRUGO|S_IWUGO : - S_IFBLK|S_IRUSR|S_IWUSR, - "%s", disk->devfs_name); - - if (disk->flags & GENHD_FL_CD) { - char dirname[64], symlink[16]; - - disk->number = alloc_unique_number(&cdrom_numspace); - - sprintf(symlink, "cdroms/cdrom%d", disk->number); - sprintf(dirname, "../%s", disk->devfs_name); - devfs_mk_symlink(symlink, dirname); - } -} - -void devfs_remove_disk(struct gendisk *disk) -{ - if (disk->minors != 1) { - devfs_remove("discs/disc%d", disk->number); - dealloc_unique_number(&disc_numspace, disk->number); - devfs_remove("%s/disc", disk->devfs_name); - } - if (disk->flags & GENHD_FL_CD) { - devfs_remove("cdroms/cdrom%d", disk->number); - dealloc_unique_number(&cdrom_numspace, disk->number); - } - devfs_remove(disk->devfs_name); -} - - diff --git a/fs/partitions/devfs.h b/fs/partitions/devfs.h deleted file mode 100644 index 176118b4e492..000000000000 --- a/fs/partitions/devfs.h +++ /dev/null @@ -1,10 +0,0 @@ - -#ifdef CONFIG_DEVFS_FS -void devfs_add_disk(struct gendisk *dev); -void devfs_add_partitioned(struct gendisk *dev); -void devfs_remove_disk(struct gendisk *dev); -#else -# define devfs_add_disk(disk) do { } while (0) -# define devfs_add_partitioned(disk) do { } while (0) -# define devfs_remove_disk(disk) do { } while (0) -#endif diff --git a/include/asm-alpha/socket.h b/include/asm-alpha/socket.h index b5193229132a..d22ab97ea72e 100644 --- a/include/asm-alpha/socket.h +++ b/include/asm-alpha/socket.h @@ -51,6 +51,7 @@ #define SCM_TIMESTAMP SO_TIMESTAMP #define SO_PEERSEC 30 +#define SO_PASSSEC 34 /* Security levels - as per NRL IPv6 - don't actually do anything */ #define SO_SECURITY_AUTHENTICATION 19 diff --git a/include/asm-arm/socket.h b/include/asm-arm/socket.h index 3c51da6438c9..19f7df702b06 100644 --- a/include/asm-arm/socket.h +++ b/include/asm-arm/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-arm26/socket.h b/include/asm-arm26/socket.h index 3c51da6438c9..19f7df702b06 100644 --- a/include/asm-arm26/socket.h +++ b/include/asm-arm26/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-cris/socket.h b/include/asm-cris/socket.h index 8b1da3e58c55..01cfdf1d6d33 100644 --- a/include/asm-cris/socket.h +++ b/include/asm-cris/socket.h @@ -50,6 +50,7 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-frv/socket.h b/include/asm-frv/socket.h index 7177f8b9817c..31db18fc871f 100644 --- a/include/asm-frv/socket.h +++ b/include/asm-frv/socket.h @@ -48,6 +48,7 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-h8300/socket.h b/include/asm-h8300/socket.h index d98cf85bafc1..ebc830fee0d0 100644 --- a/include/asm-h8300/socket.h +++ b/include/asm-h8300/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-i386/socket.h b/include/asm-i386/socket.h index 802ae76195b7..5755d57c4e95 100644 --- a/include/asm-i386/socket.h +++ b/include/asm-i386/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-ia64/socket.h b/include/asm-ia64/socket.h index a255006fb7b5..d638ef3d50c3 100644 --- a/include/asm-ia64/socket.h +++ b/include/asm-ia64/socket.h @@ -57,5 +57,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_IA64_SOCKET_H */ diff --git a/include/asm-m32r/socket.h b/include/asm-m32r/socket.h index 8b6680f223c0..acdf748fcdc8 100644 --- a/include/asm-m32r/socket.h +++ b/include/asm-m32r/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_M32R_SOCKET_H */ diff --git a/include/asm-m68k/socket.h b/include/asm-m68k/socket.h index f578ca4b776a..a5966ec005ae 100644 --- a/include/asm-m68k/socket.h +++ b/include/asm-m68k/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-mips/socket.h b/include/asm-mips/socket.h index 0bb31e5aaca6..36ebe4e186a7 100644 --- a/include/asm-mips/socket.h +++ b/include/asm-mips/socket.h @@ -69,6 +69,7 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ #define SO_PEERSEC 30 #define SO_SNDBUFFORCE 31 #define SO_RCVBUFFORCE 33 +#define SO_PASSSEC 34 #ifdef __KERNEL__ diff --git a/include/asm-parisc/socket.h b/include/asm-parisc/socket.h index 1bf54dc53c10..ce2eae1708b5 100644 --- a/include/asm-parisc/socket.h +++ b/include/asm-parisc/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 0x401c #define SO_PEERSEC 0x401d +#define SO_PASSSEC 0x401e #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-powerpc/socket.h b/include/asm-powerpc/socket.h index e4b8177d4acc..c8b1da50e72d 100644 --- a/include/asm-powerpc/socket.h +++ b/include/asm-powerpc/socket.h @@ -55,5 +55,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_POWERPC_SOCKET_H */ diff --git a/include/asm-ppc/ocp.h b/include/asm-ppc/ocp.h index 3be5d760ffcd..16dbc7d17450 100644 --- a/include/asm-ppc/ocp.h +++ b/include/asm-ppc/ocp.h @@ -26,7 +26,6 @@ #include <linux/init.h> #include <linux/list.h> -#include <linux/devfs_fs_kernel.h> #include <linux/device.h> #include <asm/mmu.h> diff --git a/include/asm-s390/socket.h b/include/asm-s390/socket.h index 15a5298c8744..1778a49a74c5 100644 --- a/include/asm-s390/socket.h +++ b/include/asm-s390/socket.h @@ -56,5 +56,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-sh/socket.h b/include/asm-sh/socket.h index 553904ff9336..ca70362eb563 100644 --- a/include/asm-sh/socket.h +++ b/include/asm-sh/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* __ASM_SH_SOCKET_H */ diff --git a/include/asm-sparc/of_device.h b/include/asm-sparc/of_device.h index 4816d102f918..80ea31f6e17f 100644 --- a/include/asm-sparc/of_device.h +++ b/include/asm-sparc/of_device.h @@ -4,10 +4,12 @@ #include <linux/device.h> #include <linux/mod_devicetable.h> +#include <asm/openprom.h> #include <asm/prom.h> extern struct bus_type ebus_bus_type; extern struct bus_type sbus_bus_type; +extern struct bus_type of_bus_type; /* * The of_device is a kind of "base class" that is a superset of @@ -16,11 +18,25 @@ extern struct bus_type sbus_bus_type; */ struct of_device { - struct device_node *node; /* OF device node */ - struct device dev; /* Generic device interface */ + struct device_node *node; + struct device dev; + struct resource resource[PROMREG_MAX]; + unsigned int irqs[PROMINTR_MAX]; + int num_irqs; + + void *sysdata; + + int slot; + int portid; + int clock_freq; }; #define to_of_device(d) container_of(d, struct of_device, dev) +extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name); +extern void of_iounmap(void __iomem *base, unsigned long size); + +extern struct of_device *of_find_device_by_node(struct device_node *); + extern const struct of_device_id *of_match_device( const struct of_device_id *matches, const struct of_device *dev); diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h index f9cf44c07164..86c13dccea3d 100644 --- a/include/asm-sparc/prom.h +++ b/include/asm-sparc/prom.h @@ -25,11 +25,6 @@ typedef u32 phandle; typedef u32 ihandle; -struct interrupt_info { - int line; - int sense; /* +ve/-ve logic, edge or level, etc. */ -}; - struct property { char *name; int length; @@ -43,9 +38,6 @@ struct device_node { char *name; char *type; phandle node; - phandle linux_phandle; - int n_intrs; - struct interrupt_info *intrs; char *path_component_name; char *full_name; @@ -69,6 +61,8 @@ struct device_node { #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) +#define OF_BAD_ADDR ((u64)-1) + static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de) { dn->pde = de; @@ -101,6 +95,8 @@ extern int of_set_property(struct device_node *node, const char *name, void *val extern int of_getintprop_default(struct device_node *np, const char *name, int def); +extern int of_n_addr_cells(struct device_node *np); +extern int of_n_size_cells(struct device_node *np); extern void prom_build_devicetree(void); diff --git a/include/asm-sparc/socket.h b/include/asm-sparc/socket.h index 4e0ce3a35ea9..f6c4e5baf3f7 100644 --- a/include/asm-sparc/socket.h +++ b/include/asm-sparc/socket.h @@ -48,6 +48,7 @@ #define SCM_TIMESTAMP SO_TIMESTAMP #define SO_PEERSEC 0x001e +#define SO_PASSSEC 0x001f /* Security levels - as per NRL IPv6 - don't actually do anything */ #define SO_SECURITY_AUTHENTICATION 0x5001 diff --git a/include/asm-sparc64/of_device.h b/include/asm-sparc64/of_device.h index 024088ef9d27..a62c7b997d66 100644 --- a/include/asm-sparc64/of_device.h +++ b/include/asm-sparc64/of_device.h @@ -4,11 +4,13 @@ #include <linux/device.h> #include <linux/mod_devicetable.h> +#include <asm/openprom.h> #include <asm/prom.h> extern struct bus_type isa_bus_type; extern struct bus_type ebus_bus_type; extern struct bus_type sbus_bus_type; +extern struct bus_type of_bus_type; /* * The of_device is a kind of "base class" that is a superset of @@ -17,11 +19,25 @@ extern struct bus_type sbus_bus_type; */ struct of_device { - struct device_node *node; /* OF device node */ - struct device dev; /* Generic device interface */ + struct device_node *node; + struct device dev; + struct resource resource[PROMREG_MAX]; + unsigned int irqs[PROMINTR_MAX]; + int num_irqs; + + void *sysdata; + + int slot; + int portid; + int clock_freq; }; #define to_of_device(d) container_of(d, struct of_device, dev) +extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name); +extern void of_iounmap(void __iomem *base, unsigned long size); + +extern struct of_device *of_find_device_by_node(struct device_node *); + extern const struct of_device_id *of_match_device( const struct of_device_id *matches, const struct of_device *dev); diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index cebe80b1da6c..dcfa7629358c 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -16,6 +16,7 @@ #include <asm/page.h> #include <asm/oplib.h> #include <asm/prom.h> +#include <asm/of_device.h> #include <asm/iommu.h> /* The abstraction used here is that there are PCI controllers, @@ -209,7 +210,6 @@ struct pci_controller_info { /* Operations which are controller specific. */ void (*scan_bus)(struct pci_controller_info *); - unsigned int (*irq_build)(struct pci_pbm_info *, struct pci_dev *, unsigned int); void (*base_address_update)(struct pci_dev *, int); void (*resource_adjust)(struct pci_dev *, struct resource *, struct resource *); @@ -217,8 +217,6 @@ struct pci_controller_info { struct pci_ops *pci_ops; unsigned int pci_first_busno; unsigned int pci_last_busno; - - void *starfire_cookie; }; /* PCI devices which are not bridges have this placed in their pci_dev @@ -228,6 +226,7 @@ struct pci_controller_info { struct pcidev_cookie { struct pci_pbm_info *pbm; struct device_node *prom_node; + struct of_device *op; struct linux_prom_pci_registers prom_regs[PROMREG_MAX]; int num_prom_regs; struct linux_prom_pci_registers prom_assignments[PROMREG_MAX]; diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h index 265614d497c4..99671ed6625d 100644 --- a/include/asm-sparc64/prom.h +++ b/include/asm-sparc64/prom.h @@ -25,11 +25,6 @@ typedef u32 phandle; typedef u32 ihandle; -struct interrupt_info { - int line; - int sense; /* +ve/-ve logic, edge or level, etc. */ -}; - struct property { char *name; int length; @@ -39,13 +34,11 @@ struct property { unsigned int unique_id; }; +struct of_irq_controller; struct device_node { char *name; char *type; phandle node; - phandle linux_phandle; - int n_intrs; - struct interrupt_info *intrs; char *path_component_name; char *full_name; @@ -61,6 +54,13 @@ struct device_node { unsigned long _flags; void *data; unsigned int unique_id; + + struct of_irq_controller *irq_trans; +}; + +struct of_irq_controller { + unsigned int (*irq_build)(struct device_node *, unsigned int, void *); + void *data; }; /* flag descriptions */ @@ -69,6 +69,8 @@ struct device_node { #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) +#define OF_BAD_ADDR ((u64)-1) + static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de) { dn->pde = de; @@ -101,6 +103,8 @@ extern int of_set_property(struct device_node *node, const char *name, void *val extern int of_getintprop_default(struct device_node *np, const char *name, int def); +extern int of_n_addr_cells(struct device_node *np); +extern int of_n_size_cells(struct device_node *np); extern void prom_build_devicetree(void); diff --git a/include/asm-sparc64/sbus.h b/include/asm-sparc64/sbus.h index 56ee985e4605..7efd49d31bb8 100644 --- a/include/asm-sparc64/sbus.h +++ b/include/asm-sparc64/sbus.h @@ -80,7 +80,6 @@ struct sbus_bus { int num_sbus_ranges; int portid; - void *starfire_cookie; }; #define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev) diff --git a/include/asm-sparc64/socket.h b/include/asm-sparc64/socket.h index 59987dad3359..754d46a50af3 100644 --- a/include/asm-sparc64/socket.h +++ b/include/asm-sparc64/socket.h @@ -48,6 +48,7 @@ #define SCM_TIMESTAMP SO_TIMESTAMP #define SO_PEERSEC 0x001e +#define SO_PASSSEC 0x001f /* Security levels - as per NRL IPv6 - don't actually do anything */ #define SO_SECURITY_AUTHENTICATION 0x5001 diff --git a/include/asm-sparc64/starfire.h b/include/asm-sparc64/starfire.h index b606cb2b32a8..48b50b5e35b0 100644 --- a/include/asm-sparc64/starfire.h +++ b/include/asm-sparc64/starfire.h @@ -14,7 +14,7 @@ extern int this_is_starfire; extern void check_if_starfire(void); extern void starfire_cpu_setup(void); extern int starfire_hard_smp_processor_id(void); -extern void *starfire_hookup(int); +extern void starfire_hookup(int); extern unsigned int starfire_translate(unsigned long imap, unsigned int upaid); #endif diff --git a/include/asm-v850/socket.h b/include/asm-v850/socket.h index 0240d366a0a4..0dfe55ac2ef2 100644 --- a/include/asm-v850/socket.h +++ b/include/asm-v850/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* __V850_SOCKET_H__ */ diff --git a/include/asm-x86_64/socket.h b/include/asm-x86_64/socket.h index f2cdbeae5d5b..b46702607933 100644 --- a/include/asm-x86_64/socket.h +++ b/include/asm-x86_64/socket.h @@ -48,5 +48,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _ASM_SOCKET_H */ diff --git a/include/asm-xtensa/socket.h b/include/asm-xtensa/socket.h index 00f83f3a6d72..971d231be60e 100644 --- a/include/asm-xtensa/socket.h +++ b/include/asm-xtensa/socket.h @@ -59,5 +59,6 @@ #define SO_ACCEPTCONN 30 #define SO_PEERSEC 31 +#define SO_PASSSEC 34 #endif /* _XTENSA_SOCKET_H */ diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h index 1eb238affb12..41788a31c438 100644 --- a/include/linux/atmdev.h +++ b/include/linux/atmdev.h @@ -7,6 +7,7 @@ #define LINUX_ATMDEV_H +#include <linux/device.h> #include <linux/atmapi.h> #include <linux/atm.h> #include <linux/atmioc.h> @@ -358,6 +359,7 @@ struct atm_dev { struct proc_dir_entry *proc_entry; /* proc entry */ char *proc_name; /* proc entry name */ #endif + struct class_device class_dev; /* sysfs class device */ struct list_head dev_list; /* linkage */ }; @@ -459,7 +461,7 @@ static inline void atm_dev_put(struct atm_dev *dev) BUG_ON(!test_bit(ATM_DF_REMOVED, &dev->flags)); if (dev->ops->dev_close) dev->ops->dev_close(dev); - kfree(dev); + class_device_put(&dev->class_dev); } } diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index 917d62e41480..269d000bb2a3 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h @@ -567,11 +567,6 @@ COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER) COMPATIBLE_IOCTL(AUTOFS_IOC_ASKREGHOST) COMPATIBLE_IOCTL(AUTOFS_IOC_TOGGLEREGHOST) COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT) -/* DEVFS */ -COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV) -COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK) -COMPATIBLE_IOCTL(DEVFSDIOC_RELEASE_EVENT_QUEUE) -COMPATIBLE_IOCTL(DEVFSDIOC_SET_DEBUG_MASK) /* Raw devices */ COMPATIBLE_IOCTL(RAW_SETBIND) COMPATIBLE_IOCTL(RAW_GETBIND) diff --git a/include/linux/devfs_fs.h b/include/linux/devfs_fs.h deleted file mode 100644 index de236f431877..000000000000 --- a/include/linux/devfs_fs.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _LINUX_DEVFS_FS_H -#define _LINUX_DEVFS_FS_H - -#include <linux/ioctl.h> - -#define DEVFSD_PROTOCOL_REVISION_KERNEL 5 - -#define DEVFSD_IOCTL_BASE 'd' - -/* These are the various ioctls */ -#define DEVFSDIOC_GET_PROTO_REV _IOR(DEVFSD_IOCTL_BASE, 0, int) -#define DEVFSDIOC_SET_EVENT_MASK _IOW(DEVFSD_IOCTL_BASE, 2, int) -#define DEVFSDIOC_RELEASE_EVENT_QUEUE _IOW(DEVFSD_IOCTL_BASE, 3, int) -#define DEVFSDIOC_SET_DEBUG_MASK _IOW(DEVFSD_IOCTL_BASE, 4, int) - -#define DEVFSD_NOTIFY_REGISTERED 0 -#define DEVFSD_NOTIFY_UNREGISTERED 1 -#define DEVFSD_NOTIFY_ASYNC_OPEN 2 -#define DEVFSD_NOTIFY_CLOSE 3 -#define DEVFSD_NOTIFY_LOOKUP 4 -#define DEVFSD_NOTIFY_CHANGE 5 -#define DEVFSD_NOTIFY_CREATE 6 -#define DEVFSD_NOTIFY_DELETE 7 - -#define DEVFS_PATHLEN 1024 /* Never change this otherwise the - binary interface will change */ - -struct devfsd_notify_struct { /* Use native C types to ensure same types in kernel and user space */ - unsigned int type; /* DEVFSD_NOTIFY_* value */ - unsigned int mode; /* Mode of the inode or device entry */ - unsigned int major; /* Major number of device entry */ - unsigned int minor; /* Minor number of device entry */ - unsigned int uid; /* Uid of process, inode or device entry */ - unsigned int gid; /* Gid of process, inode or device entry */ - unsigned int overrun_count; /* Number of lost events */ - unsigned int namelen; /* Number of characters not including '\0' */ - /* The device name MUST come last */ - char devname[DEVFS_PATHLEN]; /* This will be '\0' terminated */ -}; - -#endif /* _LINUX_DEVFS_FS_H */ diff --git a/include/linux/devfs_fs_kernel.h b/include/linux/devfs_fs_kernel.h deleted file mode 100644 index 0d74a6f22abc..000000000000 --- a/include/linux/devfs_fs_kernel.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef _LINUX_DEVFS_FS_KERNEL_H -#define _LINUX_DEVFS_FS_KERNEL_H - -#include <linux/fs.h> -#include <linux/spinlock.h> -#include <linux/types.h> - -#include <asm/semaphore.h> - -#define DEVFS_SUPER_MAGIC 0x1373 - -#ifdef CONFIG_DEVFS_FS -extern int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...) - __attribute__ ((format(printf, 3, 4))); -extern int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...) - __attribute__ ((format(printf, 3, 4))); -extern int devfs_mk_symlink(const char *name, const char *link); -extern int devfs_mk_dir(const char *fmt, ...) - __attribute__ ((format(printf, 1, 2))); -extern void devfs_remove(const char *fmt, ...) - __attribute__ ((format(printf, 1, 2))); -extern int devfs_register_tape(const char *name); -extern void devfs_unregister_tape(int num); -extern void mount_devfs_fs(void); -#else /* CONFIG_DEVFS_FS */ -static inline int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...) -{ - return 0; -} -static inline int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...) -{ - return 0; -} -static inline int devfs_mk_symlink(const char *name, const char *link) -{ - return 0; -} -static inline int devfs_mk_dir(const char *fmt, ...) -{ - return 0; -} -static inline void devfs_remove(const char *fmt, ...) -{ -} -static inline int devfs_register_tape(const char *name) -{ - return -1; -} -static inline void devfs_unregister_tape(int num) -{ -} -static inline void mount_devfs_fs(void) -{ - return; -} -#endif /* CONFIG_DEVFS_FS */ -#endif /* _LINUX_DEVFS_FS_KERNEL_H */ diff --git a/include/linux/fb.h b/include/linux/fb.h index 07a08e92bc73..b45928f5c63f 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -380,7 +380,6 @@ struct fb_cursor { #include <linux/tty.h> #include <linux/device.h> #include <linux/workqueue.h> -#include <linux/devfs_fs_kernel.h> #include <linux/notifier.h> #include <linux/list.h> #include <asm/io.h> diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 3498a0c68184..e4af57e87c17 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -112,8 +112,6 @@ struct gendisk { sector_t capacity; int flags; - char devfs_name[64]; /* devfs crap */ - int number; /* more of the same */ struct device *driverfs_dev; struct kobject kobj; struct kobject *holder_dir; diff --git a/include/linux/ide.h b/include/linux/ide.h index 0c100168c0cf..285316c836b5 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -552,7 +552,6 @@ typedef struct ide_drive_s { struct hd_driveid *id; /* drive model identification info */ struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ struct ide_settings_s *settings;/* /proc/ide/ drive settings */ - char devfs_name[64]; /* devfs crap */ struct hwif_s *hwif; /* actually (ide_hwif_t *) */ diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index 5b584dafb5a6..b03cfb91e228 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -40,7 +40,6 @@ struct miscdevice { struct list_head list; struct device *dev; struct class_device *class; - char devfs_name[64]; }; extern int misc_register(struct miscdevice * misc); diff --git a/include/linux/net.h b/include/linux/net.h index 385e68f5bd93..b20c53c74413 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -61,6 +61,7 @@ typedef enum { #define SOCK_ASYNC_WAITDATA 1 #define SOCK_NOSPACE 2 #define SOCK_PASSCRED 3 +#define SOCK_PASSSEC 4 #ifndef ARCH_HAS_SOCKET_TYPES /** diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 03cd7551a7a1..aa2d3c12c4d8 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -315,6 +315,8 @@ struct net_device #define NETIF_F_GSO_SHIFT 16 #define NETIF_F_TSO (SKB_GSO_TCPV4 << NETIF_F_GSO_SHIFT) #define NETIF_F_UFO (SKB_GSO_UDPV4 << NETIF_F_GSO_SHIFT) +#define NETIF_F_GSO_ROBUST (SKB_GSO_DODGY << NETIF_F_GSO_SHIFT) +#define NETIF_F_TSO_ECN (SKB_GSO_TCPV4_ECN << NETIF_F_GSO_SHIFT) #define NETIF_F_GEN_CSUM (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM) #define NETIF_F_ALL_CSUM (NETIF_F_IP_CSUM | NETIF_F_GEN_CSUM) @@ -543,7 +545,8 @@ struct packet_type { struct net_device *, struct packet_type *, struct net_device *); - struct sk_buff *(*gso_segment)(struct sk_buff *skb, int sg); + struct sk_buff *(*gso_segment)(struct sk_buff *skb, + int features); void *af_packet_priv; struct list_head list; }; @@ -968,7 +971,7 @@ extern int netdev_max_backlog; extern int weight_p; extern int netdev_set_master(struct net_device *dev, struct net_device *master); extern int skb_checksum_help(struct sk_buff *skb, int inward); -extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, int sg); +extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features); #ifdef CONFIG_BUG extern void netdev_rx_csum_fault(struct net_device *dev); #else @@ -988,11 +991,16 @@ extern void dev_seq_stop(struct seq_file *seq, void *v); extern void linkwatch_run_queue(void); +static inline int skb_gso_ok(struct sk_buff *skb, int features) +{ + int feature = skb_shinfo(skb)->gso_size ? + skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT : 0; + return (features & feature) == feature; +} + static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb) { - int feature = skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT; - return skb_shinfo(skb)->gso_size && - (dev->features & feature) != feature; + return !skb_gso_ok(skb, dev->features); } #endif /* __KERNEL__ */ diff --git a/include/linux/security.h b/include/linux/security.h index 51805806f974..c7ea15716dce 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -67,7 +67,7 @@ struct xfrm_state; struct xfrm_user_sec_ctx; extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); -extern int cap_netlink_recv(struct sk_buff *skb); +extern int cap_netlink_recv(struct sk_buff *skb, int cap); /* * Values used in the task_security_ops calls @@ -656,6 +656,7 @@ struct swap_info_struct; * Check permission before processing the received netlink message in * @skb. * @skb contains the sk_buff structure for the netlink message. + * @cap indicates the capability required * Return 0 if permission is granted. * * Security hooks for Unix domain networking. @@ -1266,7 +1267,7 @@ struct security_operations { struct sembuf * sops, unsigned nsops, int alter); int (*netlink_send) (struct sock * sk, struct sk_buff * skb); - int (*netlink_recv) (struct sk_buff * skb); + int (*netlink_recv) (struct sk_buff * skb, int cap); /* allow module stacking */ int (*register_security) (const char *name, @@ -2032,9 +2033,9 @@ static inline int security_netlink_send(struct sock *sk, struct sk_buff * skb) return security_ops->netlink_send(sk, skb); } -static inline int security_netlink_recv(struct sk_buff * skb) +static inline int security_netlink_recv(struct sk_buff * skb, int cap) { - return security_ops->netlink_recv(skb); + return security_ops->netlink_recv(skb, cap); } /* prototypes */ @@ -2670,9 +2671,9 @@ static inline int security_netlink_send (struct sock *sk, struct sk_buff *skb) return cap_netlink_send (sk, skb); } -static inline int security_netlink_recv (struct sk_buff *skb) +static inline int security_netlink_recv (struct sk_buff *skb, int cap) { - return cap_netlink_recv (skb); + return cap_netlink_recv (skb, cap); } static inline struct dentry *securityfs_create_dir(const char *name, diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 951c4e858274..fc1104a2cfa9 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -336,7 +336,6 @@ struct uart_driver { struct module *owner; const char *driver_name; const char *dev_name; - const char *devfs_name; int major; int minor; int nr; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 16eef03ce0eb..59918be91d0a 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -172,6 +172,12 @@ enum { enum { SKB_GSO_TCPV4 = 1 << 0, SKB_GSO_UDPV4 = 1 << 1, + + /* This indicates the skb is from an untrusted source. */ + SKB_GSO_DODGY = 1 << 2, + + /* This indicates the tcp segment has CWR set. */ + SKB_GSO_TCPV4_ECN = 1 << 3, }; /** @@ -1298,8 +1304,7 @@ extern void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to); extern void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len); -extern void skb_release_data(struct sk_buff *skb); -extern struct sk_buff *skb_segment(struct sk_buff *skb, int sg); +extern struct sk_buff *skb_segment(struct sk_buff *skb, int features); static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, int len, void *buffer) diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index b368b296d035..58c961c9e170 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -157,7 +157,6 @@ struct tty_driver { struct cdev cdev; struct module *owner; const char *driver_name; - const char *devfs_name; const char *name; int name_base; /* offset of printed name */ int major; /* major device number */ @@ -242,8 +241,15 @@ void tty_set_operations(struct tty_driver *driver, struct tty_operations *op); * is also a promise, if the above case is true, not to signal * overruns, either.) * - * TTY_DRIVER_NO_DEVFS --- if set, do not create devfs entries. This - * is only used by tty_register_driver(). + * TTY_DRIVER_DYNAMIC_DEV --- if set, the individual tty devices need + * to be registered with a call to tty_register_driver() when the + * device is found in the system and unregistered with a call to + * tty_unregister_device() so the devices will be show up + * properly in sysfs. If not set, driver->num entries will be + * created by the tty core in sysfs when tty_register_driver() is + * called. This is to be used by drivers that have tty devices + * that can appear and disappear while the main tty driver is + * registered with the tty core. * * TTY_DRIVER_DEVPTS_MEM -- don't use the standard arrays, instead * use dynamic memory keyed through the devpts filesystem. This @@ -252,7 +258,7 @@ void tty_set_operations(struct tty_driver *driver, struct tty_operations *op); #define TTY_DRIVER_INSTALLED 0x0001 #define TTY_DRIVER_RESET_TERMIOS 0x0002 #define TTY_DRIVER_REAL_RAW 0x0004 -#define TTY_DRIVER_NO_DEVFS 0x0008 +#define TTY_DRIVER_DYNAMIC_DEV 0x0008 #define TTY_DRIVER_DEVPTS_MEM 0x0010 /* tty driver types */ diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index a1b473190e65..62dae1a8c441 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -314,7 +314,6 @@ void *priv; /* for videodev.c intenal usage -- please don't touch */ int users; /* video_exclusive_{open|close} ... */ struct mutex lock; /* ... helper function uses these */ - char devfs_name[64]; /* devfs */ struct class_device class_dev; /* sysfs */ }; diff --git a/include/net/af_unix.h b/include/net/af_unix.h index 795f81f9ec7f..5ba72d95280c 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -53,10 +53,16 @@ struct unix_address { struct unix_skb_parms { struct ucred creds; /* Skb credentials */ struct scm_fp_list *fp; /* Passed files */ +#ifdef CONFIG_SECURITY_NETWORK + char *secdata; /* Security context */ + u32 seclen; /* Security length */ +#endif }; #define UNIXCB(skb) (*(struct unix_skb_parms*)&((skb)->cb)) #define UNIXCREDS(skb) (&UNIXCB((skb)).creds) +#define UNIXSECDATA(skb) (&UNIXCB((skb)).secdata) +#define UNIXSECLEN(skb) (&UNIXCB((skb)).seclen) #define unix_state_rlock(s) spin_lock(&unix_sk(s)->lock) #define unix_state_runlock(s) spin_unlock(&unix_sk(s)->lock) diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 75b5b9333fc7..1925c65e617b 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -169,17 +169,23 @@ psched_tod_diff(int delta_sec, int bound) #define PSCHED_TADD2(tv, delta, tv_res) \ ({ \ - int __delta = (tv).tv_usec + (delta); \ - (tv_res).tv_sec = (tv).tv_sec; \ - if (__delta > USEC_PER_SEC) { (tv_res).tv_sec++; __delta -= USEC_PER_SEC; } \ + int __delta = (delta); \ + (tv_res) = (tv); \ + while(__delta >= USEC_PER_SEC){ \ + (tv_res).tv_sec++; \ + __delta -= USEC_PER_SEC; \ + } \ (tv_res).tv_usec = __delta; \ }) #define PSCHED_TADD(tv, delta) \ ({ \ - (tv).tv_usec += (delta); \ - if ((tv).tv_usec > USEC_PER_SEC) { (tv).tv_sec++; \ - (tv).tv_usec -= USEC_PER_SEC; } \ + int __delta = (delta); \ + while(__delta >= USEC_PER_SEC){ \ + (tv).tv_sec++; \ + __delta -= USEC_PER_SEC; \ + } \ + (tv).tv_usec = __delta; \ }) /* Set/check that time is in the "past perfect"; diff --git a/include/net/protocol.h b/include/net/protocol.h index 3b6dc15c68a5..40b6b9c9973f 100644 --- a/include/net/protocol.h +++ b/include/net/protocol.h @@ -36,7 +36,8 @@ struct net_protocol { int (*handler)(struct sk_buff *skb); void (*err_handler)(struct sk_buff *skb, u32 info); - struct sk_buff *(*gso_segment)(struct sk_buff *skb, int sg); + struct sk_buff *(*gso_segment)(struct sk_buff *skb, + int features); int no_policy; }; diff --git a/include/net/scm.h b/include/net/scm.h index 540619cb7160..02daa097cdcd 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -19,6 +19,10 @@ struct scm_cookie { struct ucred creds; /* Skb credentials */ struct scm_fp_list *fp; /* Passed files */ +#ifdef CONFIG_SECURITY_NETWORK + char *secdata; /* Security context */ + u32 seclen; /* Security length */ +#endif unsigned long seq; /* Connection seqno */ }; @@ -48,6 +52,17 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, return __scm_send(sock, msg, scm); } +#ifdef CONFIG_SECURITY_NETWORK +static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) +{ + if (test_bit(SOCK_PASSSEC, &sock->flags) && scm->secdata != NULL) + put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, scm->seclen, scm->secdata); +} +#else +static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) +{ } +#endif /* CONFIG_SECURITY_NETWORK */ + static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm, int flags) { @@ -62,6 +77,8 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, if (test_bit(SOCK_PASSCRED, &sock->flags)) put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds); + scm_passec(sock, msg, scm); + if (!scm->fp) return; diff --git a/include/net/sock.h b/include/net/sock.h index 2d8d6adf1616..7136bae48c2f 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -383,7 +383,6 @@ enum sock_flags { SOCK_USE_WRITE_QUEUE, /* whether to call sk->sk_write_space in sock_wfree */ SOCK_DBG, /* %SO_DEBUG setting */ SOCK_RCVTSTAMP, /* %SO_TIMESTAMP setting */ - SOCK_NO_LARGESEND, /* whether to sent large segments or not */ SOCK_LOCALROUTE, /* route locally only, %SO_DONTROUTE setting */ SOCK_QUEUE_SHRUNK, /* write queue has been shrunk recently */ }; @@ -1033,7 +1032,7 @@ static inline void sk_setup_caps(struct sock *sk, struct dst_entry *dst) if (sk->sk_route_caps & NETIF_F_GSO) sk->sk_route_caps |= NETIF_F_TSO; if (sk->sk_route_caps & NETIF_F_TSO) { - if (sock_flag(sk, SOCK_NO_LARGESEND) || dst->header_len) + if (dst->header_len) sk->sk_route_caps &= ~NETIF_F_TSO; else sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM; diff --git a/include/net/tcp.h b/include/net/tcp.h index ca3d38dfc00b..624921e76332 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1086,7 +1086,7 @@ extern struct request_sock_ops tcp_request_sock_ops; extern int tcp_v4_destroy_sock(struct sock *sk); -extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg); +extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features); #ifdef CONFIG_PROC_FS extern int tcp4_proc_init(void); diff --git a/include/net/tcp_ecn.h b/include/net/tcp_ecn.h index c6b84397448d..7bb366f70934 100644 --- a/include/net/tcp_ecn.h +++ b/include/net/tcp_ecn.h @@ -31,10 +31,9 @@ static inline void TCP_ECN_send_syn(struct sock *sk, struct tcp_sock *tp, struct sk_buff *skb) { tp->ecn_flags = 0; - if (sysctl_tcp_ecn && !(sk->sk_route_caps & NETIF_F_TSO)) { + if (sysctl_tcp_ecn) { TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ECE|TCPCB_FLAG_CWR; tp->ecn_flags = TCP_ECN_OK; - sock_set_flag(sk, SOCK_NO_LARGESEND); } } @@ -56,6 +55,9 @@ static inline void TCP_ECN_send(struct sock *sk, struct tcp_sock *tp, if (tp->ecn_flags&TCP_ECN_QUEUE_CWR) { tp->ecn_flags &= ~TCP_ECN_QUEUE_CWR; skb->h.th->cwr = 1; + if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) + skb_shinfo(skb)->gso_type |= + SKB_GSO_TCPV4_ECN; } } else { /* ACK or retransmitted segment: clear ECT|CE */ diff --git a/init/Makefile b/init/Makefile index a2300078f2b7..633a268d270d 100644 --- a/init/Makefile +++ b/init/Makefile @@ -6,7 +6,6 @@ obj-y := main.o version.o mounts.o initramfs.o obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o mounts-y := do_mounts.o -mounts-$(CONFIG_DEVFS_FS) += do_mounts_devfs.o mounts-$(CONFIG_BLK_DEV_RAM) += do_mounts_rd.o mounts-$(CONFIG_BLK_DEV_INITRD) += do_mounts_initrd.o mounts-$(CONFIG_BLK_DEV_MD) += do_mounts_md.o diff --git a/init/do_mounts.c b/init/do_mounts.c index 21b3b8f33a72..94aeec7aa917 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -325,7 +325,7 @@ static int __init mount_nfs_root(void) { void *data = nfs_root_data(); - create_dev("/dev/root", ROOT_DEV, NULL); + create_dev("/dev/root", ROOT_DEV); if (data && do_mount_root("/dev/root", "nfs", root_mountflags, data) == 0) return 1; @@ -386,7 +386,7 @@ void __init mount_root(void) change_floppy("root floppy"); } #endif - create_dev("/dev/root", ROOT_DEV, root_device_name); + create_dev("/dev/root", ROOT_DEV); mount_block_root("/dev/root", root_mountflags); } @@ -397,8 +397,6 @@ void __init prepare_namespace(void) { int is_floppy; - mount_devfs(); - if (root_delay) { printk(KERN_INFO "Waiting %dsec before mounting root device...\n", root_delay); @@ -428,10 +426,8 @@ void __init prepare_namespace(void) mount_root(); out: - umount_devfs("/dev"); sys_mount(".", "/", NULL, MS_MOVE, NULL); sys_chroot("."); security_sb_post_mountroot(); - mount_devfs_fs (); } diff --git a/init/do_mounts.h b/init/do_mounts.h index e0a7ac9649e1..e7f2e7fa066e 100644 --- a/init/do_mounts.h +++ b/init/do_mounts.h @@ -1,6 +1,5 @@ #include <linux/config.h> #include <linux/kernel.h> -#include <linux/devfs_fs_kernel.h> #include <linux/init.h> #include <linux/syscalls.h> #include <linux/unistd.h> @@ -15,25 +14,12 @@ void mount_root(void); extern int root_mountflags; extern char *root_device_name; -#ifdef CONFIG_DEVFS_FS - -void mount_devfs(void); -void umount_devfs(char *path); -int create_dev(char *name, dev_t dev, char *devfs_name); - -#else - -static inline void mount_devfs(void) {} -static inline void umount_devfs(const char *path) {} - -static inline int create_dev(char *name, dev_t dev, char *devfs_name) +static inline int create_dev(char *name, dev_t dev) { sys_unlink(name); return sys_mknod(name, S_IFBLK|0600, new_encode_dev(dev)); } -#endif - #if BITS_PER_LONG == 32 static inline u32 bstat(char *name) { diff --git a/init/do_mounts_devfs.c b/init/do_mounts_devfs.c deleted file mode 100644 index cc526474690a..000000000000 --- a/init/do_mounts_devfs.c +++ /dev/null @@ -1,137 +0,0 @@ - -#include <linux/kernel.h> -#include <linux/dirent.h> -#include <linux/string.h> - -#include "do_mounts.h" - -void __init mount_devfs(void) -{ - sys_mount("devfs", "/dev", "devfs", 0, NULL); -} - -void __init umount_devfs(char *path) -{ - sys_umount(path, 0); -} - -/* - * If the dir will fit in *buf, return its length. If it won't fit, return - * zero. Return -ve on error. - */ -static int __init do_read_dir(int fd, void *buf, int len) -{ - long bytes, n; - char *p = buf; - sys_lseek(fd, 0, 0); - - for (bytes = 0; bytes < len; bytes += n) { - n = sys_getdents64(fd, (struct linux_dirent64 *)(p + bytes), - len - bytes); - if (n < 0) - return n; - if (n == 0) - return bytes; - } - return 0; -} - -/* - * Try to read all of a directory. Returns the contents at *p, which - * is kmalloced memory. Returns the number of bytes read at *len. Returns - * NULL on error. - */ -static void * __init read_dir(char *path, int *len) -{ - int size; - int fd = sys_open(path, 0, 0); - - *len = 0; - if (fd < 0) - return NULL; - - for (size = 1 << 9; size <= (PAGE_SIZE << MAX_ORDER); size <<= 1) { - void *p = kmalloc(size, GFP_KERNEL); - int n; - if (!p) - break; - n = do_read_dir(fd, p, size); - if (n > 0) { - sys_close(fd); - *len = n; - return p; - } - kfree(p); - if (n == -EINVAL) - continue; /* Try a larger buffer */ - if (n < 0) - break; - } - sys_close(fd); - return NULL; -} - -/* - * recursively scan <path>, looking for a device node of type <dev> - */ -static int __init find_in_devfs(char *path, unsigned dev) -{ - char *end = path + strlen(path); - int rest = path + 64 - end; - int size; - char *p = read_dir(path, &size); - char *s; - - if (!p) - return -1; - for (s = p; s < p + size; s += ((struct linux_dirent64 *)s)->d_reclen) { - struct linux_dirent64 *d = (struct linux_dirent64 *)s; - if (strlen(d->d_name) + 2 > rest) - continue; - switch (d->d_type) { - case DT_BLK: - sprintf(end, "/%s", d->d_name); - if (bstat(path) != dev) - break; - kfree(p); - return 0; - case DT_DIR: - if (strcmp(d->d_name, ".") == 0) - break; - if (strcmp(d->d_name, "..") == 0) - break; - sprintf(end, "/%s", d->d_name); - if (find_in_devfs(path, dev) < 0) - break; - kfree(p); - return 0; - } - } - kfree(p); - return -1; -} - -/* - * create a device node called <name> which points to - * <devfs_name> if possible, otherwise find a device node - * which matches <dev> and make <name> a symlink pointing to it. - */ -int __init create_dev(char *name, dev_t dev, char *devfs_name) -{ - char path[64]; - - sys_unlink(name); - if (devfs_name && devfs_name[0]) { - if (strncmp(devfs_name, "/dev/", 5) == 0) - devfs_name += 5; - sprintf(path, "/dev/%s", devfs_name); - if (sys_access(path, 0) == 0) - return sys_symlink(devfs_name, name); - } - if (!dev) - return -1; - strcpy(path, "/dev"); - if (find_in_devfs(path, new_encode_dev(dev)) < 0) - return -1; - return sys_symlink(path + 5, name); -} diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c index 405f9031af87..a06f037fa000 100644 --- a/init/do_mounts_initrd.c +++ b/init/do_mounts_initrd.c @@ -44,7 +44,7 @@ static void __init handle_initrd(void) int pid; real_root_dev = new_encode_dev(ROOT_DEV); - create_dev("/dev/root.old", Root_RAM0, NULL); + create_dev("/dev/root.old", Root_RAM0); /* mount initrd on rootfs' /root */ mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY); sys_mkdir("/old", 0700); @@ -54,7 +54,6 @@ static void __init handle_initrd(void) sys_chdir("/root"); sys_mount(".", "/", NULL, MS_MOVE, NULL); sys_chroot("."); - mount_devfs_fs (); current->flags |= PF_NOFREEZE; pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); @@ -71,7 +70,6 @@ static void __init handle_initrd(void) sys_chroot("."); sys_close(old_fd); sys_close(root_fd); - umount_devfs("/old/dev"); if (new_decode_dev(real_root_dev) == Root_RAM0) { sys_chdir("/old"); @@ -107,7 +105,7 @@ static void __init handle_initrd(void) int __init initrd_load(void) { if (mount_initrd) { - create_dev("/dev/ram", Root_RAM0, NULL); + create_dev("/dev/ram", Root_RAM0); /* * Load the initrd data into /dev/ram0. Execute it as initrd * unless /dev/ram0 is supposed to be our actual root device, diff --git a/init/do_mounts_md.c b/init/do_mounts_md.c index f6f36806f84a..2429e1bf8c60 100644 --- a/init/do_mounts_md.c +++ b/init/do_mounts_md.c @@ -125,19 +125,18 @@ static void __init md_setup_drive(void) int err = 0; char *devname; mdu_disk_info_t dinfo; - char name[16], devfs_name[16]; + char name[16]; minor = md_setup_args[ent].minor; partitioned = md_setup_args[ent].partitioned; devname = md_setup_args[ent].device_names; sprintf(name, "/dev/md%s%d", partitioned?"_d":"", minor); - sprintf(devfs_name, "/dev/md/%s%d", partitioned?"d":"", minor); if (partitioned) dev = MKDEV(mdp_major, minor << MdpMinorShift); else dev = MKDEV(MD_MAJOR, minor); - create_dev(name, dev, devfs_name); + create_dev(name, dev); for (i = 0; i < MD_SB_DISKS && devname != 0; i++) { char *p; char comp_name[64]; @@ -272,7 +271,7 @@ __setup("md=", md_setup); void __init md_run_setup(void) { - create_dev("/dev/md0", MKDEV(MD_MAJOR, 0), "md/0"); + create_dev("/dev/md0", MKDEV(MD_MAJOR, 0)); if (raid_noautodetect) printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n"); else { diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c index c2683fcd792d..ed652f40f075 100644 --- a/init/do_mounts_rd.c +++ b/init/do_mounts_rd.c @@ -262,8 +262,8 @@ int __init rd_load_disk(int n) { if (rd_prompt) change_floppy("root floppy disk to be loaded into RAM disk"); - create_dev("/dev/root", ROOT_DEV, root_device_name); - create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, n), NULL); + create_dev("/dev/root", ROOT_DEV); + create_dev("/dev/ram", MKDEV(RAMDISK_MAJOR, n)); return rd_load_image("/dev/root"); } diff --git a/init/main.c b/init/main.c index 0d57f6ccb63a..bce0eb7f4f8f 100644 --- a/init/main.c +++ b/init/main.c @@ -15,7 +15,6 @@ #include <linux/types.h> #include <linux/module.h> #include <linux/proc_fs.h> -#include <linux/devfs_fs_kernel.h> #include <linux/kernel.h> #include <linux/syscalls.h> #include <linux/string.h> diff --git a/kernel/audit.c b/kernel/audit.c index 82443fb433ef..d417ca1db79b 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -445,7 +445,7 @@ void audit_send_reply(int pid, int seq, int type, int done, int multi, * Check for appropriate CAP_AUDIT_ capabilities on incoming audit * control messages. */ -static int audit_netlink_ok(kernel_cap_t eff_cap, u16 msg_type) +static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type) { int err = 0; @@ -459,13 +459,13 @@ static int audit_netlink_ok(kernel_cap_t eff_cap, u16 msg_type) case AUDIT_DEL: case AUDIT_DEL_RULE: case AUDIT_SIGNAL_INFO: - if (!cap_raised(eff_cap, CAP_AUDIT_CONTROL)) + if (security_netlink_recv(skb, CAP_AUDIT_CONTROL)) err = -EPERM; break; case AUDIT_USER: case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG: case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2: - if (!cap_raised(eff_cap, CAP_AUDIT_WRITE)) + if (security_netlink_recv(skb, CAP_AUDIT_WRITE)) err = -EPERM; break; default: /* bad msg */ @@ -488,7 +488,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) char *ctx; u32 len; - err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type); + err = audit_netlink_ok(skb, msg_type); if (err) return err; diff --git a/mm/shmem.c b/mm/shmem.c index ea64c07cbe72..b14ff817d162 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -26,7 +26,6 @@ #include <linux/config.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/devfs_fs_kernel.h> #include <linux/fs.h> #include <linux/mm.h> #include <linux/mman.h> @@ -2252,9 +2251,7 @@ static int __init init_tmpfs(void) printk(KERN_ERR "Could not register tmpfs\n"); goto out2; } -#ifdef CONFIG_TMPFS - devfs_mk_dir("shm"); -#endif + shm_mnt = vfs_kern_mount(&tmpfs_fs_type, MS_NOUSER, tmpfs_fs_type.name, NULL); if (IS_ERR(shm_mnt)) { diff --git a/mm/tiny-shmem.c b/mm/tiny-shmem.c index f9d6a9cc91c4..5f2cbf0f153c 100644 --- a/mm/tiny-shmem.c +++ b/mm/tiny-shmem.c @@ -12,7 +12,6 @@ #include <linux/fs.h> #include <linux/init.h> -#include <linux/devfs_fs_kernel.h> #include <linux/vfs.h> #include <linux/mount.h> #include <linux/file.h> @@ -33,9 +32,6 @@ static int __init init_tmpfs(void) { BUG_ON(register_filesystem(&tmpfs_fs_type) != 0); -#ifdef CONFIG_TMPFS - devfs_mk_dir("shm"); -#endif shm_mnt = kern_mount(&tmpfs_fs_type); BUG_ON(IS_ERR(shm_mnt)); diff --git a/net/atm/Makefile b/net/atm/Makefile index d5818751f6ba..89656d6c0b90 100644 --- a/net/atm/Makefile +++ b/net/atm/Makefile @@ -2,7 +2,7 @@ # Makefile for the ATM Protocol Families. # -atm-y := addr.o pvc.o signaling.o svc.o ioctl.o common.o atm_misc.o raw.o resources.o +atm-y := addr.o pvc.o signaling.o svc.o ioctl.o common.o atm_misc.o raw.o resources.o atm_sysfs.o mpoa-objs := mpc.o mpoa_caches.o mpoa_proc.o obj-$(CONFIG_ATM) += atm.o diff --git a/net/atm/atm_sysfs.c b/net/atm/atm_sysfs.c new file mode 100644 index 000000000000..5df4b9a068bb --- /dev/null +++ b/net/atm/atm_sysfs.c @@ -0,0 +1,176 @@ +/* ATM driver model support. */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/kobject.h> +#include <linux/atmdev.h> +#include "common.h" +#include "resources.h" + +#define to_atm_dev(cldev) container_of(cldev, struct atm_dev, class_dev) + +static ssize_t show_type(struct class_device *cdev, char *buf) +{ + struct atm_dev *adev = to_atm_dev(cdev); + return sprintf(buf, "%s\n", adev->type); +} + +static ssize_t show_address(struct class_device *cdev, char *buf) +{ + char *pos = buf; + struct atm_dev *adev = to_atm_dev(cdev); + int i; + + for (i = 0; i < (ESI_LEN - 1); i++) + pos += sprintf(pos, "%02x:", adev->esi[i]); + pos += sprintf(pos, "%02x\n", adev->esi[i]); + + return pos - buf; +} + +static ssize_t show_atmaddress(struct class_device *cdev, char *buf) +{ + unsigned long flags; + char *pos = buf; + struct atm_dev *adev = to_atm_dev(cdev); + struct atm_dev_addr *aaddr; + int bin[] = { 1, 2, 10, 6, 1 }, *fmt = bin; + int i, j; + + spin_lock_irqsave(&adev->lock, flags); + list_for_each_entry(aaddr, &adev->local, entry) { + for(i = 0, j = 0; i < ATM_ESA_LEN; ++i, ++j) { + if (j == *fmt) { + pos += sprintf(pos, "."); + ++fmt; + j = 0; + } + pos += sprintf(pos, "%02x", aaddr->addr.sas_addr.prv[i]); + } + pos += sprintf(pos, "\n"); + } + spin_unlock_irqrestore(&adev->lock, flags); + + return pos - buf; +} + +static ssize_t show_carrier(struct class_device *cdev, char *buf) +{ + char *pos = buf; + struct atm_dev *adev = to_atm_dev(cdev); + + pos += sprintf(pos, "%d\n", + adev->signal == ATM_PHY_SIG_LOST ? 0 : 1); + + return pos - buf; +} + +static ssize_t show_link_rate(struct class_device *cdev, char *buf) +{ + char *pos = buf; + struct atm_dev *adev = to_atm_dev(cdev); + int link_rate; + + /* show the link rate, not the data rate */ + switch (adev->link_rate) { + case ATM_OC3_PCR: + link_rate = 155520000; + break; + case ATM_OC12_PCR: + link_rate = 622080000; + break; + case ATM_25_PCR: + link_rate = 25600000; + break; + default: + link_rate = adev->link_rate * 8 * 53; + } + pos += sprintf(pos, "%d\n", link_rate); + + return pos - buf; +} + +static CLASS_DEVICE_ATTR(address, S_IRUGO, show_address, NULL); +static CLASS_DEVICE_ATTR(atmaddress, S_IRUGO, show_atmaddress, NULL); +static CLASS_DEVICE_ATTR(carrier, S_IRUGO, show_carrier, NULL); +static CLASS_DEVICE_ATTR(type, S_IRUGO, show_type, NULL); +static CLASS_DEVICE_ATTR(link_rate, S_IRUGO, show_link_rate, NULL); + +static struct class_device_attribute *atm_attrs[] = { + &class_device_attr_atmaddress, + &class_device_attr_address, + &class_device_attr_carrier, + &class_device_attr_type, + &class_device_attr_link_rate, + NULL +}; + +static int atm_uevent(struct class_device *cdev, char **envp, int num_envp, char *buf, int size) +{ + struct atm_dev *adev; + int i = 0, len = 0; + + if (!cdev) + return -ENODEV; + + adev = to_atm_dev(cdev); + if (!adev) + return -ENODEV; + + if (add_uevent_var(envp, num_envp, &i, buf, size, &len, + "NAME=%s%d", adev->type, adev->number)) + return -ENOMEM; + + envp[i] = NULL; + return 0; +} + +static void atm_release(struct class_device *cdev) +{ + struct atm_dev *adev = to_atm_dev(cdev); + + kfree(adev); +} + +static struct class atm_class = { + .name = "atm", + .release = atm_release, + .uevent = atm_uevent, +}; + +int atm_register_sysfs(struct atm_dev *adev) +{ + struct class_device *cdev = &adev->class_dev; + int i, err; + + cdev->class = &atm_class; + class_set_devdata(cdev, adev); + + snprintf(cdev->class_id, BUS_ID_SIZE, "%s%d", adev->type, adev->number); + err = class_device_register(cdev); + if (err < 0) + return err; + + for (i = 0; atm_attrs[i]; i++) + class_device_create_file(cdev, atm_attrs[i]); + + return 0; +} + +void atm_unregister_sysfs(struct atm_dev *adev) +{ + struct class_device *cdev = &adev->class_dev; + + class_device_del(cdev); +} + +int __init atm_sysfs_init(void) +{ + return class_register(&atm_class); +} + +void __exit atm_sysfs_exit(void) +{ + class_unregister(&atm_class); +} diff --git a/net/atm/common.c b/net/atm/common.c index ae002220fa99..35ab1a61e831 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -791,8 +791,14 @@ static int __init atm_init(void) printk(KERN_ERR "atm_proc_init() failed with %d\n",error); goto out_atmsvc_exit; } + if ((error = atm_sysfs_init()) < 0) { + printk(KERN_ERR "atm_sysfs_init() failed with %d\n",error); + goto out_atmproc_exit; + } out: return error; +out_atmproc_exit: + atm_proc_exit(); out_atmsvc_exit: atmsvc_exit(); out_atmpvc_exit: @@ -805,6 +811,7 @@ out_unregister_vcc_proto: static void __exit atm_exit(void) { atm_proc_exit(); + atm_sysfs_exit(); atmsvc_exit(); atmpvc_exit(); proto_unregister(&vcc_proto); diff --git a/net/atm/common.h b/net/atm/common.h index 4887c317cefe..a422da7788fb 100644 --- a/net/atm/common.h +++ b/net/atm/common.h @@ -28,6 +28,8 @@ int atmpvc_init(void); void atmpvc_exit(void); int atmsvc_init(void); void atmsvc_exit(void); +int atm_sysfs_init(void); +void atm_sysfs_exit(void); #ifdef CONFIG_PROC_FS int atm_proc_init(void); diff --git a/net/atm/resources.c b/net/atm/resources.c index 18ac80698f83..534baf704056 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c @@ -114,14 +114,27 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, printk(KERN_ERR "atm_dev_register: " "atm_proc_dev_register failed for dev %s\n", type); - mutex_unlock(&atm_dev_mutex); - kfree(dev); - return NULL; + goto out_fail; + } + + if (atm_register_sysfs(dev) < 0) { + printk(KERN_ERR "atm_dev_register: " + "atm_register_sysfs failed for dev %s\n", + type); + atm_proc_dev_deregister(dev); + goto out_fail; } + list_add_tail(&dev->dev_list, &atm_devs); - mutex_unlock(&atm_dev_mutex); +out: + mutex_unlock(&atm_dev_mutex); return dev; + +out_fail: + kfree(dev); + dev = NULL; + goto out; } @@ -140,6 +153,7 @@ void atm_dev_deregister(struct atm_dev *dev) mutex_unlock(&atm_dev_mutex); atm_dev_release_vccs(dev); + atm_unregister_sysfs(dev); atm_proc_dev_deregister(dev); atm_dev_put(dev); diff --git a/net/atm/resources.h b/net/atm/resources.h index ac7222fee7a8..644989980c37 100644 --- a/net/atm/resources.h +++ b/net/atm/resources.h @@ -43,4 +43,6 @@ static inline void atm_proc_dev_deregister(struct atm_dev *dev) #endif /* CONFIG_PROC_FS */ +int atm_register_sysfs(struct atm_dev *adev); +void atm_unregister_sysfs(struct atm_dev *adev); #endif diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index b81fad893328..b105a715fa93 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -1021,13 +1021,12 @@ int rfcomm_init_ttys(void) rfcomm_tty_driver->owner = THIS_MODULE; rfcomm_tty_driver->driver_name = "rfcomm"; - rfcomm_tty_driver->devfs_name = "bluetooth/rfcomm/"; rfcomm_tty_driver->name = "rfcomm"; rfcomm_tty_driver->major = RFCOMM_TTY_MAJOR; rfcomm_tty_driver->minor_start = RFCOMM_TTY_MINOR; rfcomm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL; - rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; rfcomm_tty_driver->init_termios = tty_std_termios; rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; tty_set_operations(rfcomm_tty_driver, &rfcomm_ops); diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 2afdc7c0736c..f8dbcee80eba 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -184,6 +184,6 @@ void br_dev_setup(struct net_device *dev) dev->set_mac_address = br_set_mac_address; dev->priv_flags = IFF_EBRIDGE; - dev->features = NETIF_F_SG | NETIF_F_FRAGLIST - | NETIF_F_HIGHDMA | NETIF_F_TSO | NETIF_F_NO_CSUM; + dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | + NETIF_F_TSO | NETIF_F_NO_CSUM | NETIF_F_GSO_ROBUST; } diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 07956ecf545e..f55ef682ef84 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -392,7 +392,8 @@ void br_features_recompute(struct net_bridge *br) features &= feature; } - br->dev->features = features | checksum | NETIF_F_LLTX; + br->dev->features = features | checksum | NETIF_F_LLTX | + NETIF_F_GSO_ROBUST; } /* called with RTNL */ diff --git a/net/core/dev.c b/net/core/dev.c index f1c52cbd6ef7..08976b08df5b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1190,11 +1190,14 @@ out: /** * skb_gso_segment - Perform segmentation on skb. * @skb: buffer to segment - * @sg: whether scatter-gather is supported on the target. + * @features: features for the output path (see dev->features) * * This function segments the given skb and returns a list of segments. + * + * It may return NULL if the skb requires no segmentation. This is + * only possible when GSO is used for verifying header integrity. */ -struct sk_buff *skb_gso_segment(struct sk_buff *skb, int sg) +struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features) { struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); struct packet_type *ptype; @@ -1210,12 +1213,14 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, int sg) rcu_read_lock(); list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) { if (ptype->type == type && !ptype->dev && ptype->gso_segment) { - segs = ptype->gso_segment(skb, sg); + segs = ptype->gso_segment(skb, features); break; } } rcu_read_unlock(); + __skb_push(skb, skb->data - skb->mac.raw); + return segs; } @@ -1234,7 +1239,6 @@ void netdev_rx_csum_fault(struct net_device *dev) EXPORT_SYMBOL(netdev_rx_csum_fault); #endif -#ifdef CONFIG_HIGHMEM /* Actually, we should eliminate this check as soon as we know, that: * 1. IOMMU is present and allows to map all the memory. * 2. No high memory really exists on this machine. @@ -1242,6 +1246,7 @@ EXPORT_SYMBOL(netdev_rx_csum_fault); static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb) { +#ifdef CONFIG_HIGHMEM int i; if (dev->features & NETIF_F_HIGHDMA) @@ -1251,11 +1256,9 @@ static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb) if (PageHighMem(skb_shinfo(skb)->frags[i].page)) return 1; +#endif return 0; } -#else -#define illegal_highdma(dev, skb) (0) -#endif struct dev_gso_cb { void (*destructor)(struct sk_buff *skb); @@ -1291,9 +1294,15 @@ static int dev_gso_segment(struct sk_buff *skb) { struct net_device *dev = skb->dev; struct sk_buff *segs; + int features = dev->features & ~(illegal_highdma(dev, skb) ? + NETIF_F_SG : 0); + + segs = skb_gso_segment(skb, features); + + /* Verifying header integrity only. */ + if (!segs) + return 0; - segs = skb_gso_segment(skb, dev->features & NETIF_F_SG && - !illegal_highdma(dev, skb)); if (unlikely(IS_ERR(segs))) return PTR_ERR(segs); @@ -1310,13 +1319,17 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (netdev_nit) dev_queue_xmit_nit(skb, dev); - if (!netif_needs_gso(dev, skb)) - return dev->hard_start_xmit(skb, dev); + if (netif_needs_gso(dev, skb)) { + if (unlikely(dev_gso_segment(skb))) + goto out_kfree_skb; + if (skb->next) + goto gso; + } - if (unlikely(dev_gso_segment(skb))) - goto out_kfree_skb; + return dev->hard_start_xmit(skb, dev); } +gso: do { struct sk_buff *nskb = skb->next; int rc; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 3fcfa9c59e1f..f25aac17497a 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -663,7 +663,7 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) sz_idx = type>>2; kind = type&3; - if (kind != 2 && security_netlink_recv(skb)) { + if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN)) { *errp = -EPERM; return -1; } diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 6edbb90cbcec..a1c9ecf4f1e0 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -272,7 +272,7 @@ static void skb_clone_fraglist(struct sk_buff *skb) skb_get(list); } -void skb_release_data(struct sk_buff *skb) +static void skb_release_data(struct sk_buff *skb) { if (!skb->cloned || !atomic_sub_return(skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1, @@ -1848,13 +1848,13 @@ EXPORT_SYMBOL_GPL(skb_pull_rcsum); /** * skb_segment - Perform protocol segmentation on skb. * @skb: buffer to segment - * @sg: whether scatter-gather can be used for generated segments + * @features: features for the output path (see dev->features) * * This function performs segmentation on the given skb. It returns * the segment at the given position. It returns NULL if there are * no more segments to generate, or when an error is encountered. */ -struct sk_buff *skb_segment(struct sk_buff *skb, int sg) +struct sk_buff *skb_segment(struct sk_buff *skb, int features) { struct sk_buff *segs = NULL; struct sk_buff *tail = NULL; @@ -1863,6 +1863,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int sg) unsigned int offset = doffset; unsigned int headroom; unsigned int len; + int sg = features & NETIF_F_SG; int nfrags = skb_shinfo(skb)->nr_frags; int err = -ENOMEM; int i = 0; diff --git a/net/core/sock.c b/net/core/sock.c index 5d820c376653..204a8dec65cc 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -565,6 +565,13 @@ set_rcvbuf: ret = -ENONET; break; + case SO_PASSSEC: + if (valbool) + set_bit(SOCK_PASSSEC, &sock->flags); + else + clear_bit(SOCK_PASSSEC, &sock->flags); + break; + /* We implement the SO_SNDLOWAT etc to not be settable (1003.1g 5.3) */ default: @@ -723,6 +730,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname, v.val = sk->sk_state == TCP_LISTEN; break; + case SO_PASSSEC: + v.val = test_bit(SOCK_PASSSEC, &sock->flags) ? 1 : 0; + break; + case SO_PEERSEC: return security_socket_getpeersec_stream(sock, optval, optlen, len); diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c index 74133ecd7700..8b99bd33540d 100644 --- a/net/decnet/netfilter/dn_rtmsg.c +++ b/net/decnet/netfilter/dn_rtmsg.c @@ -107,7 +107,7 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb) if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) return; - if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) + if (security_netlink_recv(skb, CAP_NET_ADMIN)) RCV_SKB_FAIL(-EPERM); /* Eventually we might send routing messages too */ diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 461216b47948..8d157157bf8e 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1097,7 +1097,7 @@ int inet_sk_rebuild_header(struct sock *sk) EXPORT_SYMBOL(inet_sk_rebuild_header); -static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int sg) +static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features) { struct sk_buff *segs = ERR_PTR(-EINVAL); struct iphdr *iph; @@ -1126,10 +1126,10 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int sg) rcu_read_lock(); ops = rcu_dereference(inet_protos[proto]); if (ops && ops->gso_segment) - segs = ops->gso_segment(skb, sg); + segs = ops->gso_segment(skb, features); rcu_read_unlock(); - if (IS_ERR(segs)) + if (!segs || unlikely(IS_ERR(segs))) goto out; skb = segs; diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index e1d7f5fbc526..ef0b5aac5838 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -332,7 +332,7 @@ config IP_NF_MATCH_HASHLIMIT help This option adds a new iptables `hashlimit' match. - As opposed to `limit', this match dynamically crates a hash table + As opposed to `limit', this match dynamically creates a hash table of limit buckets, based on your selection of source/destination ip addresses and/or ports. diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index d0d19192026d..ad39bf640567 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -1120,7 +1120,8 @@ int arpt_register_table(struct arpt_table *table, return ret; } - if (xt_register_table(table, &bootstrap, newinfo) != 0) { + ret = xt_register_table(table, &bootstrap, newinfo); + if (ret != 0) { xt_free_table_info(newinfo); return ret; } diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index b93f0494362f..198ac36db861 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -457,11 +457,19 @@ dev_cmp(struct ipq_queue_entry *entry, unsigned long ifindex) if (entry->info->indev) if (entry->info->indev->ifindex == ifindex) return 1; - if (entry->info->outdev) if (entry->info->outdev->ifindex == ifindex) return 1; - +#ifdef CONFIG_BRIDGE_NETFILTER + if (entry->skb->nf_bridge) { + if (entry->skb->nf_bridge->physindev && + entry->skb->nf_bridge->physindev->ifindex == ifindex) + return 1; + if (entry->skb->nf_bridge->physoutdev && + entry->skb->nf_bridge->physoutdev->ifindex == ifindex) + return 1; + } +#endif return 0; } @@ -507,7 +515,7 @@ ipq_rcv_skb(struct sk_buff *skb) if (type <= IPQM_BASE) return; - if (security_netlink_recv(skb)) + if (security_netlink_recv(skb, CAP_NET_ADMIN)) RCV_SKB_FAIL(-EPERM); write_lock_bh(&queue_lock); diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 706c0025ec5e..7aaaf92efb59 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -2113,7 +2113,8 @@ int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl) return ret; } - if (xt_register_table(table, &bootstrap, newinfo) != 0) { + ret = xt_register_table(table, &bootstrap, newinfo); + if (ret != 0) { xt_free_table_info(newinfo); return ret; } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index c04176be7ed1..0336422c88a0 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2145,7 +2145,7 @@ int compat_tcp_getsockopt(struct sock *sk, int level, int optname, EXPORT_SYMBOL(compat_tcp_getsockopt); #endif -struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg) +struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features) { struct sk_buff *segs = ERR_PTR(-EINVAL); struct tcphdr *th; @@ -2166,10 +2166,14 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg) if (!pskb_may_pull(skb, thlen)) goto out; + segs = NULL; + if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) + goto out; + oldlen = (u16)~skb->len; __skb_pull(skb, thlen); - segs = skb_segment(skb, sg); + segs = skb_segment(skb, features); if (IS_ERR(segs)) goto out; diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index c148c1081880..b56399c7cc12 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c @@ -26,7 +26,10 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, const struct tcp_sock *tp = tcp_sk(sk); struct tcp_info *info = _info; - r->idiag_rqueue = tp->rcv_nxt - tp->copied_seq; + if (sk->sk_state == TCP_LISTEN) + r->idiag_rqueue = sk->sk_ack_backlog; + else + r->idiag_rqueue = tp->rcv_nxt - tp->copied_seq; r->idiag_wqueue = tp->write_seq - tp->snd_una; if (info != NULL) tcp_get_info(sk, info); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 94fe5b1f9dcb..7fa0b4a8a389 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4178,8 +4178,6 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, */ TCP_ECN_rcv_synack(tp, th); - if (tp->ecn_flags&TCP_ECN_OK) - sock_set_flag(sk, SOCK_NO_LARGESEND); tp->snd_wl1 = TCP_SKB_CB(skb)->seq; tcp_ack(sk, skb, FLAG_SLOWPATH); @@ -4322,8 +4320,6 @@ discard: tp->max_window = tp->snd_wnd; TCP_ECN_rcv_syn(tp, th); - if (tp->ecn_flags&TCP_ECN_OK) - sock_set_flag(sk, SOCK_NO_LARGESEND); tcp_mtup_init(sk); tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 25ecc6e2478b..4c6ef47eb1c3 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1726,7 +1726,8 @@ static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i) sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX " "%08X %5d %8d %lu %d %p %u %u %u %u %d", i, src, srcp, dest, destp, sp->sk_state, - tp->write_seq - tp->snd_una, tp->rcv_nxt - tp->copied_seq, + tp->write_seq - tp->snd_una, + (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq), timer_active, jiffies_to_clock_t(timer_expires - jiffies), icsk->icsk_retransmits, diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 2b9b7f6c7f7c..54b2ef7d3efe 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -440,8 +440,6 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, newicsk->icsk_ack.last_seg_size = skb->len - newtp->tcp_header_len; newtp->rx_opt.mss_clamp = req->mss; TCP_ECN_openreq_child(newtp, req); - if (newtp->ecn_flags&TCP_ECN_OK) - sock_set_flag(newsk, SOCK_NO_LARGESEND); TCP_INC_STATS_BH(TCP_MIB_PASSIVEOPENS); } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index bdd71db8bf90..5a7cb4a9c867 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2044,8 +2044,6 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, memset(th, 0, sizeof(struct tcphdr)); th->syn = 1; th->ack = 1; - if (dst->dev->features&NETIF_F_TSO) - ireq->ecn_ok = 0; TCP_ECN_make_synack(req, th); th->source = inet_sk(sk)->sport; th->dest = ireq->rmt_port; diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index b4b7d441af25..968a14be0d05 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -505,7 +505,7 @@ ipq_rcv_skb(struct sk_buff *skb) if (type <= IPQM_BASE) return; - if (security_netlink_recv(skb)) + if (security_netlink_recv(skb, CAP_NET_ADMIN)) RCV_SKB_FAIL(-EPERM); write_lock_bh(&queue_lock); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 2e72f89a7019..0b5bd5587a3e 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1281,7 +1281,8 @@ int ip6t_register_table(struct xt_table *table, return ret; } - if (xt_register_table(table, &bootstrap, newinfo) != 0) { + ret = xt_register_table(table, &bootstrap, newinfo); + if (ret != 0) { xt_free_table_info(newinfo); return ret; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index a50eb306e9e2..b36d5b2e7c30 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1469,7 +1469,8 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], destp, sp->sk_state, - tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq, + tp->write_seq-tp->snd_una, + (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq), timer_active, jiffies_to_clock_t(timer_expires - jiffies), icsk->icsk_retransmits, diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 6f20b4206e08..b592c4bc3331 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -124,7 +124,6 @@ static int __init ircomm_tty_init(void) driver->owner = THIS_MODULE; driver->driver_name = "ircomm"; driver->name = "ircomm"; - driver->devfs_name = "ircomm"; driver->major = IRCOMM_TTY_MAJOR; driver->minor_start = IRCOMM_TTY_MINOR; driver->type = TTY_DRIVER_TYPE_SERIAL; diff --git a/net/irda/irlan/irlan_client.c b/net/irda/irlan/irlan_client.c index f8e6cb0db04b..95cf1234ea17 100644 --- a/net/irda/irlan/irlan_client.c +++ b/net/irda/irlan/irlan_client.c @@ -173,13 +173,14 @@ void irlan_client_discovery_indication(discinfo_t *discovery, rcu_read_lock(); self = irlan_get_any(); if (self) { - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); + IRDA_ASSERT(self->magic == IRLAN_MAGIC, goto out;); IRDA_DEBUG(1, "%s(), Found instance (%08x)!\n", __FUNCTION__ , daddr); irlan_client_wakeup(self, saddr, daddr); } +IRDA_ASSERT_LABEL(out:) rcu_read_unlock(); } diff --git a/net/irda/irnet/irnet.h b/net/irda/irnet/irnet.h index e4fe1e80029c..ad6caba02a7b 100644 --- a/net/irda/irnet/irnet.h +++ b/net/irda/irnet/irnet.h @@ -244,7 +244,6 @@ #include <linux/skbuff.h> #include <linux/tty.h> #include <linux/proc_fs.h> -#include <linux/devfs_fs_kernel.h> #include <linux/netdevice.h> #include <linux/miscdevice.h> #include <linux/poll.h> diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index b1622b7de1cf..42a178aa30f9 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -411,7 +411,10 @@ config NETFILTER_XT_MATCH_STATISTIC tristate '"statistic" match support' depends on NETFILTER_XTABLES help - statistic module + This option adds a `statistic' match, which allows you to match + on packets periodically or randomly with a given percentage. + + To compile it as a module, choose M here. If unsure, say N. config NETFILTER_XT_MATCH_STRING tristate '"string" match support' diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index b8c7c567c9df..af4845971f70 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -29,6 +29,7 @@ #include <linux/errno.h> #include <linux/netlink.h> #include <linux/spinlock.h> +#include <linux/interrupt.h> #include <linux/notifier.h> #include <linux/netfilter.h> diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 0c6da496cfa9..0839b701b930 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -28,6 +28,8 @@ #include <linux/sctp.h> #include <linux/string.h> #include <linux/seq_file.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> #include <net/netfilter/nf_conntrack.h> #include <net/netfilter/nf_conntrack_protocol.h> diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index b88e82a1a987..ec9f0efea6bb 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -229,7 +229,7 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, NFNL_SUBSYS_ID(nlh->nlmsg_type), NFNL_MSG_TYPE(nlh->nlmsg_type)); - if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) { + if (security_netlink_recv(skb, CAP_NET_ADMIN)) { DEBUGP("missing CAP_NET_ADMIN\n"); *errp = -EPERM; return -1; diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 86a4ac33de34..49ef41e34c48 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -680,11 +680,19 @@ dev_cmp(struct nfqnl_queue_entry *entry, unsigned long ifindex) if (entinf->indev) if (entinf->indev->ifindex == ifindex) return 1; - if (entinf->outdev) if (entinf->outdev->ifindex == ifindex) return 1; - +#ifdef CONFIG_BRIDGE_NETFILTER + if (entry->skb->nf_bridge) { + if (entry->skb->nf_bridge->physindev && + entry->skb->nf_bridge->physindev->ifindex == ifindex) + return 1; + if (entry->skb->nf_bridge->physoutdev && + entry->skb->nf_bridge->physoutdev->ifindex == ifindex) + return 1; + } +#endif return 0; } diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c index 9316c753692f..843383e01d41 100644 --- a/net/netfilter/xt_sctp.c +++ b/net/netfilter/xt_sctp.c @@ -151,7 +151,7 @@ match(const struct sk_buff *skb, && SCCHECK(((ntohs(sh->dest) >= info->dpts[0]) && (ntohs(sh->dest) <= info->dpts[1])), XT_SCTP_DEST_PORTS, info->flags, info->invflags) - && SCCHECK(match_packet(skb, protoff, + && SCCHECK(match_packet(skb, protoff + sizeof (sctp_sctphdr_t), info->chunkmap, info->chunk_match_type, info->flag_info, info->flag_count, hotdrop), diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c index 1b61dac9c873..a9a63aa68936 100644 --- a/net/netfilter/xt_tcpudp.c +++ b/net/netfilter/xt_tcpudp.c @@ -260,7 +260,7 @@ static int __init xt_tcpudp_init(void) return ret; out_unreg_udp: - xt_unregister_match(&tcp_matchstruct); + xt_unregister_match(&udp_matchstruct); out_unreg_tcp6: xt_unregister_match(&tcp6_matchstruct); out_unreg_tcp: diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index f329b72578f5..edf084becd5e 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -320,7 +320,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, goto errout; } - if ((ops->flags & GENL_ADMIN_PERM) && security_netlink_recv(skb)) { + if ((ops->flags & GENL_ADMIN_PERM) && security_netlink_recv(skb, CAP_NET_ADMIN)) { err = -EPERM; goto errout; } diff --git a/net/tipc/core.c b/net/tipc/core.c index 5003acb15919..0539a8362858 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -191,7 +191,8 @@ static int __init tipc_init(void) int res; tipc_log_reinit(CONFIG_TIPC_LOG); - info("Activated (compiled " __DATE__ " " __TIME__ ")\n"); + info("Activated (version " TIPC_MOD_VER + " compiled " __DATE__ " " __TIME__ ")\n"); tipc_own_addr = 0; tipc_remote_management = 1; diff --git a/net/tipc/link.c b/net/tipc/link.c index d64658053746..c6831c75cfa4 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -2,7 +2,7 @@ * net/tipc/link.c: TIPC link code * * Copyright (c) 1996-2006, Ericsson AB - * Copyright (c) 2004-2005, Wind River Systems + * Copyright (c) 2004-2006, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -988,17 +988,18 @@ static int link_bundle_buf(struct link *l_ptr, struct tipc_msg *bundler_msg = buf_msg(bundler); struct tipc_msg *msg = buf_msg(buf); u32 size = msg_size(msg); - u32 to_pos = align(msg_size(bundler_msg)); - u32 rest = link_max_pkt(l_ptr) - to_pos; + u32 bundle_size = msg_size(bundler_msg); + u32 to_pos = align(bundle_size); + u32 pad = to_pos - bundle_size; if (msg_user(bundler_msg) != MSG_BUNDLER) return 0; if (msg_type(bundler_msg) != OPEN_MSG) return 0; - if (rest < align(size)) + if (skb_tailroom(bundler) < (pad + size)) return 0; - skb_put(bundler, (to_pos - msg_size(bundler_msg)) + size); + skb_put(bundler, pad + size); memcpy(bundler->data + to_pos, buf->data, size); msg_set_size(bundler_msg, to_pos + size); msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1); diff --git a/net/tipc/node.c b/net/tipc/node.c index 861322b935da..fc6d09630ccd 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -2,7 +2,7 @@ * net/tipc/node.c: TIPC node management routines * * Copyright (c) 2000-2006, Ericsson AB - * Copyright (c) 2005, Wind River Systems + * Copyright (c) 2005-2006, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -592,6 +592,7 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space) struct sk_buff *buf; struct node *n_ptr; struct tipc_node_info node_info; + u32 payload_size; if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); @@ -608,8 +609,11 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space) /* For now, get space for all other nodes (will need to modify this when slave nodes are supported */ - buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(node_info)) * - (tipc_max_nodes - 1)); + payload_size = TLV_SPACE(sizeof(node_info)) * (tipc_max_nodes - 1); + if (payload_size > 32768u) + return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED + " (too many nodes)"); + buf = tipc_cfg_reply_alloc(payload_size); if (!buf) return NULL; @@ -633,6 +637,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space) struct sk_buff *buf; struct node *n_ptr; struct tipc_link_info link_info; + u32 payload_size; if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); @@ -645,12 +650,15 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space) if (!tipc_nodes) return tipc_cfg_reply_none(); - - /* For now, get space for 2 links to all other nodes + bcast link - (will need to modify this when slave nodes are supported */ - - buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(link_info)) * - (2 * (tipc_max_nodes - 1) + 1)); + + /* Get space for all unicast links + multicast link */ + + payload_size = TLV_SPACE(sizeof(link_info)) * + (tipc_net.zones[tipc_zone(tipc_own_addr)]->links + 1); + if (payload_size > 32768u) + return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED + " (too many links)"); + buf = tipc_cfg_reply_alloc(payload_size); if (!buf) return NULL; diff --git a/net/tipc/zone.h b/net/tipc/zone.h index 267999c5a240..5ab3d08602e2 100644 --- a/net/tipc/zone.h +++ b/net/tipc/zone.h @@ -2,7 +2,7 @@ * net/tipc/zone.h: Include file for TIPC zone management routines * * Copyright (c) 2000-2006, Ericsson AB - * Copyright (c) 2005, Wind River Systems + * Copyright (c) 2005-2006, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,7 +45,7 @@ * struct _zone - TIPC zone structure * @addr: network address of zone * @clusters: array of pointers to all clusters within zone - * @links: (used for inter-zone communication) + * @links: number of (unicast) links to zone */ struct _zone { diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index d901465ce013..fd11d4048b52 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -128,6 +128,30 @@ static atomic_t unix_nr_socks = ATOMIC_INIT(0); #define UNIX_ABSTRACT(sk) (unix_sk(sk)->addr->hash != UNIX_HASH_SIZE) +#ifdef CONFIG_SECURITY_NETWORK +static void unix_get_peersec_dgram(struct sk_buff *skb) +{ + int err; + + err = security_socket_getpeersec_dgram(skb, UNIXSECDATA(skb), + UNIXSECLEN(skb)); + if (err) + *(UNIXSECDATA(skb)) = NULL; +} + +static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) +{ + scm->secdata = *UNIXSECDATA(skb); + scm->seclen = *UNIXSECLEN(skb); +} +#else +static void unix_get_peersec_dgram(struct sk_buff *skb) +{ } + +static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) +{ } +#endif /* CONFIG_SECURITY_NETWORK */ + /* * SMP locking strategy: * hash table is protected with spinlock unix_table_lock @@ -1291,6 +1315,8 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, if (siocb->scm->fp) unix_attach_fds(siocb->scm, skb); + unix_get_peersec_dgram(skb); + skb->h.raw = skb->data; err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); if (err) @@ -1570,6 +1596,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, memset(&tmp_scm, 0, sizeof(tmp_scm)); } siocb->scm->creds = *UNIXCREDS(skb); + unix_set_secdata(siocb->scm, skb); if (!(flags & MSG_PEEK)) { diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 17b29ec3c417..43f00fc28a3d 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1164,8 +1164,6 @@ int xfrm_state_mtu(struct xfrm_state *x, int mtu) return res; } -EXPORT_SYMBOL(xfrm_state_mtu); - int xfrm_init_state(struct xfrm_state *x) { struct xfrm_state_afinfo *afinfo; diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index c21dc26141ea..3e6a722d072e 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1435,7 +1435,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err link = &xfrm_dispatch[type]; /* All operations require privileges, even GET */ - if (security_netlink_recv(skb)) { + if (security_netlink_recv(skb, CAP_NET_ADMIN)) { *errp = -EPERM; return -1; } diff --git a/security/commoncap.c b/security/commoncap.c index 841eb4e5c62b..57673ee07ceb 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -33,9 +33,9 @@ int cap_netlink_send(struct sock *sk, struct sk_buff *skb) EXPORT_SYMBOL(cap_netlink_send); -int cap_netlink_recv(struct sk_buff *skb) +int cap_netlink_recv(struct sk_buff *skb, int cap) { - if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) + if (!cap_raised(NETLINK_CB(skb).eff_cap, cap)) return -EPERM; return 0; } diff --git a/security/dummy.c b/security/dummy.c index 310fcdf7b749..913540808577 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -675,9 +675,9 @@ static int dummy_netlink_send (struct sock *sk, struct sk_buff *skb) return 0; } -static int dummy_netlink_recv (struct sk_buff *skb) +static int dummy_netlink_recv (struct sk_buff *skb, int cap) { - if (!cap_raised (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN)) + if (!cap_raised (NETLINK_CB (skb).eff_cap, cap)) return -EPERM; return 0; } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 28832e689800..b85afcf38527 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -69,6 +69,7 @@ #include <linux/sysctl.h> #include <linux/audit.h> #include <linux/string.h> +#include <linux/selinux.h> #include "avc.h" #include "objsec.h" @@ -3420,7 +3421,13 @@ out: static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, u32 *seclen) { int err = 0; - u32 peer_sid = selinux_socket_getpeer_dgram(skb); + u32 peer_sid; + + if (skb->sk->sk_family == PF_UNIX) + selinux_get_inode_sid(SOCK_INODE(skb->sk->sk_socket), + &peer_sid); + else + peer_sid = selinux_socket_getpeer_dgram(skb); if (peer_sid == SECSID_NULL) return -EINVAL; @@ -3432,8 +3439,6 @@ static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, return 0; } - - static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) { return sk_alloc_security(sk, family, priority); @@ -3641,32 +3646,32 @@ static unsigned int selinux_ipv6_postroute_last(unsigned int hooknum, static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) { - struct task_security_struct *tsec; - struct av_decision avd; int err; err = secondary_ops->netlink_send(sk, skb); if (err) return err; - tsec = current->security; - - avd.allowed = 0; - avc_has_perm_noaudit(tsec->sid, tsec->sid, - SECCLASS_CAPABILITY, ~0, &avd); - cap_mask(NETLINK_CB(skb).eff_cap, avd.allowed); - if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS) err = selinux_nlmsg_perm(sk, skb); return err; } -static int selinux_netlink_recv(struct sk_buff *skb) +static int selinux_netlink_recv(struct sk_buff *skb, int capability) { - if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) - return -EPERM; - return 0; + int err; + struct avc_audit_data ad; + + err = secondary_ops->netlink_recv(skb, capability); + if (err) + return err; + + AVC_AUDIT_DATA_INIT(&ad, CAP); + ad.u.cap = capability; + + return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid, + SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad); } static int ipc_alloc_security(struct task_struct *task, diff --git a/sound/core/info.c b/sound/core/info.c index 10c1772bf3ea..340332c6d973 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -29,7 +29,6 @@ #include <sound/info.h> #include <sound/version.h> #include <linux/proc_fs.h> -#include <linux/devfs_fs_kernel.h> #include <linux/mutex.h> #include <stdarg.h> diff --git a/sound/core/sound.c b/sound/core/sound.c index cd862728346c..264f2efd1af8 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -32,7 +32,6 @@ #include <sound/control.h> #include <sound/initval.h> #include <linux/kmod.h> -#include <linux/devfs_fs_kernel.h> #include <linux/mutex.h> #define SNDRV_OS_MINORS 256 @@ -42,7 +41,6 @@ int snd_major; EXPORT_SYMBOL(snd_major); static int cards_limit = 1; -static int device_mode = S_IFCHR | S_IRUGO | S_IWUGO; MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards."); @@ -51,10 +49,6 @@ module_param(major, int, 0444); MODULE_PARM_DESC(major, "Major # for sound driver."); module_param(cards_limit, int, 0444); MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards."); -#ifdef CONFIG_DEVFS_FS -module_param(device_mode, int, 0444); -MODULE_PARM_DESC(device_mode, "Device file permission mask for devfs."); -#endif MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR); /* this one holds the actual max. card number currently available. @@ -273,8 +267,6 @@ int snd_register_device(int type, struct snd_card *card, int dev, return minor; } snd_minors[minor] = preg; - if (type != SNDRV_DEVICE_TYPE_CONTROL || preg->card >= cards_limit) - devfs_mk_cdev(MKDEV(major, minor), S_IFCHR | device_mode, "snd/%s", name); if (card) device = card->dev; class_device_create(sound_class, NULL, MKDEV(major, minor), device, "%s", name); @@ -314,9 +306,6 @@ int snd_unregister_device(int type, struct snd_card *card, int dev) return -EINVAL; } - if (mptr->type != SNDRV_DEVICE_TYPE_CONTROL || - mptr->card >= cards_limit) /* created in sound.c */ - devfs_remove("snd/%s", mptr->name); class_device_destroy(sound_class, MKDEV(major, minor)); snd_minors[minor] = NULL; @@ -411,24 +400,17 @@ int __exit snd_minor_info_done(void) static int __init alsa_sound_init(void) { - short controlnum; - snd_major = major; snd_ecards_limit = cards_limit; - devfs_mk_dir("snd"); if (register_chrdev(major, "alsa", &snd_fops)) { snd_printk(KERN_ERR "unable to register native major device number %d\n", major); - devfs_remove("snd"); return -EIO; } if (snd_info_init() < 0) { unregister_chrdev(major, "alsa"); - devfs_remove("snd"); return -ENOMEM; } snd_info_minor_register(); - for (controlnum = 0; controlnum < cards_limit; controlnum++) - devfs_mk_cdev(MKDEV(major, controlnum<<5), S_IFCHR | device_mode, "snd/controlC%d", controlnum); #ifndef MODULE printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"); #endif @@ -437,16 +419,10 @@ static int __init alsa_sound_init(void) static void __exit alsa_sound_exit(void) { - short controlnum; - - for (controlnum = 0; controlnum < cards_limit; controlnum++) - devfs_remove("snd/controlC%d", controlnum); - snd_info_minor_unregister(); snd_info_done(); if (unregister_chrdev(major, "alsa") != 0) snd_printk(KERN_ERR "unable to unregister major device number %d\n", major); - devfs_remove("snd"); } module_init(alsa_sound_init) diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index d33bb464f70e..a33289948902 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c @@ -38,7 +38,6 @@ #include <linux/wait.h> #include <linux/slab.h> #include <linux/ioport.h> -#include <linux/devfs_fs_kernel.h> #include <linux/major.h> #include <linux/delay.h> #include <linux/proc_fs.h> @@ -564,9 +563,6 @@ static int __init oss_init(void) sound_dmap_flag = (dmabuf > 0 ? 1 : 0); for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++) { - devfs_mk_cdev(MKDEV(SOUND_MAJOR, dev_list[i].minor), - S_IFCHR | dev_list[i].mode, - "sound/%s", dev_list[i].name); class_device_create(sound_class, NULL, MKDEV(SOUND_MAJOR, dev_list[i].minor), NULL, "%s", dev_list[i].name); @@ -574,15 +570,10 @@ static int __init oss_init(void) if (!dev_list[i].num) continue; - for (j = 1; j < *dev_list[i].num; j++) { - devfs_mk_cdev(MKDEV(SOUND_MAJOR, - dev_list[i].minor + (j*0x10)), - S_IFCHR | dev_list[i].mode, - "sound/%s%d", dev_list[i].name, j); + for (j = 1; j < *dev_list[i].num; j++) class_device_create(sound_class, NULL, MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10)), NULL, "%s%d", dev_list[i].name, j); - } } if (sound_nblocks >= 1024) @@ -596,14 +587,11 @@ static void __exit oss_cleanup(void) int i, j; for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++) { - devfs_remove("sound/%s", dev_list[i].name); class_device_destroy(sound_class, MKDEV(SOUND_MAJOR, dev_list[i].minor)); if (!dev_list[i].num) continue; - for (j = 1; j < *dev_list[i].num; j++) { - devfs_remove("sound/%s%d", dev_list[i].name, j); + for (j = 1; j < *dev_list[i].num; j++) class_device_destroy(sound_class, MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10))); - } } unregister_sound_special(1); diff --git a/sound/sound_core.c b/sound/sound_core.c index 6f849720aef3..7535ec821dcf 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c @@ -44,7 +44,6 @@ #include <linux/sound.h> #include <linux/major.h> #include <linux/kmod.h> -#include <linux/devfs_fs_kernel.h> #include <linux/device.h> #define SOUND_STEP 16 @@ -172,8 +171,6 @@ static int sound_insert_unit(struct sound_unit **list, const struct file_operati else sprintf(s->name, "sound/%s%d", name, r / SOUND_STEP); - devfs_mk_cdev(MKDEV(SOUND_MAJOR, s->unit_minor), - S_IFCHR | mode, s->name); class_device_create(sound_class, NULL, MKDEV(SOUND_MAJOR, s->unit_minor), dev, s->name+6); return r; @@ -197,7 +194,6 @@ static void sound_remove_unit(struct sound_unit **list, int unit) p = __sound_remove_unit(list, unit); spin_unlock(&sound_loader_lock); if (p) { - devfs_remove(p->name); class_device_destroy(sound_class, MKDEV(SOUND_MAJOR, p->unit_minor)); kfree(p); } @@ -570,7 +566,6 @@ static void __exit cleanup_soundcore(void) /* We have nothing to really do here - we know the lists must be empty */ unregister_chrdev(SOUND_MAJOR, "sound"); - devfs_remove("sound"); class_destroy(sound_class); } @@ -580,7 +575,6 @@ static int __init init_soundcore(void) printk(KERN_ERR "soundcore: sound device already in use.\n"); return -EBUSY; } - devfs_mk_dir ("sound"); sound_class = class_create(THIS_MODULE, "sound"); if (IS_ERR(sound_class)) return PTR_ERR(sound_class); |